]> Pileus Git - ~andy/gtk/blob - gtk/gtktreeview.c
Merge branch 'client-side-windows'
[~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   if (tree_view->priv->search_entry_avoid_unhandled_binding)
5381     {
5382       tree_view->priv->search_entry_avoid_unhandled_binding = FALSE;
5383       return FALSE;
5384     }
5385
5386   /* We pass the event to the search_entry.  If its text changes, then we start
5387    * the typeahead find capabilities. */
5388   if (GTK_WIDGET_HAS_FOCUS (tree_view)
5389       && tree_view->priv->enable_search
5390       && !tree_view->priv->search_custom_entry_set)
5391     {
5392       GdkEvent *new_event;
5393       char *old_text;
5394       const char *new_text;
5395       gboolean retval;
5396       GdkScreen *screen;
5397       gboolean text_modified;
5398       gulong popup_menu_id;
5399
5400       gtk_tree_view_ensure_interactive_directory (tree_view);
5401
5402       /* Make a copy of the current text */
5403       old_text = g_strdup (gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry)));
5404       new_event = gdk_event_copy ((GdkEvent *) event);
5405       g_object_unref (((GdkEventKey *) new_event)->window);
5406       ((GdkEventKey *) new_event)->window = g_object_ref (tree_view->priv->search_window->window);
5407       gtk_widget_realize (tree_view->priv->search_window);
5408
5409       popup_menu_id = g_signal_connect (tree_view->priv->search_entry, 
5410                                         "popup-menu", G_CALLBACK (gtk_true),
5411                                         NULL);
5412
5413       /* Move the entry off screen */
5414       screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
5415       gtk_window_move (GTK_WINDOW (tree_view->priv->search_window),
5416                        gdk_screen_get_width (screen) + 1,
5417                        gdk_screen_get_height (screen) + 1);
5418       gtk_widget_show (tree_view->priv->search_window);
5419
5420       /* Send the event to the window.  If the preedit_changed signal is emitted
5421        * during this event, we will set priv->imcontext_changed  */
5422       tree_view->priv->imcontext_changed = FALSE;
5423       retval = gtk_widget_event (tree_view->priv->search_window, new_event);
5424       gdk_event_free (new_event);
5425       gtk_widget_hide (tree_view->priv->search_window);
5426
5427       g_signal_handler_disconnect (tree_view->priv->search_entry, 
5428                                    popup_menu_id);
5429
5430       /* We check to make sure that the entry tried to handle the text, and that
5431        * the text has changed.
5432        */
5433       new_text = gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry));
5434       text_modified = strcmp (old_text, new_text) != 0;
5435       g_free (old_text);
5436       if (tree_view->priv->imcontext_changed ||    /* we're in a preedit */
5437           (retval && text_modified))               /* ...or the text was modified */
5438         {
5439           if (gtk_tree_view_real_start_interactive_search (tree_view, FALSE))
5440             {
5441               gtk_widget_grab_focus (GTK_WIDGET (tree_view));
5442               return TRUE;
5443             }
5444           else
5445             {
5446               gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
5447               return FALSE;
5448             }
5449         }
5450     }
5451
5452   return FALSE;
5453 }
5454
5455 static gboolean
5456 gtk_tree_view_key_release (GtkWidget   *widget,
5457                            GdkEventKey *event)
5458 {
5459   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
5460
5461   if (tree_view->priv->rubber_band_status)
5462     return TRUE;
5463
5464   return GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->key_release_event (widget, event);
5465 }
5466
5467 /* FIXME Is this function necessary? Can I get an enter_notify event
5468  * w/o either an expose event or a mouse motion event?
5469  */
5470 static gboolean
5471 gtk_tree_view_enter_notify (GtkWidget        *widget,
5472                             GdkEventCrossing *event)
5473 {
5474   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
5475   GtkRBTree *tree;
5476   GtkRBNode *node;
5477   gint new_y;
5478
5479   /* Sanity check it */
5480   if (event->window != tree_view->priv->bin_window)
5481     return FALSE;
5482
5483   if (tree_view->priv->tree == NULL)
5484     return FALSE;
5485
5486   /* find the node internally */
5487   new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
5488   if (new_y < 0)
5489     new_y = 0;
5490   _gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
5491
5492   if ((tree_view->priv->button_pressed_node == NULL) ||
5493       (tree_view->priv->button_pressed_node == node))
5494     prelight_or_select (tree_view, tree, node, event->x, event->y);
5495
5496   return TRUE;
5497 }
5498
5499 static gboolean
5500 gtk_tree_view_leave_notify (GtkWidget        *widget,
5501                             GdkEventCrossing *event)
5502 {
5503   GtkTreeView *tree_view;
5504
5505   if (event->mode == GDK_CROSSING_GRAB)
5506     return TRUE;
5507
5508   tree_view = GTK_TREE_VIEW (widget);
5509
5510   if (tree_view->priv->prelight_node)
5511     _gtk_tree_view_queue_draw_node (tree_view,
5512                                    tree_view->priv->prelight_tree,
5513                                    tree_view->priv->prelight_node,
5514                                    NULL);
5515
5516   prelight_or_select (tree_view,
5517                       NULL, NULL,
5518                       -1000, -1000); /* coords not possibly over an arrow */
5519
5520   return TRUE;
5521 }
5522
5523
5524 static gint
5525 gtk_tree_view_focus_out (GtkWidget     *widget,
5526                          GdkEventFocus *event)
5527 {
5528   GtkTreeView *tree_view;
5529
5530   tree_view = GTK_TREE_VIEW (widget);
5531
5532   gtk_widget_queue_draw (widget);
5533
5534   /* destroy interactive search dialog */
5535   if (tree_view->priv->search_window)
5536     gtk_tree_view_search_dialog_hide (tree_view->priv->search_window, tree_view);
5537
5538   return FALSE;
5539 }
5540
5541
5542 /* Incremental Reflow
5543  */
5544
5545 static void
5546 gtk_tree_view_node_queue_redraw (GtkTreeView *tree_view,
5547                                  GtkRBTree   *tree,
5548                                  GtkRBNode   *node)
5549 {
5550   gint y;
5551
5552   y = _gtk_rbtree_node_find_offset (tree, node)
5553     - tree_view->priv->vadjustment->value
5554     + TREE_VIEW_HEADER_HEIGHT (tree_view);
5555
5556   gtk_widget_queue_draw_area (GTK_WIDGET (tree_view),
5557                               0, y,
5558                               GTK_WIDGET (tree_view)->allocation.width,
5559                               GTK_RBNODE_GET_HEIGHT (node));
5560 }
5561
5562 static gboolean
5563 node_is_visible (GtkTreeView *tree_view,
5564                  GtkRBTree   *tree,
5565                  GtkRBNode   *node)
5566 {
5567   int y;
5568   int height;
5569
5570   y = _gtk_rbtree_node_find_offset (tree, node);
5571   height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
5572
5573   if (y >= tree_view->priv->vadjustment->value &&
5574       y + height <= (tree_view->priv->vadjustment->value
5575                      + tree_view->priv->vadjustment->page_size))
5576     return TRUE;
5577
5578   return FALSE;
5579 }
5580
5581 /* Returns TRUE if it updated the size
5582  */
5583 static gboolean
5584 validate_row (GtkTreeView *tree_view,
5585               GtkRBTree   *tree,
5586               GtkRBNode   *node,
5587               GtkTreeIter *iter,
5588               GtkTreePath *path)
5589 {
5590   GtkTreeViewColumn *column;
5591   GList *list, *first_column, *last_column;
5592   gint height = 0;
5593   gint horizontal_separator;
5594   gint vertical_separator;
5595   gint focus_line_width;
5596   gint depth = gtk_tree_path_get_depth (path);
5597   gboolean retval = FALSE;
5598   gboolean is_separator = FALSE;
5599   gboolean draw_vgrid_lines, draw_hgrid_lines;
5600   gint focus_pad;
5601   gint grid_line_width;
5602   gboolean wide_separators;
5603   gint separator_height;
5604
5605   /* double check the row needs validating */
5606   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) &&
5607       ! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
5608     return FALSE;
5609
5610   is_separator = row_is_separator (tree_view, iter, NULL);
5611
5612   gtk_widget_style_get (GTK_WIDGET (tree_view),
5613                         "focus-padding", &focus_pad,
5614                         "focus-line-width", &focus_line_width,
5615                         "horizontal-separator", &horizontal_separator,
5616                         "vertical-separator", &vertical_separator,
5617                         "grid-line-width", &grid_line_width,
5618                         "wide-separators",  &wide_separators,
5619                         "separator-height", &separator_height,
5620                         NULL);
5621   
5622   draw_vgrid_lines =
5623     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_VERTICAL
5624     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
5625   draw_hgrid_lines =
5626     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_HORIZONTAL
5627     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
5628
5629   for (last_column = g_list_last (tree_view->priv->columns);
5630        last_column && !(GTK_TREE_VIEW_COLUMN (last_column->data)->visible);
5631        last_column = last_column->prev)
5632     ;
5633
5634   for (first_column = g_list_first (tree_view->priv->columns);
5635        first_column && !(GTK_TREE_VIEW_COLUMN (first_column->data)->visible);
5636        first_column = first_column->next)
5637     ;
5638
5639   for (list = tree_view->priv->columns; list; list = list->next)
5640     {
5641       gint tmp_width;
5642       gint tmp_height;
5643
5644       column = list->data;
5645
5646       if (! column->visible)
5647         continue;
5648
5649       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID) && !column->dirty)
5650         continue;
5651
5652       gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, iter,
5653                                                GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
5654                                                node->children?TRUE:FALSE);
5655       gtk_tree_view_column_cell_get_size (column,
5656                                           NULL, NULL, NULL,
5657                                           &tmp_width, &tmp_height);
5658
5659       if (!is_separator)
5660         {
5661           tmp_height += vertical_separator;
5662           height = MAX (height, tmp_height);
5663           height = MAX (height, tree_view->priv->expander_size);
5664         }
5665       else
5666         {
5667           if (wide_separators)
5668             height = separator_height + 2 * focus_pad;
5669           else
5670             height = 2 + 2 * focus_pad;
5671         }
5672
5673       if (gtk_tree_view_is_expander_column (tree_view, column))
5674         {
5675           tmp_width = tmp_width + horizontal_separator + (depth - 1) * tree_view->priv->level_indentation;
5676
5677           if (TREE_VIEW_DRAW_EXPANDERS (tree_view))
5678             tmp_width += depth * tree_view->priv->expander_size;
5679         }
5680       else
5681         tmp_width = tmp_width + horizontal_separator;
5682
5683       if (draw_vgrid_lines)
5684         {
5685           if (list->data == first_column || list->data == last_column)
5686             tmp_width += grid_line_width / 2.0;
5687           else
5688             tmp_width += grid_line_width;
5689         }
5690
5691       if (tmp_width > column->requested_width)
5692         {
5693           retval = TRUE;
5694           column->requested_width = tmp_width;
5695         }
5696     }
5697
5698   if (draw_hgrid_lines)
5699     height += grid_line_width;
5700
5701   if (height != GTK_RBNODE_GET_HEIGHT (node))
5702     {
5703       retval = TRUE;
5704       _gtk_rbtree_node_set_height (tree, node, height);
5705     }
5706   _gtk_rbtree_node_mark_valid (tree, node);
5707   tree_view->priv->post_validation_flag = TRUE;
5708
5709   return retval;
5710 }
5711
5712
5713 static void
5714 validate_visible_area (GtkTreeView *tree_view)
5715 {
5716   GtkTreePath *path = NULL;
5717   GtkTreePath *above_path = NULL;
5718   GtkTreeIter iter;
5719   GtkRBTree *tree = NULL;
5720   GtkRBNode *node = NULL;
5721   gboolean need_redraw = FALSE;
5722   gboolean size_changed = FALSE;
5723   gint total_height;
5724   gint area_above = 0;
5725   gint area_below = 0;
5726
5727   if (tree_view->priv->tree == NULL)
5728     return;
5729
5730   if (! GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID) &&
5731       tree_view->priv->scroll_to_path == NULL)
5732     return;
5733
5734   total_height = GTK_WIDGET (tree_view)->allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view);
5735
5736   if (total_height == 0)
5737     return;
5738
5739   /* First, we check to see if we need to scroll anywhere
5740    */
5741   if (tree_view->priv->scroll_to_path)
5742     {
5743       path = gtk_tree_row_reference_get_path (tree_view->priv->scroll_to_path);
5744       if (path && !_gtk_tree_view_find_node (tree_view, path, &tree, &node))
5745         {
5746           /* we are going to scroll, and will update dy */
5747           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
5748           if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
5749               GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
5750             {
5751               _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
5752               if (validate_row (tree_view, tree, node, &iter, path))
5753                 size_changed = TRUE;
5754             }
5755
5756           if (tree_view->priv->scroll_to_use_align)
5757             {
5758               gint height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
5759               area_above = (total_height - height) *
5760                 tree_view->priv->scroll_to_row_align;
5761               area_below = total_height - area_above - height;
5762               area_above = MAX (area_above, 0);
5763               area_below = MAX (area_below, 0);
5764             }
5765           else
5766             {
5767               /* two cases:
5768                * 1) row not visible
5769                * 2) row visible
5770                */
5771               gint dy;
5772               gint height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
5773
5774               dy = _gtk_rbtree_node_find_offset (tree, node);
5775
5776               if (dy >= tree_view->priv->vadjustment->value &&
5777                   dy + height <= (tree_view->priv->vadjustment->value
5778                                   + tree_view->priv->vadjustment->page_size))
5779                 {
5780                   /* row visible: keep the row at the same position */
5781                   area_above = dy - tree_view->priv->vadjustment->value;
5782                   area_below = (tree_view->priv->vadjustment->value +
5783                                 tree_view->priv->vadjustment->page_size)
5784                                - dy - height;
5785                 }
5786               else
5787                 {
5788                   /* row not visible */
5789                   if (dy >= 0
5790                       && dy + height <= tree_view->priv->vadjustment->page_size)
5791                     {
5792                       /* row at the beginning -- fixed */
5793                       area_above = dy;
5794                       area_below = tree_view->priv->vadjustment->page_size
5795                                    - area_above - height;
5796                     }
5797                   else if (dy >= (tree_view->priv->vadjustment->upper -
5798                                   tree_view->priv->vadjustment->page_size))
5799                     {
5800                       /* row at the end -- fixed */
5801                       area_above = dy - (tree_view->priv->vadjustment->upper -
5802                                    tree_view->priv->vadjustment->page_size);
5803                       area_below = tree_view->priv->vadjustment->page_size -
5804                                    area_above - height;
5805
5806                       if (area_below < 0)
5807                         {
5808                           area_above = tree_view->priv->vadjustment->page_size - height;
5809                           area_below = 0;
5810                         }
5811                     }
5812                   else
5813                     {
5814                       /* row somewhere in the middle, bring it to the top
5815                        * of the view
5816                        */
5817                       area_above = 0;
5818                       area_below = total_height - height;
5819                     }
5820                 }
5821             }
5822         }
5823       else
5824         /* the scroll to isn't valid; ignore it.
5825          */
5826         {
5827           if (tree_view->priv->scroll_to_path && !path)
5828             {
5829               gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
5830               tree_view->priv->scroll_to_path = NULL;
5831             }
5832           if (path)
5833             gtk_tree_path_free (path);
5834           path = NULL;
5835         }      
5836     }
5837
5838   /* We didn't have a scroll_to set, so we just handle things normally
5839    */
5840   if (path == NULL)
5841     {
5842       gint offset;
5843
5844       offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
5845                                         TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, 0),
5846                                         &tree, &node);
5847       if (node == NULL)
5848         {
5849           /* In this case, nothing has been validated */
5850           path = gtk_tree_path_new_first ();
5851           _gtk_tree_view_find_node (tree_view, path, &tree, &node);
5852         }
5853       else
5854         {
5855           path = _gtk_tree_view_find_path (tree_view, tree, node);
5856           total_height += offset;
5857         }
5858
5859       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
5860
5861       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
5862           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
5863         {
5864           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
5865           if (validate_row (tree_view, tree, node, &iter, path))
5866             size_changed = TRUE;
5867         }
5868       area_above = 0;
5869       area_below = total_height - ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
5870     }
5871
5872   above_path = gtk_tree_path_copy (path);
5873
5874   /* if we do not validate any row above the new top_row, we will make sure
5875    * that the row immediately above top_row has been validated. (if we do not
5876    * do this, _gtk_rbtree_find_offset will find the row above top_row, because
5877    * when invalidated that row's height will be zero. and this will mess up
5878    * scrolling).
5879    */
5880   if (area_above == 0)
5881     {
5882       GtkRBTree *tmptree;
5883       GtkRBNode *tmpnode;
5884
5885       _gtk_tree_view_find_node (tree_view, above_path, &tmptree, &tmpnode);
5886       _gtk_rbtree_prev_full (tmptree, tmpnode, &tmptree, &tmpnode);
5887
5888       if (tmpnode)
5889         {
5890           GtkTreePath *tmppath;
5891           GtkTreeIter tmpiter;
5892
5893           tmppath = _gtk_tree_view_find_path (tree_view, tmptree, tmpnode);
5894           gtk_tree_model_get_iter (tree_view->priv->model, &tmpiter, tmppath);
5895
5896           if (GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_INVALID) ||
5897               GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_COLUMN_INVALID))
5898             {
5899               _gtk_tree_view_queue_draw_node (tree_view, tmptree, tmpnode, NULL);
5900               if (validate_row (tree_view, tmptree, tmpnode, &tmpiter, tmppath))
5901                 size_changed = TRUE;
5902             }
5903
5904           gtk_tree_path_free (tmppath);
5905         }
5906     }
5907
5908   /* Now, we walk forwards and backwards, measuring rows. Unfortunately,
5909    * backwards is much slower then forward, as there is no iter_prev function.
5910    * We go forwards first in case we run out of tree.  Then we go backwards to
5911    * fill out the top.
5912    */
5913   while (node && area_below > 0)
5914     {
5915       if (node->children)
5916         {
5917           GtkTreeIter parent = iter;
5918           gboolean has_child;
5919
5920           tree = node->children;
5921           node = tree->root;
5922
5923           g_assert (node != tree->nil);
5924
5925           while (node->left != tree->nil)
5926             node = node->left;
5927           has_child = gtk_tree_model_iter_children (tree_view->priv->model,
5928                                                     &iter,
5929                                                     &parent);
5930           TREE_VIEW_INTERNAL_ASSERT_VOID (has_child);
5931           gtk_tree_path_down (path);
5932         }
5933       else
5934         {
5935           gboolean done = FALSE;
5936           do
5937             {
5938               node = _gtk_rbtree_next (tree, node);
5939               if (node != NULL)
5940                 {
5941                   gboolean has_next = gtk_tree_model_iter_next (tree_view->priv->model, &iter);
5942                   done = TRUE;
5943                   gtk_tree_path_next (path);
5944
5945                   /* Sanity Check! */
5946                   TREE_VIEW_INTERNAL_ASSERT_VOID (has_next);
5947                 }
5948               else
5949                 {
5950                   GtkTreeIter parent_iter = iter;
5951                   gboolean has_parent;
5952
5953                   node = tree->parent_node;
5954                   tree = tree->parent_tree;
5955                   if (tree == NULL)
5956                     break;
5957                   has_parent = gtk_tree_model_iter_parent (tree_view->priv->model,
5958                                                            &iter,
5959                                                            &parent_iter);
5960                   gtk_tree_path_up (path);
5961
5962                   /* Sanity check */
5963                   TREE_VIEW_INTERNAL_ASSERT_VOID (has_parent);
5964                 }
5965             }
5966           while (!done);
5967         }
5968
5969       if (!node)
5970         break;
5971
5972       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
5973           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
5974         {
5975           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
5976           if (validate_row (tree_view, tree, node, &iter, path))
5977               size_changed = TRUE;
5978         }
5979
5980       area_below -= ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
5981     }
5982   gtk_tree_path_free (path);
5983
5984   /* If we ran out of tree, and have extra area_below left, we need to add it
5985    * to area_above */
5986   if (area_below > 0)
5987     area_above += area_below;
5988
5989   _gtk_tree_view_find_node (tree_view, above_path, &tree, &node);
5990
5991   /* We walk backwards */
5992   while (area_above > 0)
5993     {
5994       _gtk_rbtree_prev_full (tree, node, &tree, &node);
5995       if (! gtk_tree_path_prev (above_path) && node != NULL)
5996         {
5997           gtk_tree_path_free (above_path);
5998           above_path = _gtk_tree_view_find_path (tree_view, tree, node);
5999         }
6000       gtk_tree_model_get_iter (tree_view->priv->model, &iter, above_path);
6001
6002       if (node == NULL)
6003         break;
6004
6005       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6006           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6007         {
6008           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
6009           if (validate_row (tree_view, tree, node, &iter, above_path))
6010             size_changed = TRUE;
6011         }
6012       area_above -= ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
6013     }
6014
6015   /* if we scrolled to a path, we need to set the dy here,
6016    * and sync the top row accordingly
6017    */
6018   if (tree_view->priv->scroll_to_path)
6019     {
6020       gtk_tree_view_set_top_row (tree_view, above_path, -area_above);
6021       gtk_tree_view_top_row_to_dy (tree_view);
6022
6023       need_redraw = TRUE;
6024     }
6025   else if (tree_view->priv->height <= tree_view->priv->vadjustment->page_size)
6026     {
6027       /* when we are not scrolling, we should never set dy to something
6028        * else than zero. we update top_row to be in sync with dy = 0.
6029        */
6030       gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
6031       gtk_tree_view_dy_to_top_row (tree_view);
6032     }
6033   else if (tree_view->priv->vadjustment->value + tree_view->priv->vadjustment->page_size > tree_view->priv->height)
6034     {
6035       gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), tree_view->priv->height - tree_view->priv->vadjustment->page_size);
6036       gtk_tree_view_dy_to_top_row (tree_view);
6037     }
6038   else
6039     gtk_tree_view_top_row_to_dy (tree_view);
6040
6041   /* update width/height and queue a resize */
6042   if (size_changed)
6043     {
6044       GtkRequisition requisition;
6045
6046       /* We temporarily guess a size, under the assumption that it will be the
6047        * same when we get our next size_allocate.  If we don't do this, we'll be
6048        * in an inconsistent state if we call top_row_to_dy. */
6049
6050       gtk_widget_size_request (GTK_WIDGET (tree_view), &requisition);
6051       tree_view->priv->hadjustment->upper = MAX (tree_view->priv->hadjustment->upper, (gfloat)requisition.width);
6052       tree_view->priv->vadjustment->upper = MAX (tree_view->priv->vadjustment->upper, (gfloat)requisition.height);
6053       gtk_adjustment_changed (tree_view->priv->hadjustment);
6054       gtk_adjustment_changed (tree_view->priv->vadjustment);
6055       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6056     }
6057
6058   if (tree_view->priv->scroll_to_path)
6059     {
6060       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
6061       tree_view->priv->scroll_to_path = NULL;
6062     }
6063
6064   if (above_path)
6065     gtk_tree_path_free (above_path);
6066
6067   if (tree_view->priv->scroll_to_column)
6068     {
6069       tree_view->priv->scroll_to_column = NULL;
6070     }
6071   if (need_redraw)
6072     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
6073 }
6074
6075 static void
6076 initialize_fixed_height_mode (GtkTreeView *tree_view)
6077 {
6078   if (!tree_view->priv->tree)
6079     return;
6080
6081   if (tree_view->priv->fixed_height < 0)
6082     {
6083       GtkTreeIter iter;
6084       GtkTreePath *path;
6085
6086       GtkRBTree *tree = NULL;
6087       GtkRBNode *node = NULL;
6088
6089       tree = tree_view->priv->tree;
6090       node = tree->root;
6091
6092       path = _gtk_tree_view_find_path (tree_view, tree, node);
6093       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6094
6095       validate_row (tree_view, tree, node, &iter, path);
6096
6097       gtk_tree_path_free (path);
6098
6099       tree_view->priv->fixed_height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
6100     }
6101
6102    _gtk_rbtree_set_fixed_height (tree_view->priv->tree,
6103                                  tree_view->priv->fixed_height, TRUE);
6104 }
6105
6106 /* Our strategy for finding nodes to validate is a little convoluted.  We find
6107  * the left-most uninvalidated node.  We then try walking right, validating
6108  * nodes.  Once we find a valid node, we repeat the previous process of finding
6109  * the first invalid node.
6110  */
6111
6112 static gboolean
6113 do_validate_rows (GtkTreeView *tree_view, gboolean queue_resize)
6114 {
6115   GtkRBTree *tree = NULL;
6116   GtkRBNode *node = NULL;
6117   gboolean validated_area = FALSE;
6118   gint retval = TRUE;
6119   GtkTreePath *path = NULL;
6120   GtkTreeIter iter;
6121   gint i = 0;
6122
6123   gint prev_height = -1;
6124   gboolean fixed_height = TRUE;
6125
6126   g_assert (tree_view);
6127
6128   if (tree_view->priv->tree == NULL)
6129       return FALSE;
6130
6131   if (tree_view->priv->fixed_height_mode)
6132     {
6133       if (tree_view->priv->fixed_height < 0)
6134         initialize_fixed_height_mode (tree_view);
6135
6136       return FALSE;
6137     }
6138
6139   do
6140     {
6141       if (! GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID))
6142         {
6143           retval = FALSE;
6144           goto done;
6145         }
6146
6147       if (path != NULL)
6148         {
6149           node = _gtk_rbtree_next (tree, node);
6150           if (node != NULL)
6151             {
6152               TREE_VIEW_INTERNAL_ASSERT (gtk_tree_model_iter_next (tree_view->priv->model, &iter), FALSE);
6153               gtk_tree_path_next (path);
6154             }
6155           else
6156             {
6157               gtk_tree_path_free (path);
6158               path = NULL;
6159             }
6160         }
6161
6162       if (path == NULL)
6163         {
6164           tree = tree_view->priv->tree;
6165           node = tree_view->priv->tree->root;
6166
6167           g_assert (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_DESCENDANTS_INVALID));
6168
6169           do
6170             {
6171               if (node->left != tree->nil &&
6172                   GTK_RBNODE_FLAG_SET (node->left, GTK_RBNODE_DESCENDANTS_INVALID))
6173                 {
6174                   node = node->left;
6175                 }
6176               else if (node->right != tree->nil &&
6177                        GTK_RBNODE_FLAG_SET (node->right, GTK_RBNODE_DESCENDANTS_INVALID))
6178                 {
6179                   node = node->right;
6180                 }
6181               else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6182                        GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6183                 {
6184                   break;
6185                 }
6186               else if (node->children != NULL)
6187                 {
6188                   tree = node->children;
6189                   node = tree->root;
6190                 }
6191               else
6192                 /* RBTree corruption!  All bad */
6193                 g_assert_not_reached ();
6194             }
6195           while (TRUE);
6196           path = _gtk_tree_view_find_path (tree_view, tree, node);
6197           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6198         }
6199
6200       validated_area = validate_row (tree_view, tree, node, &iter, path) ||
6201                        validated_area;
6202
6203       if (!tree_view->priv->fixed_height_check)
6204         {
6205           gint height;
6206
6207           height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
6208           if (prev_height < 0)
6209             prev_height = height;
6210           else if (prev_height != height)
6211             fixed_height = FALSE;
6212         }
6213
6214       i++;
6215     }
6216   while (i < GTK_TREE_VIEW_NUM_ROWS_PER_IDLE);
6217
6218   if (!tree_view->priv->fixed_height_check)
6219    {
6220      if (fixed_height)
6221        _gtk_rbtree_set_fixed_height (tree_view->priv->tree, prev_height, FALSE);
6222
6223      tree_view->priv->fixed_height_check = 1;
6224    }
6225   
6226  done:
6227   if (validated_area)
6228     {
6229       GtkRequisition requisition;
6230       /* We temporarily guess a size, under the assumption that it will be the
6231        * same when we get our next size_allocate.  If we don't do this, we'll be
6232        * in an inconsistent state when we call top_row_to_dy. */
6233
6234       gtk_widget_size_request (GTK_WIDGET (tree_view), &requisition);
6235       tree_view->priv->hadjustment->upper = MAX (tree_view->priv->hadjustment->upper, (gfloat)requisition.width);
6236       tree_view->priv->vadjustment->upper = MAX (tree_view->priv->vadjustment->upper, (gfloat)requisition.height);
6237       gtk_adjustment_changed (tree_view->priv->hadjustment);
6238       gtk_adjustment_changed (tree_view->priv->vadjustment);
6239
6240       if (queue_resize)
6241         gtk_widget_queue_resize_no_redraw (GTK_WIDGET (tree_view));
6242     }
6243
6244   if (path) gtk_tree_path_free (path);
6245
6246   return retval;
6247 }
6248
6249 static gboolean
6250 validate_rows (GtkTreeView *tree_view)
6251 {
6252   gboolean retval;
6253   
6254   retval = do_validate_rows (tree_view, TRUE);
6255   
6256   if (! retval && tree_view->priv->validate_rows_timer)
6257     {
6258       g_source_remove (tree_view->priv->validate_rows_timer);
6259       tree_view->priv->validate_rows_timer = 0;
6260     }
6261
6262   return retval;
6263 }
6264
6265 static gboolean
6266 validate_rows_handler (GtkTreeView *tree_view)
6267 {
6268   gboolean retval;
6269
6270   retval = do_validate_rows (tree_view, TRUE);
6271   if (! retval && tree_view->priv->validate_rows_timer)
6272     {
6273       g_source_remove (tree_view->priv->validate_rows_timer);
6274       tree_view->priv->validate_rows_timer = 0;
6275     }
6276
6277   return retval;
6278 }
6279
6280 static gboolean
6281 do_presize_handler (GtkTreeView *tree_view)
6282 {
6283   if (tree_view->priv->mark_rows_col_dirty)
6284     {
6285       if (tree_view->priv->tree)
6286         _gtk_rbtree_column_invalid (tree_view->priv->tree);
6287       tree_view->priv->mark_rows_col_dirty = FALSE;
6288     }
6289   validate_visible_area (tree_view);
6290   tree_view->priv->presize_handler_timer = 0;
6291
6292   if (tree_view->priv->fixed_height_mode)
6293     {
6294       GtkRequisition requisition;
6295
6296       gtk_widget_size_request (GTK_WIDGET (tree_view), &requisition);
6297
6298       tree_view->priv->hadjustment->upper = MAX (tree_view->priv->hadjustment->upper, (gfloat)requisition.width);
6299       tree_view->priv->vadjustment->upper = MAX (tree_view->priv->vadjustment->upper, (gfloat)requisition.height);
6300       gtk_adjustment_changed (tree_view->priv->hadjustment);
6301       gtk_adjustment_changed (tree_view->priv->vadjustment);
6302       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6303     }
6304                    
6305   return FALSE;
6306 }
6307
6308 static gboolean
6309 presize_handler_callback (gpointer data)
6310 {
6311   do_presize_handler (GTK_TREE_VIEW (data));
6312                    
6313   return FALSE;
6314 }
6315
6316 static void
6317 install_presize_handler (GtkTreeView *tree_view)
6318 {
6319   if (! GTK_WIDGET_REALIZED (tree_view))
6320     return;
6321
6322   if (! tree_view->priv->presize_handler_timer)
6323     {
6324       tree_view->priv->presize_handler_timer =
6325         gdk_threads_add_idle_full (GTK_PRIORITY_RESIZE - 2, presize_handler_callback, tree_view, NULL);
6326     }
6327   if (! tree_view->priv->validate_rows_timer)
6328     {
6329       tree_view->priv->validate_rows_timer =
6330         gdk_threads_add_idle_full (GTK_TREE_VIEW_PRIORITY_VALIDATE, (GSourceFunc) validate_rows_handler, tree_view, NULL);
6331     }
6332 }
6333
6334 static gboolean
6335 scroll_sync_handler (GtkTreeView *tree_view)
6336 {
6337   if (tree_view->priv->height <= tree_view->priv->vadjustment->page_size)
6338     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
6339   else if (gtk_tree_row_reference_valid (tree_view->priv->top_row))
6340     gtk_tree_view_top_row_to_dy (tree_view);
6341   else
6342     gtk_tree_view_dy_to_top_row (tree_view);
6343
6344   tree_view->priv->scroll_sync_timer = 0;
6345
6346   return FALSE;
6347 }
6348
6349 static void
6350 install_scroll_sync_handler (GtkTreeView *tree_view)
6351 {
6352   if (! GTK_WIDGET_REALIZED (tree_view))
6353     return;
6354
6355   if (!tree_view->priv->scroll_sync_timer)
6356     {
6357       tree_view->priv->scroll_sync_timer =
6358         gdk_threads_add_idle_full (GTK_TREE_VIEW_PRIORITY_SCROLL_SYNC, (GSourceFunc) scroll_sync_handler, tree_view, NULL);
6359     }
6360 }
6361
6362 static void
6363 gtk_tree_view_set_top_row (GtkTreeView *tree_view,
6364                            GtkTreePath *path,
6365                            gint         offset)
6366 {
6367   gtk_tree_row_reference_free (tree_view->priv->top_row);
6368
6369   if (!path)
6370     {
6371       tree_view->priv->top_row = NULL;
6372       tree_view->priv->top_row_dy = 0;
6373     }
6374   else
6375     {
6376       tree_view->priv->top_row = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
6377       tree_view->priv->top_row_dy = offset;
6378     }
6379 }
6380
6381 /* Always call this iff dy is in the visible range.  If the tree is empty, then
6382  * it's set to be NULL, and top_row_dy is 0;
6383  */
6384 static void
6385 gtk_tree_view_dy_to_top_row (GtkTreeView *tree_view)
6386 {
6387   gint offset;
6388   GtkTreePath *path;
6389   GtkRBTree *tree;
6390   GtkRBNode *node;
6391
6392   if (tree_view->priv->tree == NULL)
6393     {
6394       gtk_tree_view_set_top_row (tree_view, NULL, 0);
6395     }
6396   else
6397     {
6398       offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
6399                                         tree_view->priv->dy,
6400                                         &tree, &node);
6401
6402       if (tree == NULL)
6403         {
6404           tree_view->priv->top_row = NULL;
6405           tree_view->priv->top_row_dy = 0;
6406         }
6407       else
6408         {
6409           path = _gtk_tree_view_find_path (tree_view, tree, node);
6410           gtk_tree_view_set_top_row (tree_view, path, offset);
6411           gtk_tree_path_free (path);
6412         }
6413     }
6414 }
6415
6416 static void
6417 gtk_tree_view_top_row_to_dy (GtkTreeView *tree_view)
6418 {
6419   GtkTreePath *path;
6420   GtkRBTree *tree;
6421   GtkRBNode *node;
6422   int new_dy;
6423
6424   if (tree_view->priv->top_row)
6425     path = gtk_tree_row_reference_get_path (tree_view->priv->top_row);
6426   else
6427     path = NULL;
6428
6429   if (!path)
6430     tree = NULL;
6431   else
6432     _gtk_tree_view_find_node (tree_view, path, &tree, &node);
6433
6434   if (path)
6435     gtk_tree_path_free (path);
6436
6437   if (tree == NULL)
6438     {
6439       /* keep dy and set new toprow */
6440       gtk_tree_row_reference_free (tree_view->priv->top_row);
6441       tree_view->priv->top_row = NULL;
6442       tree_view->priv->top_row_dy = 0;
6443       /* DO NOT install the idle handler */
6444       gtk_tree_view_dy_to_top_row (tree_view);
6445       return;
6446     }
6447
6448   if (ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node))
6449       < tree_view->priv->top_row_dy)
6450     {
6451       /* new top row -- do NOT install the idle handler */
6452       gtk_tree_view_dy_to_top_row (tree_view);
6453       return;
6454     }
6455
6456   new_dy = _gtk_rbtree_node_find_offset (tree, node);
6457   new_dy += tree_view->priv->top_row_dy;
6458
6459   if (new_dy + tree_view->priv->vadjustment->page_size > tree_view->priv->height)
6460     new_dy = tree_view->priv->height - tree_view->priv->vadjustment->page_size;
6461
6462   new_dy = MAX (0, new_dy);
6463
6464   tree_view->priv->in_top_row_to_dy = TRUE;
6465   gtk_adjustment_set_value (tree_view->priv->vadjustment, (gdouble)new_dy);
6466   tree_view->priv->in_top_row_to_dy = FALSE;
6467 }
6468
6469
6470 void
6471 _gtk_tree_view_install_mark_rows_col_dirty (GtkTreeView *tree_view)
6472 {
6473   tree_view->priv->mark_rows_col_dirty = TRUE;
6474
6475   install_presize_handler (tree_view);
6476 }
6477
6478 /*
6479  * This function works synchronously (due to the while (validate_rows...)
6480  * loop).
6481  *
6482  * There was a check for column_type != GTK_TREE_VIEW_COLUMN_AUTOSIZE
6483  * here. You now need to check that yourself.
6484  */
6485 void
6486 _gtk_tree_view_column_autosize (GtkTreeView *tree_view,
6487                                 GtkTreeViewColumn *column)
6488 {
6489   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
6490   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (column));
6491
6492   _gtk_tree_view_column_cell_set_dirty (column, FALSE);
6493
6494   do_presize_handler (tree_view);
6495   while (validate_rows (tree_view));
6496
6497   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6498 }
6499
6500 /* Drag-and-drop */
6501
6502 static void
6503 set_source_row (GdkDragContext *context,
6504                 GtkTreeModel   *model,
6505                 GtkTreePath    *source_row)
6506 {
6507   g_object_set_data_full (G_OBJECT (context),
6508                           I_("gtk-tree-view-source-row"),
6509                           source_row ? gtk_tree_row_reference_new (model, source_row) : NULL,
6510                           (GDestroyNotify) (source_row ? gtk_tree_row_reference_free : NULL));
6511 }
6512
6513 static GtkTreePath*
6514 get_source_row (GdkDragContext *context)
6515 {
6516   GtkTreeRowReference *ref =
6517     g_object_get_data (G_OBJECT (context), "gtk-tree-view-source-row");
6518
6519   if (ref)
6520     return gtk_tree_row_reference_get_path (ref);
6521   else
6522     return NULL;
6523 }
6524
6525 typedef struct
6526 {
6527   GtkTreeRowReference *dest_row;
6528   guint                path_down_mode   : 1;
6529   guint                empty_view_drop  : 1;
6530   guint                drop_append_mode : 1;
6531 }
6532 DestRow;
6533
6534 static void
6535 dest_row_free (gpointer data)
6536 {
6537   DestRow *dr = (DestRow *)data;
6538
6539   gtk_tree_row_reference_free (dr->dest_row);
6540   g_slice_free (DestRow, dr);
6541 }
6542
6543 static void
6544 set_dest_row (GdkDragContext *context,
6545               GtkTreeModel   *model,
6546               GtkTreePath    *dest_row,
6547               gboolean        path_down_mode,
6548               gboolean        empty_view_drop,
6549               gboolean        drop_append_mode)
6550 {
6551   DestRow *dr;
6552
6553   if (!dest_row)
6554     {
6555       g_object_set_data_full (G_OBJECT (context), I_("gtk-tree-view-dest-row"),
6556                               NULL, NULL);
6557       return;
6558     }
6559
6560   dr = g_slice_new (DestRow);
6561
6562   dr->dest_row = gtk_tree_row_reference_new (model, dest_row);
6563   dr->path_down_mode = path_down_mode != FALSE;
6564   dr->empty_view_drop = empty_view_drop != FALSE;
6565   dr->drop_append_mode = drop_append_mode != FALSE;
6566
6567   g_object_set_data_full (G_OBJECT (context), I_("gtk-tree-view-dest-row"),
6568                           dr, (GDestroyNotify) dest_row_free);
6569 }
6570
6571 static GtkTreePath*
6572 get_dest_row (GdkDragContext *context,
6573               gboolean       *path_down_mode)
6574 {
6575   DestRow *dr =
6576     g_object_get_data (G_OBJECT (context), "gtk-tree-view-dest-row");
6577
6578   if (dr)
6579     {
6580       GtkTreePath *path = NULL;
6581
6582       if (path_down_mode)
6583         *path_down_mode = dr->path_down_mode;
6584
6585       if (dr->dest_row)
6586         path = gtk_tree_row_reference_get_path (dr->dest_row);
6587       else if (dr->empty_view_drop)
6588         path = gtk_tree_path_new_from_indices (0, -1);
6589       else
6590         path = NULL;
6591
6592       if (path && dr->drop_append_mode)
6593         gtk_tree_path_next (path);
6594
6595       return path;
6596     }
6597   else
6598     return NULL;
6599 }
6600
6601 /* Get/set whether drag_motion requested the drag data and
6602  * drag_data_received should thus not actually insert the data,
6603  * since the data doesn't result from a drop.
6604  */
6605 static void
6606 set_status_pending (GdkDragContext *context,
6607                     GdkDragAction   suggested_action)
6608 {
6609   g_object_set_data (G_OBJECT (context),
6610                      I_("gtk-tree-view-status-pending"),
6611                      GINT_TO_POINTER (suggested_action));
6612 }
6613
6614 static GdkDragAction
6615 get_status_pending (GdkDragContext *context)
6616 {
6617   return GPOINTER_TO_INT (g_object_get_data (G_OBJECT (context),
6618                                              "gtk-tree-view-status-pending"));
6619 }
6620
6621 static TreeViewDragInfo*
6622 get_info (GtkTreeView *tree_view)
6623 {
6624   return g_object_get_data (G_OBJECT (tree_view), "gtk-tree-view-drag-info");
6625 }
6626
6627 static void
6628 destroy_info (TreeViewDragInfo *di)
6629 {
6630   g_slice_free (TreeViewDragInfo, di);
6631 }
6632
6633 static TreeViewDragInfo*
6634 ensure_info (GtkTreeView *tree_view)
6635 {
6636   TreeViewDragInfo *di;
6637
6638   di = get_info (tree_view);
6639
6640   if (di == NULL)
6641     {
6642       di = g_slice_new0 (TreeViewDragInfo);
6643
6644       g_object_set_data_full (G_OBJECT (tree_view),
6645                               I_("gtk-tree-view-drag-info"),
6646                               di,
6647                               (GDestroyNotify) destroy_info);
6648     }
6649
6650   return di;
6651 }
6652
6653 static void
6654 remove_info (GtkTreeView *tree_view)
6655 {
6656   g_object_set_data (G_OBJECT (tree_view), I_("gtk-tree-view-drag-info"), NULL);
6657 }
6658
6659 #if 0
6660 static gint
6661 drag_scan_timeout (gpointer data)
6662 {
6663   GtkTreeView *tree_view;
6664   gint x, y;
6665   GdkModifierType state;
6666   GtkTreePath *path = NULL;
6667   GtkTreeViewColumn *column = NULL;
6668   GdkRectangle visible_rect;
6669
6670   GDK_THREADS_ENTER ();
6671
6672   tree_view = GTK_TREE_VIEW (data);
6673
6674   gdk_window_get_pointer (tree_view->priv->bin_window,
6675                           &x, &y, &state);
6676
6677   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
6678
6679   /* See if we are near the edge. */
6680   if ((x - visible_rect.x) < SCROLL_EDGE_SIZE ||
6681       (visible_rect.x + visible_rect.width - x) < SCROLL_EDGE_SIZE ||
6682       (y - visible_rect.y) < SCROLL_EDGE_SIZE ||
6683       (visible_rect.y + visible_rect.height - y) < SCROLL_EDGE_SIZE)
6684     {
6685       gtk_tree_view_get_path_at_pos (tree_view,
6686                                      tree_view->priv->bin_window,
6687                                      x, y,
6688                                      &path,
6689                                      &column,
6690                                      NULL,
6691                                      NULL);
6692
6693       if (path != NULL)
6694         {
6695           gtk_tree_view_scroll_to_cell (tree_view,
6696                                         path,
6697                                         column,
6698                                         TRUE,
6699                                         0.5, 0.5);
6700
6701           gtk_tree_path_free (path);
6702         }
6703     }
6704
6705   GDK_THREADS_LEAVE ();
6706
6707   return TRUE;
6708 }
6709 #endif /* 0 */
6710
6711 static void
6712 add_scroll_timeout (GtkTreeView *tree_view)
6713 {
6714   if (tree_view->priv->scroll_timeout == 0)
6715     {
6716       tree_view->priv->scroll_timeout =
6717         gdk_threads_add_timeout (150, scroll_row_timeout, tree_view);
6718     }
6719 }
6720
6721 static void
6722 remove_scroll_timeout (GtkTreeView *tree_view)
6723 {
6724   if (tree_view->priv->scroll_timeout != 0)
6725     {
6726       g_source_remove (tree_view->priv->scroll_timeout);
6727       tree_view->priv->scroll_timeout = 0;
6728     }
6729 }
6730
6731 static gboolean
6732 check_model_dnd (GtkTreeModel *model,
6733                  GType         required_iface,
6734                  const gchar  *signal)
6735 {
6736   if (model == NULL || !G_TYPE_CHECK_INSTANCE_TYPE ((model), required_iface))
6737     {
6738       g_warning ("You must override the default '%s' handler "
6739                  "on GtkTreeView when using models that don't support "
6740                  "the %s interface and enabling drag-and-drop. The simplest way to do this "
6741                  "is to connect to '%s' and call "
6742                  "g_signal_stop_emission_by_name() in your signal handler to prevent "
6743                  "the default handler from running. Look at the source code "
6744                  "for the default handler in gtktreeview.c to get an idea what "
6745                  "your handler should do. (gtktreeview.c is in the GTK source "
6746                  "code.) If you're using GTK from a language other than C, "
6747                  "there may be a more natural way to override default handlers, e.g. via derivation.",
6748                  signal, g_type_name (required_iface), signal);
6749       return FALSE;
6750     }
6751   else
6752     return TRUE;
6753 }
6754
6755 static void
6756 remove_open_timeout (GtkTreeView *tree_view)
6757 {
6758   if (tree_view->priv->open_dest_timeout != 0)
6759     {
6760       g_source_remove (tree_view->priv->open_dest_timeout);
6761       tree_view->priv->open_dest_timeout = 0;
6762     }
6763 }
6764
6765
6766 static gint
6767 open_row_timeout (gpointer data)
6768 {
6769   GtkTreeView *tree_view = data;
6770   GtkTreePath *dest_path = NULL;
6771   GtkTreeViewDropPosition pos;
6772   gboolean result = FALSE;
6773
6774   gtk_tree_view_get_drag_dest_row (tree_view,
6775                                    &dest_path,
6776                                    &pos);
6777
6778   if (dest_path &&
6779       (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
6780        pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
6781     {
6782       gtk_tree_view_expand_row (tree_view, dest_path, FALSE);
6783       tree_view->priv->open_dest_timeout = 0;
6784
6785       gtk_tree_path_free (dest_path);
6786     }
6787   else
6788     {
6789       if (dest_path)
6790         gtk_tree_path_free (dest_path);
6791
6792       result = TRUE;
6793     }
6794
6795   return result;
6796 }
6797
6798 static gboolean
6799 scroll_row_timeout (gpointer data)
6800 {
6801   GtkTreeView *tree_view = data;
6802
6803   gtk_tree_view_vertical_autoscroll (tree_view);
6804
6805   if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
6806     gtk_tree_view_update_rubber_band (tree_view);
6807
6808   return TRUE;
6809 }
6810
6811 /* Returns TRUE if event should not be propagated to parent widgets */
6812 static gboolean
6813 set_destination_row (GtkTreeView    *tree_view,
6814                      GdkDragContext *context,
6815                      /* coordinates relative to the widget */
6816                      gint            x,
6817                      gint            y,
6818                      GdkDragAction  *suggested_action,
6819                      GdkAtom        *target)
6820 {
6821   GtkTreePath *path = NULL;
6822   GtkTreeViewDropPosition pos;
6823   GtkTreeViewDropPosition old_pos;
6824   TreeViewDragInfo *di;
6825   GtkWidget *widget;
6826   GtkTreePath *old_dest_path = NULL;
6827   gboolean can_drop = FALSE;
6828
6829   *suggested_action = 0;
6830   *target = GDK_NONE;
6831
6832   widget = GTK_WIDGET (tree_view);
6833
6834   di = get_info (tree_view);
6835
6836   if (di == NULL || y - TREE_VIEW_HEADER_HEIGHT (tree_view) < 0)
6837     {
6838       /* someone unset us as a drag dest, note that if
6839        * we return FALSE drag_leave isn't called
6840        */
6841
6842       gtk_tree_view_set_drag_dest_row (tree_view,
6843                                        NULL,
6844                                        GTK_TREE_VIEW_DROP_BEFORE);
6845
6846       remove_scroll_timeout (GTK_TREE_VIEW (widget));
6847       remove_open_timeout (GTK_TREE_VIEW (widget));
6848
6849       return FALSE; /* no longer a drop site */
6850     }
6851
6852   *target = gtk_drag_dest_find_target (widget, context,
6853                                        gtk_drag_dest_get_target_list (widget));
6854   if (*target == GDK_NONE)
6855     {
6856       return FALSE;
6857     }
6858
6859   if (!gtk_tree_view_get_dest_row_at_pos (tree_view,
6860                                           x, y,
6861                                           &path,
6862                                           &pos))
6863     {
6864       gint n_children;
6865       GtkTreeModel *model;
6866
6867       remove_open_timeout (tree_view);
6868
6869       /* the row got dropped on empty space, let's setup a special case
6870        */
6871
6872       if (path)
6873         gtk_tree_path_free (path);
6874
6875       model = gtk_tree_view_get_model (tree_view);
6876
6877       n_children = gtk_tree_model_iter_n_children (model, NULL);
6878       if (n_children)
6879         {
6880           pos = GTK_TREE_VIEW_DROP_AFTER;
6881           path = gtk_tree_path_new_from_indices (n_children - 1, -1);
6882         }
6883       else
6884         {
6885           pos = GTK_TREE_VIEW_DROP_BEFORE;
6886           path = gtk_tree_path_new_from_indices (0, -1);
6887         }
6888
6889       can_drop = TRUE;
6890
6891       goto out;
6892     }
6893
6894   g_assert (path);
6895
6896   /* If we left the current row's "open" zone, unset the timeout for
6897    * opening the row
6898    */
6899   gtk_tree_view_get_drag_dest_row (tree_view,
6900                                    &old_dest_path,
6901                                    &old_pos);
6902
6903   if (old_dest_path &&
6904       (gtk_tree_path_compare (path, old_dest_path) != 0 ||
6905        !(pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
6906          pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE)))
6907     remove_open_timeout (tree_view);
6908
6909   if (old_dest_path)
6910     gtk_tree_path_free (old_dest_path);
6911
6912   if (TRUE /* FIXME if the location droppable predicate */)
6913     {
6914       can_drop = TRUE;
6915     }
6916
6917 out:
6918   if (can_drop)
6919     {
6920       GtkWidget *source_widget;
6921
6922       *suggested_action = context->suggested_action;
6923       source_widget = gtk_drag_get_source_widget (context);
6924
6925       if (source_widget == widget)
6926         {
6927           /* Default to MOVE, unless the user has
6928            * pressed ctrl or shift to affect available actions
6929            */
6930           if ((context->actions & GDK_ACTION_MOVE) != 0)
6931             *suggested_action = GDK_ACTION_MOVE;
6932         }
6933
6934       gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
6935                                        path, pos);
6936     }
6937   else
6938     {
6939       /* can't drop here */
6940       remove_open_timeout (tree_view);
6941
6942       gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
6943                                        NULL,
6944                                        GTK_TREE_VIEW_DROP_BEFORE);
6945     }
6946
6947   if (path)
6948     gtk_tree_path_free (path);
6949
6950   return TRUE;
6951 }
6952
6953 static GtkTreePath*
6954 get_logical_dest_row (GtkTreeView *tree_view,
6955                       gboolean    *path_down_mode,
6956                       gboolean    *drop_append_mode)
6957 {
6958   /* adjust path to point to the row the drop goes in front of */
6959   GtkTreePath *path = NULL;
6960   GtkTreeViewDropPosition pos;
6961
6962   g_return_val_if_fail (path_down_mode != NULL, NULL);
6963   g_return_val_if_fail (drop_append_mode != NULL, NULL);
6964
6965   *path_down_mode = FALSE;
6966   *drop_append_mode = 0;
6967
6968   gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
6969
6970   if (path == NULL)
6971     return NULL;
6972
6973   if (pos == GTK_TREE_VIEW_DROP_BEFORE)
6974     ; /* do nothing */
6975   else if (pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE ||
6976            pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER)
6977     *path_down_mode = TRUE;
6978   else
6979     {
6980       GtkTreeIter iter;
6981       GtkTreeModel *model = gtk_tree_view_get_model (tree_view);
6982
6983       g_assert (pos == GTK_TREE_VIEW_DROP_AFTER);
6984
6985       if (!gtk_tree_model_get_iter (model, &iter, path) ||
6986           !gtk_tree_model_iter_next (model, &iter))
6987         *drop_append_mode = 1;
6988       else
6989         {
6990           *drop_append_mode = 0;
6991           gtk_tree_path_next (path);
6992         }
6993     }
6994
6995   return path;
6996 }
6997
6998 static gboolean
6999 gtk_tree_view_maybe_begin_dragging_row (GtkTreeView      *tree_view,
7000                                         GdkEventMotion   *event)
7001 {
7002   GtkWidget *widget = GTK_WIDGET (tree_view);
7003   GdkDragContext *context;
7004   TreeViewDragInfo *di;
7005   GtkTreePath *path = NULL;
7006   gint button;
7007   gint cell_x, cell_y;
7008   GtkTreeModel *model;
7009   gboolean retval = FALSE;
7010
7011   di = get_info (tree_view);
7012
7013   if (di == NULL || !di->source_set)
7014     goto out;
7015
7016   if (tree_view->priv->pressed_button < 0)
7017     goto out;
7018
7019   if (!gtk_drag_check_threshold (widget,
7020                                  tree_view->priv->press_start_x,
7021                                  tree_view->priv->press_start_y,
7022                                  event->x, event->y))
7023     goto out;
7024
7025   model = gtk_tree_view_get_model (tree_view);
7026
7027   if (model == NULL)
7028     goto out;
7029
7030   button = tree_view->priv->pressed_button;
7031   tree_view->priv->pressed_button = -1;
7032
7033   gtk_tree_view_get_path_at_pos (tree_view,
7034                                  tree_view->priv->press_start_x,
7035                                  tree_view->priv->press_start_y,
7036                                  &path,
7037                                  NULL,
7038                                  &cell_x,
7039                                  &cell_y);
7040
7041   if (path == NULL)
7042     goto out;
7043
7044   if (!GTK_IS_TREE_DRAG_SOURCE (model) ||
7045       !gtk_tree_drag_source_row_draggable (GTK_TREE_DRAG_SOURCE (model),
7046                                            path))
7047     goto out;
7048
7049   if (!(GDK_BUTTON1_MASK << (button - 1) & di->start_button_mask))
7050     goto out;
7051
7052   /* Now we can begin the drag */
7053
7054   retval = TRUE;
7055
7056   context = gtk_drag_begin (widget,
7057                             gtk_drag_source_get_target_list (widget),
7058                             di->source_actions,
7059                             button,
7060                             (GdkEvent*)event);
7061
7062   set_source_row (context, model, path);
7063
7064  out:
7065   if (path)
7066     gtk_tree_path_free (path);
7067
7068   return retval;
7069 }
7070
7071
7072 static void
7073 gtk_tree_view_drag_begin (GtkWidget      *widget,
7074                           GdkDragContext *context)
7075 {
7076   GtkTreeView *tree_view;
7077   GtkTreePath *path = NULL;
7078   gint cell_x, cell_y;
7079   GdkPixmap *row_pix;
7080   TreeViewDragInfo *di;
7081
7082   tree_view = GTK_TREE_VIEW (widget);
7083
7084   /* if the user uses a custom DND source impl, we don't set the icon here */
7085   di = get_info (tree_view);
7086
7087   if (di == NULL || !di->source_set)
7088     return;
7089
7090   gtk_tree_view_get_path_at_pos (tree_view,
7091                                  tree_view->priv->press_start_x,
7092                                  tree_view->priv->press_start_y,
7093                                  &path,
7094                                  NULL,
7095                                  &cell_x,
7096                                  &cell_y);
7097
7098   g_return_if_fail (path != NULL);
7099
7100   row_pix = gtk_tree_view_create_row_drag_icon (tree_view,
7101                                                 path);
7102
7103   gtk_drag_set_icon_pixmap (context,
7104                             gdk_drawable_get_colormap (row_pix),
7105                             row_pix,
7106                             NULL,
7107                             /* the + 1 is for the black border in the icon */
7108                             tree_view->priv->press_start_x + 1,
7109                             cell_y + 1);
7110
7111   g_object_unref (row_pix);
7112   gtk_tree_path_free (path);
7113 }
7114
7115 static void
7116 gtk_tree_view_drag_end (GtkWidget      *widget,
7117                         GdkDragContext *context)
7118 {
7119   /* do nothing */
7120 }
7121
7122 /* Default signal implementations for the drag signals */
7123 static void
7124 gtk_tree_view_drag_data_get (GtkWidget        *widget,
7125                              GdkDragContext   *context,
7126                              GtkSelectionData *selection_data,
7127                              guint             info,
7128                              guint             time)
7129 {
7130   GtkTreeView *tree_view;
7131   GtkTreeModel *model;
7132   TreeViewDragInfo *di;
7133   GtkTreePath *source_row;
7134
7135   tree_view = GTK_TREE_VIEW (widget);
7136
7137   model = gtk_tree_view_get_model (tree_view);
7138
7139   if (model == NULL)
7140     return;
7141
7142   di = get_info (GTK_TREE_VIEW (widget));
7143
7144   if (di == NULL)
7145     return;
7146
7147   source_row = get_source_row (context);
7148
7149   if (source_row == NULL)
7150     return;
7151
7152   /* We can implement the GTK_TREE_MODEL_ROW target generically for
7153    * any model; for DragSource models there are some other targets
7154    * we also support.
7155    */
7156
7157   if (GTK_IS_TREE_DRAG_SOURCE (model) &&
7158       gtk_tree_drag_source_drag_data_get (GTK_TREE_DRAG_SOURCE (model),
7159                                           source_row,
7160                                           selection_data))
7161     goto done;
7162
7163   /* If drag_data_get does nothing, try providing row data. */
7164   if (selection_data->target == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
7165     {
7166       gtk_tree_set_row_drag_data (selection_data,
7167                                   model,
7168                                   source_row);
7169     }
7170
7171  done:
7172   gtk_tree_path_free (source_row);
7173 }
7174
7175
7176 static void
7177 gtk_tree_view_drag_data_delete (GtkWidget      *widget,
7178                                 GdkDragContext *context)
7179 {
7180   TreeViewDragInfo *di;
7181   GtkTreeModel *model;
7182   GtkTreeView *tree_view;
7183   GtkTreePath *source_row;
7184
7185   tree_view = GTK_TREE_VIEW (widget);
7186   model = gtk_tree_view_get_model (tree_view);
7187
7188   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_SOURCE, "drag_data_delete"))
7189     return;
7190
7191   di = get_info (tree_view);
7192
7193   if (di == NULL)
7194     return;
7195
7196   source_row = get_source_row (context);
7197
7198   if (source_row == NULL)
7199     return;
7200
7201   gtk_tree_drag_source_drag_data_delete (GTK_TREE_DRAG_SOURCE (model),
7202                                          source_row);
7203
7204   gtk_tree_path_free (source_row);
7205
7206   set_source_row (context, NULL, NULL);
7207 }
7208
7209 static void
7210 gtk_tree_view_drag_leave (GtkWidget      *widget,
7211                           GdkDragContext *context,
7212                           guint             time)
7213 {
7214   /* unset any highlight row */
7215   gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7216                                    NULL,
7217                                    GTK_TREE_VIEW_DROP_BEFORE);
7218
7219   remove_scroll_timeout (GTK_TREE_VIEW (widget));
7220   remove_open_timeout (GTK_TREE_VIEW (widget));
7221 }
7222
7223
7224 static gboolean
7225 gtk_tree_view_drag_motion (GtkWidget        *widget,
7226                            GdkDragContext   *context,
7227                            /* coordinates relative to the widget */
7228                            gint              x,
7229                            gint              y,
7230                            guint             time)
7231 {
7232   gboolean empty;
7233   GtkTreePath *path = NULL;
7234   GtkTreeViewDropPosition pos;
7235   GtkTreeView *tree_view;
7236   GdkDragAction suggested_action = 0;
7237   GdkAtom target;
7238
7239   tree_view = GTK_TREE_VIEW (widget);
7240
7241   if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
7242     return FALSE;
7243
7244   gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
7245
7246   /* we only know this *after* set_desination_row */
7247   empty = tree_view->priv->empty_view_drop;
7248
7249   if (path == NULL && !empty)
7250     {
7251       /* Can't drop here. */
7252       gdk_drag_status (context, 0, time);
7253     }
7254   else
7255     {
7256       if (tree_view->priv->open_dest_timeout == 0 &&
7257           (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
7258            pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
7259         {
7260           tree_view->priv->open_dest_timeout =
7261             gdk_threads_add_timeout (AUTO_EXPAND_TIMEOUT, open_row_timeout, tree_view);
7262         }
7263       else
7264         {
7265           add_scroll_timeout (tree_view);
7266         }
7267
7268       if (target == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
7269         {
7270           /* Request data so we can use the source row when
7271            * determining whether to accept the drop
7272            */
7273           set_status_pending (context, suggested_action);
7274           gtk_drag_get_data (widget, context, target, time);
7275         }
7276       else
7277         {
7278           set_status_pending (context, 0);
7279           gdk_drag_status (context, suggested_action, time);
7280         }
7281     }
7282
7283   if (path)
7284     gtk_tree_path_free (path);
7285
7286   return TRUE;
7287 }
7288
7289
7290 static gboolean
7291 gtk_tree_view_drag_drop (GtkWidget        *widget,
7292                          GdkDragContext   *context,
7293                          /* coordinates relative to the widget */
7294                          gint              x,
7295                          gint              y,
7296                          guint             time)
7297 {
7298   GtkTreeView *tree_view;
7299   GtkTreePath *path;
7300   GdkDragAction suggested_action = 0;
7301   GdkAtom target = GDK_NONE;
7302   TreeViewDragInfo *di;
7303   GtkTreeModel *model;
7304   gboolean path_down_mode;
7305   gboolean drop_append_mode;
7306
7307   tree_view = GTK_TREE_VIEW (widget);
7308
7309   model = gtk_tree_view_get_model (tree_view);
7310
7311   remove_scroll_timeout (GTK_TREE_VIEW (widget));
7312   remove_open_timeout (GTK_TREE_VIEW (widget));
7313
7314   di = get_info (tree_view);
7315
7316   if (di == NULL)
7317     return FALSE;
7318
7319   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_drop"))
7320     return FALSE;
7321
7322   if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
7323     return FALSE;
7324
7325   path = get_logical_dest_row (tree_view, &path_down_mode, &drop_append_mode);
7326
7327   if (target != GDK_NONE && path != NULL)
7328     {
7329       /* in case a motion had requested drag data, change things so we
7330        * treat drag data receives as a drop.
7331        */
7332       set_status_pending (context, 0);
7333       set_dest_row (context, model, path,
7334                     path_down_mode, tree_view->priv->empty_view_drop,
7335                     drop_append_mode);
7336     }
7337
7338   if (path)
7339     gtk_tree_path_free (path);
7340
7341   /* Unset this thing */
7342   gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7343                                    NULL,
7344                                    GTK_TREE_VIEW_DROP_BEFORE);
7345
7346   if (target != GDK_NONE)
7347     {
7348       gtk_drag_get_data (widget, context, target, time);
7349       return TRUE;
7350     }
7351   else
7352     return FALSE;
7353 }
7354
7355 static void
7356 gtk_tree_view_drag_data_received (GtkWidget        *widget,
7357                                   GdkDragContext   *context,
7358                                   /* coordinates relative to the widget */
7359                                   gint              x,
7360                                   gint              y,
7361                                   GtkSelectionData *selection_data,
7362                                   guint             info,
7363                                   guint             time)
7364 {
7365   GtkTreePath *path;
7366   TreeViewDragInfo *di;
7367   gboolean accepted = FALSE;
7368   GtkTreeModel *model;
7369   GtkTreeView *tree_view;
7370   GtkTreePath *dest_row;
7371   GdkDragAction suggested_action;
7372   gboolean path_down_mode;
7373   gboolean drop_append_mode;
7374
7375   tree_view = GTK_TREE_VIEW (widget);
7376
7377   model = gtk_tree_view_get_model (tree_view);
7378
7379   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_data_received"))
7380     return;
7381
7382   di = get_info (tree_view);
7383
7384   if (di == NULL)
7385     return;
7386
7387   suggested_action = get_status_pending (context);
7388
7389   if (suggested_action)
7390     {
7391       /* We are getting this data due to a request in drag_motion,
7392        * rather than due to a request in drag_drop, so we are just
7393        * supposed to call drag_status, not actually paste in the
7394        * data.
7395        */
7396       path = get_logical_dest_row (tree_view, &path_down_mode,
7397                                    &drop_append_mode);
7398
7399       if (path == NULL)
7400         suggested_action = 0;
7401       else if (path_down_mode)
7402         gtk_tree_path_down (path);
7403
7404       if (suggested_action)
7405         {
7406           if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
7407                                                      path,
7408                                                      selection_data))
7409             {
7410               if (path_down_mode)
7411                 {
7412                   path_down_mode = FALSE;
7413                   gtk_tree_path_up (path);
7414
7415                   if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
7416                                                              path,
7417                                                              selection_data))
7418                     suggested_action = 0;
7419                 }
7420               else
7421                 suggested_action = 0;
7422             }
7423         }
7424
7425       gdk_drag_status (context, suggested_action, time);
7426
7427       if (path)
7428         gtk_tree_path_free (path);
7429
7430       /* If you can't drop, remove user drop indicator until the next motion */
7431       if (suggested_action == 0)
7432         gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7433                                          NULL,
7434                                          GTK_TREE_VIEW_DROP_BEFORE);
7435
7436       return;
7437     }
7438
7439   dest_row = get_dest_row (context, &path_down_mode);
7440
7441   if (dest_row == NULL)
7442     return;
7443
7444   if (selection_data->length >= 0)
7445     {
7446       if (path_down_mode)
7447         {
7448           gtk_tree_path_down (dest_row);
7449           if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
7450                                                      dest_row, selection_data))
7451             gtk_tree_path_up (dest_row);
7452         }
7453     }
7454
7455   if (selection_data->length >= 0)
7456     {
7457       if (gtk_tree_drag_dest_drag_data_received (GTK_TREE_DRAG_DEST (model),
7458                                                  dest_row,
7459                                                  selection_data))
7460         accepted = TRUE;
7461     }
7462
7463   gtk_drag_finish (context,
7464                    accepted,
7465                    (context->action == GDK_ACTION_MOVE),
7466                    time);
7467
7468   if (gtk_tree_path_get_depth (dest_row) == 1
7469       && gtk_tree_path_get_indices (dest_row)[0] == 0)
7470     {
7471       /* special special case drag to "0", scroll to first item */
7472       if (!tree_view->priv->scroll_to_path)
7473         gtk_tree_view_scroll_to_cell (tree_view, dest_row, NULL, FALSE, 0.0, 0.0);
7474     }
7475
7476   gtk_tree_path_free (dest_row);
7477
7478   /* drop dest_row */
7479   set_dest_row (context, NULL, NULL, FALSE, FALSE, FALSE);
7480 }
7481
7482
7483
7484 /* GtkContainer Methods
7485  */
7486
7487
7488 static void
7489 gtk_tree_view_remove (GtkContainer *container,
7490                       GtkWidget    *widget)
7491 {
7492   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
7493   GtkTreeViewChild *child = NULL;
7494   GList *tmp_list;
7495
7496   tmp_list = tree_view->priv->children;
7497   while (tmp_list)
7498     {
7499       child = tmp_list->data;
7500       if (child->widget == widget)
7501         {
7502           gtk_widget_unparent (widget);
7503
7504           tree_view->priv->children = g_list_remove_link (tree_view->priv->children, tmp_list);
7505           g_list_free_1 (tmp_list);
7506           g_slice_free (GtkTreeViewChild, child);
7507           return;
7508         }
7509
7510       tmp_list = tmp_list->next;
7511     }
7512
7513   tmp_list = tree_view->priv->columns;
7514
7515   while (tmp_list)
7516     {
7517       GtkTreeViewColumn *column;
7518       column = tmp_list->data;
7519       if (column->button == widget)
7520         {
7521           gtk_widget_unparent (widget);
7522           return;
7523         }
7524       tmp_list = tmp_list->next;
7525     }
7526 }
7527
7528 static void
7529 gtk_tree_view_forall (GtkContainer *container,
7530                       gboolean      include_internals,
7531                       GtkCallback   callback,
7532                       gpointer      callback_data)
7533 {
7534   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
7535   GtkTreeViewChild *child = NULL;
7536   GtkTreeViewColumn *column;
7537   GList *tmp_list;
7538
7539   tmp_list = tree_view->priv->children;
7540   while (tmp_list)
7541     {
7542       child = tmp_list->data;
7543       tmp_list = tmp_list->next;
7544
7545       (* callback) (child->widget, callback_data);
7546     }
7547   if (include_internals == FALSE)
7548     return;
7549
7550   for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
7551     {
7552       column = tmp_list->data;
7553
7554       if (column->button)
7555         (* callback) (column->button, callback_data);
7556     }
7557 }
7558
7559 /* Returns TRUE if the treeview contains no "special" (editable or activatable)
7560  * cells. If so we draw one big row-spanning focus rectangle.
7561  */
7562 static gboolean
7563 gtk_tree_view_has_special_cell (GtkTreeView *tree_view)
7564 {
7565   GList *list;
7566
7567   for (list = tree_view->priv->columns; list; list = list->next)
7568     {
7569       if (!((GtkTreeViewColumn *)list->data)->visible)
7570         continue;
7571       if (_gtk_tree_view_column_count_special_cells (list->data))
7572         return TRUE;
7573     }
7574
7575   return FALSE;
7576 }
7577
7578 static void
7579 column_sizing_notify (GObject    *object,
7580                       GParamSpec *pspec,
7581                       gpointer    data)
7582 {
7583   GtkTreeViewColumn *c = GTK_TREE_VIEW_COLUMN (object);
7584
7585   if (gtk_tree_view_column_get_sizing (c) != GTK_TREE_VIEW_COLUMN_FIXED)
7586     /* disable fixed height mode */
7587     g_object_set (data, "fixed-height-mode", FALSE, NULL);
7588 }
7589
7590 /**
7591  * gtk_tree_view_set_fixed_height_mode:
7592  * @tree_view: a #GtkTreeView 
7593  * @enable: %TRUE to enable fixed height mode
7594  * 
7595  * Enables or disables the fixed height mode of @tree_view. 
7596  * Fixed height mode speeds up #GtkTreeView by assuming that all 
7597  * rows have the same height. 
7598  * Only enable this option if all rows are the same height and all
7599  * columns are of type %GTK_TREE_VIEW_COLUMN_FIXED.
7600  *
7601  * Since: 2.6 
7602  **/
7603 void
7604 gtk_tree_view_set_fixed_height_mode (GtkTreeView *tree_view,
7605                                      gboolean     enable)
7606 {
7607   GList *l;
7608   
7609   enable = enable != FALSE;
7610
7611   if (enable == tree_view->priv->fixed_height_mode)
7612     return;
7613
7614   if (!enable)
7615     {
7616       tree_view->priv->fixed_height_mode = 0;
7617       tree_view->priv->fixed_height = -1;
7618
7619       /* force a revalidation */
7620       install_presize_handler (tree_view);
7621     }
7622   else 
7623     {
7624       /* make sure all columns are of type FIXED */
7625       for (l = tree_view->priv->columns; l; l = l->next)
7626         {
7627           GtkTreeViewColumn *c = l->data;
7628           
7629           g_return_if_fail (gtk_tree_view_column_get_sizing (c) == GTK_TREE_VIEW_COLUMN_FIXED);
7630         }
7631       
7632       /* yes, we really have to do this is in a separate loop */
7633       for (l = tree_view->priv->columns; l; l = l->next)
7634         g_signal_connect (l->data, "notify::sizing",
7635                           G_CALLBACK (column_sizing_notify), tree_view);
7636       
7637       tree_view->priv->fixed_height_mode = 1;
7638       tree_view->priv->fixed_height = -1;
7639       
7640       if (tree_view->priv->tree)
7641         initialize_fixed_height_mode (tree_view);
7642     }
7643
7644   g_object_notify (G_OBJECT (tree_view), "fixed-height-mode");
7645 }
7646
7647 /**
7648  * gtk_tree_view_get_fixed_height_mode:
7649  * @tree_view: a #GtkTreeView
7650  * 
7651  * Returns whether fixed height mode is turned on for @tree_view.
7652  * 
7653  * Return value: %TRUE if @tree_view is in fixed height mode
7654  * 
7655  * Since: 2.6
7656  **/
7657 gboolean
7658 gtk_tree_view_get_fixed_height_mode (GtkTreeView *tree_view)
7659 {
7660   return tree_view->priv->fixed_height_mode;
7661 }
7662
7663 /* Returns TRUE if the focus is within the headers, after the focus operation is
7664  * done
7665  */
7666 static gboolean
7667 gtk_tree_view_header_focus (GtkTreeView      *tree_view,
7668                             GtkDirectionType  dir,
7669                             gboolean          clamp_column_visible)
7670 {
7671   GtkWidget *focus_child;
7672
7673   GList *last_column, *first_column;
7674   GList *tmp_list;
7675   gboolean rtl;
7676
7677   if (! GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
7678     return FALSE;
7679
7680   focus_child = GTK_CONTAINER (tree_view)->focus_child;
7681
7682   first_column = tree_view->priv->columns;
7683   while (first_column)
7684     {
7685       if (GTK_WIDGET_CAN_FOCUS (GTK_TREE_VIEW_COLUMN (first_column->data)->button) &&
7686           GTK_TREE_VIEW_COLUMN (first_column->data)->visible &&
7687           (GTK_TREE_VIEW_COLUMN (first_column->data)->clickable ||
7688            GTK_TREE_VIEW_COLUMN (first_column->data)->reorderable))
7689         break;
7690       first_column = first_column->next;
7691     }
7692
7693   /* No headers are visible, or are focusable.  We can't focus in or out.
7694    */
7695   if (first_column == NULL)
7696     return FALSE;
7697
7698   last_column = g_list_last (tree_view->priv->columns);
7699   while (last_column)
7700     {
7701       if (GTK_WIDGET_CAN_FOCUS (GTK_TREE_VIEW_COLUMN (last_column->data)->button) &&
7702           GTK_TREE_VIEW_COLUMN (last_column->data)->visible &&
7703           (GTK_TREE_VIEW_COLUMN (last_column->data)->clickable ||
7704            GTK_TREE_VIEW_COLUMN (last_column->data)->reorderable))
7705         break;
7706       last_column = last_column->prev;
7707     }
7708
7709
7710   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
7711
7712   switch (dir)
7713     {
7714     case GTK_DIR_TAB_BACKWARD:
7715     case GTK_DIR_TAB_FORWARD:
7716     case GTK_DIR_UP:
7717     case GTK_DIR_DOWN:
7718       if (focus_child == NULL)
7719         {
7720           if (tree_view->priv->focus_column != NULL && GTK_WIDGET_CAN_FOCUS (tree_view->priv->focus_column->button))
7721             focus_child = tree_view->priv->focus_column->button;
7722           else
7723             focus_child = GTK_TREE_VIEW_COLUMN (first_column->data)->button;
7724           gtk_widget_grab_focus (focus_child);
7725           break;
7726         }
7727       return FALSE;
7728
7729     case GTK_DIR_LEFT:
7730     case GTK_DIR_RIGHT:
7731       if (focus_child == NULL)
7732         {
7733           if (tree_view->priv->focus_column != NULL)
7734             focus_child = tree_view->priv->focus_column->button;
7735           else if (dir == GTK_DIR_LEFT)
7736             focus_child = GTK_TREE_VIEW_COLUMN (last_column->data)->button;
7737           else
7738             focus_child = GTK_TREE_VIEW_COLUMN (first_column->data)->button;
7739           gtk_widget_grab_focus (focus_child);
7740           break;
7741         }
7742
7743       if (gtk_widget_child_focus (focus_child, dir))
7744         {
7745           /* The focus moves inside the button. */
7746           /* This is probably a great example of bad UI */
7747           break;
7748         }
7749
7750       /* We need to move the focus among the row of buttons. */
7751       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
7752         if (GTK_TREE_VIEW_COLUMN (tmp_list->data)->button == focus_child)
7753           break;
7754
7755       if ((tmp_list == first_column && dir == (rtl ? GTK_DIR_RIGHT : GTK_DIR_LEFT))
7756           || (tmp_list == last_column && dir == (rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT)))
7757         {
7758           gtk_widget_error_bell (GTK_WIDGET (tree_view));
7759           break;
7760         }
7761
7762       while (tmp_list)
7763         {
7764           GtkTreeViewColumn *column;
7765
7766           if (dir == (rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT))
7767             tmp_list = tmp_list->next;
7768           else
7769             tmp_list = tmp_list->prev;
7770
7771           if (tmp_list == NULL)
7772             {
7773               g_warning ("Internal button not found");
7774               break;
7775             }
7776           column = tmp_list->data;
7777           if (column->button &&
7778               column->visible &&
7779               GTK_WIDGET_CAN_FOCUS (column->button))
7780             {
7781               focus_child = column->button;
7782               gtk_widget_grab_focus (column->button);
7783               break;
7784             }
7785         }
7786       break;
7787     default:
7788       g_assert_not_reached ();
7789       break;
7790     }
7791
7792   /* if focus child is non-null, we assume it's been set to the current focus child
7793    */
7794   if (focus_child)
7795     {
7796       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
7797         if (GTK_TREE_VIEW_COLUMN (tmp_list->data)->button == focus_child)
7798           {
7799             tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
7800             break;
7801           }
7802
7803       if (clamp_column_visible)
7804         {
7805           gtk_tree_view_clamp_column_visible (tree_view,
7806                                               tree_view->priv->focus_column,
7807                                               FALSE);
7808         }
7809     }
7810
7811   return (focus_child != NULL);
7812 }
7813
7814 /* This function returns in 'path' the first focusable path, if the given path
7815  * is already focusable, it's the returned one.
7816  */
7817 static gboolean
7818 search_first_focusable_path (GtkTreeView  *tree_view,
7819                              GtkTreePath **path,
7820                              gboolean      search_forward,
7821                              GtkRBTree   **new_tree,
7822                              GtkRBNode   **new_node)
7823 {
7824   GtkRBTree *tree = NULL;
7825   GtkRBNode *node = NULL;
7826
7827   if (!path || !*path)
7828     return FALSE;
7829
7830   _gtk_tree_view_find_node (tree_view, *path, &tree, &node);
7831
7832   if (!tree || !node)
7833     return FALSE;
7834
7835   while (node && row_is_separator (tree_view, NULL, *path))
7836     {
7837       if (search_forward)
7838         _gtk_rbtree_next_full (tree, node, &tree, &node);
7839       else
7840         _gtk_rbtree_prev_full (tree, node, &tree, &node);
7841
7842       if (*path)
7843         gtk_tree_path_free (*path);
7844
7845       if (node)
7846         *path = _gtk_tree_view_find_path (tree_view, tree, node);
7847       else
7848         *path = NULL;
7849     }
7850
7851   if (new_tree)
7852     *new_tree = tree;
7853
7854   if (new_node)
7855     *new_node = node;
7856
7857   return (*path != NULL);
7858 }
7859
7860 static gint
7861 gtk_tree_view_focus (GtkWidget        *widget,
7862                      GtkDirectionType  direction)
7863 {
7864   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
7865   GtkContainer *container = GTK_CONTAINER (widget);
7866   GtkWidget *focus_child;
7867
7868   if (!GTK_WIDGET_IS_SENSITIVE (container) || !GTK_WIDGET_CAN_FOCUS (widget))
7869     return FALSE;
7870
7871   focus_child = container->focus_child;
7872
7873   gtk_tree_view_stop_editing (GTK_TREE_VIEW (widget), FALSE);
7874   /* Case 1.  Headers currently have focus. */
7875   if (focus_child)
7876     {
7877       switch (direction)
7878         {
7879         case GTK_DIR_LEFT:
7880         case GTK_DIR_RIGHT:
7881           gtk_tree_view_header_focus (tree_view, direction, TRUE);
7882           return TRUE;
7883         case GTK_DIR_TAB_BACKWARD:
7884         case GTK_DIR_UP:
7885           return FALSE;
7886         case GTK_DIR_TAB_FORWARD:
7887         case GTK_DIR_DOWN:
7888           gtk_widget_grab_focus (widget);
7889           return TRUE;
7890         default:
7891           g_assert_not_reached ();
7892           return FALSE;
7893         }
7894     }
7895
7896   /* Case 2. We don't have focus at all. */
7897   if (!GTK_WIDGET_HAS_FOCUS (container))
7898     {
7899       if (!gtk_tree_view_header_focus (tree_view, direction, FALSE))
7900         gtk_widget_grab_focus (widget);
7901       return TRUE;
7902     }
7903
7904   /* Case 3. We have focus already. */
7905   if (direction == GTK_DIR_TAB_BACKWARD)
7906     return (gtk_tree_view_header_focus (tree_view, direction, FALSE));
7907   else if (direction == GTK_DIR_TAB_FORWARD)
7908     return FALSE;
7909
7910   /* Other directions caught by the keybindings */
7911   gtk_widget_grab_focus (widget);
7912   return TRUE;
7913 }
7914
7915 static void
7916 gtk_tree_view_grab_focus (GtkWidget *widget)
7917 {
7918   GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->grab_focus (widget);
7919
7920   gtk_tree_view_focus_to_cursor (GTK_TREE_VIEW (widget));
7921 }
7922
7923 static void
7924 gtk_tree_view_style_set (GtkWidget *widget,
7925                          GtkStyle *previous_style)
7926 {
7927   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
7928   GList *list;
7929   GtkTreeViewColumn *column;
7930
7931   if (GTK_WIDGET_REALIZED (widget))
7932     {
7933       gdk_window_set_back_pixmap (widget->window, NULL, FALSE);
7934       gdk_window_set_background (tree_view->priv->bin_window, &widget->style->base[widget->state]);
7935       gtk_style_set_background (widget->style, tree_view->priv->header_window, GTK_STATE_NORMAL);
7936
7937       gtk_tree_view_set_grid_lines (tree_view, tree_view->priv->grid_lines);
7938       gtk_tree_view_set_enable_tree_lines (tree_view, tree_view->priv->tree_lines_enabled);
7939     }
7940
7941   gtk_widget_style_get (widget,
7942                         "expander-size", &tree_view->priv->expander_size,
7943                         NULL);
7944   tree_view->priv->expander_size += EXPANDER_EXTRA_PADDING;
7945
7946   for (list = tree_view->priv->columns; list; list = list->next)
7947     {
7948       column = list->data;
7949       _gtk_tree_view_column_cell_set_dirty (column, TRUE);
7950     }
7951
7952   tree_view->priv->fixed_height = -1;
7953   _gtk_rbtree_mark_invalid (tree_view->priv->tree);
7954
7955   gtk_widget_queue_resize (widget);
7956 }
7957
7958
7959 static void
7960 gtk_tree_view_set_focus_child (GtkContainer *container,
7961                                GtkWidget    *child)
7962 {
7963   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
7964   GList *list;
7965
7966   for (list = tree_view->priv->columns; list; list = list->next)
7967     {
7968       if (GTK_TREE_VIEW_COLUMN (list->data)->button == child)
7969         {
7970           tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (list->data);
7971           break;
7972         }
7973     }
7974
7975   GTK_CONTAINER_CLASS (gtk_tree_view_parent_class)->set_focus_child (container, child);
7976 }
7977
7978 static void
7979 gtk_tree_view_set_adjustments (GtkTreeView   *tree_view,
7980                                GtkAdjustment *hadj,
7981                                GtkAdjustment *vadj)
7982 {
7983   gboolean need_adjust = FALSE;
7984
7985   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7986
7987   if (hadj)
7988     g_return_if_fail (GTK_IS_ADJUSTMENT (hadj));
7989   else
7990     hadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
7991   if (vadj)
7992     g_return_if_fail (GTK_IS_ADJUSTMENT (vadj));
7993   else
7994     vadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
7995
7996   if (tree_view->priv->hadjustment && (tree_view->priv->hadjustment != hadj))
7997     {
7998       g_signal_handlers_disconnect_by_func (tree_view->priv->hadjustment,
7999                                             gtk_tree_view_adjustment_changed,
8000                                             tree_view);
8001       g_object_unref (tree_view->priv->hadjustment);
8002     }
8003
8004   if (tree_view->priv->vadjustment && (tree_view->priv->vadjustment != vadj))
8005     {
8006       g_signal_handlers_disconnect_by_func (tree_view->priv->vadjustment,
8007                                             gtk_tree_view_adjustment_changed,
8008                                             tree_view);
8009       g_object_unref (tree_view->priv->vadjustment);
8010     }
8011
8012   if (tree_view->priv->hadjustment != hadj)
8013     {
8014       tree_view->priv->hadjustment = hadj;
8015       g_object_ref_sink (tree_view->priv->hadjustment);
8016
8017       g_signal_connect (tree_view->priv->hadjustment, "value-changed",
8018                         G_CALLBACK (gtk_tree_view_adjustment_changed),
8019                         tree_view);
8020       need_adjust = TRUE;
8021     }
8022
8023   if (tree_view->priv->vadjustment != vadj)
8024     {
8025       tree_view->priv->vadjustment = vadj;
8026       g_object_ref_sink (tree_view->priv->vadjustment);
8027
8028       g_signal_connect (tree_view->priv->vadjustment, "value-changed",
8029                         G_CALLBACK (gtk_tree_view_adjustment_changed),
8030                         tree_view);
8031       need_adjust = TRUE;
8032     }
8033
8034   if (need_adjust)
8035     gtk_tree_view_adjustment_changed (NULL, tree_view);
8036 }
8037
8038
8039 static gboolean
8040 gtk_tree_view_real_move_cursor (GtkTreeView       *tree_view,
8041                                 GtkMovementStep    step,
8042                                 gint               count)
8043 {
8044   GdkModifierType state;
8045
8046   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
8047   g_return_val_if_fail (step == GTK_MOVEMENT_LOGICAL_POSITIONS ||
8048                         step == GTK_MOVEMENT_VISUAL_POSITIONS ||
8049                         step == GTK_MOVEMENT_DISPLAY_LINES ||
8050                         step == GTK_MOVEMENT_PAGES ||
8051                         step == GTK_MOVEMENT_BUFFER_ENDS, FALSE);
8052
8053   if (tree_view->priv->tree == NULL)
8054     return FALSE;
8055   if (!GTK_WIDGET_HAS_FOCUS (GTK_WIDGET (tree_view)))
8056     return FALSE;
8057
8058   gtk_tree_view_stop_editing (tree_view, FALSE);
8059   GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
8060   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
8061
8062   if (gtk_get_current_event_state (&state))
8063     {
8064       if ((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
8065         tree_view->priv->ctrl_pressed = TRUE;
8066       if ((state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
8067         tree_view->priv->shift_pressed = TRUE;
8068     }
8069   /* else we assume not pressed */
8070
8071   switch (step)
8072     {
8073       /* currently we make no distinction.  When we go bi-di, we need to */
8074     case GTK_MOVEMENT_LOGICAL_POSITIONS:
8075     case GTK_MOVEMENT_VISUAL_POSITIONS:
8076       gtk_tree_view_move_cursor_left_right (tree_view, count);
8077       break;
8078     case GTK_MOVEMENT_DISPLAY_LINES:
8079       gtk_tree_view_move_cursor_up_down (tree_view, count);
8080       break;
8081     case GTK_MOVEMENT_PAGES:
8082       gtk_tree_view_move_cursor_page_up_down (tree_view, count);
8083       break;
8084     case GTK_MOVEMENT_BUFFER_ENDS:
8085       gtk_tree_view_move_cursor_start_end (tree_view, count);
8086       break;
8087     default:
8088       g_assert_not_reached ();
8089     }
8090
8091   tree_view->priv->ctrl_pressed = FALSE;
8092   tree_view->priv->shift_pressed = FALSE;
8093
8094   return TRUE;
8095 }
8096
8097 static void
8098 gtk_tree_view_put (GtkTreeView *tree_view,
8099                    GtkWidget   *child_widget,
8100                    /* in bin_window coordinates */
8101                    gint         x,
8102                    gint         y,
8103                    gint         width,
8104                    gint         height)
8105 {
8106   GtkTreeViewChild *child;
8107   
8108   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8109   g_return_if_fail (GTK_IS_WIDGET (child_widget));
8110
8111   child = g_slice_new (GtkTreeViewChild);
8112
8113   child->widget = child_widget;
8114   child->x = x;
8115   child->y = y;
8116   child->width = width;
8117   child->height = height;
8118
8119   tree_view->priv->children = g_list_append (tree_view->priv->children, child);
8120
8121   if (GTK_WIDGET_REALIZED (tree_view))
8122     gtk_widget_set_parent_window (child->widget, tree_view->priv->bin_window);
8123   
8124   gtk_widget_set_parent (child_widget, GTK_WIDGET (tree_view));
8125 }
8126
8127 void
8128 _gtk_tree_view_child_move_resize (GtkTreeView *tree_view,
8129                                   GtkWidget   *widget,
8130                                   /* in tree coordinates */
8131                                   gint         x,
8132                                   gint         y,
8133                                   gint         width,
8134                                   gint         height)
8135 {
8136   GtkTreeViewChild *child = NULL;
8137   GList *list;
8138   GdkRectangle allocation;
8139
8140   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8141   g_return_if_fail (GTK_IS_WIDGET (widget));
8142
8143   for (list = tree_view->priv->children; list; list = list->next)
8144     {
8145       if (((GtkTreeViewChild *)list->data)->widget == widget)
8146         {
8147           child = list->data;
8148           break;
8149         }
8150     }
8151   if (child == NULL)
8152     return;
8153
8154   allocation.x = child->x = x;
8155   allocation.y = child->y = y;
8156   allocation.width = child->width = width;
8157   allocation.height = child->height = height;
8158
8159   if (GTK_WIDGET_REALIZED (widget))
8160     gtk_widget_size_allocate (widget, &allocation);
8161 }
8162
8163
8164 /* TreeModel Callbacks
8165  */
8166
8167 static void
8168 gtk_tree_view_row_changed (GtkTreeModel *model,
8169                            GtkTreePath  *path,
8170                            GtkTreeIter  *iter,
8171                            gpointer      data)
8172 {
8173   GtkTreeView *tree_view = (GtkTreeView *)data;
8174   GtkRBTree *tree;
8175   GtkRBNode *node;
8176   gboolean free_path = FALSE;
8177   GList *list;
8178   GtkTreePath *cursor_path;
8179
8180   g_return_if_fail (path != NULL || iter != NULL);
8181
8182   if (tree_view->priv->cursor != NULL)
8183     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
8184   else
8185     cursor_path = NULL;
8186
8187   if (tree_view->priv->edited_column &&
8188       (cursor_path == NULL || gtk_tree_path_compare (cursor_path, path) == 0))
8189     gtk_tree_view_stop_editing (tree_view, TRUE);
8190
8191   if (cursor_path != NULL)
8192     gtk_tree_path_free (cursor_path);
8193
8194   if (path == NULL)
8195     {
8196       path = gtk_tree_model_get_path (model, iter);
8197       free_path = TRUE;
8198     }
8199   else if (iter == NULL)
8200     gtk_tree_model_get_iter (model, iter, path);
8201
8202   if (_gtk_tree_view_find_node (tree_view,
8203                                 path,
8204                                 &tree,
8205                                 &node))
8206     /* We aren't actually showing the node */
8207     goto done;
8208
8209   if (tree == NULL)
8210     goto done;
8211
8212   if (tree_view->priv->fixed_height_mode
8213       && tree_view->priv->fixed_height >= 0)
8214     {
8215       _gtk_rbtree_node_set_height (tree, node, tree_view->priv->fixed_height);
8216       if (GTK_WIDGET_REALIZED (tree_view))
8217         gtk_tree_view_node_queue_redraw (tree_view, tree, node);
8218     }
8219   else
8220     {
8221       _gtk_rbtree_node_mark_invalid (tree, node);
8222       for (list = tree_view->priv->columns; list; list = list->next)
8223         {
8224           GtkTreeViewColumn *column;
8225
8226           column = list->data;
8227           if (! column->visible)
8228             continue;
8229
8230           if (column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
8231             {
8232               _gtk_tree_view_column_cell_set_dirty (column, TRUE);
8233             }
8234         }
8235     }
8236
8237  done:
8238   if (GTK_WIDGET_REALIZED (tree_view) && !tree_view->priv->fixed_height_mode)
8239     install_presize_handler (tree_view);
8240   if (free_path)
8241     gtk_tree_path_free (path);
8242 }
8243
8244 static void
8245 gtk_tree_view_row_inserted (GtkTreeModel *model,
8246                             GtkTreePath  *path,
8247                             GtkTreeIter  *iter,
8248                             gpointer      data)
8249 {
8250   GtkTreeView *tree_view = (GtkTreeView *) data;
8251   gint *indices;
8252   GtkRBTree *tmptree, *tree;
8253   GtkRBNode *tmpnode = NULL;
8254   gint depth;
8255   gint i = 0;
8256   gint height;
8257   gboolean free_path = FALSE;
8258   gboolean node_visible = TRUE;
8259
8260   g_return_if_fail (path != NULL || iter != NULL);
8261
8262   if (tree_view->priv->fixed_height_mode
8263       && tree_view->priv->fixed_height >= 0)
8264     height = tree_view->priv->fixed_height;
8265   else
8266     height = 0;
8267
8268   if (path == NULL)
8269     {
8270       path = gtk_tree_model_get_path (model, iter);
8271       free_path = TRUE;
8272     }
8273   else if (iter == NULL)
8274     gtk_tree_model_get_iter (model, iter, path);
8275
8276   if (tree_view->priv->tree == NULL)
8277     tree_view->priv->tree = _gtk_rbtree_new ();
8278
8279   tmptree = tree = tree_view->priv->tree;
8280
8281   /* Update all row-references */
8282   gtk_tree_row_reference_inserted (G_OBJECT (data), path);
8283   depth = gtk_tree_path_get_depth (path);
8284   indices = gtk_tree_path_get_indices (path);
8285
8286   /* First, find the parent tree */
8287   while (i < depth - 1)
8288     {
8289       if (tmptree == NULL)
8290         {
8291           /* We aren't showing the node */
8292           node_visible = FALSE;
8293           goto done;
8294         }
8295
8296       tmpnode = _gtk_rbtree_find_count (tmptree, indices[i] + 1);
8297       if (tmpnode == NULL)
8298         {
8299           g_warning ("A node was inserted with a parent that's not in the tree.\n" \
8300                      "This possibly means that a GtkTreeModel inserted a child node\n" \
8301                      "before the parent was inserted.");
8302           goto done;
8303         }
8304       else if (!GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_IS_PARENT))
8305         {
8306           /* FIXME enforce correct behavior on model, probably */
8307           /* In theory, the model should have emitted has_child_toggled here.  We
8308            * try to catch it anyway, just to be safe, in case the model hasn't.
8309            */
8310           GtkTreePath *tmppath = _gtk_tree_view_find_path (tree_view,
8311                                                            tree,
8312                                                            tmpnode);
8313           gtk_tree_view_row_has_child_toggled (model, tmppath, NULL, data);
8314           gtk_tree_path_free (tmppath);
8315           goto done;
8316         }
8317
8318       tmptree = tmpnode->children;
8319       tree = tmptree;
8320       i++;
8321     }
8322
8323   if (tree == NULL)
8324     {
8325       node_visible = FALSE;
8326       goto done;
8327     }
8328
8329   /* ref the node */
8330   gtk_tree_model_ref_node (tree_view->priv->model, iter);
8331   if (indices[depth - 1] == 0)
8332     {
8333       tmpnode = _gtk_rbtree_find_count (tree, 1);
8334       tmpnode = _gtk_rbtree_insert_before (tree, tmpnode, height, FALSE);
8335     }
8336   else
8337     {
8338       tmpnode = _gtk_rbtree_find_count (tree, indices[depth - 1]);
8339       tmpnode = _gtk_rbtree_insert_after (tree, tmpnode, height, FALSE);
8340     }
8341
8342  done:
8343   if (height > 0)
8344     {
8345       if (tree)
8346         _gtk_rbtree_node_mark_valid (tree, tmpnode);
8347
8348       if (node_visible && node_is_visible (tree_view, tree, tmpnode))
8349         gtk_widget_queue_resize (GTK_WIDGET (tree_view));
8350       else
8351         gtk_widget_queue_resize_no_redraw (GTK_WIDGET (tree_view));
8352     }
8353   else
8354     install_presize_handler (tree_view);
8355   if (free_path)
8356     gtk_tree_path_free (path);
8357 }
8358
8359 static void
8360 gtk_tree_view_row_has_child_toggled (GtkTreeModel *model,
8361                                      GtkTreePath  *path,
8362                                      GtkTreeIter  *iter,
8363                                      gpointer      data)
8364 {
8365   GtkTreeView *tree_view = (GtkTreeView *)data;
8366   GtkTreeIter real_iter;
8367   gboolean has_child;
8368   GtkRBTree *tree;
8369   GtkRBNode *node;
8370   gboolean free_path = FALSE;
8371
8372   g_return_if_fail (path != NULL || iter != NULL);
8373
8374   if (iter)
8375     real_iter = *iter;
8376
8377   if (path == NULL)
8378     {
8379       path = gtk_tree_model_get_path (model, iter);
8380       free_path = TRUE;
8381     }
8382   else if (iter == NULL)
8383     gtk_tree_model_get_iter (model, &real_iter, path);
8384
8385   if (_gtk_tree_view_find_node (tree_view,
8386                                 path,
8387                                 &tree,
8388                                 &node))
8389     /* We aren't actually showing the node */
8390     goto done;
8391
8392   if (tree == NULL)
8393     goto done;
8394
8395   has_child = gtk_tree_model_iter_has_child (model, &real_iter);
8396   /* Sanity check.
8397    */
8398   if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT) == has_child)
8399     goto done;
8400
8401   if (has_child)
8402     GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_PARENT);
8403   else
8404     GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_PARENT);
8405
8406   if (has_child && GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IS_LIST))
8407     {
8408       GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IS_LIST);
8409       if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS))
8410         {
8411           GList *list;
8412
8413           for (list = tree_view->priv->columns; list; list = list->next)
8414             if (GTK_TREE_VIEW_COLUMN (list->data)->visible)
8415               {
8416                 GTK_TREE_VIEW_COLUMN (list->data)->dirty = TRUE;
8417                 _gtk_tree_view_column_cell_set_dirty (GTK_TREE_VIEW_COLUMN (list->data), TRUE);
8418                 break;
8419               }
8420         }
8421       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
8422     }
8423   else
8424     {
8425       _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
8426     }
8427
8428  done:
8429   if (free_path)
8430     gtk_tree_path_free (path);
8431 }
8432
8433 static void
8434 count_children_helper (GtkRBTree *tree,
8435                        GtkRBNode *node,
8436                        gpointer   data)
8437 {
8438   if (node->children)
8439     _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, data);
8440   (*((gint *)data))++;
8441 }
8442
8443 static void
8444 check_selection_helper (GtkRBTree *tree,
8445                         GtkRBNode *node,
8446                         gpointer   data)
8447 {
8448   gint *value = (gint *)data;
8449
8450   *value = GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED);
8451
8452   if (node->children && !*value)
8453     _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, check_selection_helper, data);
8454 }
8455
8456 static void
8457 gtk_tree_view_row_deleted (GtkTreeModel *model,
8458                            GtkTreePath  *path,
8459                            gpointer      data)
8460 {
8461   GtkTreeView *tree_view = (GtkTreeView *)data;
8462   GtkRBTree *tree;
8463   GtkRBNode *node;
8464   GList *list;
8465   gint selection_changed = FALSE;
8466
8467   g_return_if_fail (path != NULL);
8468
8469   gtk_tree_row_reference_deleted (G_OBJECT (data), path);
8470
8471   if (_gtk_tree_view_find_node (tree_view, path, &tree, &node))
8472     return;
8473
8474   if (tree == NULL)
8475     return;
8476
8477   /* check if the selection has been changed */
8478   _gtk_rbtree_traverse (tree, node, G_POST_ORDER,
8479                         check_selection_helper, &selection_changed);
8480
8481   for (list = tree_view->priv->columns; list; list = list->next)
8482     if (((GtkTreeViewColumn *)list->data)->visible &&
8483         ((GtkTreeViewColumn *)list->data)->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
8484       _gtk_tree_view_column_cell_set_dirty ((GtkTreeViewColumn *)list->data, TRUE);
8485
8486   /* Ensure we don't have a dangling pointer to a dead node */
8487   ensure_unprelighted (tree_view);
8488
8489   /* Cancel editting if we've started */
8490   gtk_tree_view_stop_editing (tree_view, TRUE);
8491
8492   /* If we have a node expanded/collapsed timeout, remove it */
8493   remove_expand_collapse_timeout (tree_view);
8494
8495   if (tree_view->priv->destroy_count_func)
8496     {
8497       gint child_count = 0;
8498       if (node->children)
8499         _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, &child_count);
8500       tree_view->priv->destroy_count_func (tree_view, path, child_count, tree_view->priv->destroy_count_data);
8501     }
8502
8503   if (tree->root->count == 1)
8504     {
8505       if (tree_view->priv->tree == tree)
8506         tree_view->priv->tree = NULL;
8507
8508       _gtk_rbtree_remove (tree);
8509     }
8510   else
8511     {
8512       _gtk_rbtree_remove_node (tree, node);
8513     }
8514
8515   if (! gtk_tree_row_reference_valid (tree_view->priv->top_row))
8516     {
8517       gtk_tree_row_reference_free (tree_view->priv->top_row);
8518       tree_view->priv->top_row = NULL;
8519     }
8520
8521   install_scroll_sync_handler (tree_view);
8522
8523   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
8524
8525   if (selection_changed)
8526     g_signal_emit_by_name (tree_view->priv->selection, "changed");
8527 }
8528
8529 static void
8530 gtk_tree_view_rows_reordered (GtkTreeModel *model,
8531                               GtkTreePath  *parent,
8532                               GtkTreeIter  *iter,
8533                               gint         *new_order,
8534                               gpointer      data)
8535 {
8536   GtkTreeView *tree_view = GTK_TREE_VIEW (data);
8537   GtkRBTree *tree;
8538   GtkRBNode *node;
8539   gint len;
8540
8541   len = gtk_tree_model_iter_n_children (model, iter);
8542
8543   if (len < 2)
8544     return;
8545
8546   gtk_tree_row_reference_reordered (G_OBJECT (data),
8547                                     parent,
8548                                     iter,
8549                                     new_order);
8550
8551   if (_gtk_tree_view_find_node (tree_view,
8552                                 parent,
8553                                 &tree,
8554                                 &node))
8555     return;
8556
8557   /* We need to special case the parent path */
8558   if (tree == NULL)
8559     tree = tree_view->priv->tree;
8560   else
8561     tree = node->children;
8562
8563   if (tree == NULL)
8564     return;
8565
8566   if (tree_view->priv->edited_column)
8567     gtk_tree_view_stop_editing (tree_view, TRUE);
8568
8569   /* we need to be unprelighted */
8570   ensure_unprelighted (tree_view);
8571
8572   /* clear the timeout */
8573   cancel_arrow_animation (tree_view);
8574   
8575   _gtk_rbtree_reorder (tree, new_order, len);
8576
8577   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
8578
8579   gtk_tree_view_dy_to_top_row (tree_view);
8580 }
8581
8582
8583 /* Internal tree functions
8584  */
8585
8586
8587 static void
8588 gtk_tree_view_get_background_xrange (GtkTreeView       *tree_view,
8589                                      GtkRBTree         *tree,
8590                                      GtkTreeViewColumn *column,
8591                                      gint              *x1,
8592                                      gint              *x2)
8593 {
8594   GtkTreeViewColumn *tmp_column = NULL;
8595   gint total_width;
8596   GList *list;
8597   gboolean rtl;
8598
8599   if (x1)
8600     *x1 = 0;
8601
8602   if (x2)
8603     *x2 = 0;
8604
8605   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
8606
8607   total_width = 0;
8608   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
8609        list;
8610        list = (rtl ? list->prev : list->next))
8611     {
8612       tmp_column = list->data;
8613
8614       if (tmp_column == column)
8615         break;
8616
8617       if (tmp_column->visible)
8618         total_width += tmp_column->width;
8619     }
8620
8621   if (tmp_column != column)
8622     {
8623       g_warning (G_STRLOC": passed-in column isn't in the tree");
8624       return;
8625     }
8626
8627   if (x1)
8628     *x1 = total_width;
8629
8630   if (x2)
8631     {
8632       if (column->visible)
8633         *x2 = total_width + column->width;
8634       else
8635         *x2 = total_width; /* width of 0 */
8636     }
8637 }
8638 static void
8639 gtk_tree_view_get_arrow_xrange (GtkTreeView *tree_view,
8640                                 GtkRBTree   *tree,
8641                                 gint        *x1,
8642                                 gint        *x2)
8643 {
8644   gint x_offset = 0;
8645   GList *list;
8646   GtkTreeViewColumn *tmp_column = NULL;
8647   gint total_width;
8648   gboolean indent_expanders;
8649   gboolean rtl;
8650
8651   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
8652
8653   total_width = 0;
8654   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
8655        list;
8656        list = (rtl ? list->prev : list->next))
8657     {
8658       tmp_column = list->data;
8659
8660       if (gtk_tree_view_is_expander_column (tree_view, tmp_column))
8661         {
8662           if (rtl)
8663             x_offset = total_width + tmp_column->width - tree_view->priv->expander_size;
8664           else
8665             x_offset = total_width;
8666           break;
8667         }
8668
8669       if (tmp_column->visible)
8670         total_width += tmp_column->width;
8671     }
8672
8673   gtk_widget_style_get (GTK_WIDGET (tree_view),
8674                         "indent-expanders", &indent_expanders,
8675                         NULL);
8676
8677   if (indent_expanders)
8678     {
8679       if (rtl)
8680         x_offset -= tree_view->priv->expander_size * _gtk_rbtree_get_depth (tree);
8681       else
8682         x_offset += tree_view->priv->expander_size * _gtk_rbtree_get_depth (tree);
8683     }
8684
8685   *x1 = x_offset;
8686   
8687   if (tmp_column && tmp_column->visible)
8688     /* +1 because x2 isn't included in the range. */
8689     *x2 = *x1 + tree_view->priv->expander_size + 1;
8690   else
8691     *x2 = *x1;
8692 }
8693
8694 static void
8695 gtk_tree_view_build_tree (GtkTreeView *tree_view,
8696                           GtkRBTree   *tree,
8697                           GtkTreeIter *iter,
8698                           gint         depth,
8699                           gboolean     recurse)
8700 {
8701   GtkRBNode *temp = NULL;
8702   GtkTreePath *path = NULL;
8703   gboolean is_list = GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IS_LIST);
8704
8705   do
8706     {
8707       gtk_tree_model_ref_node (tree_view->priv->model, iter);
8708       temp = _gtk_rbtree_insert_after (tree, temp, 0, FALSE);
8709
8710       if (tree_view->priv->fixed_height > 0)
8711         {
8712           if (GTK_RBNODE_FLAG_SET (temp, GTK_RBNODE_INVALID))
8713             {
8714               _gtk_rbtree_node_set_height (tree, temp, tree_view->priv->fixed_height);
8715               _gtk_rbtree_node_mark_valid (tree, temp);
8716             }
8717         }
8718
8719       if (is_list)
8720         continue;
8721
8722       if (recurse)
8723         {
8724           GtkTreeIter child;
8725
8726           if (!path)
8727             path = gtk_tree_model_get_path (tree_view->priv->model, iter);
8728           else
8729             gtk_tree_path_next (path);
8730
8731           if (gtk_tree_model_iter_children (tree_view->priv->model, &child, iter))
8732             {
8733               gboolean expand;
8734
8735               g_signal_emit (tree_view, tree_view_signals[TEST_EXPAND_ROW], 0, iter, path, &expand);
8736
8737               if (gtk_tree_model_iter_has_child (tree_view->priv->model, iter)
8738                   && !expand)
8739                 {
8740                   temp->children = _gtk_rbtree_new ();
8741                   temp->children->parent_tree = tree;
8742                   temp->children->parent_node = temp;
8743                   gtk_tree_view_build_tree (tree_view, temp->children, &child, depth + 1, recurse);
8744                 }
8745             }
8746         }
8747
8748       if (gtk_tree_model_iter_has_child (tree_view->priv->model, iter))
8749         {
8750           if ((temp->flags&GTK_RBNODE_IS_PARENT) != GTK_RBNODE_IS_PARENT)
8751             temp->flags ^= GTK_RBNODE_IS_PARENT;
8752         }
8753     }
8754   while (gtk_tree_model_iter_next (tree_view->priv->model, iter));
8755
8756   if (path)
8757     gtk_tree_path_free (path);
8758 }
8759
8760 /* If height is non-NULL, then we set it to be the new height.  if it's all
8761  * dirty, then height is -1.  We know we'll remeasure dirty rows, anyways.
8762  */
8763 static gboolean
8764 gtk_tree_view_discover_dirty_iter (GtkTreeView *tree_view,
8765                                    GtkTreeIter *iter,
8766                                    gint         depth,
8767                                    gint        *height,
8768                                    GtkRBNode   *node)
8769 {
8770   GtkTreeViewColumn *column;
8771   GList *list;
8772   gboolean retval = FALSE;
8773   gint tmpheight;
8774   gint horizontal_separator;
8775
8776   gtk_widget_style_get (GTK_WIDGET (tree_view),
8777                         "horizontal-separator", &horizontal_separator,
8778                         NULL);
8779
8780   if (height)
8781     *height = -1;
8782
8783   for (list = tree_view->priv->columns; list; list = list->next)
8784     {
8785       gint width;
8786       column = list->data;
8787       if (column->dirty == TRUE)
8788         continue;
8789       if (height == NULL && column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
8790         continue;
8791       if (!column->visible)
8792         continue;
8793
8794       gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, iter,
8795                                                GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
8796                                                node->children?TRUE:FALSE);
8797
8798       if (height)
8799         {
8800           gtk_tree_view_column_cell_get_size (column,
8801                                               NULL, NULL, NULL,
8802                                               &width, &tmpheight);
8803           *height = MAX (*height, tmpheight);
8804         }
8805       else
8806         {
8807           gtk_tree_view_column_cell_get_size (column,
8808                                               NULL, NULL, NULL,
8809                                               &width, NULL);
8810         }
8811
8812       if (gtk_tree_view_is_expander_column (tree_view, column))
8813         {
8814           int tmp = 0;
8815
8816           tmp = horizontal_separator + width + (depth - 1) * tree_view->priv->level_indentation;
8817           if (TREE_VIEW_DRAW_EXPANDERS (tree_view))
8818             tmp += depth * tree_view->priv->expander_size;
8819
8820           if (tmp > column->requested_width)
8821             {
8822               _gtk_tree_view_column_cell_set_dirty (column, TRUE);
8823               retval = TRUE;
8824             }
8825         }
8826       else
8827         {
8828           if (horizontal_separator + width > column->requested_width)
8829             {
8830               _gtk_tree_view_column_cell_set_dirty (column, TRUE);
8831               retval = TRUE;
8832             }
8833         }
8834     }
8835
8836   return retval;
8837 }
8838
8839 static void
8840 gtk_tree_view_discover_dirty (GtkTreeView *tree_view,
8841                               GtkRBTree   *tree,
8842                               GtkTreeIter *iter,
8843                               gint         depth)
8844 {
8845   GtkRBNode *temp = tree->root;
8846   GtkTreeViewColumn *column;
8847   GList *list;
8848   GtkTreeIter child;
8849   gboolean is_all_dirty;
8850
8851   TREE_VIEW_INTERNAL_ASSERT_VOID (tree != NULL);
8852
8853   while (temp->left != tree->nil)
8854     temp = temp->left;
8855
8856   do
8857     {
8858       TREE_VIEW_INTERNAL_ASSERT_VOID (temp != NULL);
8859       is_all_dirty = TRUE;
8860       for (list = tree_view->priv->columns; list; list = list->next)
8861         {
8862           column = list->data;
8863           if (column->dirty == FALSE)
8864             {
8865               is_all_dirty = FALSE;
8866               break;
8867             }
8868         }
8869
8870       if (is_all_dirty)
8871         return;
8872
8873       gtk_tree_view_discover_dirty_iter (tree_view,
8874                                          iter,
8875                                          depth,
8876                                          NULL,
8877                                          temp);
8878       if (gtk_tree_model_iter_children (tree_view->priv->model, &child, iter) &&
8879           temp->children != NULL)
8880         gtk_tree_view_discover_dirty (tree_view, temp->children, &child, depth + 1);
8881       temp = _gtk_rbtree_next (tree, temp);
8882     }
8883   while (gtk_tree_model_iter_next (tree_view->priv->model, iter));
8884 }
8885
8886
8887 /* Make sure the node is visible vertically */
8888 static void
8889 gtk_tree_view_clamp_node_visible (GtkTreeView *tree_view,
8890                                   GtkRBTree   *tree,
8891                                   GtkRBNode   *node)
8892 {
8893   gint node_dy, height;
8894   GtkTreePath *path = NULL;
8895
8896   if (!GTK_WIDGET_REALIZED (tree_view))
8897     return;
8898
8899   /* just return if the node is visible, avoiding a costly expose */
8900   node_dy = _gtk_rbtree_node_find_offset (tree, node);
8901   height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
8902   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID)
8903       && node_dy >= tree_view->priv->vadjustment->value
8904       && node_dy + height <= (tree_view->priv->vadjustment->value
8905                               + tree_view->priv->vadjustment->page_size))
8906     return;
8907
8908   path = _gtk_tree_view_find_path (tree_view, tree, node);
8909   if (path)
8910     {
8911       /* We process updates because we want to clear old selected items when we scroll.
8912        * if this is removed, we get a "selection streak" at the bottom. */
8913       gdk_window_process_updates (tree_view->priv->bin_window, TRUE);
8914       gtk_tree_view_scroll_to_cell (tree_view, path, NULL, FALSE, 0.0, 0.0);
8915       gtk_tree_path_free (path);
8916     }
8917 }
8918
8919 static void
8920 gtk_tree_view_clamp_column_visible (GtkTreeView       *tree_view,
8921                                     GtkTreeViewColumn *column,
8922                                     gboolean           focus_to_cell)
8923 {
8924   gint x, width;
8925
8926   if (column == NULL)
8927     return;
8928
8929   x = column->button->allocation.x;
8930   width = column->button->allocation.width;
8931
8932   if (width > tree_view->priv->hadjustment->page_size)
8933     {
8934       /* The column is larger than the horizontal page size.  If the
8935        * column has cells which can be focussed individually, then we make
8936        * sure the cell which gets focus is fully visible (if even the
8937        * focus cell is bigger than the page size, we make sure the
8938        * left-hand side of the cell is visible).
8939        *
8940        * If the column does not have those so-called special cells, we
8941        * make sure the left-hand side of the column is visible.
8942        */
8943
8944       if (focus_to_cell && gtk_tree_view_has_special_cell (tree_view))
8945         {
8946           GtkTreePath *cursor_path;
8947           GdkRectangle background_area, cell_area, focus_area;
8948
8949           cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
8950
8951           gtk_tree_view_get_cell_area (tree_view,
8952                                        cursor_path, column, &cell_area);
8953           gtk_tree_view_get_background_area (tree_view,
8954                                              cursor_path, column,
8955                                              &background_area);
8956
8957           gtk_tree_path_free (cursor_path);
8958
8959           _gtk_tree_view_column_get_focus_area (column,
8960                                                 &background_area,
8961                                                 &cell_area,
8962                                                 &focus_area);
8963
8964           x = focus_area.x;
8965           width = focus_area.width;
8966
8967           if (width < tree_view->priv->hadjustment->page_size)
8968             {
8969               if ((tree_view->priv->hadjustment->value + tree_view->priv->hadjustment->page_size) < (x + width))
8970                 gtk_adjustment_set_value (tree_view->priv->hadjustment,
8971                                           x + width - tree_view->priv->hadjustment->page_size);
8972               else if (tree_view->priv->hadjustment->value > x)
8973                 gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
8974             }
8975         }
8976
8977       gtk_adjustment_set_value (tree_view->priv->hadjustment,
8978                                 CLAMP (x,
8979                                        tree_view->priv->hadjustment->lower,
8980                                        tree_view->priv->hadjustment->upper
8981                                        - tree_view->priv->hadjustment->page_size));
8982     }
8983   else
8984     {
8985       if ((tree_view->priv->hadjustment->value + tree_view->priv->hadjustment->page_size) < (x + width))
8986           gtk_adjustment_set_value (tree_view->priv->hadjustment,
8987                                     x + width - tree_view->priv->hadjustment->page_size);
8988       else if (tree_view->priv->hadjustment->value > x)
8989         gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
8990   }
8991 }
8992
8993 /* This function could be more efficient.  I'll optimize it if profiling seems
8994  * to imply that it is important */
8995 GtkTreePath *
8996 _gtk_tree_view_find_path (GtkTreeView *tree_view,
8997                           GtkRBTree   *tree,
8998                           GtkRBNode   *node)
8999 {
9000   GtkTreePath *path;
9001   GtkRBTree *tmp_tree;
9002   GtkRBNode *tmp_node, *last;
9003   gint count;
9004
9005   path = gtk_tree_path_new ();
9006
9007   g_return_val_if_fail (node != NULL, path);
9008   g_return_val_if_fail (node != tree->nil, path);
9009
9010   count = 1 + node->left->count;
9011
9012   last = node;
9013   tmp_node = node->parent;
9014   tmp_tree = tree;
9015   while (tmp_tree)
9016     {
9017       while (tmp_node != tmp_tree->nil)
9018         {
9019           if (tmp_node->right == last)
9020             count += 1 + tmp_node->left->count;
9021           last = tmp_node;
9022           tmp_node = tmp_node->parent;
9023         }
9024       gtk_tree_path_prepend_index (path, count - 1);
9025       last = tmp_tree->parent_node;
9026       tmp_tree = tmp_tree->parent_tree;
9027       if (last)
9028         {
9029           count = 1 + last->left->count;
9030           tmp_node = last->parent;
9031         }
9032     }
9033   return path;
9034 }
9035
9036 /* Returns TRUE if we ran out of tree before finding the path.  If the path is
9037  * invalid (ie. points to a node that's not in the tree), *tree and *node are
9038  * both set to NULL.
9039  */
9040 gboolean
9041 _gtk_tree_view_find_node (GtkTreeView  *tree_view,
9042                           GtkTreePath  *path,
9043                           GtkRBTree   **tree,
9044                           GtkRBNode   **node)
9045 {
9046   GtkRBNode *tmpnode = NULL;
9047   GtkRBTree *tmptree = tree_view->priv->tree;
9048   gint *indices = gtk_tree_path_get_indices (path);
9049   gint depth = gtk_tree_path_get_depth (path);
9050   gint i = 0;
9051
9052   *node = NULL;
9053   *tree = NULL;
9054
9055   if (depth == 0 || tmptree == NULL)
9056     return FALSE;
9057   do
9058     {
9059       tmpnode = _gtk_rbtree_find_count (tmptree, indices[i] + 1);
9060       ++i;
9061       if (tmpnode == NULL)
9062         {
9063           *tree = NULL;
9064           *node = NULL;
9065           return FALSE;
9066         }
9067       if (i >= depth)
9068         {
9069           *tree = tmptree;
9070           *node = tmpnode;
9071           return FALSE;
9072         }
9073       *tree = tmptree;
9074       *node = tmpnode;
9075       tmptree = tmpnode->children;
9076       if (tmptree == NULL)
9077         return TRUE;
9078     }
9079   while (1);
9080 }
9081
9082 static gboolean
9083 gtk_tree_view_is_expander_column (GtkTreeView       *tree_view,
9084                                   GtkTreeViewColumn *column)
9085 {
9086   GList *list;
9087
9088   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IS_LIST))
9089     return FALSE;
9090
9091   if (tree_view->priv->expander_column != NULL)
9092     {
9093       if (tree_view->priv->expander_column == column)
9094         return TRUE;
9095       return FALSE;
9096     }
9097   else
9098     {
9099       for (list = tree_view->priv->columns;
9100            list;
9101            list = list->next)
9102         if (((GtkTreeViewColumn *)list->data)->visible)
9103           break;
9104       if (list && list->data == column)
9105         return TRUE;
9106     }
9107   return FALSE;
9108 }
9109
9110 static void
9111 gtk_tree_view_add_move_binding (GtkBindingSet  *binding_set,
9112                                 guint           keyval,
9113                                 guint           modmask,
9114                                 gboolean        add_shifted_binding,
9115                                 GtkMovementStep step,
9116                                 gint            count)
9117 {
9118   
9119   gtk_binding_entry_add_signal (binding_set, keyval, modmask,
9120                                 "move-cursor", 2,
9121                                 G_TYPE_ENUM, step,
9122                                 G_TYPE_INT, count);
9123
9124   if (add_shifted_binding)
9125     gtk_binding_entry_add_signal (binding_set, keyval, GDK_SHIFT_MASK,
9126                                   "move-cursor", 2,
9127                                   G_TYPE_ENUM, step,
9128                                   G_TYPE_INT, count);
9129
9130   if ((modmask & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
9131    return;
9132
9133   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK | GDK_SHIFT_MASK,
9134                                 "move-cursor", 2,
9135                                 G_TYPE_ENUM, step,
9136                                 G_TYPE_INT, count);
9137
9138   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK,
9139                                 "move-cursor", 2,
9140                                 G_TYPE_ENUM, step,
9141                                 G_TYPE_INT, count);
9142 }
9143
9144 static gint
9145 gtk_tree_view_unref_tree_helper (GtkTreeModel *model,
9146                                  GtkTreeIter  *iter,
9147                                  GtkRBTree    *tree,
9148                                  GtkRBNode    *node)
9149 {
9150   gint retval = FALSE;
9151   do
9152     {
9153       g_return_val_if_fail (node != NULL, FALSE);
9154
9155       if (node->children)
9156         {
9157           GtkTreeIter child;
9158           GtkRBTree *new_tree;
9159           GtkRBNode *new_node;
9160
9161           new_tree = node->children;
9162           new_node = new_tree->root;
9163
9164           while (new_node && new_node->left != new_tree->nil)
9165             new_node = new_node->left;
9166
9167           if (!gtk_tree_model_iter_children (model, &child, iter))
9168             return FALSE;
9169
9170           retval = retval || gtk_tree_view_unref_tree_helper (model, &child, new_tree, new_node);
9171         }
9172
9173       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
9174         retval = TRUE;
9175       gtk_tree_model_unref_node (model, iter);
9176       node = _gtk_rbtree_next (tree, node);
9177     }
9178   while (gtk_tree_model_iter_next (model, iter));
9179
9180   return retval;
9181 }
9182
9183 static gint
9184 gtk_tree_view_unref_and_check_selection_tree (GtkTreeView *tree_view,
9185                                               GtkRBTree   *tree)
9186 {
9187   GtkTreeIter iter;
9188   GtkTreePath *path;
9189   GtkRBNode *node;
9190   gint retval;
9191
9192   if (!tree)
9193     return FALSE;
9194
9195   node = tree->root;
9196   while (node && node->left != tree->nil)
9197     node = node->left;
9198
9199   g_return_val_if_fail (node != NULL, FALSE);
9200   path = _gtk_tree_view_find_path (tree_view, tree, node);
9201   gtk_tree_model_get_iter (GTK_TREE_MODEL (tree_view->priv->model),
9202                            &iter, path);
9203   retval = gtk_tree_view_unref_tree_helper (GTK_TREE_MODEL (tree_view->priv->model), &iter, tree, node);
9204   gtk_tree_path_free (path);
9205
9206   return retval;
9207 }
9208
9209 static void
9210 gtk_tree_view_set_column_drag_info (GtkTreeView       *tree_view,
9211                                     GtkTreeViewColumn *column)
9212 {
9213   GtkTreeViewColumn *left_column;
9214   GtkTreeViewColumn *cur_column = NULL;
9215   GtkTreeViewColumnReorder *reorder;
9216   gboolean rtl;
9217   GList *tmp_list;
9218   gint left;
9219
9220   /* We want to precalculate the motion list such that we know what column slots
9221    * are available.
9222    */
9223   left_column = NULL;
9224   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
9225
9226   /* First, identify all possible drop spots */
9227   if (rtl)
9228     tmp_list = g_list_last (tree_view->priv->columns);
9229   else
9230     tmp_list = g_list_first (tree_view->priv->columns);
9231
9232   while (tmp_list)
9233     {
9234       cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
9235       tmp_list = rtl?g_list_previous (tmp_list):g_list_next (tmp_list);
9236
9237       if (cur_column->visible == FALSE)
9238         continue;
9239
9240       /* If it's not the column moving and func tells us to skip over the column, we continue. */
9241       if (left_column != column && cur_column != column &&
9242           tree_view->priv->column_drop_func &&
9243           ! tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
9244         {
9245           left_column = cur_column;
9246           continue;
9247         }
9248       reorder = g_slice_new0 (GtkTreeViewColumnReorder);
9249       reorder->left_column = left_column;
9250       left_column = reorder->right_column = cur_column;
9251
9252       tree_view->priv->column_drag_info = g_list_append (tree_view->priv->column_drag_info, reorder);
9253     }
9254
9255   /* Add the last one */
9256   if (tree_view->priv->column_drop_func == NULL ||
9257       ((left_column != column) &&
9258        tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data)))
9259     {
9260       reorder = g_slice_new0 (GtkTreeViewColumnReorder);
9261       reorder->left_column = left_column;
9262       reorder->right_column = NULL;
9263       tree_view->priv->column_drag_info = g_list_append (tree_view->priv->column_drag_info, reorder);
9264     }
9265
9266   /* We quickly check to see if it even makes sense to reorder columns. */
9267   /* If there is nothing that can be moved, then we return */
9268
9269   if (tree_view->priv->column_drag_info == NULL)
9270     return;
9271
9272   /* We know there are always 2 slots possbile, as you can always return column. */
9273   /* If that's all there is, return */
9274   if (tree_view->priv->column_drag_info->next == NULL || 
9275       (tree_view->priv->column_drag_info->next->next == NULL &&
9276        ((GtkTreeViewColumnReorder *)tree_view->priv->column_drag_info->data)->right_column == column &&
9277        ((GtkTreeViewColumnReorder *)tree_view->priv->column_drag_info->next->data)->left_column == column))
9278     {
9279       for (tmp_list = tree_view->priv->column_drag_info; tmp_list; tmp_list = tmp_list->next)
9280         g_slice_free (GtkTreeViewColumnReorder, tmp_list->data);
9281       g_list_free (tree_view->priv->column_drag_info);
9282       tree_view->priv->column_drag_info = NULL;
9283       return;
9284     }
9285   /* We fill in the ranges for the columns, now that we've isolated them */
9286   left = - TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER (tree_view);
9287
9288   for (tmp_list = tree_view->priv->column_drag_info; tmp_list; tmp_list = tmp_list->next)
9289     {
9290       reorder = (GtkTreeViewColumnReorder *) tmp_list->data;
9291
9292       reorder->left_align = left;
9293       if (tmp_list->next != NULL)
9294         {
9295           g_assert (tmp_list->next->data);
9296           left = reorder->right_align = (reorder->right_column->button->allocation.x +
9297                                          reorder->right_column->button->allocation.width +
9298                                          ((GtkTreeViewColumnReorder *)tmp_list->next->data)->left_column->button->allocation.x)/2;
9299         }
9300       else
9301         {
9302           gint width;
9303
9304           gdk_drawable_get_size (tree_view->priv->header_window, &width, NULL);
9305           reorder->right_align = width + TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER (tree_view);
9306         }
9307     }
9308 }
9309
9310 void
9311 _gtk_tree_view_column_start_drag (GtkTreeView       *tree_view,
9312                                   GtkTreeViewColumn *column)
9313 {
9314   GdkEvent *send_event;
9315   GtkAllocation allocation;
9316   gint x, y, width, height;
9317   GdkScreen *screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
9318   GdkDisplay *display = gdk_screen_get_display (screen);
9319
9320   g_return_if_fail (tree_view->priv->column_drag_info == NULL);
9321   g_return_if_fail (tree_view->priv->cur_reorder == NULL);
9322
9323   gtk_tree_view_set_column_drag_info (tree_view, column);
9324
9325   if (tree_view->priv->column_drag_info == NULL)
9326     return;
9327
9328   if (tree_view->priv->drag_window == NULL)
9329     {
9330       GdkWindowAttr attributes;
9331       guint attributes_mask;
9332
9333       attributes.window_type = GDK_WINDOW_CHILD;
9334       attributes.wclass = GDK_INPUT_OUTPUT;
9335       attributes.x = column->button->allocation.x;
9336       attributes.y = 0;
9337       attributes.width = column->button->allocation.width;
9338       attributes.height = column->button->allocation.height;
9339       attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
9340       attributes.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
9341       attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
9342       attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
9343
9344       tree_view->priv->drag_window = gdk_window_new (tree_view->priv->bin_window,
9345                                                      &attributes,
9346                                                      attributes_mask);
9347       gdk_window_set_user_data (tree_view->priv->drag_window, GTK_WIDGET (tree_view));
9348     }
9349
9350   gdk_display_pointer_ungrab (display, GDK_CURRENT_TIME);
9351   gdk_display_keyboard_ungrab (display, GDK_CURRENT_TIME);
9352
9353   gtk_grab_remove (column->button);
9354
9355   send_event = gdk_event_new (GDK_LEAVE_NOTIFY);
9356   send_event->crossing.send_event = TRUE;
9357   send_event->crossing.window = g_object_ref (GTK_BUTTON (column->button)->event_window);
9358   send_event->crossing.subwindow = NULL;
9359   send_event->crossing.detail = GDK_NOTIFY_ANCESTOR;
9360   send_event->crossing.time = GDK_CURRENT_TIME;
9361
9362   gtk_propagate_event (column->button, send_event);
9363   gdk_event_free (send_event);
9364
9365   send_event = gdk_event_new (GDK_BUTTON_RELEASE);
9366   send_event->button.window = g_object_ref (gdk_screen_get_root_window (screen));
9367   send_event->button.send_event = TRUE;
9368   send_event->button.time = GDK_CURRENT_TIME;
9369   send_event->button.x = -1;
9370   send_event->button.y = -1;
9371   send_event->button.axes = NULL;
9372   send_event->button.state = 0;
9373   send_event->button.button = 1;
9374   send_event->button.device = gdk_display_get_core_pointer (display);
9375   send_event->button.x_root = 0;
9376   send_event->button.y_root = 0;
9377
9378   gtk_propagate_event (column->button, send_event);
9379   gdk_event_free (send_event);
9380
9381   /* Kids, don't try this at home */
9382   g_object_ref (column->button);
9383   gtk_container_remove (GTK_CONTAINER (tree_view), column->button);
9384   gtk_widget_set_parent_window (column->button, tree_view->priv->drag_window);
9385   gtk_widget_set_parent (column->button, GTK_WIDGET (tree_view));
9386   g_object_unref (column->button);
9387
9388   tree_view->priv->drag_column_x = column->button->allocation.x;
9389   allocation = column->button->allocation;
9390   allocation.x = 0;
9391   gtk_widget_size_allocate (column->button, &allocation);
9392   gtk_widget_set_parent_window (column->button, tree_view->priv->drag_window);
9393
9394   tree_view->priv->drag_column = column;
9395   gdk_window_show (tree_view->priv->drag_window);
9396
9397   gdk_window_get_origin (tree_view->priv->header_window, &x, &y);
9398   gdk_drawable_get_size (tree_view->priv->header_window, &width, &height);
9399
9400   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
9401   while (gtk_events_pending ())
9402     gtk_main_iteration ();
9403
9404   GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG);
9405   gdk_pointer_grab (tree_view->priv->drag_window,
9406                     FALSE,
9407                     GDK_POINTER_MOTION_MASK|GDK_BUTTON_RELEASE_MASK,
9408                     NULL, NULL, GDK_CURRENT_TIME);
9409   gdk_keyboard_grab (tree_view->priv->drag_window,
9410                      FALSE,
9411                      GDK_CURRENT_TIME);
9412 }
9413
9414 static void
9415 gtk_tree_view_queue_draw_arrow (GtkTreeView        *tree_view,
9416                                 GtkRBTree          *tree,
9417                                 GtkRBNode          *node,
9418                                 const GdkRectangle *clip_rect)
9419 {
9420   GdkRectangle rect;
9421
9422   if (!GTK_WIDGET_REALIZED (tree_view))
9423     return;
9424
9425   rect.x = 0;
9426   rect.width = MAX (tree_view->priv->expander_size, MAX (tree_view->priv->width, GTK_WIDGET (tree_view)->allocation.width));
9427
9428   rect.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
9429   rect.height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
9430
9431   if (clip_rect)
9432     {
9433       GdkRectangle new_rect;
9434
9435       gdk_rectangle_intersect (clip_rect, &rect, &new_rect);
9436
9437       gdk_window_invalidate_rect (tree_view->priv->bin_window, &new_rect, TRUE);
9438     }
9439   else
9440     {
9441       gdk_window_invalidate_rect (tree_view->priv->bin_window, &rect, TRUE);
9442     }
9443 }
9444
9445 void
9446 _gtk_tree_view_queue_draw_node (GtkTreeView        *tree_view,
9447                                 GtkRBTree          *tree,
9448                                 GtkRBNode          *node,
9449                                 const GdkRectangle *clip_rect)
9450 {
9451   GdkRectangle rect;
9452
9453   if (!GTK_WIDGET_REALIZED (tree_view))
9454     return;
9455
9456   rect.x = 0;
9457   rect.width = MAX (tree_view->priv->width, GTK_WIDGET (tree_view)->allocation.width);
9458
9459   rect.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
9460   rect.height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
9461
9462   if (clip_rect)
9463     {
9464       GdkRectangle new_rect;
9465
9466       gdk_rectangle_intersect (clip_rect, &rect, &new_rect);
9467
9468       gdk_window_invalidate_rect (tree_view->priv->bin_window, &new_rect, TRUE);
9469     }
9470   else
9471     {
9472       gdk_window_invalidate_rect (tree_view->priv->bin_window, &rect, TRUE);
9473     }
9474 }
9475
9476 static void
9477 gtk_tree_view_queue_draw_path (GtkTreeView        *tree_view,
9478                                GtkTreePath        *path,
9479                                const GdkRectangle *clip_rect)
9480 {
9481   GtkRBTree *tree = NULL;
9482   GtkRBNode *node = NULL;
9483
9484   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
9485
9486   if (tree)
9487     _gtk_tree_view_queue_draw_node (tree_view, tree, node, clip_rect);
9488 }
9489
9490 /* x and y are the mouse position
9491  */
9492 static void
9493 gtk_tree_view_draw_arrow (GtkTreeView *tree_view,
9494                           GtkRBTree   *tree,
9495                           GtkRBNode   *node,
9496                           /* in bin_window coordinates */
9497                           gint         x,
9498                           gint         y)
9499 {
9500   GdkRectangle area;
9501   GtkStateType state;
9502   GtkWidget *widget;
9503   gint x_offset = 0;
9504   gint x2;
9505   gint vertical_separator;
9506   gint expander_size;
9507   GtkExpanderStyle expander_style;
9508
9509   gtk_widget_style_get (GTK_WIDGET (tree_view),
9510                         "vertical-separator", &vertical_separator,
9511                         NULL);
9512   expander_size = tree_view->priv->expander_size - EXPANDER_EXTRA_PADDING;
9513
9514   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
9515     return;
9516
9517   widget = GTK_WIDGET (tree_view);
9518
9519   gtk_tree_view_get_arrow_xrange (tree_view, tree, &x_offset, &x2);
9520
9521   area.x = x_offset;
9522   area.y = CELL_FIRST_PIXEL (tree_view, tree, node, vertical_separator);
9523   area.width = expander_size + 2;
9524   area.height = MAX (CELL_HEIGHT (node, vertical_separator), (expander_size - vertical_separator));
9525
9526   if (GTK_WIDGET_STATE (tree_view) == GTK_STATE_INSENSITIVE)
9527     {
9528       state = GTK_STATE_INSENSITIVE;
9529     }
9530   else if (node == tree_view->priv->button_pressed_node)
9531     {
9532       if (x >= area.x && x <= (area.x + area.width) &&
9533           y >= area.y && y <= (area.y + area.height))
9534         state = GTK_STATE_ACTIVE;
9535       else
9536         state = GTK_STATE_NORMAL;
9537     }
9538   else
9539     {
9540       if (node == tree_view->priv->prelight_node &&
9541           GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT))
9542         state = GTK_STATE_PRELIGHT;
9543       else
9544         state = GTK_STATE_NORMAL;
9545     }
9546
9547   if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_EXPANDED))
9548     expander_style = GTK_EXPANDER_SEMI_EXPANDED;
9549   else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_COLLAPSED))
9550     expander_style = GTK_EXPANDER_SEMI_COLLAPSED;
9551   else if (node->children != NULL)
9552     expander_style = GTK_EXPANDER_EXPANDED;
9553   else
9554     expander_style = GTK_EXPANDER_COLLAPSED;
9555
9556   gtk_paint_expander (widget->style,
9557                       tree_view->priv->bin_window,
9558                       state,
9559                       &area,
9560                       widget,
9561                       "treeview",
9562                       area.x + area.width / 2,
9563                       area.y + area.height / 2,
9564                       expander_style);
9565 }
9566
9567 static void
9568 gtk_tree_view_focus_to_cursor (GtkTreeView *tree_view)
9569
9570 {
9571   GtkTreePath *cursor_path;
9572
9573   if ((tree_view->priv->tree == NULL) ||
9574       (! GTK_WIDGET_REALIZED (tree_view)))
9575     return;
9576
9577   cursor_path = NULL;
9578   if (tree_view->priv->cursor)
9579     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
9580
9581   if (cursor_path == NULL)
9582     {
9583       /* Consult the selection before defaulting to the
9584        * first focusable element
9585        */
9586       GList *selected_rows;
9587       GtkTreeModel *model;
9588       GtkTreeSelection *selection;
9589
9590       selection = gtk_tree_view_get_selection (tree_view);
9591       selected_rows = gtk_tree_selection_get_selected_rows (selection, &model);
9592
9593       if (selected_rows)
9594         {
9595           cursor_path = gtk_tree_path_copy((const GtkTreePath *)(selected_rows->data));
9596           g_list_foreach (selected_rows, (GFunc)gtk_tree_path_free, NULL);
9597           g_list_free (selected_rows);
9598         }
9599       else
9600         {
9601           cursor_path = gtk_tree_path_new_first ();
9602           search_first_focusable_path (tree_view, &cursor_path,
9603                                        TRUE, NULL, NULL);
9604         }
9605
9606       gtk_tree_row_reference_free (tree_view->priv->cursor);
9607       tree_view->priv->cursor = NULL;
9608
9609       if (cursor_path)
9610         {
9611           if (tree_view->priv->selection->type == GTK_SELECTION_MULTIPLE)
9612             gtk_tree_view_real_set_cursor (tree_view, cursor_path, FALSE, FALSE);
9613           else
9614             gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE);
9615         }
9616     }
9617
9618   if (cursor_path)
9619     {
9620       GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
9621
9622       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
9623       gtk_tree_path_free (cursor_path);
9624
9625       if (tree_view->priv->focus_column == NULL)
9626         {
9627           GList *list;
9628           for (list = tree_view->priv->columns; list; list = list->next)
9629             {
9630               if (GTK_TREE_VIEW_COLUMN (list->data)->visible)
9631                 {
9632                   tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (list->data);
9633                   break;
9634                 }
9635             }
9636         }
9637     }
9638 }
9639
9640 static void
9641 gtk_tree_view_move_cursor_up_down (GtkTreeView *tree_view,
9642                                    gint         count)
9643 {
9644   gint selection_count;
9645   GtkRBTree *cursor_tree = NULL;
9646   GtkRBNode *cursor_node = NULL;
9647   GtkRBTree *new_cursor_tree = NULL;
9648   GtkRBNode *new_cursor_node = NULL;
9649   GtkTreePath *cursor_path = NULL;
9650   gboolean grab_focus = TRUE;
9651   gboolean selectable;
9652
9653   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
9654     return;
9655
9656   cursor_path = NULL;
9657   if (!gtk_tree_row_reference_valid (tree_view->priv->cursor))
9658     /* FIXME: we lost the cursor; should we get the first? */
9659     return;
9660
9661   cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
9662   _gtk_tree_view_find_node (tree_view, cursor_path,
9663                             &cursor_tree, &cursor_node);
9664
9665   if (cursor_tree == NULL)
9666     /* FIXME: we lost the cursor; should we get the first? */
9667     return;
9668
9669   selection_count = gtk_tree_selection_count_selected_rows (tree_view->priv->selection);
9670   selectable = _gtk_tree_selection_row_is_selectable (tree_view->priv->selection,
9671                                                       cursor_node,
9672                                                       cursor_path);
9673
9674   if (selection_count == 0
9675       && tree_view->priv->selection->type != GTK_SELECTION_NONE
9676       && !tree_view->priv->ctrl_pressed
9677       && selectable)
9678     {
9679       /* Don't move the cursor, but just select the current node */
9680       new_cursor_tree = cursor_tree;
9681       new_cursor_node = cursor_node;
9682     }
9683   else
9684     {
9685       if (count == -1)
9686         _gtk_rbtree_prev_full (cursor_tree, cursor_node,
9687                                &new_cursor_tree, &new_cursor_node);
9688       else
9689         _gtk_rbtree_next_full (cursor_tree, cursor_node,
9690                                &new_cursor_tree, &new_cursor_node);
9691     }
9692
9693   gtk_tree_path_free (cursor_path);
9694
9695   if (new_cursor_node)
9696     {
9697       cursor_path = _gtk_tree_view_find_path (tree_view,
9698                                               new_cursor_tree, new_cursor_node);
9699
9700       search_first_focusable_path (tree_view, &cursor_path,
9701                                    (count != -1),
9702                                    &new_cursor_tree,
9703                                    &new_cursor_node);
9704
9705       if (cursor_path)
9706         gtk_tree_path_free (cursor_path);
9707     }
9708
9709   /*
9710    * If the list has only one item and multi-selection is set then select
9711    * the row (if not yet selected).
9712    */
9713   if (tree_view->priv->selection->type == GTK_SELECTION_MULTIPLE &&
9714       new_cursor_node == NULL)
9715     {
9716       if (count == -1)
9717         _gtk_rbtree_next_full (cursor_tree, cursor_node,
9718                                &new_cursor_tree, &new_cursor_node);
9719       else
9720         _gtk_rbtree_prev_full (cursor_tree, cursor_node,
9721                                &new_cursor_tree, &new_cursor_node);
9722
9723       if (new_cursor_node == NULL
9724           && !GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_SELECTED))
9725         {
9726           new_cursor_node = cursor_node;
9727           new_cursor_tree = cursor_tree;
9728         }
9729       else
9730         {
9731           new_cursor_node = NULL;
9732         }
9733     }
9734
9735   if (new_cursor_node)
9736     {
9737       cursor_path = _gtk_tree_view_find_path (tree_view, new_cursor_tree, new_cursor_node);
9738       gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, TRUE);
9739       gtk_tree_path_free (cursor_path);
9740     }
9741   else
9742     {
9743       gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
9744
9745       if (!tree_view->priv->shift_pressed)
9746         {
9747           if (! gtk_widget_keynav_failed (GTK_WIDGET (tree_view),
9748                                           count < 0 ?
9749                                           GTK_DIR_UP : GTK_DIR_DOWN))
9750             {
9751               GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (tree_view));
9752
9753               if (toplevel)
9754                 gtk_widget_child_focus (toplevel,
9755                                         count < 0 ?
9756                                         GTK_DIR_TAB_BACKWARD :
9757                                         GTK_DIR_TAB_FORWARD);
9758
9759               grab_focus = FALSE;
9760             }
9761         }
9762       else
9763         {
9764           gtk_widget_error_bell (GTK_WIDGET (tree_view));
9765         }
9766     }
9767
9768   if (grab_focus)
9769     gtk_widget_grab_focus (GTK_WIDGET (tree_view));
9770 }
9771
9772 static void
9773 gtk_tree_view_move_cursor_page_up_down (GtkTreeView *tree_view,
9774                                         gint         count)
9775 {
9776   GtkRBTree *cursor_tree = NULL;
9777   GtkRBNode *cursor_node = NULL;
9778   GtkTreePath *old_cursor_path = NULL;
9779   GtkTreePath *cursor_path = NULL;
9780   GtkRBTree *start_cursor_tree = NULL;
9781   GtkRBNode *start_cursor_node = NULL;
9782   gint y;
9783   gint window_y;
9784   gint vertical_separator;
9785
9786   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
9787     return;
9788
9789   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
9790     old_cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
9791   else
9792     /* This is sorta weird.  Focus in should give us a cursor */
9793     return;
9794
9795   gtk_widget_style_get (GTK_WIDGET (tree_view), "vertical-separator", &vertical_separator, NULL);
9796   _gtk_tree_view_find_node (tree_view, old_cursor_path,
9797                             &cursor_tree, &cursor_node);
9798
9799   if (cursor_tree == NULL)
9800     {
9801       /* FIXME: we lost the cursor.  Should we try to get one? */
9802       gtk_tree_path_free (old_cursor_path);
9803       return;
9804     }
9805   g_return_if_fail (cursor_node != NULL);
9806
9807   y = _gtk_rbtree_node_find_offset (cursor_tree, cursor_node);
9808   window_y = RBTREE_Y_TO_TREE_WINDOW_Y (tree_view, y);
9809   y += tree_view->priv->cursor_offset;
9810   y += count * (int)tree_view->priv->vadjustment->page_increment;
9811   y = CLAMP (y, (gint)tree_view->priv->vadjustment->lower,  (gint)tree_view->priv->vadjustment->upper - vertical_separator);
9812
9813   if (y >= tree_view->priv->height)
9814     y = tree_view->priv->height - 1;
9815
9816   tree_view->priv->cursor_offset =
9817     _gtk_rbtree_find_offset (tree_view->priv->tree, y,
9818                              &cursor_tree, &cursor_node);
9819
9820   if (tree_view->priv->cursor_offset > BACKGROUND_HEIGHT (cursor_node))
9821     {
9822       _gtk_rbtree_next_full (cursor_tree, cursor_node,
9823                              &cursor_tree, &cursor_node);
9824       tree_view->priv->cursor_offset -= BACKGROUND_HEIGHT (cursor_node);
9825     }
9826
9827   y -= tree_view->priv->cursor_offset;
9828   cursor_path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
9829
9830   start_cursor_tree = cursor_tree;
9831   start_cursor_node = cursor_node;
9832
9833   if (! search_first_focusable_path (tree_view, &cursor_path,
9834                                      (count != -1),
9835                                      &cursor_tree, &cursor_node))
9836     {
9837       /* It looks like we reached the end of the view without finding
9838        * a focusable row.  We will step backwards to find the last
9839        * focusable row.
9840        */
9841       cursor_tree = start_cursor_tree;
9842       cursor_node = start_cursor_node;
9843       cursor_path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
9844
9845       search_first_focusable_path (tree_view, &cursor_path,
9846                                    (count == -1),
9847                                    &cursor_tree, &cursor_node);
9848     }
9849
9850   if (!cursor_path)
9851     goto cleanup;
9852
9853   /* update y */
9854   y = _gtk_rbtree_node_find_offset (cursor_tree, cursor_node);
9855
9856   gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE);
9857
9858   y -= window_y;
9859   gtk_tree_view_scroll_to_point (tree_view, -1, y);
9860   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
9861   _gtk_tree_view_queue_draw_node (tree_view, cursor_tree, cursor_node, NULL);
9862
9863   if (!gtk_tree_path_compare (old_cursor_path, cursor_path))
9864     gtk_widget_error_bell (GTK_WIDGET (tree_view));
9865
9866 cleanup:
9867   gtk_tree_path_free (old_cursor_path);
9868   gtk_tree_path_free (cursor_path);
9869 }
9870
9871 static void
9872 gtk_tree_view_move_cursor_left_right (GtkTreeView *tree_view,
9873                                       gint         count)
9874 {
9875   GtkRBTree *cursor_tree = NULL;
9876   GtkRBNode *cursor_node = NULL;
9877   GtkTreePath *cursor_path = NULL;
9878   GtkTreeViewColumn *column;
9879   GtkTreeIter iter;
9880   GList *list;
9881   gboolean found_column = FALSE;
9882   gboolean rtl;
9883
9884   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
9885
9886   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
9887     return;
9888
9889   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
9890     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
9891   else
9892     return;
9893
9894   _gtk_tree_view_find_node (tree_view, cursor_path, &cursor_tree, &cursor_node);
9895   if (cursor_tree == NULL)
9896     return;
9897   if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path) == FALSE)
9898     {
9899       gtk_tree_path_free (cursor_path);
9900       return;
9901     }
9902   gtk_tree_path_free (cursor_path);
9903
9904   list = rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns);
9905   if (tree_view->priv->focus_column)
9906     {
9907       for (; list; list = (rtl ? list->prev : list->next))
9908         {
9909           if (list->data == tree_view->priv->focus_column)
9910             break;
9911         }
9912     }
9913
9914   while (list)
9915     {
9916       gboolean left, right;
9917
9918       column = list->data;
9919       if (column->visible == FALSE)
9920         goto loop_end;
9921
9922       gtk_tree_view_column_cell_set_cell_data (column,
9923                                                tree_view->priv->model,
9924                                                &iter,
9925                                                GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_PARENT),
9926                                                cursor_node->children?TRUE:FALSE);
9927
9928       if (rtl)
9929         {
9930           right = list->prev ? TRUE : FALSE;
9931           left = list->next ? TRUE : FALSE;
9932         }
9933       else
9934         {
9935           left = list->prev ? TRUE : FALSE;
9936           right = list->next ? TRUE : FALSE;
9937         }
9938
9939       if (_gtk_tree_view_column_cell_focus (column, count, left, right))
9940         {
9941           tree_view->priv->focus_column = column;
9942           found_column = TRUE;
9943           break;
9944         }
9945     loop_end:
9946       if (count == 1)
9947         list = rtl ? list->prev : list->next;
9948       else
9949         list = rtl ? list->next : list->prev;
9950     }
9951
9952   if (found_column)
9953     {
9954       if (!gtk_tree_view_has_special_cell (tree_view))
9955         _gtk_tree_view_queue_draw_node (tree_view,
9956                                         cursor_tree,
9957                                         cursor_node,
9958                                         NULL);
9959       g_signal_emit (tree_view, tree_view_signals[CURSOR_CHANGED], 0);
9960     }
9961   else
9962     {
9963       gtk_widget_error_bell (GTK_WIDGET (tree_view));
9964     }
9965
9966   gtk_tree_view_clamp_column_visible (tree_view,
9967                                       tree_view->priv->focus_column, TRUE);
9968 }
9969
9970 static void
9971 gtk_tree_view_move_cursor_start_end (GtkTreeView *tree_view,
9972                                      gint         count)
9973 {
9974   GtkRBTree *cursor_tree;
9975   GtkRBNode *cursor_node;
9976   GtkTreePath *path;
9977   GtkTreePath *old_path;
9978
9979   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
9980     return;
9981
9982   g_return_if_fail (tree_view->priv->tree != NULL);
9983
9984   gtk_tree_view_get_cursor (tree_view, &old_path, NULL);
9985
9986   cursor_tree = tree_view->priv->tree;
9987   cursor_node = cursor_tree->root;
9988
9989   if (count == -1)
9990     {
9991       while (cursor_node && cursor_node->left != cursor_tree->nil)
9992         cursor_node = cursor_node->left;
9993
9994       /* Now go forward to find the first focusable row. */
9995       path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
9996       search_first_focusable_path (tree_view, &path,
9997                                    TRUE, &cursor_tree, &cursor_node);
9998     }
9999   else
10000     {
10001       do
10002         {
10003           while (cursor_node && cursor_node->right != cursor_tree->nil)
10004             cursor_node = cursor_node->right;
10005           if (cursor_node->children == NULL)
10006             break;
10007
10008           cursor_tree = cursor_node->children;
10009           cursor_node = cursor_tree->root;
10010         }
10011       while (1);
10012
10013       /* Now go backwards to find last focusable row. */
10014       path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
10015       search_first_focusable_path (tree_view, &path,
10016                                    FALSE, &cursor_tree, &cursor_node);
10017     }
10018
10019   if (!path)
10020     goto cleanup;
10021
10022   if (gtk_tree_path_compare (old_path, path))
10023     {
10024       gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
10025     }
10026   else
10027     {
10028       gtk_widget_error_bell (GTK_WIDGET (tree_view));
10029     }
10030
10031 cleanup:
10032   gtk_tree_path_free (old_path);
10033   gtk_tree_path_free (path);
10034 }
10035
10036 static gboolean
10037 gtk_tree_view_real_select_all (GtkTreeView *tree_view)
10038 {
10039   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
10040     return FALSE;
10041
10042   if (tree_view->priv->selection->type != GTK_SELECTION_MULTIPLE)
10043     return FALSE;
10044
10045   gtk_tree_selection_select_all (tree_view->priv->selection);
10046
10047   return TRUE;
10048 }
10049
10050 static gboolean
10051 gtk_tree_view_real_unselect_all (GtkTreeView *tree_view)
10052 {
10053   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
10054     return FALSE;
10055
10056   if (tree_view->priv->selection->type != GTK_SELECTION_MULTIPLE)
10057     return FALSE;
10058
10059   gtk_tree_selection_unselect_all (tree_view->priv->selection);
10060
10061   return TRUE;
10062 }
10063
10064 static gboolean
10065 gtk_tree_view_real_select_cursor_row (GtkTreeView *tree_view,
10066                                       gboolean     start_editing)
10067 {
10068   GtkRBTree *new_tree = NULL;
10069   GtkRBNode *new_node = NULL;
10070   GtkRBTree *cursor_tree = NULL;
10071   GtkRBNode *cursor_node = NULL;
10072   GtkTreePath *cursor_path = NULL;
10073   GtkTreeSelectMode mode = 0;
10074
10075   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
10076     return FALSE;
10077
10078   if (tree_view->priv->cursor)
10079     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10080
10081   if (cursor_path == NULL)
10082     return FALSE;
10083
10084   _gtk_tree_view_find_node (tree_view, cursor_path,
10085                             &cursor_tree, &cursor_node);
10086
10087   if (cursor_tree == NULL)
10088     {
10089       gtk_tree_path_free (cursor_path);
10090       return FALSE;
10091     }
10092
10093   if (!tree_view->priv->shift_pressed && start_editing &&
10094       tree_view->priv->focus_column)
10095     {
10096       if (gtk_tree_view_start_editing (tree_view, cursor_path))
10097         {
10098           gtk_tree_path_free (cursor_path);
10099           return TRUE;
10100         }
10101     }
10102
10103   if (tree_view->priv->ctrl_pressed)
10104     mode |= GTK_TREE_SELECT_MODE_TOGGLE;
10105   if (tree_view->priv->shift_pressed)
10106     mode |= GTK_TREE_SELECT_MODE_EXTEND;
10107
10108   _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
10109                                             cursor_node,
10110                                             cursor_tree,
10111                                             cursor_path,
10112                                             mode,
10113                                             FALSE);
10114
10115   /* We bail out if the original (tree, node) don't exist anymore after
10116    * handling the selection-changed callback.  We do return TRUE because
10117    * the key press has been handled at this point.
10118    */
10119   _gtk_tree_view_find_node (tree_view, cursor_path, &new_tree, &new_node);
10120
10121   if (cursor_tree != new_tree || cursor_node != new_node)
10122     return FALSE;
10123
10124   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10125
10126   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10127   _gtk_tree_view_queue_draw_node (tree_view, cursor_tree, cursor_node, NULL);
10128
10129   if (!tree_view->priv->shift_pressed)
10130     gtk_tree_view_row_activated (tree_view, cursor_path,
10131                                  tree_view->priv->focus_column);
10132     
10133   gtk_tree_path_free (cursor_path);
10134
10135   return TRUE;
10136 }
10137
10138 static gboolean
10139 gtk_tree_view_real_toggle_cursor_row (GtkTreeView *tree_view)
10140 {
10141   GtkRBTree *new_tree = NULL;
10142   GtkRBNode *new_node = NULL;
10143   GtkRBTree *cursor_tree = NULL;
10144   GtkRBNode *cursor_node = NULL;
10145   GtkTreePath *cursor_path = NULL;
10146
10147   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
10148     return FALSE;
10149
10150   cursor_path = NULL;
10151   if (tree_view->priv->cursor)
10152     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10153
10154   if (cursor_path == NULL)
10155     return FALSE;
10156
10157   _gtk_tree_view_find_node (tree_view, cursor_path,
10158                             &cursor_tree, &cursor_node);
10159   if (cursor_tree == NULL)
10160     {
10161       gtk_tree_path_free (cursor_path);
10162       return FALSE;
10163     }
10164
10165   _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
10166                                             cursor_node,
10167                                             cursor_tree,
10168                                             cursor_path,
10169                                             GTK_TREE_SELECT_MODE_TOGGLE,
10170                                             FALSE);
10171
10172   /* We bail out if the original (tree, node) don't exist anymore after
10173    * handling the selection-changed callback.  We do return TRUE because
10174    * the key press has been handled at this point.
10175    */
10176   _gtk_tree_view_find_node (tree_view, cursor_path, &new_tree, &new_node);
10177
10178   if (cursor_tree != new_tree || cursor_node != new_node)
10179     return FALSE;
10180
10181   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10182
10183   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10184   gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10185   gtk_tree_path_free (cursor_path);
10186
10187   return TRUE;
10188 }
10189
10190 static gboolean
10191 gtk_tree_view_real_expand_collapse_cursor_row (GtkTreeView *tree_view,
10192                                                gboolean     logical,
10193                                                gboolean     expand,
10194                                                gboolean     open_all)
10195 {
10196   GtkTreePath *cursor_path = NULL;
10197   GtkRBTree *tree;
10198   GtkRBNode *node;
10199
10200   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
10201     return FALSE;
10202
10203   cursor_path = NULL;
10204   if (tree_view->priv->cursor)
10205     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10206
10207   if (cursor_path == NULL)
10208     return FALSE;
10209
10210   if (_gtk_tree_view_find_node (tree_view, cursor_path, &tree, &node))
10211     return FALSE;
10212
10213   /* Don't handle the event if we aren't an expander */
10214   if (!((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT))
10215     return FALSE;
10216
10217   if (!logical
10218       && gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL)
10219     expand = !expand;
10220
10221   if (expand)
10222     gtk_tree_view_real_expand_row (tree_view, cursor_path, tree, node, open_all, TRUE);
10223   else
10224     gtk_tree_view_real_collapse_row (tree_view, cursor_path, tree, node, TRUE);
10225
10226   gtk_tree_path_free (cursor_path);
10227
10228   return TRUE;
10229 }
10230
10231 static gboolean
10232 gtk_tree_view_real_select_cursor_parent (GtkTreeView *tree_view)
10233 {
10234   GtkRBTree *cursor_tree = NULL;
10235   GtkRBNode *cursor_node = NULL;
10236   GtkTreePath *cursor_path = NULL;
10237   GdkModifierType state;
10238
10239   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
10240     goto out;
10241
10242   cursor_path = NULL;
10243   if (tree_view->priv->cursor)
10244     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10245
10246   if (cursor_path == NULL)
10247     goto out;
10248
10249   _gtk_tree_view_find_node (tree_view, cursor_path,
10250                             &cursor_tree, &cursor_node);
10251   if (cursor_tree == NULL)
10252     {
10253       gtk_tree_path_free (cursor_path);
10254       goto out;
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       if (gtk_get_current_event_state (&state))
10266         {
10267           if ((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
10268             tree_view->priv->ctrl_pressed = TRUE;
10269         }
10270
10271       gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE);
10272       gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10273
10274       gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10275       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10276       gtk_tree_path_free (cursor_path);
10277
10278       tree_view->priv->ctrl_pressed = FALSE;
10279
10280       return TRUE;
10281     }
10282
10283  out:
10284
10285   tree_view->priv->search_entry_avoid_unhandled_binding = TRUE;
10286   return FALSE;
10287 }
10288
10289 static gboolean
10290 gtk_tree_view_search_entry_flush_timeout (GtkTreeView *tree_view)
10291 {
10292   gtk_tree_view_search_dialog_hide (tree_view->priv->search_window, tree_view);
10293   tree_view->priv->typeselect_flush_timeout = 0;
10294
10295   return FALSE;
10296 }
10297
10298 /* Cut and paste from gtkwindow.c */
10299 static void
10300 send_focus_change (GtkWidget *widget,
10301                    gboolean   in)
10302 {
10303   GdkEvent *fevent = gdk_event_new (GDK_FOCUS_CHANGE);
10304
10305   g_object_ref (widget);
10306    
10307  if (in)
10308     GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
10309   else
10310     GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
10311
10312   fevent->focus_change.type = GDK_FOCUS_CHANGE;
10313   fevent->focus_change.window = g_object_ref (widget->window);
10314   fevent->focus_change.in = in;
10315   
10316   gtk_widget_event (widget, fevent);
10317   
10318   g_object_notify (G_OBJECT (widget), "has-focus");
10319
10320   g_object_unref (widget);
10321   gdk_event_free (fevent);
10322 }
10323
10324 static void
10325 gtk_tree_view_ensure_interactive_directory (GtkTreeView *tree_view)
10326 {
10327   GtkWidget *frame, *vbox, *toplevel;
10328   GdkScreen *screen;
10329
10330   if (tree_view->priv->search_custom_entry_set)
10331     return;
10332
10333   toplevel = gtk_widget_get_toplevel (GTK_WIDGET (tree_view));
10334   screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
10335
10336    if (tree_view->priv->search_window != NULL)
10337      {
10338        if (GTK_WINDOW (toplevel)->group)
10339          gtk_window_group_add_window (GTK_WINDOW (toplevel)->group,
10340                                       GTK_WINDOW (tree_view->priv->search_window));
10341        else if (GTK_WINDOW (tree_view->priv->search_window)->group)
10342          gtk_window_group_remove_window (GTK_WINDOW (tree_view->priv->search_window)->group,
10343                                          GTK_WINDOW (tree_view->priv->search_window));
10344        gtk_window_set_screen (GTK_WINDOW (tree_view->priv->search_window), screen);
10345        return;
10346      }
10347    
10348   tree_view->priv->search_window = gtk_window_new (GTK_WINDOW_POPUP);
10349   gtk_window_set_screen (GTK_WINDOW (tree_view->priv->search_window), screen);
10350
10351   if (GTK_WINDOW (toplevel)->group)
10352     gtk_window_group_add_window (GTK_WINDOW (toplevel)->group,
10353                                  GTK_WINDOW (tree_view->priv->search_window));
10354
10355   gtk_window_set_type_hint (GTK_WINDOW (tree_view->priv->search_window),
10356                             GDK_WINDOW_TYPE_HINT_UTILITY);
10357   gtk_window_set_modal (GTK_WINDOW (tree_view->priv->search_window), TRUE);
10358   g_signal_connect (tree_view->priv->search_window, "delete-event",
10359                     G_CALLBACK (gtk_tree_view_search_delete_event),
10360                     tree_view);
10361   g_signal_connect (tree_view->priv->search_window, "key-press-event",
10362                     G_CALLBACK (gtk_tree_view_search_key_press_event),
10363                     tree_view);
10364   g_signal_connect (tree_view->priv->search_window, "button-press-event",
10365                     G_CALLBACK (gtk_tree_view_search_button_press_event),
10366                     tree_view);
10367   g_signal_connect (tree_view->priv->search_window, "scroll-event",
10368                     G_CALLBACK (gtk_tree_view_search_scroll_event),
10369                     tree_view);
10370
10371   frame = gtk_frame_new (NULL);
10372   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
10373   gtk_widget_show (frame);
10374   gtk_container_add (GTK_CONTAINER (tree_view->priv->search_window), frame);
10375
10376   vbox = gtk_vbox_new (FALSE, 0);
10377   gtk_widget_show (vbox);
10378   gtk_container_add (GTK_CONTAINER (frame), vbox);
10379   gtk_container_set_border_width (GTK_CONTAINER (vbox), 3);
10380
10381   /* add entry */
10382   tree_view->priv->search_entry = gtk_entry_new ();
10383   gtk_widget_show (tree_view->priv->search_entry);
10384   g_signal_connect (tree_view->priv->search_entry, "populate-popup",
10385                     G_CALLBACK (gtk_tree_view_search_disable_popdown),
10386                     tree_view);
10387   g_signal_connect (tree_view->priv->search_entry,
10388                     "activate", G_CALLBACK (gtk_tree_view_search_activate),
10389                     tree_view);
10390   g_signal_connect (GTK_ENTRY (tree_view->priv->search_entry)->im_context,
10391                     "preedit-changed",
10392                     G_CALLBACK (gtk_tree_view_search_preedit_changed),
10393                     tree_view);
10394   gtk_container_add (GTK_CONTAINER (vbox),
10395                      tree_view->priv->search_entry);
10396
10397   gtk_widget_realize (tree_view->priv->search_entry);
10398 }
10399
10400 /* Pops up the interactive search entry.  If keybinding is TRUE then the user
10401  * started this by typing the start_interactive_search keybinding.  Otherwise, it came from 
10402  */
10403 static gboolean
10404 gtk_tree_view_real_start_interactive_search (GtkTreeView *tree_view,
10405                                              gboolean     keybinding)
10406 {
10407   /* We only start interactive search if we have focus or the columns
10408    * have focus.  If one of our children have focus, we don't want to
10409    * start the search.
10410    */
10411   GList *list;
10412   gboolean found_focus = FALSE;
10413   GtkWidgetClass *entry_parent_class;
10414   
10415   if (!tree_view->priv->enable_search && !keybinding)
10416     return FALSE;
10417
10418   if (tree_view->priv->search_custom_entry_set)
10419     return FALSE;
10420
10421   if (tree_view->priv->search_window != NULL &&
10422       GTK_WIDGET_VISIBLE (tree_view->priv->search_window))
10423     return TRUE;
10424
10425   for (list = tree_view->priv->columns; list; list = list->next)
10426     {
10427       GtkTreeViewColumn *column;
10428
10429       column = list->data;
10430       if (! column->visible)
10431         continue;
10432
10433       if (GTK_WIDGET_HAS_FOCUS (column->button))
10434         {
10435           found_focus = TRUE;
10436           break;
10437         }
10438     }
10439   
10440   if (GTK_WIDGET_HAS_FOCUS (tree_view))
10441     found_focus = TRUE;
10442
10443   if (!found_focus)
10444     return FALSE;
10445
10446   if (tree_view->priv->search_column < 0)
10447     return FALSE;
10448
10449   gtk_tree_view_ensure_interactive_directory (tree_view);
10450
10451   if (keybinding)
10452     gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
10453
10454   /* done, show it */
10455   tree_view->priv->search_position_func (tree_view, tree_view->priv->search_window, tree_view->priv->search_position_user_data);
10456   gtk_widget_show (tree_view->priv->search_window);
10457   if (tree_view->priv->search_entry_changed_id == 0)
10458     {
10459       tree_view->priv->search_entry_changed_id =
10460         g_signal_connect (tree_view->priv->search_entry, "changed",
10461                           G_CALLBACK (gtk_tree_view_search_init),
10462                           tree_view);
10463     }
10464
10465   tree_view->priv->typeselect_flush_timeout =
10466     gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
10467                    (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
10468                    tree_view);
10469
10470   /* Grab focus will select all the text.  We don't want that to happen, so we
10471    * call the parent instance and bypass the selection change.  This is probably
10472    * really non-kosher. */
10473   entry_parent_class = g_type_class_peek_parent (GTK_ENTRY_GET_CLASS (tree_view->priv->search_entry));
10474   (entry_parent_class->grab_focus) (tree_view->priv->search_entry);
10475
10476   /* send focus-in event */
10477   send_focus_change (tree_view->priv->search_entry, TRUE);
10478
10479   /* search first matching iter */
10480   gtk_tree_view_search_init (tree_view->priv->search_entry, tree_view);
10481
10482   return TRUE;
10483 }
10484
10485 static gboolean
10486 gtk_tree_view_start_interactive_search (GtkTreeView *tree_view)
10487 {
10488   return gtk_tree_view_real_start_interactive_search (tree_view, TRUE);
10489 }
10490
10491 /* this function returns the new width of the column being resized given
10492  * the column and x position of the cursor; the x cursor position is passed
10493  * in as a pointer and automagicly corrected if it's beyond min/max limits
10494  */
10495 static gint
10496 gtk_tree_view_new_column_width (GtkTreeView *tree_view,
10497                                 gint       i,
10498                                 gint      *x)
10499 {
10500   GtkTreeViewColumn *column;
10501   gint width;
10502   gboolean rtl;
10503
10504   /* first translate the x position from widget->window
10505    * to clist->clist_window
10506    */
10507   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
10508   column = g_list_nth (tree_view->priv->columns, i)->data;
10509   width = rtl ? (column->button->allocation.x + column->button->allocation.width - *x) : (*x - column->button->allocation.x);
10510  
10511   /* Clamp down the value */
10512   if (column->min_width == -1)
10513     width = MAX (column->button->requisition.width,
10514                  width);
10515   else
10516     width = MAX (column->min_width,
10517                  width);
10518   if (column->max_width != -1)
10519     width = MIN (width, column->max_width);
10520
10521   *x = rtl ? (column->button->allocation.x + column->button->allocation.width - width) : (column->button->allocation.x + width);
10522  
10523   return width;
10524 }
10525
10526
10527 /* FIXME this adjust_allocation is a big cut-and-paste from
10528  * GtkCList, needs to be some "official" way to do this
10529  * factored out.
10530  */
10531 typedef struct
10532 {
10533   GdkWindow *window;
10534   int dx;
10535   int dy;
10536 } ScrollData;
10537
10538 /* The window to which widget->window is relative */
10539 #define ALLOCATION_WINDOW(widget)               \
10540    (GTK_WIDGET_NO_WINDOW (widget) ?             \
10541     (widget)->window :                          \
10542      gdk_window_get_parent ((widget)->window))
10543
10544 static void
10545 adjust_allocation_recurse (GtkWidget *widget,
10546                            gpointer   data)
10547 {
10548   ScrollData *scroll_data = data;
10549
10550   /* Need to really size allocate instead of just poking
10551    * into widget->allocation if the widget is not realized.
10552    * FIXME someone figure out why this was.
10553    */
10554   if (!GTK_WIDGET_REALIZED (widget))
10555     {
10556       if (GTK_WIDGET_VISIBLE (widget))
10557         {
10558           GdkRectangle tmp_rectangle = widget->allocation;
10559           tmp_rectangle.x += scroll_data->dx;
10560           tmp_rectangle.y += scroll_data->dy;
10561           
10562           gtk_widget_size_allocate (widget, &tmp_rectangle);
10563         }
10564     }
10565   else
10566     {
10567       if (ALLOCATION_WINDOW (widget) == scroll_data->window)
10568         {
10569           widget->allocation.x += scroll_data->dx;
10570           widget->allocation.y += scroll_data->dy;
10571           
10572           if (GTK_IS_CONTAINER (widget))
10573             gtk_container_forall (GTK_CONTAINER (widget),
10574                                   adjust_allocation_recurse,
10575                                   data);
10576         }
10577     }
10578 }
10579
10580 static void
10581 adjust_allocation (GtkWidget *widget,
10582                    int        dx,
10583                    int        dy)
10584 {
10585   ScrollData scroll_data;
10586
10587   if (GTK_WIDGET_REALIZED (widget))
10588     scroll_data.window = ALLOCATION_WINDOW (widget);
10589   else
10590     scroll_data.window = NULL;
10591     
10592   scroll_data.dx = dx;
10593   scroll_data.dy = dy;
10594   
10595   adjust_allocation_recurse (widget, &scroll_data);
10596 }
10597
10598 /* Callbacks */
10599 static void
10600 gtk_tree_view_adjustment_changed (GtkAdjustment *adjustment,
10601                                   GtkTreeView   *tree_view)
10602 {
10603   if (GTK_WIDGET_REALIZED (tree_view))
10604     {
10605       gint dy;
10606         
10607       gdk_window_move (tree_view->priv->bin_window,
10608                        - tree_view->priv->hadjustment->value,
10609                        TREE_VIEW_HEADER_HEIGHT (tree_view));
10610       gdk_window_move (tree_view->priv->header_window,
10611                        - tree_view->priv->hadjustment->value,
10612                        0);
10613       dy = tree_view->priv->dy - (int) tree_view->priv->vadjustment->value;
10614       if (dy && tree_view->priv->edited_column)
10615         {
10616           if (GTK_IS_WIDGET (tree_view->priv->edited_column->editable_widget))
10617             {
10618               GList *list;
10619               GtkWidget *widget;
10620               GtkTreeViewChild *child = NULL;
10621
10622               widget = GTK_WIDGET (tree_view->priv->edited_column->editable_widget);
10623               adjust_allocation (widget, 0, dy); 
10624               
10625               for (list = tree_view->priv->children; list; list = list->next)
10626                 {
10627                   child = (GtkTreeViewChild *)list->data;
10628                   if (child->widget == widget)
10629                     {
10630                       child->y += dy;
10631                       break;
10632                     }
10633                 }
10634             }
10635         }
10636       gdk_window_scroll (tree_view->priv->bin_window, 0, dy);
10637
10638       if (tree_view->priv->dy != (int) tree_view->priv->vadjustment->value)
10639         {
10640           /* update our dy and top_row */
10641           tree_view->priv->dy = (int) tree_view->priv->vadjustment->value;
10642
10643           if (!tree_view->priv->in_top_row_to_dy)
10644             gtk_tree_view_dy_to_top_row (tree_view);
10645         }
10646     }
10647 }
10648
10649 \f
10650
10651 /* Public methods
10652  */
10653
10654 /**
10655  * gtk_tree_view_new:
10656  *
10657  * Creates a new #GtkTreeView widget.
10658  *
10659  * Return value: A newly created #GtkTreeView widget.
10660  **/
10661 GtkWidget *
10662 gtk_tree_view_new (void)
10663 {
10664   return g_object_new (GTK_TYPE_TREE_VIEW, NULL);
10665 }
10666
10667 /**
10668  * gtk_tree_view_new_with_model:
10669  * @model: the model.
10670  *
10671  * Creates a new #GtkTreeView widget with the model initialized to @model.
10672  *
10673  * Return value: A newly created #GtkTreeView widget.
10674  **/
10675 GtkWidget *
10676 gtk_tree_view_new_with_model (GtkTreeModel *model)
10677 {
10678   return g_object_new (GTK_TYPE_TREE_VIEW, "model", model, NULL);
10679 }
10680
10681 /* Public Accessors
10682  */
10683
10684 /**
10685  * gtk_tree_view_get_model:
10686  * @tree_view: a #GtkTreeView
10687  *
10688  * Returns the model the #GtkTreeView is based on.  Returns %NULL if the
10689  * model is unset.
10690  *
10691  * Return value: A #GtkTreeModel, or %NULL if none is currently being used.
10692  **/
10693 GtkTreeModel *
10694 gtk_tree_view_get_model (GtkTreeView *tree_view)
10695 {
10696   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
10697
10698   return tree_view->priv->model;
10699 }
10700
10701 /**
10702  * gtk_tree_view_set_model:
10703  * @tree_view: A #GtkTreeNode.
10704  * @model: The model.
10705  *
10706  * Sets the model for a #GtkTreeView.  If the @tree_view already has a model
10707  * set, it will remove it before setting the new model.  If @model is %NULL, 
10708  * then it will unset the old model.
10709  **/
10710 void
10711 gtk_tree_view_set_model (GtkTreeView  *tree_view,
10712                          GtkTreeModel *model)
10713 {
10714   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
10715   g_return_if_fail (model == NULL || GTK_IS_TREE_MODEL (model));
10716
10717   if (model == tree_view->priv->model)
10718     return;
10719
10720   if (tree_view->priv->scroll_to_path)
10721     {
10722       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
10723       tree_view->priv->scroll_to_path = NULL;
10724     }
10725
10726   if (tree_view->priv->model)
10727     {
10728       GList *tmplist = tree_view->priv->columns;
10729
10730       gtk_tree_view_unref_and_check_selection_tree (tree_view, tree_view->priv->tree);
10731       gtk_tree_view_stop_editing (tree_view, TRUE);
10732
10733       remove_expand_collapse_timeout (tree_view);
10734
10735       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
10736                                             gtk_tree_view_row_changed,
10737                                             tree_view);
10738       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
10739                                             gtk_tree_view_row_inserted,
10740                                             tree_view);
10741       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
10742                                             gtk_tree_view_row_has_child_toggled,
10743                                             tree_view);
10744       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
10745                                             gtk_tree_view_row_deleted,
10746                                             tree_view);
10747       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
10748                                             gtk_tree_view_rows_reordered,
10749                                             tree_view);
10750
10751       for (; tmplist; tmplist = tmplist->next)
10752         _gtk_tree_view_column_unset_model (tmplist->data,
10753                                            tree_view->priv->model);
10754
10755       if (tree_view->priv->tree)
10756         gtk_tree_view_free_rbtree (tree_view);
10757
10758       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
10759       tree_view->priv->drag_dest_row = NULL;
10760       gtk_tree_row_reference_free (tree_view->priv->cursor);
10761       tree_view->priv->cursor = NULL;
10762       gtk_tree_row_reference_free (tree_view->priv->anchor);
10763       tree_view->priv->anchor = NULL;
10764       gtk_tree_row_reference_free (tree_view->priv->top_row);
10765       tree_view->priv->top_row = NULL;
10766       gtk_tree_row_reference_free (tree_view->priv->last_button_press);
10767       tree_view->priv->last_button_press = NULL;
10768       gtk_tree_row_reference_free (tree_view->priv->last_button_press_2);
10769       tree_view->priv->last_button_press_2 = NULL;
10770       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
10771       tree_view->priv->scroll_to_path = NULL;
10772
10773       tree_view->priv->scroll_to_column = NULL;
10774
10775       g_object_unref (tree_view->priv->model);
10776
10777       tree_view->priv->search_column = -1;
10778       tree_view->priv->fixed_height_check = 0;
10779       tree_view->priv->fixed_height = -1;
10780       tree_view->priv->dy = tree_view->priv->top_row_dy = 0;
10781     }
10782
10783   tree_view->priv->model = model;
10784
10785   if (tree_view->priv->model)
10786     {
10787       gint i;
10788       GtkTreePath *path;
10789       GtkTreeIter iter;
10790       GtkTreeModelFlags flags;
10791
10792       if (tree_view->priv->search_column == -1)
10793         {
10794           for (i = 0; i < gtk_tree_model_get_n_columns (model); i++)
10795             {
10796               GType type = gtk_tree_model_get_column_type (model, i);
10797
10798               if (g_value_type_transformable (type, G_TYPE_STRING))
10799                 {
10800                   tree_view->priv->search_column = i;
10801                   break;
10802                 }
10803             }
10804         }
10805
10806       g_object_ref (tree_view->priv->model);
10807       g_signal_connect (tree_view->priv->model,
10808                         "row-changed",
10809                         G_CALLBACK (gtk_tree_view_row_changed),
10810                         tree_view);
10811       g_signal_connect (tree_view->priv->model,
10812                         "row-inserted",
10813                         G_CALLBACK (gtk_tree_view_row_inserted),
10814                         tree_view);
10815       g_signal_connect (tree_view->priv->model,
10816                         "row-has-child-toggled",
10817                         G_CALLBACK (gtk_tree_view_row_has_child_toggled),
10818                         tree_view);
10819       g_signal_connect (tree_view->priv->model,
10820                         "row-deleted",
10821                         G_CALLBACK (gtk_tree_view_row_deleted),
10822                         tree_view);
10823       g_signal_connect (tree_view->priv->model,
10824                         "rows-reordered",
10825                         G_CALLBACK (gtk_tree_view_rows_reordered),
10826                         tree_view);
10827
10828       flags = gtk_tree_model_get_flags (tree_view->priv->model);
10829       if ((flags & GTK_TREE_MODEL_LIST_ONLY) == GTK_TREE_MODEL_LIST_ONLY)
10830         GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_IS_LIST);
10831       else
10832         GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IS_LIST);
10833
10834       path = gtk_tree_path_new_first ();
10835       if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, path))
10836         {
10837           tree_view->priv->tree = _gtk_rbtree_new ();
10838           gtk_tree_view_build_tree (tree_view, tree_view->priv->tree, &iter, 1, FALSE);
10839         }
10840       gtk_tree_path_free (path);
10841
10842       /*  FIXME: do I need to do this? gtk_tree_view_create_buttons (tree_view); */
10843       install_presize_handler (tree_view);
10844     }
10845
10846   g_object_notify (G_OBJECT (tree_view), "model");
10847
10848   if (tree_view->priv->selection)
10849   _gtk_tree_selection_emit_changed (tree_view->priv->selection);
10850
10851   if (GTK_WIDGET_REALIZED (tree_view))
10852     gtk_widget_queue_resize (GTK_WIDGET (tree_view));
10853 }
10854
10855 /**
10856  * gtk_tree_view_get_selection:
10857  * @tree_view: A #GtkTreeView.
10858  *
10859  * Gets the #GtkTreeSelection associated with @tree_view.
10860  *
10861  * Return value: A #GtkTreeSelection object.
10862  **/
10863 GtkTreeSelection *
10864 gtk_tree_view_get_selection (GtkTreeView *tree_view)
10865 {
10866   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
10867
10868   return tree_view->priv->selection;
10869 }
10870
10871 /**
10872  * gtk_tree_view_get_hadjustment:
10873  * @tree_view: A #GtkTreeView
10874  *
10875  * Gets the #GtkAdjustment currently being used for the horizontal aspect.
10876  *
10877  * Return value: A #GtkAdjustment object, or %NULL if none is currently being
10878  * used.
10879  **/
10880 GtkAdjustment *
10881 gtk_tree_view_get_hadjustment (GtkTreeView *tree_view)
10882 {
10883   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
10884
10885   if (tree_view->priv->hadjustment == NULL)
10886     gtk_tree_view_set_hadjustment (tree_view, NULL);
10887
10888   return tree_view->priv->hadjustment;
10889 }
10890
10891 /**
10892  * gtk_tree_view_set_hadjustment:
10893  * @tree_view: A #GtkTreeView
10894  * @adjustment: The #GtkAdjustment to set, or %NULL
10895  *
10896  * Sets the #GtkAdjustment for the current horizontal aspect.
10897  **/
10898 void
10899 gtk_tree_view_set_hadjustment (GtkTreeView   *tree_view,
10900                                GtkAdjustment *adjustment)
10901 {
10902   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
10903
10904   gtk_tree_view_set_adjustments (tree_view,
10905                                  adjustment,
10906                                  tree_view->priv->vadjustment);
10907
10908   g_object_notify (G_OBJECT (tree_view), "hadjustment");
10909 }
10910
10911 /**
10912  * gtk_tree_view_get_vadjustment:
10913  * @tree_view: A #GtkTreeView
10914  *
10915  * Gets the #GtkAdjustment currently being used for the vertical aspect.
10916  *
10917  * Return value: A #GtkAdjustment object, or %NULL if none is currently being
10918  * used.
10919  **/
10920 GtkAdjustment *
10921 gtk_tree_view_get_vadjustment (GtkTreeView *tree_view)
10922 {
10923   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
10924
10925   if (tree_view->priv->vadjustment == NULL)
10926     gtk_tree_view_set_vadjustment (tree_view, NULL);
10927
10928   return tree_view->priv->vadjustment;
10929 }
10930
10931 /**
10932  * gtk_tree_view_set_vadjustment:
10933  * @tree_view: A #GtkTreeView
10934  * @adjustment: The #GtkAdjustment to set, or %NULL
10935  *
10936  * Sets the #GtkAdjustment for the current vertical aspect.
10937  **/
10938 void
10939 gtk_tree_view_set_vadjustment (GtkTreeView   *tree_view,
10940                                GtkAdjustment *adjustment)
10941 {
10942   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
10943
10944   gtk_tree_view_set_adjustments (tree_view,
10945                                  tree_view->priv->hadjustment,
10946                                  adjustment);
10947
10948   g_object_notify (G_OBJECT (tree_view), "vadjustment");
10949 }
10950
10951 /* Column and header operations */
10952
10953 /**
10954  * gtk_tree_view_get_headers_visible:
10955  * @tree_view: A #GtkTreeView.
10956  *
10957  * Returns %TRUE if the headers on the @tree_view are visible.
10958  *
10959  * Return value: Whether the headers are visible or not.
10960  **/
10961 gboolean
10962 gtk_tree_view_get_headers_visible (GtkTreeView *tree_view)
10963 {
10964   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
10965
10966   return GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE);
10967 }
10968
10969 /**
10970  * gtk_tree_view_set_headers_visible:
10971  * @tree_view: A #GtkTreeView.
10972  * @headers_visible: %TRUE if the headers are visible
10973  *
10974  * Sets the visibility state of the headers.
10975  **/
10976 void
10977 gtk_tree_view_set_headers_visible (GtkTreeView *tree_view,
10978                                    gboolean     headers_visible)
10979 {
10980   gint x, y;
10981   GList *list;
10982   GtkTreeViewColumn *column;
10983
10984   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
10985
10986   headers_visible = !! headers_visible;
10987
10988   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE) == headers_visible)
10989     return;
10990
10991   if (headers_visible)
10992     GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE);
10993   else
10994     GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE);
10995
10996   if (GTK_WIDGET_REALIZED (tree_view))
10997     {
10998       gdk_window_get_position (tree_view->priv->bin_window, &x, &y);
10999       if (headers_visible)
11000         {
11001           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));
11002
11003           if (GTK_WIDGET_MAPPED (tree_view))
11004             gtk_tree_view_map_buttons (tree_view);
11005         }
11006       else
11007         {
11008           gdk_window_move_resize (tree_view->priv->bin_window, x, y, tree_view->priv->width, tree_view->priv->height);
11009
11010           for (list = tree_view->priv->columns; list; list = list->next)
11011             {
11012               column = list->data;
11013               gtk_widget_unmap (column->button);
11014             }
11015           gdk_window_hide (tree_view->priv->header_window);
11016         }
11017     }
11018
11019   tree_view->priv->vadjustment->page_size = GTK_WIDGET (tree_view)->allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view);
11020   tree_view->priv->vadjustment->page_increment = (GTK_WIDGET (tree_view)->allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view)) / 2;
11021   tree_view->priv->vadjustment->lower = 0;
11022   tree_view->priv->vadjustment->upper = tree_view->priv->height;
11023   gtk_adjustment_changed (tree_view->priv->vadjustment);
11024
11025   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11026
11027   g_object_notify (G_OBJECT (tree_view), "headers-visible");
11028 }
11029
11030 /**
11031  * gtk_tree_view_columns_autosize:
11032  * @tree_view: A #GtkTreeView.
11033  *
11034  * Resizes all columns to their optimal width. Only works after the
11035  * treeview has been realized.
11036  **/
11037 void
11038 gtk_tree_view_columns_autosize (GtkTreeView *tree_view)
11039 {
11040   gboolean dirty = FALSE;
11041   GList *list;
11042   GtkTreeViewColumn *column;
11043
11044   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11045
11046   for (list = tree_view->priv->columns; list; list = list->next)
11047     {
11048       column = list->data;
11049       if (column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
11050         continue;
11051       _gtk_tree_view_column_cell_set_dirty (column, TRUE);
11052       dirty = TRUE;
11053     }
11054
11055   if (dirty)
11056     gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11057 }
11058
11059 /**
11060  * gtk_tree_view_set_headers_clickable:
11061  * @tree_view: A #GtkTreeView.
11062  * @setting: %TRUE if the columns are clickable.
11063  *
11064  * Allow the column title buttons to be clicked.
11065  **/
11066 void
11067 gtk_tree_view_set_headers_clickable (GtkTreeView *tree_view,
11068                                      gboolean   setting)
11069 {
11070   GList *list;
11071
11072   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11073
11074   for (list = tree_view->priv->columns; list; list = list->next)
11075     gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (list->data), setting);
11076
11077   g_object_notify (G_OBJECT (tree_view), "headers-clickable");
11078 }
11079
11080
11081 /**
11082  * gtk_tree_view_get_headers_clickable:
11083  * @tree_view: A #GtkTreeView.
11084  *
11085  * Returns whether all header columns are clickable.
11086  *
11087  * Return value: %TRUE if all header columns are clickable, otherwise %FALSE
11088  *
11089  * Since: 2.10
11090  **/
11091 gboolean 
11092 gtk_tree_view_get_headers_clickable (GtkTreeView *tree_view)
11093 {
11094   GList *list;
11095   
11096   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
11097
11098   for (list = tree_view->priv->columns; list; list = list->next)
11099     if (!GTK_TREE_VIEW_COLUMN (list->data)->clickable)
11100       return FALSE;
11101
11102   return TRUE;
11103 }
11104
11105 /**
11106  * gtk_tree_view_set_rules_hint
11107  * @tree_view: a #GtkTreeView
11108  * @setting: %TRUE if the tree requires reading across rows
11109  *
11110  * This function tells GTK+ that the user interface for your
11111  * application requires users to read across tree rows and associate
11112  * cells with one another. By default, GTK+ will then render the tree
11113  * with alternating row colors. Do <emphasis>not</emphasis> use it
11114  * just because you prefer the appearance of the ruled tree; that's a
11115  * question for the theme. Some themes will draw tree rows in
11116  * alternating colors even when rules are turned off, and users who
11117  * prefer that appearance all the time can choose those themes. You
11118  * should call this function only as a <emphasis>semantic</emphasis>
11119  * hint to the theme engine that your tree makes alternating colors
11120  * useful from a functional standpoint (since it has lots of columns,
11121  * generally).
11122  *
11123  **/
11124 void
11125 gtk_tree_view_set_rules_hint (GtkTreeView  *tree_view,
11126                               gboolean      setting)
11127 {
11128   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11129
11130   setting = setting != FALSE;
11131
11132   if (tree_view->priv->has_rules != setting)
11133     {
11134       tree_view->priv->has_rules = setting;
11135       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
11136     }
11137
11138   g_object_notify (G_OBJECT (tree_view), "rules-hint");
11139 }
11140
11141 /**
11142  * gtk_tree_view_get_rules_hint
11143  * @tree_view: a #GtkTreeView
11144  *
11145  * Gets the setting set by gtk_tree_view_set_rules_hint().
11146  *
11147  * Return value: %TRUE if rules are useful for the user of this tree
11148  **/
11149 gboolean
11150 gtk_tree_view_get_rules_hint (GtkTreeView  *tree_view)
11151 {
11152   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
11153
11154   return tree_view->priv->has_rules;
11155 }
11156
11157 /* Public Column functions
11158  */
11159
11160 /**
11161  * gtk_tree_view_append_column:
11162  * @tree_view: A #GtkTreeView.
11163  * @column: The #GtkTreeViewColumn to add.
11164  *
11165  * Appends @column to the list of columns. If @tree_view has "fixed_height"
11166  * mode enabled, then @column must have its "sizing" property set to be
11167  * GTK_TREE_VIEW_COLUMN_FIXED.
11168  *
11169  * Return value: The number of columns in @tree_view after appending.
11170  **/
11171 gint
11172 gtk_tree_view_append_column (GtkTreeView       *tree_view,
11173                              GtkTreeViewColumn *column)
11174 {
11175   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11176   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
11177   g_return_val_if_fail (column->tree_view == NULL, -1);
11178
11179   return gtk_tree_view_insert_column (tree_view, column, -1);
11180 }
11181
11182
11183 /**
11184  * gtk_tree_view_remove_column:
11185  * @tree_view: A #GtkTreeView.
11186  * @column: The #GtkTreeViewColumn to remove.
11187  *
11188  * Removes @column from @tree_view.
11189  *
11190  * Return value: The number of columns in @tree_view after removing.
11191  **/
11192 gint
11193 gtk_tree_view_remove_column (GtkTreeView       *tree_view,
11194                              GtkTreeViewColumn *column)
11195 {
11196   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11197   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
11198   g_return_val_if_fail (column->tree_view == GTK_WIDGET (tree_view), -1);
11199
11200   if (tree_view->priv->focus_column == column)
11201     tree_view->priv->focus_column = NULL;
11202
11203   if (tree_view->priv->edited_column == column)
11204     {
11205       gtk_tree_view_stop_editing (tree_view, TRUE);
11206
11207       /* no need to, but just to be sure ... */
11208       tree_view->priv->edited_column = NULL;
11209     }
11210
11211   g_signal_handlers_disconnect_by_func (column,
11212                                         G_CALLBACK (column_sizing_notify),
11213                                         tree_view);
11214
11215   _gtk_tree_view_column_unset_tree_view (column);
11216
11217   tree_view->priv->columns = g_list_remove (tree_view->priv->columns, column);
11218   tree_view->priv->n_columns--;
11219
11220   if (GTK_WIDGET_REALIZED (tree_view))
11221     {
11222       GList *list;
11223
11224       _gtk_tree_view_column_unrealize_button (column);
11225       for (list = tree_view->priv->columns; list; list = list->next)
11226         {
11227           GtkTreeViewColumn *tmp_column;
11228
11229           tmp_column = GTK_TREE_VIEW_COLUMN (list->data);
11230           if (tmp_column->visible)
11231             _gtk_tree_view_column_cell_set_dirty (tmp_column, TRUE);
11232         }
11233
11234       if (tree_view->priv->n_columns == 0 &&
11235           gtk_tree_view_get_headers_visible (tree_view))
11236         gdk_window_hide (tree_view->priv->header_window);
11237
11238       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11239     }
11240
11241   g_object_unref (column);
11242   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
11243
11244   return tree_view->priv->n_columns;
11245 }
11246
11247 /**
11248  * gtk_tree_view_insert_column:
11249  * @tree_view: A #GtkTreeView.
11250  * @column: The #GtkTreeViewColumn to be inserted.
11251  * @position: The position to insert @column in.
11252  *
11253  * This inserts the @column into the @tree_view at @position.  If @position is
11254  * -1, then the column is inserted at the end. If @tree_view has
11255  * "fixed_height" mode enabled, then @column must have its "sizing" property
11256  * set to be GTK_TREE_VIEW_COLUMN_FIXED.
11257  *
11258  * Return value: The number of columns in @tree_view after insertion.
11259  **/
11260 gint
11261 gtk_tree_view_insert_column (GtkTreeView       *tree_view,
11262                              GtkTreeViewColumn *column,
11263                              gint               position)
11264 {
11265   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11266   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
11267   g_return_val_if_fail (column->tree_view == NULL, -1);
11268
11269   if (tree_view->priv->fixed_height_mode)
11270     g_return_val_if_fail (gtk_tree_view_column_get_sizing (column)
11271                           == GTK_TREE_VIEW_COLUMN_FIXED, -1);
11272
11273   g_object_ref_sink (column);
11274
11275   if (tree_view->priv->n_columns == 0 &&
11276       GTK_WIDGET_REALIZED (tree_view) &&
11277       gtk_tree_view_get_headers_visible (tree_view))
11278     {
11279       gdk_window_show (tree_view->priv->header_window);
11280     }
11281
11282   g_signal_connect (column, "notify::sizing",
11283                     G_CALLBACK (column_sizing_notify), tree_view);
11284
11285   tree_view->priv->columns = g_list_insert (tree_view->priv->columns,
11286                                             column, position);
11287   tree_view->priv->n_columns++;
11288
11289   _gtk_tree_view_column_set_tree_view (column, tree_view);
11290
11291   if (GTK_WIDGET_REALIZED (tree_view))
11292     {
11293       GList *list;
11294
11295       _gtk_tree_view_column_realize_button (column);
11296
11297       for (list = tree_view->priv->columns; list; list = list->next)
11298         {
11299           column = GTK_TREE_VIEW_COLUMN (list->data);
11300           if (column->visible)
11301             _gtk_tree_view_column_cell_set_dirty (column, TRUE);
11302         }
11303       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11304     }
11305
11306   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
11307
11308   return tree_view->priv->n_columns;
11309 }
11310
11311 /**
11312  * gtk_tree_view_insert_column_with_attributes:
11313  * @tree_view: A #GtkTreeView
11314  * @position: The position to insert the new column in.
11315  * @title: The title to set the header to.
11316  * @cell: The #GtkCellRenderer.
11317  * @Varargs: A %NULL-terminated list of attributes.
11318  *
11319  * Creates a new #GtkTreeViewColumn and inserts it into the @tree_view at
11320  * @position.  If @position is -1, then the newly created column is inserted at
11321  * the end.  The column is initialized with the attributes given. If @tree_view
11322  * has "fixed_height" mode enabled, then the new column will have its sizing
11323  * property set to be GTK_TREE_VIEW_COLUMN_FIXED.
11324  *
11325  * Return value: The number of columns in @tree_view after insertion.
11326  **/
11327 gint
11328 gtk_tree_view_insert_column_with_attributes (GtkTreeView     *tree_view,
11329                                              gint             position,
11330                                              const gchar     *title,
11331                                              GtkCellRenderer *cell,
11332                                              ...)
11333 {
11334   GtkTreeViewColumn *column;
11335   gchar *attribute;
11336   va_list args;
11337   gint column_id;
11338
11339   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11340
11341   column = gtk_tree_view_column_new ();
11342   if (tree_view->priv->fixed_height_mode)
11343     gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
11344
11345   gtk_tree_view_column_set_title (column, title);
11346   gtk_tree_view_column_pack_start (column, cell, TRUE);
11347
11348   va_start (args, cell);
11349
11350   attribute = va_arg (args, gchar *);
11351
11352   while (attribute != NULL)
11353     {
11354       column_id = va_arg (args, gint);
11355       gtk_tree_view_column_add_attribute (column, cell, attribute, column_id);
11356       attribute = va_arg (args, gchar *);
11357     }
11358
11359   va_end (args);
11360
11361   gtk_tree_view_insert_column (tree_view, column, position);
11362
11363   return tree_view->priv->n_columns;
11364 }
11365
11366 /**
11367  * gtk_tree_view_insert_column_with_data_func:
11368  * @tree_view: a #GtkTreeView
11369  * @position: Position to insert, -1 for append
11370  * @title: column title
11371  * @cell: cell renderer for column
11372  * @func: function to set attributes of cell renderer
11373  * @data: data for @func
11374  * @dnotify: destroy notifier for @data
11375  *
11376  * Convenience function that inserts a new column into the #GtkTreeView
11377  * with the given cell renderer and a #GtkCellDataFunc to set cell renderer
11378  * attributes (normally using data from the model). See also
11379  * gtk_tree_view_column_set_cell_data_func(), gtk_tree_view_column_pack_start().
11380  * If @tree_view has "fixed_height" mode enabled, then the new column will have its
11381  * "sizing" property set to be GTK_TREE_VIEW_COLUMN_FIXED.
11382  *
11383  * Return value: number of columns in the tree view post-insert
11384  **/
11385 gint
11386 gtk_tree_view_insert_column_with_data_func  (GtkTreeView               *tree_view,
11387                                              gint                       position,
11388                                              const gchar               *title,
11389                                              GtkCellRenderer           *cell,
11390                                              GtkTreeCellDataFunc        func,
11391                                              gpointer                   data,
11392                                              GDestroyNotify             dnotify)
11393 {
11394   GtkTreeViewColumn *column;
11395
11396   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11397
11398   column = gtk_tree_view_column_new ();
11399   if (tree_view->priv->fixed_height_mode)
11400     gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
11401
11402   gtk_tree_view_column_set_title (column, title);
11403   gtk_tree_view_column_pack_start (column, cell, TRUE);
11404   gtk_tree_view_column_set_cell_data_func (column, cell, func, data, dnotify);
11405
11406   gtk_tree_view_insert_column (tree_view, column, position);
11407
11408   return tree_view->priv->n_columns;
11409 }
11410
11411 /**
11412  * gtk_tree_view_get_column:
11413  * @tree_view: A #GtkTreeView.
11414  * @n: The position of the column, counting from 0.
11415  *
11416  * Gets the #GtkTreeViewColumn at the given position in the #tree_view.
11417  *
11418  * Return value: The #GtkTreeViewColumn, or %NULL if the position is outside the
11419  * range of columns.
11420  **/
11421 GtkTreeViewColumn *
11422 gtk_tree_view_get_column (GtkTreeView *tree_view,
11423                           gint         n)
11424 {
11425   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11426
11427   if (n < 0 || n >= tree_view->priv->n_columns)
11428     return NULL;
11429
11430   if (tree_view->priv->columns == NULL)
11431     return NULL;
11432
11433   return GTK_TREE_VIEW_COLUMN (g_list_nth (tree_view->priv->columns, n)->data);
11434 }
11435
11436 /**
11437  * gtk_tree_view_get_columns:
11438  * @tree_view: A #GtkTreeView
11439  *
11440  * Returns a #GList of all the #GtkTreeViewColumn s currently in @tree_view.
11441  * The returned list must be freed with g_list_free ().
11442  *
11443  * Return value: A list of #GtkTreeViewColumn s
11444  **/
11445 GList *
11446 gtk_tree_view_get_columns (GtkTreeView *tree_view)
11447 {
11448   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11449
11450   return g_list_copy (tree_view->priv->columns);
11451 }
11452
11453 /**
11454  * gtk_tree_view_move_column_after:
11455  * @tree_view: A #GtkTreeView
11456  * @column: The #GtkTreeViewColumn to be moved.
11457  * @base_column: The #GtkTreeViewColumn to be moved relative to, or %NULL.
11458  *
11459  * Moves @column to be after to @base_column.  If @base_column is %NULL, then
11460  * @column is placed in the first position.
11461  **/
11462 void
11463 gtk_tree_view_move_column_after (GtkTreeView       *tree_view,
11464                                  GtkTreeViewColumn *column,
11465                                  GtkTreeViewColumn *base_column)
11466 {
11467   GList *column_list_el, *base_el = NULL;
11468
11469   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11470
11471   column_list_el = g_list_find (tree_view->priv->columns, column);
11472   g_return_if_fail (column_list_el != NULL);
11473
11474   if (base_column)
11475     {
11476       base_el = g_list_find (tree_view->priv->columns, base_column);
11477       g_return_if_fail (base_el != NULL);
11478     }
11479
11480   if (column_list_el->prev == base_el)
11481     return;
11482
11483   tree_view->priv->columns = g_list_remove_link (tree_view->priv->columns, column_list_el);
11484   if (base_el == NULL)
11485     {
11486       column_list_el->prev = NULL;
11487       column_list_el->next = tree_view->priv->columns;
11488       if (column_list_el->next)
11489         column_list_el->next->prev = column_list_el;
11490       tree_view->priv->columns = column_list_el;
11491     }
11492   else
11493     {
11494       column_list_el->prev = base_el;
11495       column_list_el->next = base_el->next;
11496       if (column_list_el->next)
11497         column_list_el->next->prev = column_list_el;
11498       base_el->next = column_list_el;
11499     }
11500
11501   if (GTK_WIDGET_REALIZED (tree_view))
11502     {
11503       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11504       gtk_tree_view_size_allocate_columns (GTK_WIDGET (tree_view), NULL);
11505     }
11506
11507   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
11508 }
11509
11510 /**
11511  * gtk_tree_view_set_expander_column:
11512  * @tree_view: A #GtkTreeView
11513  * @column: %NULL, or the column to draw the expander arrow at.
11514  *
11515  * Sets the column to draw the expander arrow at. It must be in @tree_view.  
11516  * If @column is %NULL, then the expander arrow is always at the first 
11517  * visible column.
11518  *
11519  * If you do not want expander arrow to appear in your tree, set the 
11520  * expander column to a hidden column.
11521  **/
11522 void
11523 gtk_tree_view_set_expander_column (GtkTreeView       *tree_view,
11524                                    GtkTreeViewColumn *column)
11525 {
11526   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11527   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
11528
11529   if (tree_view->priv->expander_column != column)
11530     {
11531       GList *list;
11532
11533       if (column)
11534         {
11535           /* Confirm that column is in tree_view */
11536           for (list = tree_view->priv->columns; list; list = list->next)
11537             if (list->data == column)
11538               break;
11539           g_return_if_fail (list != NULL);
11540         }
11541
11542       tree_view->priv->expander_column = column;
11543       g_object_notify (G_OBJECT (tree_view), "expander-column");
11544     }
11545 }
11546
11547 /**
11548  * gtk_tree_view_get_expander_column:
11549  * @tree_view: A #GtkTreeView
11550  *
11551  * Returns the column that is the current expander column.  This
11552  * column has the expander arrow drawn next to it.
11553  *
11554  * Return value: The expander column.
11555  **/
11556 GtkTreeViewColumn *
11557 gtk_tree_view_get_expander_column (GtkTreeView *tree_view)
11558 {
11559   GList *list;
11560
11561   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11562
11563   for (list = tree_view->priv->columns; list; list = list->next)
11564     if (gtk_tree_view_is_expander_column (tree_view, GTK_TREE_VIEW_COLUMN (list->data)))
11565       return (GtkTreeViewColumn *) list->data;
11566   return NULL;
11567 }
11568
11569
11570 /**
11571  * gtk_tree_view_set_column_drag_function:
11572  * @tree_view: A #GtkTreeView.
11573  * @func: A function to determine which columns are reorderable, or %NULL.
11574  * @user_data: User data to be passed to @func, or %NULL
11575  * @destroy: Destroy notifier for @user_data, or %NULL
11576  *
11577  * Sets a user function for determining where a column may be dropped when
11578  * dragged.  This function is called on every column pair in turn at the
11579  * beginning of a column drag to determine where a drop can take place.  The
11580  * arguments passed to @func are: the @tree_view, the #GtkTreeViewColumn being
11581  * dragged, the two #GtkTreeViewColumn s determining the drop spot, and
11582  * @user_data.  If either of the #GtkTreeViewColumn arguments for the drop spot
11583  * are %NULL, then they indicate an edge.  If @func is set to be %NULL, then
11584  * @tree_view reverts to the default behavior of allowing all columns to be
11585  * dropped everywhere.
11586  **/
11587 void
11588 gtk_tree_view_set_column_drag_function (GtkTreeView               *tree_view,
11589                                         GtkTreeViewColumnDropFunc  func,
11590                                         gpointer                   user_data,
11591                                         GDestroyNotify             destroy)
11592 {
11593   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11594
11595   if (tree_view->priv->column_drop_func_data_destroy)
11596     tree_view->priv->column_drop_func_data_destroy (tree_view->priv->column_drop_func_data);
11597
11598   tree_view->priv->column_drop_func = func;
11599   tree_view->priv->column_drop_func_data = user_data;
11600   tree_view->priv->column_drop_func_data_destroy = destroy;
11601 }
11602
11603 /**
11604  * gtk_tree_view_scroll_to_point:
11605  * @tree_view: a #GtkTreeView
11606  * @tree_x: X coordinate of new top-left pixel of visible area, or -1
11607  * @tree_y: Y coordinate of new top-left pixel of visible area, or -1
11608  *
11609  * Scrolls the tree view such that the top-left corner of the visible
11610  * area is @tree_x, @tree_y, where @tree_x and @tree_y are specified
11611  * in tree coordinates.  The @tree_view must be realized before
11612  * this function is called.  If it isn't, you probably want to be
11613  * using gtk_tree_view_scroll_to_cell().
11614  *
11615  * If either @tree_x or @tree_y are -1, then that direction isn't scrolled.
11616  **/
11617 void
11618 gtk_tree_view_scroll_to_point (GtkTreeView *tree_view,
11619                                gint         tree_x,
11620                                gint         tree_y)
11621 {
11622   GtkAdjustment *hadj;
11623   GtkAdjustment *vadj;
11624
11625   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11626   g_return_if_fail (GTK_WIDGET_REALIZED (tree_view));
11627
11628   hadj = tree_view->priv->hadjustment;
11629   vadj = tree_view->priv->vadjustment;
11630
11631   if (tree_x != -1)
11632     gtk_adjustment_set_value (hadj, CLAMP (tree_x, hadj->lower, hadj->upper - hadj->page_size));
11633   if (tree_y != -1)
11634     gtk_adjustment_set_value (vadj, CLAMP (tree_y, vadj->lower, vadj->upper - vadj->page_size));
11635 }
11636
11637 /**
11638  * gtk_tree_view_scroll_to_cell:
11639  * @tree_view: A #GtkTreeView.
11640  * @path: The path of the row to move to, or %NULL.
11641  * @column: The #GtkTreeViewColumn to move horizontally to, or %NULL.
11642  * @use_align: whether to use alignment arguments, or %FALSE.
11643  * @row_align: The vertical alignment of the row specified by @path.
11644  * @col_align: The horizontal alignment of the column specified by @column.
11645  *
11646  * Moves the alignments of @tree_view to the position specified by @column and
11647  * @path.  If @column is %NULL, then no horizontal scrolling occurs.  Likewise,
11648  * if @path is %NULL no vertical scrolling occurs.  At a minimum, one of @column
11649  * or @path need to be non-%NULL.  @row_align determines where the row is
11650  * placed, and @col_align determines where @column is placed.  Both are expected
11651  * to be between 0.0 and 1.0. 0.0 means left/top alignment, 1.0 means
11652  * right/bottom alignment, 0.5 means center.
11653  *
11654  * If @use_align is %FALSE, then the alignment arguments are ignored, and the
11655  * tree does the minimum amount of work to scroll the cell onto the screen.
11656  * This means that the cell will be scrolled to the edge closest to its current
11657  * position.  If the cell is currently visible on the screen, nothing is done.
11658  *
11659  * This function only works if the model is set, and @path is a valid row on the
11660  * model.  If the model changes before the @tree_view is realized, the centered
11661  * path will be modified to reflect this change.
11662  **/
11663 void
11664 gtk_tree_view_scroll_to_cell (GtkTreeView       *tree_view,
11665                               GtkTreePath       *path,
11666                               GtkTreeViewColumn *column,
11667                               gboolean           use_align,
11668                               gfloat             row_align,
11669                               gfloat             col_align)
11670 {
11671   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11672   g_return_if_fail (tree_view->priv->model != NULL);
11673   g_return_if_fail (tree_view->priv->tree != NULL);
11674   g_return_if_fail (row_align >= 0.0 && row_align <= 1.0);
11675   g_return_if_fail (col_align >= 0.0 && col_align <= 1.0);
11676   g_return_if_fail (path != NULL || column != NULL);
11677
11678 #if 0
11679   g_print ("gtk_tree_view_scroll_to_cell:\npath: %s\ncolumn: %s\nuse_align: %d\nrow_align: %f\ncol_align: %f\n",
11680            gtk_tree_path_to_string (path), column?"non-null":"null", use_align, row_align, col_align);
11681 #endif
11682   row_align = CLAMP (row_align, 0.0, 1.0);
11683   col_align = CLAMP (col_align, 0.0, 1.0);
11684
11685
11686   /* Note: Despite the benefits that come from having one code path for the
11687    * scrolling code, we short-circuit validate_visible_area's immplementation as
11688    * it is much slower than just going to the point.
11689    */
11690   if (! GTK_WIDGET_VISIBLE (tree_view) ||
11691       ! GTK_WIDGET_REALIZED (tree_view) ||
11692       GTK_WIDGET_ALLOC_NEEDED (tree_view) || 
11693       GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID))
11694     {
11695       if (tree_view->priv->scroll_to_path)
11696         gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
11697
11698       tree_view->priv->scroll_to_path = NULL;
11699       tree_view->priv->scroll_to_column = NULL;
11700
11701       if (path)
11702         tree_view->priv->scroll_to_path = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
11703       if (column)
11704         tree_view->priv->scroll_to_column = column;
11705       tree_view->priv->scroll_to_use_align = use_align;
11706       tree_view->priv->scroll_to_row_align = row_align;
11707       tree_view->priv->scroll_to_col_align = col_align;
11708
11709       install_presize_handler (tree_view);
11710     }
11711   else
11712     {
11713       GdkRectangle cell_rect;
11714       GdkRectangle vis_rect;
11715       gint dest_x, dest_y;
11716
11717       gtk_tree_view_get_background_area (tree_view, path, column, &cell_rect);
11718       gtk_tree_view_get_visible_rect (tree_view, &vis_rect);
11719
11720       cell_rect.y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, cell_rect.y);
11721
11722       dest_x = vis_rect.x;
11723       dest_y = vis_rect.y;
11724
11725       if (column)
11726         {
11727           if (use_align)
11728             {
11729               dest_x = cell_rect.x - ((vis_rect.width - cell_rect.width) * col_align);
11730             }
11731           else
11732             {
11733               if (cell_rect.x < vis_rect.x)
11734                 dest_x = cell_rect.x;
11735               if (cell_rect.x + cell_rect.width > vis_rect.x + vis_rect.width)
11736                 dest_x = cell_rect.x + cell_rect.width - vis_rect.width;
11737             }
11738         }
11739
11740       if (path)
11741         {
11742           if (use_align)
11743             {
11744               dest_y = cell_rect.y - ((vis_rect.height - cell_rect.height) * row_align);
11745               dest_y = MAX (dest_y, 0);
11746             }
11747           else
11748             {
11749               if (cell_rect.y < vis_rect.y)
11750                 dest_y = cell_rect.y;
11751               if (cell_rect.y + cell_rect.height > vis_rect.y + vis_rect.height)
11752                 dest_y = cell_rect.y + cell_rect.height - vis_rect.height;
11753             }
11754         }
11755
11756       gtk_tree_view_scroll_to_point (tree_view, dest_x, dest_y);
11757     }
11758 }
11759
11760 /**
11761  * gtk_tree_view_row_activated:
11762  * @tree_view: A #GtkTreeView
11763  * @path: The #GtkTreePath to be activated.
11764  * @column: The #GtkTreeViewColumn to be activated.
11765  *
11766  * Activates the cell determined by @path and @column.
11767  **/
11768 void
11769 gtk_tree_view_row_activated (GtkTreeView       *tree_view,
11770                              GtkTreePath       *path,
11771                              GtkTreeViewColumn *column)
11772 {
11773   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11774
11775   g_signal_emit (tree_view, tree_view_signals[ROW_ACTIVATED], 0, path, column);
11776 }
11777
11778
11779 static void
11780 gtk_tree_view_expand_all_emission_helper (GtkRBTree *tree,
11781                                           GtkRBNode *node,
11782                                           gpointer   data)
11783 {
11784   GtkTreeView *tree_view = data;
11785
11786   if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT &&
11787       node->children)
11788     {
11789       GtkTreePath *path;
11790       GtkTreeIter iter;
11791
11792       path = _gtk_tree_view_find_path (tree_view, tree, node);
11793       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
11794
11795       g_signal_emit (tree_view, tree_view_signals[ROW_EXPANDED], 0, &iter, path);
11796
11797       gtk_tree_path_free (path);
11798     }
11799
11800   if (node->children)
11801     _gtk_rbtree_traverse (node->children,
11802                           node->children->root,
11803                           G_PRE_ORDER,
11804                           gtk_tree_view_expand_all_emission_helper,
11805                           tree_view);
11806 }
11807
11808 /**
11809  * gtk_tree_view_expand_all:
11810  * @tree_view: A #GtkTreeView.
11811  *
11812  * Recursively expands all nodes in the @tree_view.
11813  **/
11814 void
11815 gtk_tree_view_expand_all (GtkTreeView *tree_view)
11816 {
11817   GtkTreePath *path;
11818   GtkRBTree *tree;
11819   GtkRBNode *node;
11820
11821   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11822
11823   if (tree_view->priv->tree == NULL)
11824     return;
11825
11826   path = gtk_tree_path_new_first ();
11827   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
11828
11829   while (node)
11830     {
11831       gtk_tree_view_real_expand_row (tree_view, path, tree, node, TRUE, FALSE);
11832       node = _gtk_rbtree_next (tree, node);
11833       gtk_tree_path_next (path);
11834   }
11835
11836   gtk_tree_path_free (path);
11837 }
11838
11839 /* Timeout to animate the expander during expands and collapses */
11840 static gboolean
11841 expand_collapse_timeout (gpointer data)
11842 {
11843   return do_expand_collapse (data);
11844 }
11845
11846 static void
11847 add_expand_collapse_timeout (GtkTreeView *tree_view,
11848                              GtkRBTree   *tree,
11849                              GtkRBNode   *node,
11850                              gboolean     expand)
11851 {
11852   if (tree_view->priv->expand_collapse_timeout != 0)
11853     return;
11854
11855   tree_view->priv->expand_collapse_timeout =
11856       gdk_threads_add_timeout (50, expand_collapse_timeout, tree_view);
11857   tree_view->priv->expanded_collapsed_tree = tree;
11858   tree_view->priv->expanded_collapsed_node = node;
11859
11860   if (expand)
11861     GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
11862   else
11863     GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
11864 }
11865
11866 static void
11867 remove_expand_collapse_timeout (GtkTreeView *tree_view)
11868 {
11869   if (tree_view->priv->expand_collapse_timeout)
11870     {
11871       g_source_remove (tree_view->priv->expand_collapse_timeout);
11872       tree_view->priv->expand_collapse_timeout = 0;
11873     }
11874
11875   if (tree_view->priv->expanded_collapsed_node != NULL)
11876     {
11877       GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_EXPANDED);
11878       GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_COLLAPSED);
11879
11880       tree_view->priv->expanded_collapsed_node = NULL;
11881     }
11882 }
11883
11884 static void
11885 cancel_arrow_animation (GtkTreeView *tree_view)
11886 {
11887   if (tree_view->priv->expand_collapse_timeout)
11888     {
11889       while (do_expand_collapse (tree_view));
11890
11891       remove_expand_collapse_timeout (tree_view);
11892     }
11893 }
11894
11895 static gboolean
11896 do_expand_collapse (GtkTreeView *tree_view)
11897 {
11898   GtkRBNode *node;
11899   GtkRBTree *tree;
11900   gboolean expanding;
11901   gboolean redraw;
11902
11903   redraw = FALSE;
11904   expanding = TRUE;
11905
11906   node = tree_view->priv->expanded_collapsed_node;
11907   tree = tree_view->priv->expanded_collapsed_tree;
11908
11909   if (node->children == NULL)
11910     expanding = FALSE;
11911
11912   if (expanding)
11913     {
11914       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_COLLAPSED))
11915         {
11916           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
11917           GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
11918
11919           redraw = TRUE;
11920
11921         }
11922       else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_EXPANDED))
11923         {
11924           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
11925
11926           redraw = TRUE;
11927         }
11928     }
11929   else
11930     {
11931       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_EXPANDED))
11932         {
11933           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
11934           GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
11935
11936           redraw = TRUE;
11937         }
11938       else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_COLLAPSED))
11939         {
11940           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
11941
11942           redraw = TRUE;
11943
11944         }
11945     }
11946
11947   if (redraw)
11948     {
11949       gtk_tree_view_queue_draw_arrow (tree_view, tree, node, NULL);
11950
11951       return TRUE;
11952     }
11953
11954   return FALSE;
11955 }
11956
11957 /**
11958  * gtk_tree_view_collapse_all:
11959  * @tree_view: A #GtkTreeView.
11960  *
11961  * Recursively collapses all visible, expanded nodes in @tree_view.
11962  **/
11963 void
11964 gtk_tree_view_collapse_all (GtkTreeView *tree_view)
11965 {
11966   GtkRBTree *tree;
11967   GtkRBNode *node;
11968   GtkTreePath *path;
11969   gint *indices;
11970
11971   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11972
11973   if (tree_view->priv->tree == NULL)
11974     return;
11975
11976   path = gtk_tree_path_new ();
11977   gtk_tree_path_down (path);
11978   indices = gtk_tree_path_get_indices (path);
11979
11980   tree = tree_view->priv->tree;
11981   node = tree->root;
11982   while (node && node->left != tree->nil)
11983     node = node->left;
11984
11985   while (node)
11986     {
11987       if (node->children)
11988         gtk_tree_view_real_collapse_row (tree_view, path, tree, node, FALSE);
11989       indices[0]++;
11990       node = _gtk_rbtree_next (tree, node);
11991     }
11992
11993   gtk_tree_path_free (path);
11994 }
11995
11996 /**
11997  * gtk_tree_view_expand_to_path:
11998  * @tree_view: A #GtkTreeView.
11999  * @path: path to a row.
12000  *
12001  * Expands the row at @path. This will also expand all parent rows of
12002  * @path as necessary.
12003  *
12004  * Since: 2.2
12005  **/
12006 void
12007 gtk_tree_view_expand_to_path (GtkTreeView *tree_view,
12008                               GtkTreePath *path)
12009 {
12010   gint i, depth;
12011   gint *indices;
12012   GtkTreePath *tmp;
12013
12014   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12015   g_return_if_fail (path != NULL);
12016
12017   depth = gtk_tree_path_get_depth (path);
12018   indices = gtk_tree_path_get_indices (path);
12019
12020   tmp = gtk_tree_path_new ();
12021   g_return_if_fail (tmp != NULL);
12022
12023   for (i = 0; i < depth; i++)
12024     {
12025       gtk_tree_path_append_index (tmp, indices[i]);
12026       gtk_tree_view_expand_row (tree_view, tmp, FALSE);
12027     }
12028
12029   gtk_tree_path_free (tmp);
12030 }
12031
12032 /* FIXME the bool return values for expand_row and collapse_row are
12033  * not analagous; they should be TRUE if the row had children and
12034  * was not already in the requested state.
12035  */
12036
12037
12038 static gboolean
12039 gtk_tree_view_real_expand_row (GtkTreeView *tree_view,
12040                                GtkTreePath *path,
12041                                GtkRBTree   *tree,
12042                                GtkRBNode   *node,
12043                                gboolean     open_all,
12044                                gboolean     animate)
12045 {
12046   GtkTreeIter iter;
12047   GtkTreeIter temp;
12048   gboolean expand;
12049
12050   if (animate)
12051     g_object_get (gtk_widget_get_settings (GTK_WIDGET (tree_view)),
12052                   "gtk-enable-animations", &animate,
12053                   NULL);
12054
12055   remove_auto_expand_timeout (tree_view);
12056
12057   if (node->children && !open_all)
12058     return FALSE;
12059
12060   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
12061     return FALSE;
12062
12063   gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
12064   if (! gtk_tree_model_iter_has_child (tree_view->priv->model, &iter))
12065     return FALSE;
12066
12067
12068    if (node->children && open_all)
12069     {
12070       gboolean retval = FALSE;
12071       GtkTreePath *tmp_path = gtk_tree_path_copy (path);
12072
12073       gtk_tree_path_append_index (tmp_path, 0);
12074       tree = node->children;
12075       node = tree->root;
12076       while (node->left != tree->nil)
12077         node = node->left;
12078       /* try to expand the children */
12079       do
12080         {
12081          gboolean t;
12082          t = gtk_tree_view_real_expand_row (tree_view, tmp_path, tree, node,
12083                                             TRUE, animate);
12084          if (t)
12085            retval = TRUE;
12086
12087          gtk_tree_path_next (tmp_path);
12088          node = _gtk_rbtree_next (tree, node);
12089        }
12090       while (node != NULL);
12091
12092       gtk_tree_path_free (tmp_path);
12093
12094       return retval;
12095     }
12096
12097   g_signal_emit (tree_view, tree_view_signals[TEST_EXPAND_ROW], 0, &iter, path, &expand);
12098
12099   if (!gtk_tree_model_iter_has_child (tree_view->priv->model, &iter))
12100     return FALSE;
12101
12102   if (expand)
12103     return FALSE;
12104
12105   node->children = _gtk_rbtree_new ();
12106   node->children->parent_tree = tree;
12107   node->children->parent_node = node;
12108
12109   gtk_tree_model_iter_children (tree_view->priv->model, &temp, &iter);
12110
12111   gtk_tree_view_build_tree (tree_view,
12112                             node->children,
12113                             &temp,
12114                             gtk_tree_path_get_depth (path) + 1,
12115                             open_all);
12116
12117   remove_expand_collapse_timeout (tree_view);
12118
12119   if (animate)
12120     add_expand_collapse_timeout (tree_view, tree, node, TRUE);
12121
12122   install_presize_handler (tree_view);
12123
12124   g_signal_emit (tree_view, tree_view_signals[ROW_EXPANDED], 0, &iter, path);
12125   if (open_all && node->children)
12126     {
12127       _gtk_rbtree_traverse (node->children,
12128                             node->children->root,
12129                             G_PRE_ORDER,
12130                             gtk_tree_view_expand_all_emission_helper,
12131                             tree_view);
12132     }
12133   return TRUE;
12134 }
12135
12136
12137 /**
12138  * gtk_tree_view_expand_row:
12139  * @tree_view: a #GtkTreeView
12140  * @path: path to a row
12141  * @open_all: whether to recursively expand, or just expand immediate children
12142  *
12143  * Opens the row so its children are visible.
12144  *
12145  * Return value: %TRUE if the row existed and had children
12146  **/
12147 gboolean
12148 gtk_tree_view_expand_row (GtkTreeView *tree_view,
12149                           GtkTreePath *path,
12150                           gboolean     open_all)
12151 {
12152   GtkRBTree *tree;
12153   GtkRBNode *node;
12154
12155   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12156   g_return_val_if_fail (tree_view->priv->model != NULL, FALSE);
12157   g_return_val_if_fail (path != NULL, FALSE);
12158
12159   if (_gtk_tree_view_find_node (tree_view,
12160                                 path,
12161                                 &tree,
12162                                 &node))
12163     return FALSE;
12164
12165   if (tree != NULL)
12166     return gtk_tree_view_real_expand_row (tree_view, path, tree, node, open_all, FALSE);
12167   else
12168     return FALSE;
12169 }
12170
12171 static gboolean
12172 gtk_tree_view_real_collapse_row (GtkTreeView *tree_view,
12173                                  GtkTreePath *path,
12174                                  GtkRBTree   *tree,
12175                                  GtkRBNode   *node,
12176                                  gboolean     animate)
12177 {
12178   GtkTreeIter iter;
12179   GtkTreeIter children;
12180   gboolean collapse;
12181   gint x, y;
12182   GList *list;
12183   GdkWindow *child, *parent;
12184
12185   if (animate)
12186     g_object_get (gtk_widget_get_settings (GTK_WIDGET (tree_view)),
12187                   "gtk-enable-animations", &animate,
12188                   NULL);
12189
12190   remove_auto_expand_timeout (tree_view);
12191
12192   if (node->children == NULL)
12193     return FALSE;
12194
12195   gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
12196
12197   g_signal_emit (tree_view, tree_view_signals[TEST_COLLAPSE_ROW], 0, &iter, path, &collapse);
12198
12199   if (collapse)
12200     return FALSE;
12201
12202   /* if the prelighted node is a child of us, we want to unprelight it.  We have
12203    * a chance to prelight the correct node below */
12204
12205   if (tree_view->priv->prelight_tree)
12206     {
12207       GtkRBTree *parent_tree;
12208       GtkRBNode *parent_node;
12209
12210       parent_tree = tree_view->priv->prelight_tree->parent_tree;
12211       parent_node = tree_view->priv->prelight_tree->parent_node;
12212       while (parent_tree)
12213         {
12214           if (parent_tree == tree && parent_node == node)
12215             {
12216               ensure_unprelighted (tree_view);
12217               break;
12218             }
12219           parent_node = parent_tree->parent_node;
12220           parent_tree = parent_tree->parent_tree;
12221         }
12222     }
12223
12224   TREE_VIEW_INTERNAL_ASSERT (gtk_tree_model_iter_children (tree_view->priv->model, &children, &iter), FALSE);
12225
12226   for (list = tree_view->priv->columns; list; list = list->next)
12227     {
12228       GtkTreeViewColumn *column = list->data;
12229
12230       if (column->visible == FALSE)
12231         continue;
12232       if (gtk_tree_view_column_get_sizing (column) == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
12233         _gtk_tree_view_column_cell_set_dirty (column, TRUE);
12234     }
12235
12236   if (tree_view->priv->destroy_count_func)
12237     {
12238       GtkTreePath *child_path;
12239       gint child_count = 0;
12240       child_path = gtk_tree_path_copy (path);
12241       gtk_tree_path_down (child_path);
12242       if (node->children)
12243         _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, &child_count);
12244       tree_view->priv->destroy_count_func (tree_view, child_path, child_count, tree_view->priv->destroy_count_data);
12245       gtk_tree_path_free (child_path);
12246     }
12247
12248   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
12249     {
12250       GtkTreePath *cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
12251
12252       if (gtk_tree_path_is_ancestor (path, cursor_path))
12253         {
12254           gtk_tree_row_reference_free (tree_view->priv->cursor);
12255           tree_view->priv->cursor = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
12256                                                                       tree_view->priv->model,
12257                                                                       path);
12258         }
12259       gtk_tree_path_free (cursor_path);
12260     }
12261
12262   if (gtk_tree_row_reference_valid (tree_view->priv->anchor))
12263     {
12264       GtkTreePath *anchor_path = gtk_tree_row_reference_get_path (tree_view->priv->anchor);
12265       if (gtk_tree_path_is_ancestor (path, anchor_path))
12266         {
12267           gtk_tree_row_reference_free (tree_view->priv->anchor);
12268           tree_view->priv->anchor = NULL;
12269         }
12270       gtk_tree_path_free (anchor_path);
12271     }
12272
12273   if (gtk_tree_row_reference_valid (tree_view->priv->last_button_press))
12274     {
12275       GtkTreePath *lsc = gtk_tree_row_reference_get_path (tree_view->priv->last_button_press);
12276       if (gtk_tree_path_is_ancestor (path, lsc))
12277         {
12278           gtk_tree_row_reference_free (tree_view->priv->last_button_press);
12279           tree_view->priv->last_button_press = NULL;
12280         }
12281       gtk_tree_path_free (lsc);
12282     }
12283
12284   if (gtk_tree_row_reference_valid (tree_view->priv->last_button_press_2))
12285     {
12286       GtkTreePath *lsc = gtk_tree_row_reference_get_path (tree_view->priv->last_button_press_2);
12287       if (gtk_tree_path_is_ancestor (path, lsc))
12288         {
12289           gtk_tree_row_reference_free (tree_view->priv->last_button_press_2);
12290           tree_view->priv->last_button_press_2 = NULL;
12291         }
12292       gtk_tree_path_free (lsc);
12293     }
12294
12295   remove_expand_collapse_timeout (tree_view);
12296
12297   if (gtk_tree_view_unref_and_check_selection_tree (tree_view, node->children))
12298     {
12299       _gtk_rbtree_remove (node->children);
12300       g_signal_emit_by_name (tree_view->priv->selection, "changed");
12301     }
12302   else
12303     _gtk_rbtree_remove (node->children);
12304   
12305   if (animate)
12306     add_expand_collapse_timeout (tree_view, tree, node, FALSE);
12307   
12308   if (GTK_WIDGET_MAPPED (tree_view))
12309     {
12310       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
12311     }
12312
12313   g_signal_emit (tree_view, tree_view_signals[ROW_COLLAPSED], 0, &iter, path);
12314
12315   if (GTK_WIDGET_MAPPED (tree_view))
12316     {
12317       /* now that we've collapsed all rows, we want to try to set the prelight
12318        * again. To do this, we fake a motion event and send it to ourselves. */
12319
12320       child = tree_view->priv->bin_window;
12321       parent = gdk_window_get_parent (child);
12322
12323       if (gdk_window_get_pointer (parent, &x, &y, NULL) == child)
12324         {
12325           GdkEventMotion event;
12326           gint child_x, child_y;
12327
12328           gdk_window_get_position (child, &child_x, &child_y);
12329
12330           event.window = tree_view->priv->bin_window;
12331           event.x = x - child_x;
12332           event.y = y - child_y;
12333
12334           /* despite the fact this isn't a real event, I'm almost positive it will
12335            * never trigger a drag event.  maybe_drag is the only function that uses
12336            * more than just event.x and event.y. */
12337           gtk_tree_view_motion_bin_window (GTK_WIDGET (tree_view), &event);
12338         }
12339     }
12340
12341   return TRUE;
12342 }
12343
12344 /**
12345  * gtk_tree_view_collapse_row:
12346  * @tree_view: a #GtkTreeView
12347  * @path: path to a row in the @tree_view
12348  *
12349  * Collapses a row (hides its child rows, if they exist).
12350  *
12351  * Return value: %TRUE if the row was collapsed.
12352  **/
12353 gboolean
12354 gtk_tree_view_collapse_row (GtkTreeView *tree_view,
12355                             GtkTreePath *path)
12356 {
12357   GtkRBTree *tree;
12358   GtkRBNode *node;
12359
12360   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12361   g_return_val_if_fail (tree_view->priv->tree != NULL, FALSE);
12362   g_return_val_if_fail (path != NULL, FALSE);
12363
12364   if (_gtk_tree_view_find_node (tree_view,
12365                                 path,
12366                                 &tree,
12367                                 &node))
12368     return FALSE;
12369
12370   if (tree == NULL || node->children == NULL)
12371     return FALSE;
12372
12373   return gtk_tree_view_real_collapse_row (tree_view, path, tree, node, FALSE);
12374 }
12375
12376 static void
12377 gtk_tree_view_map_expanded_rows_helper (GtkTreeView            *tree_view,
12378                                         GtkRBTree              *tree,
12379                                         GtkTreePath            *path,
12380                                         GtkTreeViewMappingFunc  func,
12381                                         gpointer                user_data)
12382 {
12383   GtkRBNode *node;
12384
12385   if (tree == NULL || tree->root == NULL)
12386     return;
12387
12388   node = tree->root;
12389
12390   while (node && node->left != tree->nil)
12391     node = node->left;
12392
12393   while (node)
12394     {
12395       if (node->children)
12396         {
12397           (* func) (tree_view, path, user_data);
12398           gtk_tree_path_down (path);
12399           gtk_tree_view_map_expanded_rows_helper (tree_view, node->children, path, func, user_data);
12400           gtk_tree_path_up (path);
12401         }
12402       gtk_tree_path_next (path);
12403       node = _gtk_rbtree_next (tree, node);
12404     }
12405 }
12406
12407 /**
12408  * gtk_tree_view_map_expanded_rows:
12409  * @tree_view: A #GtkTreeView
12410  * @func: A function to be called
12411  * @data: User data to be passed to the function.
12412  *
12413  * Calls @func on all expanded rows.
12414  **/
12415 void
12416 gtk_tree_view_map_expanded_rows (GtkTreeView            *tree_view,
12417                                  GtkTreeViewMappingFunc  func,
12418                                  gpointer                user_data)
12419 {
12420   GtkTreePath *path;
12421
12422   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12423   g_return_if_fail (func != NULL);
12424
12425   path = gtk_tree_path_new_first ();
12426
12427   gtk_tree_view_map_expanded_rows_helper (tree_view,
12428                                           tree_view->priv->tree,
12429                                           path, func, user_data);
12430
12431   gtk_tree_path_free (path);
12432 }
12433
12434 /**
12435  * gtk_tree_view_row_expanded:
12436  * @tree_view: A #GtkTreeView.
12437  * @path: A #GtkTreePath to test expansion state.
12438  *
12439  * Returns %TRUE if the node pointed to by @path is expanded in @tree_view.
12440  *
12441  * Return value: %TRUE if #path is expanded.
12442  **/
12443 gboolean
12444 gtk_tree_view_row_expanded (GtkTreeView *tree_view,
12445                             GtkTreePath *path)
12446 {
12447   GtkRBTree *tree;
12448   GtkRBNode *node;
12449
12450   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12451   g_return_val_if_fail (path != NULL, FALSE);
12452
12453   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
12454
12455   if (node == NULL)
12456     return FALSE;
12457
12458   return (node->children != NULL);
12459 }
12460
12461 /**
12462  * gtk_tree_view_get_reorderable:
12463  * @tree_view: a #GtkTreeView
12464  *
12465  * Retrieves whether the user can reorder the tree via drag-and-drop. See
12466  * gtk_tree_view_set_reorderable().
12467  *
12468  * Return value: %TRUE if the tree can be reordered.
12469  **/
12470 gboolean
12471 gtk_tree_view_get_reorderable (GtkTreeView *tree_view)
12472 {
12473   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12474
12475   return tree_view->priv->reorderable;
12476 }
12477
12478 /**
12479  * gtk_tree_view_set_reorderable:
12480  * @tree_view: A #GtkTreeView.
12481  * @reorderable: %TRUE, if the tree can be reordered.
12482  *
12483  * This function is a convenience function to allow you to reorder
12484  * models that support the #GtkDragSourceIface and the
12485  * #GtkDragDestIface.  Both #GtkTreeStore and #GtkListStore support
12486  * these.  If @reorderable is %TRUE, then the user can reorder the
12487  * model by dragging and dropping rows. The developer can listen to
12488  * these changes by connecting to the model's row_inserted and
12489  * row_deleted signals. The reordering is implemented by setting up
12490  * the tree view as a drag source and destination. Therefore, drag and
12491  * drop can not be used in a reorderable view for any other purpose.
12492  *
12493  * This function does not give you any degree of control over the order -- any
12494  * reordering is allowed.  If more control is needed, you should probably
12495  * handle drag and drop manually.
12496  **/
12497 void
12498 gtk_tree_view_set_reorderable (GtkTreeView *tree_view,
12499                                gboolean     reorderable)
12500 {
12501   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12502
12503   reorderable = reorderable != FALSE;
12504
12505   if (tree_view->priv->reorderable == reorderable)
12506     return;
12507
12508   if (reorderable)
12509     {
12510       const GtkTargetEntry row_targets[] = {
12511         { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, 0 }
12512       };
12513
12514       gtk_tree_view_enable_model_drag_source (tree_view,
12515                                               GDK_BUTTON1_MASK,
12516                                               row_targets,
12517                                               G_N_ELEMENTS (row_targets),
12518                                               GDK_ACTION_MOVE);
12519       gtk_tree_view_enable_model_drag_dest (tree_view,
12520                                             row_targets,
12521                                             G_N_ELEMENTS (row_targets),
12522                                             GDK_ACTION_MOVE);
12523     }
12524   else
12525     {
12526       gtk_tree_view_unset_rows_drag_source (tree_view);
12527       gtk_tree_view_unset_rows_drag_dest (tree_view);
12528     }
12529
12530   tree_view->priv->reorderable = reorderable;
12531
12532   g_object_notify (G_OBJECT (tree_view), "reorderable");
12533 }
12534
12535 static void
12536 gtk_tree_view_real_set_cursor (GtkTreeView     *tree_view,
12537                                GtkTreePath     *path,
12538                                gboolean         clear_and_select,
12539                                gboolean         clamp_node)
12540 {
12541   GtkRBTree *tree = NULL;
12542   GtkRBNode *node = NULL;
12543
12544   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
12545     {
12546       GtkTreePath *cursor_path;
12547       cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
12548       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
12549       gtk_tree_path_free (cursor_path);
12550     }
12551
12552   gtk_tree_row_reference_free (tree_view->priv->cursor);
12553   tree_view->priv->cursor = NULL;
12554
12555   /* One cannot set the cursor on a separator. */
12556   if (!row_is_separator (tree_view, NULL, path))
12557     {
12558       tree_view->priv->cursor =
12559         gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
12560                                           tree_view->priv->model,
12561                                           path);
12562       _gtk_tree_view_find_node (tree_view, path, &tree, &node);
12563     }
12564
12565   if (tree != NULL)
12566     {
12567       GtkRBTree *new_tree = NULL;
12568       GtkRBNode *new_node = NULL;
12569
12570       if (clear_and_select && !tree_view->priv->ctrl_pressed)
12571         {
12572           GtkTreeSelectMode mode = 0;
12573
12574           if (tree_view->priv->ctrl_pressed)
12575             mode |= GTK_TREE_SELECT_MODE_TOGGLE;
12576           if (tree_view->priv->shift_pressed)
12577             mode |= GTK_TREE_SELECT_MODE_EXTEND;
12578
12579           _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
12580                                                     node, tree, path, mode,
12581                                                     FALSE);
12582         }
12583
12584       /* We have to re-find tree and node here again, somebody might have
12585        * cleared the node or the whole tree in the GtkTreeSelection::changed
12586        * callback. If the nodes differ we bail out here.
12587        */
12588       _gtk_tree_view_find_node (tree_view, path, &new_tree, &new_node);
12589
12590       if (tree != new_tree || node != new_node)
12591         return;
12592
12593       if (clamp_node)
12594         {
12595           gtk_tree_view_clamp_node_visible (tree_view, tree, node);
12596           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
12597         }
12598     }
12599
12600   g_signal_emit (tree_view, tree_view_signals[CURSOR_CHANGED], 0);
12601 }
12602
12603 /**
12604  * gtk_tree_view_get_cursor:
12605  * @tree_view: A #GtkTreeView
12606  * @path: A pointer to be filled with the current cursor path, or %NULL
12607  * @focus_column: A pointer to be filled with the current focus column, or %NULL
12608  *
12609  * Fills in @path and @focus_column with the current path and focus column.  If
12610  * the cursor isn't currently set, then *@path will be %NULL.  If no column
12611  * currently has focus, then *@focus_column will be %NULL.
12612  *
12613  * The returned #GtkTreePath must be freed with gtk_tree_path_free() when
12614  * you are done with it.
12615  **/
12616 void
12617 gtk_tree_view_get_cursor (GtkTreeView        *tree_view,
12618                           GtkTreePath       **path,
12619                           GtkTreeViewColumn **focus_column)
12620 {
12621   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12622
12623   if (path)
12624     {
12625       if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
12626         *path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
12627       else
12628         *path = NULL;
12629     }
12630
12631   if (focus_column)
12632     {
12633       *focus_column = tree_view->priv->focus_column;
12634     }
12635 }
12636
12637 /**
12638  * gtk_tree_view_set_cursor:
12639  * @tree_view: A #GtkTreeView
12640  * @path: A #GtkTreePath
12641  * @focus_column: A #GtkTreeViewColumn, or %NULL
12642  * @start_editing: %TRUE if the specified cell should start being edited.
12643  *
12644  * Sets the current keyboard focus to be at @path, and selects it.  This is
12645  * useful when you want to focus the user's attention on a particular row.  If
12646  * @focus_column is not %NULL, then focus is given to the column specified by 
12647  * it. Additionally, if @focus_column is specified, and @start_editing is 
12648  * %TRUE, then editing should be started in the specified cell.  
12649  * This function is often followed by @gtk_widget_grab_focus (@tree_view) 
12650  * in order to give keyboard focus to the widget.  Please note that editing 
12651  * can only happen when the widget is realized.
12652  **/
12653 void
12654 gtk_tree_view_set_cursor (GtkTreeView       *tree_view,
12655                           GtkTreePath       *path,
12656                           GtkTreeViewColumn *focus_column,
12657                           gboolean           start_editing)
12658 {
12659   gtk_tree_view_set_cursor_on_cell (tree_view, path, focus_column,
12660                                     NULL, start_editing);
12661 }
12662
12663 /**
12664  * gtk_tree_view_set_cursor_on_cell:
12665  * @tree_view: A #GtkTreeView
12666  * @path: A #GtkTreePath
12667  * @focus_column: A #GtkTreeViewColumn, or %NULL
12668  * @focus_cell: A #GtkCellRenderer, or %NULL
12669  * @start_editing: %TRUE if the specified cell should start being edited.
12670  *
12671  * Sets the current keyboard focus to be at @path, and selects it.  This is
12672  * useful when you want to focus the user's attention on a particular row.  If
12673  * @focus_column is not %NULL, then focus is given to the column specified by
12674  * it. If @focus_column and @focus_cell are not %NULL, and @focus_column
12675  * contains 2 or more editable or activatable cells, then focus is given to
12676  * the cell specified by @focus_cell. Additionally, if @focus_column is
12677  * specified, and @start_editing is %TRUE, then editing should be started in
12678  * the specified cell.  This function is often followed by
12679  * @gtk_widget_grab_focus (@tree_view) in order to give keyboard focus to the
12680  * widget.  Please note that editing can only happen when the widget is
12681  * realized.
12682  *
12683  * Since: 2.2
12684  **/
12685 void
12686 gtk_tree_view_set_cursor_on_cell (GtkTreeView       *tree_view,
12687                                   GtkTreePath       *path,
12688                                   GtkTreeViewColumn *focus_column,
12689                                   GtkCellRenderer   *focus_cell,
12690                                   gboolean           start_editing)
12691 {
12692   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12693   g_return_if_fail (tree_view->priv->tree != NULL);
12694   g_return_if_fail (path != NULL);
12695   g_return_if_fail (focus_column == NULL || GTK_IS_TREE_VIEW_COLUMN (focus_column));
12696   if (focus_cell)
12697     {
12698       g_return_if_fail (focus_column);
12699       g_return_if_fail (GTK_IS_CELL_RENDERER (focus_cell));
12700     }
12701
12702   /* cancel the current editing, if it exists */
12703   if (tree_view->priv->edited_column &&
12704       tree_view->priv->edited_column->editable_widget)
12705     gtk_tree_view_stop_editing (tree_view, TRUE);
12706
12707   gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
12708
12709   if (focus_column && focus_column->visible)
12710     {
12711       GList *list;
12712       gboolean column_in_tree = FALSE;
12713
12714       for (list = tree_view->priv->columns; list; list = list->next)
12715         if (list->data == focus_column)
12716           {
12717             column_in_tree = TRUE;
12718             break;
12719           }
12720       g_return_if_fail (column_in_tree);
12721       tree_view->priv->focus_column = focus_column;
12722       if (focus_cell)
12723         gtk_tree_view_column_focus_cell (focus_column, focus_cell);
12724       if (start_editing)
12725         gtk_tree_view_start_editing (tree_view, path);
12726     }
12727 }
12728
12729 /**
12730  * gtk_tree_view_get_bin_window:
12731  * @tree_view: A #GtkTreeView
12732  * 
12733  * Returns the window that @tree_view renders to.  This is used primarily to
12734  * compare to <literal>event->window</literal> to confirm that the event on
12735  * @tree_view is on the right window.
12736  * 
12737  * Return value: A #GdkWindow, or %NULL when @tree_view hasn't been realized yet
12738  **/
12739 GdkWindow *
12740 gtk_tree_view_get_bin_window (GtkTreeView *tree_view)
12741 {
12742   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
12743
12744   return tree_view->priv->bin_window;
12745 }
12746
12747 /**
12748  * gtk_tree_view_get_path_at_pos:
12749  * @tree_view: A #GtkTreeView.
12750  * @x: The x position to be identified (relative to bin_window).
12751  * @y: The y position to be identified (relative to bin_window).
12752  * @path: A pointer to a #GtkTreePath pointer to be filled in, or %NULL
12753  * @column: A pointer to a #GtkTreeViewColumn pointer to be filled in, or %NULL
12754  * @cell_x: A pointer where the X coordinate relative to the cell can be placed, or %NULL
12755  * @cell_y: A pointer where the Y coordinate relative to the cell can be placed, or %NULL
12756  *
12757  * Finds the path at the point (@x, @y), relative to bin_window coordinates
12758  * (please see gtk_tree_view_get_bin_window()).
12759  * That is, @x and @y are relative to an events coordinates. @x and @y must
12760  * come from an event on the @tree_view only where <literal>event->window ==
12761  * gtk_tree_view_get_bin_window (<!-- -->)</literal>. It is primarily for
12762  * things like popup menus. If @path is non-%NULL, then it will be filled
12763  * with the #GtkTreePath at that point.  This path should be freed with
12764  * gtk_tree_path_free().  If @column is non-%NULL, then it will be filled
12765  * with the column at that point.  @cell_x and @cell_y return the coordinates
12766  * relative to the cell background (i.e. the @background_area passed to
12767  * gtk_cell_renderer_render()).  This function is only meaningful if
12768  * @tree_view is realized.
12769  *
12770  * For converting widget coordinates (eg. the ones you get from
12771  * GtkWidget::query-tooltip), please see
12772  * gtk_tree_view_convert_widget_to_bin_window_coords().
12773  *
12774  * Return value: %TRUE if a row exists at that coordinate.
12775  **/
12776 gboolean
12777 gtk_tree_view_get_path_at_pos (GtkTreeView        *tree_view,
12778                                gint                x,
12779                                gint                y,
12780                                GtkTreePath       **path,
12781                                GtkTreeViewColumn **column,
12782                                gint               *cell_x,
12783                                gint               *cell_y)
12784 {
12785   GtkRBTree *tree;
12786   GtkRBNode *node;
12787   gint y_offset;
12788
12789   g_return_val_if_fail (tree_view != NULL, FALSE);
12790   g_return_val_if_fail (tree_view->priv->bin_window != NULL, FALSE);
12791
12792   if (path)
12793     *path = NULL;
12794   if (column)
12795     *column = NULL;
12796
12797   if (tree_view->priv->tree == NULL)
12798     return FALSE;
12799
12800   if (x > tree_view->priv->hadjustment->upper)
12801     return FALSE;
12802
12803   if (x < 0 || y < 0)
12804     return FALSE;
12805
12806   if (column || cell_x)
12807     {
12808       GtkTreeViewColumn *tmp_column;
12809       GtkTreeViewColumn *last_column = NULL;
12810       GList *list;
12811       gint remaining_x = x;
12812       gboolean found = FALSE;
12813       gboolean rtl;
12814
12815       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
12816       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
12817            list;
12818            list = (rtl ? list->prev : list->next))
12819         {
12820           tmp_column = list->data;
12821
12822           if (tmp_column->visible == FALSE)
12823             continue;
12824
12825           last_column = tmp_column;
12826           if (remaining_x <= tmp_column->width)
12827             {
12828               found = TRUE;
12829
12830               if (column)
12831                 *column = tmp_column;
12832
12833               if (cell_x)
12834                 *cell_x = remaining_x;
12835
12836               break;
12837             }
12838           remaining_x -= tmp_column->width;
12839         }
12840
12841       /* If found is FALSE and there is a last_column, then it the remainder
12842        * space is in that area
12843        */
12844       if (!found)
12845         {
12846           if (last_column)
12847             {
12848               if (column)
12849                 *column = last_column;
12850               
12851               if (cell_x)
12852                 *cell_x = last_column->width + remaining_x;
12853             }
12854           else
12855             {
12856               return FALSE;
12857             }
12858         }
12859     }
12860
12861   y_offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
12862                                       TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, y),
12863                                       &tree, &node);
12864
12865   if (tree == NULL)
12866     return FALSE;
12867
12868   if (cell_y)
12869     *cell_y = y_offset;
12870
12871   if (path)
12872     *path = _gtk_tree_view_find_path (tree_view, tree, node);
12873
12874   return TRUE;
12875 }
12876
12877
12878 /**
12879  * gtk_tree_view_get_cell_area:
12880  * @tree_view: a #GtkTreeView
12881  * @path: a #GtkTreePath for the row, or %NULL to get only horizontal coordinates
12882  * @column: a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordinates
12883  * @rect: rectangle to fill with cell rect
12884  *
12885  * Fills the bounding rectangle in bin_window coordinates for the cell at the
12886  * row specified by @path and the column specified by @column.  If @path is
12887  * %NULL, or points to a path not currently displayed, the @y and @height fields
12888  * of the rectangle will be filled with 0. If @column is %NULL, the @x and @width
12889  * fields will be filled with 0.  The sum of all cell rects does not cover the
12890  * entire tree; there are extra pixels in between rows, for example. The
12891  * returned rectangle is equivalent to the @cell_area passed to
12892  * gtk_cell_renderer_render().  This function is only valid if @tree_view is
12893  * realized.
12894  **/
12895 void
12896 gtk_tree_view_get_cell_area (GtkTreeView        *tree_view,
12897                              GtkTreePath        *path,
12898                              GtkTreeViewColumn  *column,
12899                              GdkRectangle       *rect)
12900 {
12901   GtkRBTree *tree = NULL;
12902   GtkRBNode *node = NULL;
12903   gint vertical_separator;
12904   gint horizontal_separator;
12905
12906   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12907   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
12908   g_return_if_fail (rect != NULL);
12909   g_return_if_fail (!column || column->tree_view == (GtkWidget *) tree_view);
12910   g_return_if_fail (GTK_WIDGET_REALIZED (tree_view));
12911
12912   gtk_widget_style_get (GTK_WIDGET (tree_view),
12913                         "vertical-separator", &vertical_separator,
12914                         "horizontal-separator", &horizontal_separator,
12915                         NULL);
12916
12917   rect->x = 0;
12918   rect->y = 0;
12919   rect->width = 0;
12920   rect->height = 0;
12921
12922   if (column)
12923     {
12924       rect->x = column->button->allocation.x + horizontal_separator/2;
12925       rect->width = column->button->allocation.width - horizontal_separator;
12926     }
12927
12928   if (path)
12929     {
12930       gboolean ret = _gtk_tree_view_find_node (tree_view, path, &tree, &node);
12931
12932       /* Get vertical coords */
12933       if ((!ret && tree == NULL) || ret)
12934         return;
12935
12936       rect->y = CELL_FIRST_PIXEL (tree_view, tree, node, vertical_separator);
12937       rect->height = MAX (CELL_HEIGHT (node, vertical_separator), tree_view->priv->expander_size - vertical_separator);
12938
12939       if (column &&
12940           gtk_tree_view_is_expander_column (tree_view, column))
12941         {
12942           gint depth = gtk_tree_path_get_depth (path);
12943           gboolean rtl;
12944
12945           rtl = gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL;
12946
12947           if (!rtl)
12948             rect->x += (depth - 1) * tree_view->priv->level_indentation;
12949           rect->width -= (depth - 1) * tree_view->priv->level_indentation;
12950
12951           if (TREE_VIEW_DRAW_EXPANDERS (tree_view))
12952             {
12953               if (!rtl)
12954                 rect->x += depth * tree_view->priv->expander_size;
12955               rect->width -= depth * tree_view->priv->expander_size;
12956             }
12957
12958           rect->width = MAX (rect->width, 0);
12959         }
12960     }
12961 }
12962
12963 /**
12964  * gtk_tree_view_get_background_area:
12965  * @tree_view: a #GtkTreeView
12966  * @path: a #GtkTreePath for the row, or %NULL to get only horizontal coordinates
12967  * @column: a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordiantes
12968  * @rect: rectangle to fill with cell background rect
12969  *
12970  * Fills the bounding rectangle in bin_window coordinates for the cell at the
12971  * row specified by @path and the column specified by @column.  If @path is
12972  * %NULL, or points to a node not found in the tree, the @y and @height fields of
12973  * the rectangle will be filled with 0. If @column is %NULL, the @x and @width
12974  * fields will be filled with 0.  The returned rectangle is equivalent to the
12975  * @background_area passed to gtk_cell_renderer_render().  These background
12976  * areas tile to cover the entire bin window.  Contrast with the @cell_area,
12977  * returned by gtk_tree_view_get_cell_area(), which returns only the cell
12978  * itself, excluding surrounding borders and the tree expander area.
12979  *
12980  **/
12981 void
12982 gtk_tree_view_get_background_area (GtkTreeView        *tree_view,
12983                                    GtkTreePath        *path,
12984                                    GtkTreeViewColumn  *column,
12985                                    GdkRectangle       *rect)
12986 {
12987   GtkRBTree *tree = NULL;
12988   GtkRBNode *node = NULL;
12989
12990   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12991   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
12992   g_return_if_fail (rect != NULL);
12993
12994   rect->x = 0;
12995   rect->y = 0;
12996   rect->width = 0;
12997   rect->height = 0;
12998
12999   if (path)
13000     {
13001       /* Get vertical coords */
13002
13003       if (!_gtk_tree_view_find_node (tree_view, path, &tree, &node) &&
13004           tree == NULL)
13005         return;
13006
13007       rect->y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
13008
13009       rect->height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
13010     }
13011
13012   if (column)
13013     {
13014       gint x2 = 0;
13015
13016       gtk_tree_view_get_background_xrange (tree_view, tree, column, &rect->x, &x2);
13017       rect->width = x2 - rect->x;
13018     }
13019 }
13020
13021 /**
13022  * gtk_tree_view_get_visible_rect:
13023  * @tree_view: a #GtkTreeView
13024  * @visible_rect: rectangle to fill
13025  *
13026  * Fills @visible_rect with the currently-visible region of the
13027  * buffer, in tree coordinates. Convert to bin_window coordinates with
13028  * gtk_tree_view_convert_tree_to_bin_window_coords().
13029  * Tree coordinates start at 0,0 for row 0 of the tree, and cover the entire
13030  * scrollable area of the tree.
13031  **/
13032 void
13033 gtk_tree_view_get_visible_rect (GtkTreeView  *tree_view,
13034                                 GdkRectangle *visible_rect)
13035 {
13036   GtkWidget *widget;
13037
13038   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13039
13040   widget = GTK_WIDGET (tree_view);
13041
13042   if (visible_rect)
13043     {
13044       visible_rect->x = tree_view->priv->hadjustment->value;
13045       visible_rect->y = tree_view->priv->vadjustment->value;
13046       visible_rect->width = widget->allocation.width;
13047       visible_rect->height = widget->allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view);
13048     }
13049 }
13050
13051 /**
13052  * gtk_tree_view_widget_to_tree_coords:
13053  * @tree_view: a #GtkTreeView
13054  * @wx: X coordinate relative to bin_window
13055  * @wy: Y coordinate relative to bin_window
13056  * @tx: return location for tree X coordinate
13057  * @ty: return location for tree Y coordinate
13058  *
13059  * Converts bin_window coordinates to coordinates for the
13060  * tree (the full scrollable area of the tree).
13061  *
13062  * Deprecated: 2.12: Due to historial reasons the name of this function is
13063  * incorrect.  For converting coordinates relative to the widget to
13064  * bin_window coordinates, please see
13065  * gtk_tree_view_convert_widget_to_bin_window_coords().
13066  *
13067  **/
13068 void
13069 gtk_tree_view_widget_to_tree_coords (GtkTreeView *tree_view,
13070                                       gint         wx,
13071                                       gint         wy,
13072                                       gint        *tx,
13073                                       gint        *ty)
13074 {
13075   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13076
13077   if (tx)
13078     *tx = wx + tree_view->priv->hadjustment->value;
13079   if (ty)
13080     *ty = wy + tree_view->priv->dy;
13081 }
13082
13083 /**
13084  * gtk_tree_view_tree_to_widget_coords:
13085  * @tree_view: a #GtkTreeView
13086  * @tx: tree X coordinate
13087  * @ty: tree Y coordinate
13088  * @wx: return location for X coordinate relative to bin_window
13089  * @wy: return location for Y coordinate relative to bin_window
13090  *
13091  * Converts tree coordinates (coordinates in full scrollable area of the tree)
13092  * to bin_window coordinates.
13093  *
13094  * Deprecated: 2.12: Due to historial reasons the name of this function is
13095  * incorrect.  For converting bin_window coordinates to coordinates relative
13096  * to bin_window, please see
13097  * gtk_tree_view_convert_bin_window_to_widget_coords().
13098  *
13099  **/
13100 void
13101 gtk_tree_view_tree_to_widget_coords (GtkTreeView *tree_view,
13102                                      gint         tx,
13103                                      gint         ty,
13104                                      gint        *wx,
13105                                      gint        *wy)
13106 {
13107   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13108
13109   if (wx)
13110     *wx = tx - tree_view->priv->hadjustment->value;
13111   if (wy)
13112     *wy = ty - tree_view->priv->dy;
13113 }
13114
13115
13116 /**
13117  * gtk_tree_view_convert_widget_to_tree_coords:
13118  * @tree_view: a #GtkTreeView
13119  * @wx: X coordinate relative to the widget
13120  * @wy: Y coordinate relative to the widget
13121  * @tx: return location for tree X coordinate
13122  * @ty: return location for tree Y coordinate
13123  *
13124  * Converts widget coordinates to coordinates for the
13125  * tree (the full scrollable area of the tree).
13126  *
13127  * Since: 2.12
13128  **/
13129 void
13130 gtk_tree_view_convert_widget_to_tree_coords (GtkTreeView *tree_view,
13131                                              gint         wx,
13132                                              gint         wy,
13133                                              gint        *tx,
13134                                              gint        *ty)
13135 {
13136   gint x, y;
13137
13138   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13139
13140   gtk_tree_view_convert_widget_to_bin_window_coords (tree_view,
13141                                                      wx, wy,
13142                                                      &x, &y);
13143   gtk_tree_view_convert_bin_window_to_tree_coords (tree_view,
13144                                                    x, y,
13145                                                    tx, ty);
13146 }
13147
13148 /**
13149  * gtk_tree_view_convert_tree_to_widget_coords:
13150  * @tree_view: a #GtkTreeView
13151  * @tx: X coordinate relative to the tree
13152  * @ty: Y coordinate relative to the tree
13153  * @wx: return location for widget X coordinate
13154  * @wy: return location for widget Y coordinate
13155  *
13156  * Converts tree coordinates (coordinates in full scrollable area of the tree)
13157  * to widget coordinates.
13158  *
13159  * Since: 2.12
13160  **/
13161 void
13162 gtk_tree_view_convert_tree_to_widget_coords (GtkTreeView *tree_view,
13163                                              gint         tx,
13164                                              gint         ty,
13165                                              gint        *wx,
13166                                              gint        *wy)
13167 {
13168   gint x, y;
13169
13170   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13171
13172   gtk_tree_view_convert_tree_to_bin_window_coords (tree_view,
13173                                                    tx, ty,
13174                                                    &x, &y);
13175   gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
13176                                                      x, y,
13177                                                      wx, wy);
13178 }
13179
13180 /**
13181  * gtk_tree_view_convert_widget_to_bin_window_coords:
13182  * @tree_view: a #GtkTreeView
13183  * @wx: X coordinate relative to the widget
13184  * @wy: Y coordinate relative to the widget
13185  * @bx: return location for bin_window X coordinate
13186  * @by: return location for bin_window Y coordinate
13187  *
13188  * Converts widget coordinates to coordinates for the bin_window
13189  * (see gtk_tree_view_get_bin_window()).
13190  *
13191  * Since: 2.12
13192  **/
13193 void
13194 gtk_tree_view_convert_widget_to_bin_window_coords (GtkTreeView *tree_view,
13195                                                    gint         wx,
13196                                                    gint         wy,
13197                                                    gint        *bx,
13198                                                    gint        *by)
13199 {
13200   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13201
13202   if (bx)
13203     *bx = wx + tree_view->priv->hadjustment->value;
13204   if (by)
13205     *by = wy - TREE_VIEW_HEADER_HEIGHT (tree_view);
13206 }
13207
13208 /**
13209  * gtk_tree_view_convert_bin_window_to_widget_coords:
13210  * @tree_view: a #GtkTreeView
13211  * @bx: bin_window X coordinate
13212  * @by: bin_window Y coordinate
13213  * @wx: return location for widget X coordinate
13214  * @wy: return location for widget Y coordinate
13215  *
13216  * Converts bin_window coordinates (see gtk_tree_view_get_bin_window())
13217  * to widget relative coordinates.
13218  *
13219  * Since: 2.12
13220  **/
13221 void
13222 gtk_tree_view_convert_bin_window_to_widget_coords (GtkTreeView *tree_view,
13223                                                    gint         bx,
13224                                                    gint         by,
13225                                                    gint        *wx,
13226                                                    gint        *wy)
13227 {
13228   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13229
13230   if (wx)
13231     *wx = bx - tree_view->priv->hadjustment->value;
13232   if (wy)
13233     *wy = by + TREE_VIEW_HEADER_HEIGHT (tree_view);
13234 }
13235
13236 /**
13237  * gtk_tree_view_convert_tree_to_bin_window_coords:
13238  * @tree_view: a #GtkTreeView
13239  * @tx: tree X coordinate
13240  * @ty: tree Y coordinate
13241  * @bx: return location for X coordinate relative to bin_window
13242  * @by: return location for Y coordinate relative to bin_window
13243  *
13244  * Converts tree coordinates (coordinates in full scrollable area of the tree)
13245  * to bin_window coordinates.
13246  *
13247  * Since: 2.12
13248  **/
13249 void
13250 gtk_tree_view_convert_tree_to_bin_window_coords (GtkTreeView *tree_view,
13251                                                  gint         tx,
13252                                                  gint         ty,
13253                                                  gint        *bx,
13254                                                  gint        *by)
13255 {
13256   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13257
13258   if (bx)
13259     *bx = tx;
13260   if (by)
13261     *by = ty - tree_view->priv->dy;
13262 }
13263
13264 /**
13265  * gtk_tree_view_convert_bin_window_to_tree_coords:
13266  * @tree_view: a #GtkTreeView
13267  * @bx: X coordinate relative to bin_window
13268  * @by: Y coordinate relative to bin_window
13269  * @tx: return location for tree X coordinate
13270  * @ty: return location for tree Y coordinate
13271  *
13272  * Converts bin_window coordinates to coordinates for the
13273  * tree (the full scrollable area of the tree).
13274  *
13275  * Since: 2.12
13276  **/
13277 void
13278 gtk_tree_view_convert_bin_window_to_tree_coords (GtkTreeView *tree_view,
13279                                                  gint         bx,
13280                                                  gint         by,
13281                                                  gint        *tx,
13282                                                  gint        *ty)
13283 {
13284   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13285
13286   if (tx)
13287     *tx = bx;
13288   if (ty)
13289     *ty = by + tree_view->priv->dy;
13290 }
13291
13292
13293
13294 /**
13295  * gtk_tree_view_get_visible_range:
13296  * @tree_view: A #GtkTreeView
13297  * @start_path: Return location for start of region, or %NULL.
13298  * @end_path: Return location for end of region, or %NULL.
13299  *
13300  * Sets @start_path and @end_path to be the first and last visible path.
13301  * Note that there may be invisible paths in between.
13302  *
13303  * The paths should be freed with gtk_tree_path_free() after use.
13304  *
13305  * Returns: %TRUE, if valid paths were placed in @start_path and @end_path.
13306  *
13307  * Since: 2.8
13308  **/
13309 gboolean
13310 gtk_tree_view_get_visible_range (GtkTreeView  *tree_view,
13311                                  GtkTreePath **start_path,
13312                                  GtkTreePath **end_path)
13313 {
13314   GtkRBTree *tree;
13315   GtkRBNode *node;
13316   gboolean retval;
13317   
13318   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
13319
13320   if (!tree_view->priv->tree)
13321     return FALSE;
13322
13323   retval = TRUE;
13324
13325   if (start_path)
13326     {
13327       _gtk_rbtree_find_offset (tree_view->priv->tree,
13328                                TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, 0),
13329                                &tree, &node);
13330       if (node)
13331         *start_path = _gtk_tree_view_find_path (tree_view, tree, node);
13332       else
13333         retval = FALSE;
13334     }
13335
13336   if (end_path)
13337     {
13338       gint y;
13339
13340       if (tree_view->priv->height < tree_view->priv->vadjustment->page_size)
13341         y = tree_view->priv->height - 1;
13342       else
13343         y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, tree_view->priv->vadjustment->page_size) - 1;
13344
13345       _gtk_rbtree_find_offset (tree_view->priv->tree, y, &tree, &node);
13346       if (node)
13347         *end_path = _gtk_tree_view_find_path (tree_view, tree, node);
13348       else
13349         retval = FALSE;
13350     }
13351
13352   return retval;
13353 }
13354
13355 static void
13356 unset_reorderable (GtkTreeView *tree_view)
13357 {
13358   if (tree_view->priv->reorderable)
13359     {
13360       tree_view->priv->reorderable = FALSE;
13361       g_object_notify (G_OBJECT (tree_view), "reorderable");
13362     }
13363 }
13364
13365 /**
13366  * gtk_tree_view_enable_model_drag_source:
13367  * @tree_view: a #GtkTreeView
13368  * @start_button_mask: Mask of allowed buttons to start drag
13369  * @targets: the table of targets that the drag will support
13370  * @n_targets: the number of items in @targets
13371  * @actions: the bitmask of possible actions for a drag from this
13372  *    widget
13373  *
13374  * Turns @tree_view into a drag source for automatic DND. Calling this
13375  * method sets #GtkTreeView:reorderable to %FALSE.
13376  **/
13377 void
13378 gtk_tree_view_enable_model_drag_source (GtkTreeView              *tree_view,
13379                                         GdkModifierType           start_button_mask,
13380                                         const GtkTargetEntry     *targets,
13381                                         gint                      n_targets,
13382                                         GdkDragAction             actions)
13383 {
13384   TreeViewDragInfo *di;
13385
13386   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13387
13388   gtk_drag_source_set (GTK_WIDGET (tree_view),
13389                        0,
13390                        targets,
13391                        n_targets,
13392                        actions);
13393
13394   di = ensure_info (tree_view);
13395
13396   di->start_button_mask = start_button_mask;
13397   di->source_actions = actions;
13398   di->source_set = TRUE;
13399
13400   unset_reorderable (tree_view);
13401 }
13402
13403 /**
13404  * gtk_tree_view_enable_model_drag_dest:
13405  * @tree_view: a #GtkTreeView
13406  * @targets: the table of targets that the drag will support
13407  * @n_targets: the number of items in @targets
13408  * @actions: the bitmask of possible actions for a drag from this
13409  *    widget
13410  * 
13411  * Turns @tree_view into a drop destination for automatic DND. Calling
13412  * this method sets #GtkTreeView:reorderable to %FALSE.
13413  **/
13414 void
13415 gtk_tree_view_enable_model_drag_dest (GtkTreeView              *tree_view,
13416                                       const GtkTargetEntry     *targets,
13417                                       gint                      n_targets,
13418                                       GdkDragAction             actions)
13419 {
13420   TreeViewDragInfo *di;
13421
13422   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13423
13424   gtk_drag_dest_set (GTK_WIDGET (tree_view),
13425                      0,
13426                      targets,
13427                      n_targets,
13428                      actions);
13429
13430   di = ensure_info (tree_view);
13431   di->dest_set = TRUE;
13432
13433   unset_reorderable (tree_view);
13434 }
13435
13436 /**
13437  * gtk_tree_view_unset_rows_drag_source:
13438  * @tree_view: a #GtkTreeView
13439  *
13440  * Undoes the effect of
13441  * gtk_tree_view_enable_model_drag_source(). Calling this method sets
13442  * #GtkTreeView:reorderable to %FALSE.
13443  **/
13444 void
13445 gtk_tree_view_unset_rows_drag_source (GtkTreeView *tree_view)
13446 {
13447   TreeViewDragInfo *di;
13448
13449   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13450
13451   di = get_info (tree_view);
13452
13453   if (di)
13454     {
13455       if (di->source_set)
13456         {
13457           gtk_drag_source_unset (GTK_WIDGET (tree_view));
13458           di->source_set = FALSE;
13459         }
13460
13461       if (!di->dest_set && !di->source_set)
13462         remove_info (tree_view);
13463     }
13464   
13465   unset_reorderable (tree_view);
13466 }
13467
13468 /**
13469  * gtk_tree_view_unset_rows_drag_dest:
13470  * @tree_view: a #GtkTreeView
13471  *
13472  * Undoes the effect of
13473  * gtk_tree_view_enable_model_drag_dest(). Calling this method sets
13474  * #GtkTreeView:reorderable to %FALSE.
13475  **/
13476 void
13477 gtk_tree_view_unset_rows_drag_dest (GtkTreeView *tree_view)
13478 {
13479   TreeViewDragInfo *di;
13480
13481   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13482
13483   di = get_info (tree_view);
13484
13485   if (di)
13486     {
13487       if (di->dest_set)
13488         {
13489           gtk_drag_dest_unset (GTK_WIDGET (tree_view));
13490           di->dest_set = FALSE;
13491         }
13492
13493       if (!di->dest_set && !di->source_set)
13494         remove_info (tree_view);
13495     }
13496
13497   unset_reorderable (tree_view);
13498 }
13499
13500 /**
13501  * gtk_tree_view_set_drag_dest_row:
13502  * @tree_view: a #GtkTreeView
13503  * @path: The path of the row to highlight, or %NULL.
13504  * @pos: Specifies whether to drop before, after or into the row
13505  * 
13506  * Sets the row that is highlighted for feedback.
13507  **/
13508 void
13509 gtk_tree_view_set_drag_dest_row (GtkTreeView            *tree_view,
13510                                  GtkTreePath            *path,
13511                                  GtkTreeViewDropPosition pos)
13512 {
13513   GtkTreePath *current_dest;
13514
13515   /* Note; this function is exported to allow a custom DND
13516    * implementation, so it can't touch TreeViewDragInfo
13517    */
13518
13519   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13520
13521   current_dest = NULL;
13522
13523   if (tree_view->priv->drag_dest_row)
13524     {
13525       current_dest = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
13526       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
13527     }
13528
13529   /* special case a drop on an empty model */
13530   tree_view->priv->empty_view_drop = 0;
13531
13532   if (pos == GTK_TREE_VIEW_DROP_BEFORE && path
13533       && gtk_tree_path_get_depth (path) == 1
13534       && gtk_tree_path_get_indices (path)[0] == 0)
13535     {
13536       gint n_children;
13537
13538       n_children = gtk_tree_model_iter_n_children (tree_view->priv->model,
13539                                                    NULL);
13540
13541       if (!n_children)
13542         tree_view->priv->empty_view_drop = 1;
13543     }
13544
13545   tree_view->priv->drag_dest_pos = pos;
13546
13547   if (path)
13548     {
13549       tree_view->priv->drag_dest_row =
13550         gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
13551       gtk_tree_view_queue_draw_path (tree_view, path, NULL);
13552     }
13553   else
13554     tree_view->priv->drag_dest_row = NULL;
13555
13556   if (current_dest)
13557     {
13558       GtkRBTree *tree, *new_tree;
13559       GtkRBNode *node, *new_node;
13560
13561       _gtk_tree_view_find_node (tree_view, current_dest, &tree, &node);
13562       _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
13563
13564       if (tree && node)
13565         {
13566           _gtk_rbtree_next_full (tree, node, &new_tree, &new_node);
13567           if (new_tree && new_node)
13568             _gtk_tree_view_queue_draw_node (tree_view, new_tree, new_node, NULL);
13569
13570           _gtk_rbtree_prev_full (tree, node, &new_tree, &new_node);
13571           if (new_tree && new_node)
13572             _gtk_tree_view_queue_draw_node (tree_view, new_tree, new_node, NULL);
13573         }
13574       gtk_tree_path_free (current_dest);
13575     }
13576 }
13577
13578 /**
13579  * gtk_tree_view_get_drag_dest_row:
13580  * @tree_view: a #GtkTreeView
13581  * @path: Return location for the path of the highlighted row, or %NULL.
13582  * @pos: Return location for the drop position, or %NULL
13583  * 
13584  * Gets information about the row that is highlighted for feedback.
13585  **/
13586 void
13587 gtk_tree_view_get_drag_dest_row (GtkTreeView              *tree_view,
13588                                  GtkTreePath             **path,
13589                                  GtkTreeViewDropPosition  *pos)
13590 {
13591   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13592
13593   if (path)
13594     {
13595       if (tree_view->priv->drag_dest_row)
13596         *path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
13597       else
13598         {
13599           if (tree_view->priv->empty_view_drop)
13600             *path = gtk_tree_path_new_from_indices (0, -1);
13601           else
13602             *path = NULL;
13603         }
13604     }
13605
13606   if (pos)
13607     *pos = tree_view->priv->drag_dest_pos;
13608 }
13609
13610 /**
13611  * gtk_tree_view_get_dest_row_at_pos:
13612  * @tree_view: a #GtkTreeView
13613  * @drag_x: the position to determine the destination row for
13614  * @drag_y: the position to determine the destination row for
13615  * @path: Return location for the path of the highlighted row, or %NULL.
13616  * @pos: Return location for the drop position, or %NULL
13617  * 
13618  * Determines the destination row for a given position.  @drag_x and
13619  * @drag_y are expected to be in widget coordinates.
13620  * 
13621  * Return value: whether there is a row at the given position.
13622  **/
13623 gboolean
13624 gtk_tree_view_get_dest_row_at_pos (GtkTreeView             *tree_view,
13625                                    gint                     drag_x,
13626                                    gint                     drag_y,
13627                                    GtkTreePath            **path,
13628                                    GtkTreeViewDropPosition *pos)
13629 {
13630   gint cell_y;
13631   gint bin_x, bin_y;
13632   gdouble offset_into_row;
13633   gdouble third;
13634   GdkRectangle cell;
13635   GtkTreeViewColumn *column = NULL;
13636   GtkTreePath *tmp_path = NULL;
13637
13638   /* Note; this function is exported to allow a custom DND
13639    * implementation, so it can't touch TreeViewDragInfo
13640    */
13641
13642   g_return_val_if_fail (tree_view != NULL, FALSE);
13643   g_return_val_if_fail (drag_x >= 0, FALSE);
13644   g_return_val_if_fail (drag_y >= 0, FALSE);
13645   g_return_val_if_fail (tree_view->priv->bin_window != NULL, FALSE);
13646
13647
13648   if (path)
13649     *path = NULL;
13650
13651   if (tree_view->priv->tree == NULL)
13652     return FALSE;
13653
13654   /* If in the top third of a row, we drop before that row; if
13655    * in the bottom third, drop after that row; if in the middle,
13656    * and the row has children, drop into the row.
13657    */
13658   gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, drag_x, drag_y,
13659                                                      &bin_x, &bin_y);
13660
13661   if (!gtk_tree_view_get_path_at_pos (tree_view,
13662                                       bin_x,
13663                                       bin_y,
13664                                       &tmp_path,
13665                                       &column,
13666                                       NULL,
13667                                       &cell_y))
13668     return FALSE;
13669
13670   gtk_tree_view_get_background_area (tree_view, tmp_path, column,
13671                                      &cell);
13672
13673   offset_into_row = cell_y;
13674
13675   if (path)
13676     *path = tmp_path;
13677   else
13678     gtk_tree_path_free (tmp_path);
13679
13680   tmp_path = NULL;
13681
13682   third = cell.height / 3.0;
13683
13684   if (pos)
13685     {
13686       if (offset_into_row < third)
13687         {
13688           *pos = GTK_TREE_VIEW_DROP_BEFORE;
13689         }
13690       else if (offset_into_row < (cell.height / 2.0))
13691         {
13692           *pos = GTK_TREE_VIEW_DROP_INTO_OR_BEFORE;
13693         }
13694       else if (offset_into_row < third * 2.0)
13695         {
13696           *pos = GTK_TREE_VIEW_DROP_INTO_OR_AFTER;
13697         }
13698       else
13699         {
13700           *pos = GTK_TREE_VIEW_DROP_AFTER;
13701         }
13702     }
13703
13704   return TRUE;
13705 }
13706
13707
13708
13709 /* KEEP IN SYNC WITH GTK_TREE_VIEW_BIN_EXPOSE */
13710 /**
13711  * gtk_tree_view_create_row_drag_icon:
13712  * @tree_view: a #GtkTreeView
13713  * @path: a #GtkTreePath in @tree_view
13714  *
13715  * Creates a #GdkPixmap representation of the row at @path.  
13716  * This image is used for a drag icon.
13717  *
13718  * Return value: a newly-allocated pixmap of the drag icon.
13719  **/
13720 GdkPixmap *
13721 gtk_tree_view_create_row_drag_icon (GtkTreeView  *tree_view,
13722                                     GtkTreePath  *path)
13723 {
13724   GtkTreeIter   iter;
13725   GtkRBTree    *tree;
13726   GtkRBNode    *node;
13727   gint cell_offset;
13728   GList *list;
13729   GdkRectangle background_area;
13730   GdkRectangle expose_area;
13731   GtkWidget *widget;
13732   gint depth;
13733   /* start drawing inside the black outline */
13734   gint x = 1, y = 1;
13735   GdkDrawable *drawable;
13736   gint bin_window_width;
13737   gboolean is_separator = FALSE;
13738   gboolean rtl;
13739
13740   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
13741   g_return_val_if_fail (path != NULL, NULL);
13742
13743   widget = GTK_WIDGET (tree_view);
13744
13745   if (!GTK_WIDGET_REALIZED (tree_view))
13746     return NULL;
13747
13748   depth = gtk_tree_path_get_depth (path);
13749
13750   _gtk_tree_view_find_node (tree_view,
13751                             path,
13752                             &tree,
13753                             &node);
13754
13755   if (tree == NULL)
13756     return NULL;
13757
13758   if (!gtk_tree_model_get_iter (tree_view->priv->model,
13759                                 &iter,
13760                                 path))
13761     return NULL;
13762   
13763   is_separator = row_is_separator (tree_view, &iter, NULL);
13764
13765   cell_offset = x;
13766
13767   background_area.y = y;
13768   background_area.height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
13769
13770   gdk_drawable_get_size (tree_view->priv->bin_window,
13771                          &bin_window_width, NULL);
13772
13773   drawable = gdk_pixmap_new (tree_view->priv->bin_window,
13774                              bin_window_width + 2,
13775                              background_area.height + 2,
13776                              -1);
13777
13778   expose_area.x = 0;
13779   expose_area.y = 0;
13780   expose_area.width = bin_window_width + 2;
13781   expose_area.height = background_area.height + 2;
13782
13783   gdk_draw_rectangle (drawable,
13784                       widget->style->base_gc [GTK_WIDGET_STATE (widget)],
13785                       TRUE,
13786                       0, 0,
13787                       bin_window_width + 2,
13788                       background_area.height + 2);
13789
13790   rtl = gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL;
13791
13792   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
13793       list;
13794       list = (rtl ? list->prev : list->next))
13795     {
13796       GtkTreeViewColumn *column = list->data;
13797       GdkRectangle cell_area;
13798       gint vertical_separator;
13799
13800       if (!column->visible)
13801         continue;
13802
13803       gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, &iter,
13804                                                GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
13805                                                node->children?TRUE:FALSE);
13806
13807       background_area.x = cell_offset;
13808       background_area.width = column->width;
13809
13810       gtk_widget_style_get (widget,
13811                             "vertical-separator", &vertical_separator,
13812                             NULL);
13813
13814       cell_area = background_area;
13815
13816       cell_area.y += vertical_separator / 2;
13817       cell_area.height -= vertical_separator;
13818
13819       if (gtk_tree_view_is_expander_column (tree_view, column))
13820         {
13821           if (!rtl)
13822             cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
13823           cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
13824
13825           if (TREE_VIEW_DRAW_EXPANDERS(tree_view))
13826             {
13827               if (!rtl)
13828                 cell_area.x += depth * tree_view->priv->expander_size;
13829               cell_area.width -= depth * tree_view->priv->expander_size;
13830             }
13831         }
13832
13833       if (gtk_tree_view_column_cell_is_visible (column))
13834         {
13835           if (is_separator)
13836             gtk_paint_hline (widget->style,
13837                              drawable,
13838                              GTK_STATE_NORMAL,
13839                              &cell_area,
13840                              widget,
13841                              NULL,
13842                              cell_area.x,
13843                              cell_area.x + cell_area.width,
13844                              cell_area.y + cell_area.height / 2);
13845           else
13846             _gtk_tree_view_column_cell_render (column,
13847                                                drawable,
13848                                                &background_area,
13849                                                &cell_area,
13850                                                &expose_area,
13851                                                0);
13852         }
13853       cell_offset += column->width;
13854     }
13855
13856   gdk_draw_rectangle (drawable,
13857                       widget->style->black_gc,
13858                       FALSE,
13859                       0, 0,
13860                       bin_window_width + 1,
13861                       background_area.height + 1);
13862
13863   return drawable;
13864 }
13865
13866
13867 /**
13868  * gtk_tree_view_set_destroy_count_func:
13869  * @tree_view: A #GtkTreeView
13870  * @func: Function to be called when a view row is destroyed, or %NULL
13871  * @data: User data to be passed to @func, or %NULL
13872  * @destroy: Destroy notifier for @data, or %NULL
13873  *
13874  * This function should almost never be used.  It is meant for private use by
13875  * ATK for determining the number of visible children that are removed when the
13876  * user collapses a row, or a row is deleted.
13877  **/
13878 void
13879 gtk_tree_view_set_destroy_count_func (GtkTreeView             *tree_view,
13880                                       GtkTreeDestroyCountFunc  func,
13881                                       gpointer                 data,
13882                                       GDestroyNotify           destroy)
13883 {
13884   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13885
13886   if (tree_view->priv->destroy_count_destroy)
13887     tree_view->priv->destroy_count_destroy (tree_view->priv->destroy_count_data);
13888
13889   tree_view->priv->destroy_count_func = func;
13890   tree_view->priv->destroy_count_data = data;
13891   tree_view->priv->destroy_count_destroy = destroy;
13892 }
13893
13894
13895 /*
13896  * Interactive search
13897  */
13898
13899 /**
13900  * gtk_tree_view_set_enable_search:
13901  * @tree_view: A #GtkTreeView
13902  * @enable_search: %TRUE, if the user can search interactively
13903  *
13904  * If @enable_search is set, then the user can type in text to search through
13905  * the tree interactively (this is sometimes called "typeahead find").
13906  * 
13907  * Note that even if this is %FALSE, the user can still initiate a search 
13908  * using the "start-interactive-search" key binding.
13909  */
13910 void
13911 gtk_tree_view_set_enable_search (GtkTreeView *tree_view,
13912                                  gboolean     enable_search)
13913 {
13914   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13915
13916   enable_search = !!enable_search;
13917   
13918   if (tree_view->priv->enable_search != enable_search)
13919     {
13920        tree_view->priv->enable_search = enable_search;
13921        g_object_notify (G_OBJECT (tree_view), "enable-search");
13922     }
13923 }
13924
13925 /**
13926  * gtk_tree_view_get_enable_search:
13927  * @tree_view: A #GtkTreeView
13928  *
13929  * Returns whether or not the tree allows to start interactive searching 
13930  * by typing in text.
13931  *
13932  * Return value: whether or not to let the user search interactively
13933  */
13934 gboolean
13935 gtk_tree_view_get_enable_search (GtkTreeView *tree_view)
13936 {
13937   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
13938
13939   return tree_view->priv->enable_search;
13940 }
13941
13942
13943 /**
13944  * gtk_tree_view_get_search_column:
13945  * @tree_view: A #GtkTreeView
13946  *
13947  * Gets the column searched on by the interactive search code.
13948  *
13949  * Return value: the column the interactive search code searches in.
13950  */
13951 gint
13952 gtk_tree_view_get_search_column (GtkTreeView *tree_view)
13953 {
13954   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
13955
13956   return (tree_view->priv->search_column);
13957 }
13958
13959 /**
13960  * gtk_tree_view_set_search_column:
13961  * @tree_view: A #GtkTreeView
13962  * @column: the column of the model to search in, or -1 to disable searching
13963  *
13964  * Sets @column as the column where the interactive search code should
13965  * search in for the current model. 
13966  * 
13967  * If the search column is set, users can use the "start-interactive-search"
13968  * key binding to bring up search popup. The enable-search property controls
13969  * whether simply typing text will also start an interactive search.
13970  *
13971  * Note that @column refers to a column of the current model. The search 
13972  * column is reset to -1 when the model is changed.
13973  */
13974 void
13975 gtk_tree_view_set_search_column (GtkTreeView *tree_view,
13976                                  gint         column)
13977 {
13978   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13979   g_return_if_fail (column >= -1);
13980
13981   if (tree_view->priv->search_column == column)
13982     return;
13983
13984   tree_view->priv->search_column = column;
13985   g_object_notify (G_OBJECT (tree_view), "search-column");
13986 }
13987
13988 /**
13989  * gtk_tree_view_get_search_equal_func:
13990  * @tree_view: A #GtkTreeView
13991  *
13992  * Returns the compare function currently in use.
13993  *
13994  * Return value: the currently used compare function for the search code.
13995  */
13996
13997 GtkTreeViewSearchEqualFunc
13998 gtk_tree_view_get_search_equal_func (GtkTreeView *tree_view)
13999 {
14000   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14001
14002   return tree_view->priv->search_equal_func;
14003 }
14004
14005 /**
14006  * gtk_tree_view_set_search_equal_func:
14007  * @tree_view: A #GtkTreeView
14008  * @search_equal_func: the compare function to use during the search
14009  * @search_user_data: user data to pass to @search_equal_func, or %NULL
14010  * @search_destroy: Destroy notifier for @search_user_data, or %NULL
14011  *
14012  * Sets the compare function for the interactive search capabilities; note
14013  * that somewhat like strcmp() returning 0 for equality
14014  * #GtkTreeViewSearchEqualFunc returns %FALSE on matches.
14015  **/
14016 void
14017 gtk_tree_view_set_search_equal_func (GtkTreeView                *tree_view,
14018                                      GtkTreeViewSearchEqualFunc  search_equal_func,
14019                                      gpointer                    search_user_data,
14020                                      GDestroyNotify              search_destroy)
14021 {
14022   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14023   g_return_if_fail (search_equal_func != NULL);
14024
14025   if (tree_view->priv->search_destroy)
14026     tree_view->priv->search_destroy (tree_view->priv->search_user_data);
14027
14028   tree_view->priv->search_equal_func = search_equal_func;
14029   tree_view->priv->search_user_data = search_user_data;
14030   tree_view->priv->search_destroy = search_destroy;
14031   if (tree_view->priv->search_equal_func == NULL)
14032     tree_view->priv->search_equal_func = gtk_tree_view_search_equal_func;
14033 }
14034
14035 /**
14036  * gtk_tree_view_get_search_entry:
14037  * @tree_view: A #GtkTreeView
14038  *
14039  * Returns the #GtkEntry which is currently in use as interactive search
14040  * entry for @tree_view.  In case the built-in entry is being used, %NULL
14041  * will be returned.
14042  *
14043  * Return value: the entry currently in use as search entry.
14044  *
14045  * Since: 2.10
14046  */
14047 GtkEntry *
14048 gtk_tree_view_get_search_entry (GtkTreeView *tree_view)
14049 {
14050   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14051
14052   if (tree_view->priv->search_custom_entry_set)
14053     return GTK_ENTRY (tree_view->priv->search_entry);
14054
14055   return NULL;
14056 }
14057
14058 /**
14059  * gtk_tree_view_set_search_entry:
14060  * @tree_view: A #GtkTreeView
14061  * @entry: the entry the interactive search code of @tree_view should use or %NULL
14062  *
14063  * Sets the entry which the interactive search code will use for this
14064  * @tree_view.  This is useful when you want to provide a search entry
14065  * in our interface at all time at a fixed position.  Passing %NULL for
14066  * @entry will make the interactive search code use the built-in popup
14067  * entry again.
14068  *
14069  * Since: 2.10
14070  */
14071 void
14072 gtk_tree_view_set_search_entry (GtkTreeView *tree_view,
14073                                 GtkEntry    *entry)
14074 {
14075   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14076   g_return_if_fail (entry == NULL || GTK_IS_ENTRY (entry));
14077
14078   if (tree_view->priv->search_custom_entry_set)
14079     {
14080       if (tree_view->priv->search_entry_changed_id)
14081         {
14082           g_signal_handler_disconnect (tree_view->priv->search_entry,
14083                                        tree_view->priv->search_entry_changed_id);
14084           tree_view->priv->search_entry_changed_id = 0;
14085         }
14086       g_signal_handlers_disconnect_by_func (tree_view->priv->search_entry,
14087                                             G_CALLBACK (gtk_tree_view_search_key_press_event),
14088                                             tree_view);
14089
14090       g_object_unref (tree_view->priv->search_entry);
14091     }
14092   else if (tree_view->priv->search_window)
14093     {
14094       gtk_widget_destroy (tree_view->priv->search_window);
14095
14096       tree_view->priv->search_window = NULL;
14097     }
14098
14099   if (entry)
14100     {
14101       tree_view->priv->search_entry = g_object_ref (entry);
14102       tree_view->priv->search_custom_entry_set = TRUE;
14103
14104       if (tree_view->priv->search_entry_changed_id == 0)
14105         {
14106           tree_view->priv->search_entry_changed_id =
14107             g_signal_connect (tree_view->priv->search_entry, "changed",
14108                               G_CALLBACK (gtk_tree_view_search_init),
14109                               tree_view);
14110         }
14111       
14112         g_signal_connect (tree_view->priv->search_entry, "key-press-event",
14113                           G_CALLBACK (gtk_tree_view_search_key_press_event),
14114                           tree_view);
14115
14116         gtk_tree_view_search_init (tree_view->priv->search_entry, tree_view);
14117     }
14118   else
14119     {
14120       tree_view->priv->search_entry = NULL;
14121       tree_view->priv->search_custom_entry_set = FALSE;
14122     }
14123 }
14124
14125 /**
14126  * gtk_tree_view_set_search_position_func:
14127  * @tree_view: A #GtkTreeView
14128  * @func: the function to use to position the search dialog, or %NULL
14129  *    to use the default search position function
14130  * @data: user data to pass to @func, or %NULL
14131  * @destroy: Destroy notifier for @data, or %NULL
14132  *
14133  * Sets the function to use when positioning the search dialog.
14134  *
14135  * Since: 2.10
14136  **/
14137 void
14138 gtk_tree_view_set_search_position_func (GtkTreeView                   *tree_view,
14139                                         GtkTreeViewSearchPositionFunc  func,
14140                                         gpointer                       user_data,
14141                                         GDestroyNotify                 destroy)
14142 {
14143   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14144
14145   if (tree_view->priv->search_position_destroy)
14146     tree_view->priv->search_position_destroy (tree_view->priv->search_position_user_data);
14147
14148   tree_view->priv->search_position_func = func;
14149   tree_view->priv->search_position_user_data = user_data;
14150   tree_view->priv->search_position_destroy = destroy;
14151   if (tree_view->priv->search_position_func == NULL)
14152     tree_view->priv->search_position_func = gtk_tree_view_search_position_func;
14153 }
14154
14155 /**
14156  * gtk_tree_view_get_search_position_func:
14157  * @tree_view: A #GtkTreeView
14158  *
14159  * Returns the positioning function currently in use.
14160  *
14161  * Return value: the currently used function for positioning the search dialog.
14162  *
14163  * Since: 2.10
14164  */
14165 GtkTreeViewSearchPositionFunc
14166 gtk_tree_view_get_search_position_func (GtkTreeView *tree_view)
14167 {
14168   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14169
14170   return tree_view->priv->search_position_func;
14171 }
14172
14173
14174 static void
14175 gtk_tree_view_search_dialog_hide (GtkWidget   *search_dialog,
14176                                   GtkTreeView *tree_view)
14177 {
14178   if (tree_view->priv->disable_popdown)
14179     return;
14180
14181   if (tree_view->priv->search_entry_changed_id)
14182     {
14183       g_signal_handler_disconnect (tree_view->priv->search_entry,
14184                                    tree_view->priv->search_entry_changed_id);
14185       tree_view->priv->search_entry_changed_id = 0;
14186     }
14187   if (tree_view->priv->typeselect_flush_timeout)
14188     {
14189       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14190       tree_view->priv->typeselect_flush_timeout = 0;
14191     }
14192         
14193   if (GTK_WIDGET_VISIBLE (search_dialog))
14194     {
14195       /* send focus-in event */
14196       send_focus_change (GTK_WIDGET (tree_view->priv->search_entry), FALSE);
14197       gtk_widget_hide (search_dialog);
14198       gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
14199       send_focus_change (GTK_WIDGET (tree_view), TRUE);
14200     }
14201 }
14202
14203 static void
14204 gtk_tree_view_search_position_func (GtkTreeView *tree_view,
14205                                     GtkWidget   *search_dialog,
14206                                     gpointer     user_data)
14207 {
14208   gint x, y;
14209   gint tree_x, tree_y;
14210   gint tree_width, tree_height;
14211   GdkWindow *tree_window = GTK_WIDGET (tree_view)->window;
14212   GdkScreen *screen = gdk_drawable_get_screen (tree_window);
14213   GtkRequisition requisition;
14214   gint monitor_num;
14215   GdkRectangle monitor;
14216
14217   monitor_num = gdk_screen_get_monitor_at_window (screen, tree_window);
14218   gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
14219
14220   gtk_widget_realize (search_dialog);
14221
14222   gdk_window_get_origin (tree_window, &tree_x, &tree_y);
14223   gdk_drawable_get_size (tree_window,
14224                          &tree_width,
14225                          &tree_height);
14226   gtk_widget_size_request (search_dialog, &requisition);
14227
14228   if (tree_x + tree_width > gdk_screen_get_width (screen))
14229     x = gdk_screen_get_width (screen) - requisition.width;
14230   else if (tree_x + tree_width - requisition.width < 0)
14231     x = 0;
14232   else
14233     x = tree_x + tree_width - requisition.width;
14234
14235   if (tree_y + tree_height + requisition.height > gdk_screen_get_height (screen))
14236     y = gdk_screen_get_height (screen) - requisition.height;
14237   else if (tree_y + tree_height < 0) /* isn't really possible ... */
14238     y = 0;
14239   else
14240     y = tree_y + tree_height;
14241
14242   gtk_window_move (GTK_WINDOW (search_dialog), x, y);
14243 }
14244
14245 static void
14246 gtk_tree_view_search_disable_popdown (GtkEntry *entry,
14247                                       GtkMenu  *menu,
14248                                       gpointer  data)
14249 {
14250   GtkTreeView *tree_view = (GtkTreeView *)data;
14251
14252   tree_view->priv->disable_popdown = 1;
14253   g_signal_connect (menu, "hide",
14254                     G_CALLBACK (gtk_tree_view_search_enable_popdown), data);
14255 }
14256
14257 /* Because we're visible but offscreen, we just set a flag in the preedit
14258  * callback.
14259  */
14260 static void
14261 gtk_tree_view_search_preedit_changed (GtkIMContext *im_context,
14262                                       GtkTreeView  *tree_view)
14263 {
14264   tree_view->priv->imcontext_changed = 1;
14265   if (tree_view->priv->typeselect_flush_timeout)
14266     {
14267       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14268       tree_view->priv->typeselect_flush_timeout =
14269         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
14270                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
14271                        tree_view);
14272     }
14273
14274 }
14275
14276 static void
14277 gtk_tree_view_search_activate (GtkEntry    *entry,
14278                                GtkTreeView *tree_view)
14279 {
14280   GtkTreePath *path;
14281   GtkRBNode *node;
14282   GtkRBTree *tree;
14283
14284   gtk_tree_view_search_dialog_hide (tree_view->priv->search_window,
14285                                     tree_view);
14286
14287   /* If we have a row selected and it's the cursor row, we activate
14288    * the row XXX */
14289   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
14290     {
14291       path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
14292       
14293       _gtk_tree_view_find_node (tree_view, path, &tree, &node);
14294       
14295       if (node && GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
14296         gtk_tree_view_row_activated (tree_view, path, tree_view->priv->focus_column);
14297       
14298       gtk_tree_path_free (path);
14299     }
14300 }
14301
14302 static gboolean
14303 gtk_tree_view_real_search_enable_popdown (gpointer data)
14304 {
14305   GtkTreeView *tree_view = (GtkTreeView *)data;
14306
14307   tree_view->priv->disable_popdown = 0;
14308
14309   return FALSE;
14310 }
14311
14312 static void
14313 gtk_tree_view_search_enable_popdown (GtkWidget *widget,
14314                                      gpointer   data)
14315 {
14316   gdk_threads_add_timeout_full (G_PRIORITY_HIGH, 200, gtk_tree_view_real_search_enable_popdown, g_object_ref (data), g_object_unref);
14317 }
14318
14319 static gboolean
14320 gtk_tree_view_search_delete_event (GtkWidget *widget,
14321                                    GdkEventAny *event,
14322                                    GtkTreeView *tree_view)
14323 {
14324   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
14325
14326   gtk_tree_view_search_dialog_hide (widget, tree_view);
14327
14328   return TRUE;
14329 }
14330
14331 static gboolean
14332 gtk_tree_view_search_button_press_event (GtkWidget *widget,
14333                                          GdkEventButton *event,
14334                                          GtkTreeView *tree_view)
14335 {
14336   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
14337
14338   gtk_tree_view_search_dialog_hide (widget, tree_view);
14339
14340   if (event->window == tree_view->priv->bin_window)
14341     gtk_tree_view_button_press (GTK_WIDGET (tree_view), event);
14342
14343   return TRUE;
14344 }
14345
14346 static gboolean
14347 gtk_tree_view_search_scroll_event (GtkWidget *widget,
14348                                    GdkEventScroll *event,
14349                                    GtkTreeView *tree_view)
14350 {
14351   gboolean retval = FALSE;
14352
14353   if (event->direction == GDK_SCROLL_UP)
14354     {
14355       gtk_tree_view_search_move (widget, tree_view, TRUE);
14356       retval = TRUE;
14357     }
14358   else if (event->direction == GDK_SCROLL_DOWN)
14359     {
14360       gtk_tree_view_search_move (widget, tree_view, FALSE);
14361       retval = TRUE;
14362     }
14363
14364   /* renew the flush timeout */
14365   if (retval && tree_view->priv->typeselect_flush_timeout
14366       && !tree_view->priv->search_custom_entry_set)
14367     {
14368       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14369       tree_view->priv->typeselect_flush_timeout =
14370         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
14371                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
14372                        tree_view);
14373     }
14374
14375   return retval;
14376 }
14377
14378 static gboolean
14379 gtk_tree_view_search_key_press_event (GtkWidget *widget,
14380                                       GdkEventKey *event,
14381                                       GtkTreeView *tree_view)
14382 {
14383   gboolean retval = FALSE;
14384
14385   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
14386   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
14387
14388   /* close window and cancel the search */
14389   if (!tree_view->priv->search_custom_entry_set
14390       && (event->keyval == GDK_Escape ||
14391           event->keyval == GDK_Tab ||
14392             event->keyval == GDK_KP_Tab ||
14393             event->keyval == GDK_ISO_Left_Tab))
14394     {
14395       gtk_tree_view_search_dialog_hide (widget, tree_view);
14396       return TRUE;
14397     }
14398
14399   /* select previous matching iter */
14400   if (event->keyval == GDK_Up || event->keyval == GDK_KP_Up)
14401     {
14402       if (!gtk_tree_view_search_move (widget, tree_view, TRUE))
14403         gtk_widget_error_bell (widget);
14404
14405       retval = TRUE;
14406     }
14407
14408   if (((event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)) == (GDK_CONTROL_MASK | GDK_SHIFT_MASK))
14409       && (event->keyval == GDK_g || event->keyval == GDK_G))
14410     {
14411       if (!gtk_tree_view_search_move (widget, tree_view, TRUE))
14412         gtk_widget_error_bell (widget);
14413
14414       retval = TRUE;
14415     }
14416
14417   /* select next matching iter */
14418   if (event->keyval == GDK_Down || event->keyval == GDK_KP_Down)
14419     {
14420       if (!gtk_tree_view_search_move (widget, tree_view, FALSE))
14421         gtk_widget_error_bell (widget);
14422
14423       retval = TRUE;
14424     }
14425
14426   if (((event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)) == GDK_CONTROL_MASK)
14427       && (event->keyval == GDK_g || event->keyval == GDK_G))
14428     {
14429       if (!gtk_tree_view_search_move (widget, tree_view, FALSE))
14430         gtk_widget_error_bell (widget);
14431
14432       retval = TRUE;
14433     }
14434
14435   /* renew the flush timeout */
14436   if (retval && tree_view->priv->typeselect_flush_timeout
14437       && !tree_view->priv->search_custom_entry_set)
14438     {
14439       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14440       tree_view->priv->typeselect_flush_timeout =
14441         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
14442                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
14443                        tree_view);
14444     }
14445
14446   return retval;
14447 }
14448
14449 /*  this function returns FALSE if there is a search string but
14450  *  nothing was found, and TRUE otherwise.
14451  */
14452 static gboolean
14453 gtk_tree_view_search_move (GtkWidget   *window,
14454                            GtkTreeView *tree_view,
14455                            gboolean     up)
14456 {
14457   gboolean ret;
14458   gint len;
14459   gint count = 0;
14460   const gchar *text;
14461   GtkTreeIter iter;
14462   GtkTreeModel *model;
14463   GtkTreeSelection *selection;
14464
14465   text = gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry));
14466
14467   g_return_val_if_fail (text != NULL, FALSE);
14468
14469   len = strlen (text);
14470
14471   if (up && tree_view->priv->selected_iter == 1)
14472     return strlen (text) < 1;
14473
14474   len = strlen (text);
14475
14476   if (len < 1)
14477     return TRUE;
14478
14479   model = gtk_tree_view_get_model (tree_view);
14480   selection = gtk_tree_view_get_selection (tree_view);
14481
14482   /* search */
14483   gtk_tree_selection_unselect_all (selection);
14484   if (!gtk_tree_model_get_iter_first (model, &iter))
14485     return TRUE;
14486
14487   ret = gtk_tree_view_search_iter (model, selection, &iter, text,
14488                                    &count, up?((tree_view->priv->selected_iter) - 1):((tree_view->priv->selected_iter + 1)));
14489
14490   if (ret)
14491     {
14492       /* found */
14493       tree_view->priv->selected_iter += up?(-1):(1);
14494       return TRUE;
14495     }
14496   else
14497     {
14498       /* return to old iter */
14499       count = 0;
14500       gtk_tree_model_get_iter_first (model, &iter);
14501       gtk_tree_view_search_iter (model, selection,
14502                                  &iter, text,
14503                                  &count, tree_view->priv->selected_iter);
14504       return FALSE;
14505     }
14506 }
14507
14508 static gboolean
14509 gtk_tree_view_search_equal_func (GtkTreeModel *model,
14510                                  gint          column,
14511                                  const gchar  *key,
14512                                  GtkTreeIter  *iter,
14513                                  gpointer      search_data)
14514 {
14515   gboolean retval = TRUE;
14516   const gchar *str;
14517   gchar *normalized_string;
14518   gchar *normalized_key;
14519   gchar *case_normalized_string = NULL;
14520   gchar *case_normalized_key = NULL;
14521   GValue value = {0,};
14522   GValue transformed = {0,};
14523
14524   gtk_tree_model_get_value (model, iter, column, &value);
14525
14526   g_value_init (&transformed, G_TYPE_STRING);
14527
14528   if (!g_value_transform (&value, &transformed))
14529     {
14530       g_value_unset (&value);
14531       return TRUE;
14532     }
14533
14534   g_value_unset (&value);
14535
14536   str = g_value_get_string (&transformed);
14537   if (!str)
14538     {
14539       g_value_unset (&transformed);
14540       return TRUE;
14541     }
14542
14543   normalized_string = g_utf8_normalize (str, -1, G_NORMALIZE_ALL);
14544   normalized_key = g_utf8_normalize (key, -1, G_NORMALIZE_ALL);
14545
14546   if (normalized_string && normalized_key)
14547     {
14548       case_normalized_string = g_utf8_casefold (normalized_string, -1);
14549       case_normalized_key = g_utf8_casefold (normalized_key, -1);
14550
14551       if (strncmp (case_normalized_key, case_normalized_string, strlen (case_normalized_key)) == 0)
14552         retval = FALSE;
14553     }
14554
14555   g_value_unset (&transformed);
14556   g_free (normalized_key);
14557   g_free (normalized_string);
14558   g_free (case_normalized_key);
14559   g_free (case_normalized_string);
14560
14561   return retval;
14562 }
14563
14564 static gboolean
14565 gtk_tree_view_search_iter (GtkTreeModel     *model,
14566                            GtkTreeSelection *selection,
14567                            GtkTreeIter      *iter,
14568                            const gchar      *text,
14569                            gint             *count,
14570                            gint              n)
14571 {
14572   GtkRBTree *tree = NULL;
14573   GtkRBNode *node = NULL;
14574   GtkTreePath *path;
14575
14576   GtkTreeView *tree_view = gtk_tree_selection_get_tree_view (selection);
14577
14578   path = gtk_tree_model_get_path (model, iter);
14579   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
14580
14581   do
14582     {
14583       if (! tree_view->priv->search_equal_func (model, tree_view->priv->search_column, text, iter, tree_view->priv->search_user_data))
14584         {
14585           (*count)++;
14586           if (*count == n)
14587             {
14588               gtk_tree_view_scroll_to_cell (tree_view, path, NULL,
14589                                             TRUE, 0.5, 0.0);
14590               gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
14591               gtk_tree_selection_select_iter (selection, iter);
14592
14593               if (path)
14594                 gtk_tree_path_free (path);
14595
14596               return TRUE;
14597             }
14598         }
14599
14600       if (node->children)
14601         {
14602           gboolean has_child;
14603           GtkTreeIter tmp;
14604
14605           tree = node->children;
14606           node = tree->root;
14607
14608           while (node->left != tree->nil)
14609             node = node->left;
14610
14611           tmp = *iter;
14612           has_child = gtk_tree_model_iter_children (model, iter, &tmp);
14613           gtk_tree_path_down (path);
14614
14615           /* sanity check */
14616           TREE_VIEW_INTERNAL_ASSERT (has_child, FALSE);
14617         }
14618       else
14619         {
14620           gboolean done = FALSE;
14621
14622           do
14623             {
14624               node = _gtk_rbtree_next (tree, node);
14625
14626               if (node)
14627                 {
14628                   gboolean has_next;
14629
14630                   has_next = gtk_tree_model_iter_next (model, iter);
14631
14632                   done = TRUE;
14633                   gtk_tree_path_next (path);
14634
14635                   /* sanity check */
14636                   TREE_VIEW_INTERNAL_ASSERT (has_next, FALSE);
14637                 }
14638               else
14639                 {
14640                   gboolean has_parent;
14641                   GtkTreeIter tmp_iter = *iter;
14642
14643                   node = tree->parent_node;
14644                   tree = tree->parent_tree;
14645
14646                   if (!tree)
14647                     {
14648                       if (path)
14649                         gtk_tree_path_free (path);
14650
14651                       /* we've run out of tree, done with this func */
14652                       return FALSE;
14653                     }
14654
14655                   has_parent = gtk_tree_model_iter_parent (model,
14656                                                            iter,
14657                                                            &tmp_iter);
14658                   gtk_tree_path_up (path);
14659
14660                   /* sanity check */
14661                   TREE_VIEW_INTERNAL_ASSERT (has_parent, FALSE);
14662                 }
14663             }
14664           while (!done);
14665         }
14666     }
14667   while (1);
14668
14669   return FALSE;
14670 }
14671
14672 static void
14673 gtk_tree_view_search_init (GtkWidget   *entry,
14674                            GtkTreeView *tree_view)
14675 {
14676   gint ret;
14677   gint len;
14678   gint count = 0;
14679   const gchar *text;
14680   GtkTreeIter iter;
14681   GtkTreeModel *model;
14682   GtkTreeSelection *selection;
14683
14684   g_return_if_fail (GTK_IS_ENTRY (entry));
14685   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14686
14687   text = gtk_entry_get_text (GTK_ENTRY (entry));
14688   len = strlen (text);
14689   model = gtk_tree_view_get_model (tree_view);
14690   selection = gtk_tree_view_get_selection (tree_view);
14691
14692   /* search */
14693   gtk_tree_selection_unselect_all (selection);
14694   if (tree_view->priv->typeselect_flush_timeout
14695       && !tree_view->priv->search_custom_entry_set)
14696     {
14697       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14698       tree_view->priv->typeselect_flush_timeout =
14699         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
14700                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
14701                        tree_view);
14702     }
14703
14704   if (len < 1)
14705     return;
14706
14707   if (!gtk_tree_model_get_iter_first (model, &iter))
14708     return;
14709
14710   ret = gtk_tree_view_search_iter (model, selection,
14711                                    &iter, text,
14712                                    &count, 1);
14713
14714   if (ret)
14715     tree_view->priv->selected_iter = 1;
14716 }
14717
14718 static void
14719 gtk_tree_view_remove_widget (GtkCellEditable *cell_editable,
14720                              GtkTreeView     *tree_view)
14721 {
14722   if (tree_view->priv->edited_column == NULL)
14723     return;
14724
14725   _gtk_tree_view_column_stop_editing (tree_view->priv->edited_column);
14726   tree_view->priv->edited_column = NULL;
14727
14728   if (GTK_WIDGET_HAS_FOCUS (cell_editable))
14729     gtk_widget_grab_focus (GTK_WIDGET (tree_view));
14730
14731   g_signal_handlers_disconnect_by_func (cell_editable,
14732                                         gtk_tree_view_remove_widget,
14733                                         tree_view);
14734
14735   gtk_container_remove (GTK_CONTAINER (tree_view),
14736                         GTK_WIDGET (cell_editable));  
14737
14738   /* FIXME should only redraw a single node */
14739   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
14740 }
14741
14742 static gboolean
14743 gtk_tree_view_start_editing (GtkTreeView *tree_view,
14744                              GtkTreePath *cursor_path)
14745 {
14746   GtkTreeIter iter;
14747   GdkRectangle background_area;
14748   GdkRectangle cell_area;
14749   GtkCellEditable *editable_widget = NULL;
14750   gchar *path_string;
14751   guint flags = 0; /* can be 0, as the flags are primarily for rendering */
14752   gint retval = FALSE;
14753   GtkRBTree *cursor_tree;
14754   GtkRBNode *cursor_node;
14755
14756   g_assert (tree_view->priv->focus_column);
14757
14758   if (! GTK_WIDGET_REALIZED (tree_view))
14759     return FALSE;
14760
14761   if (_gtk_tree_view_find_node (tree_view, cursor_path, &cursor_tree, &cursor_node) ||
14762       cursor_node == NULL)
14763     return FALSE;
14764
14765   path_string = gtk_tree_path_to_string (cursor_path);
14766   gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path);
14767
14768   validate_row (tree_view, cursor_tree, cursor_node, &iter, cursor_path);
14769
14770   gtk_tree_view_column_cell_set_cell_data (tree_view->priv->focus_column,
14771                                            tree_view->priv->model,
14772                                            &iter,
14773                                            GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_PARENT),
14774                                            cursor_node->children?TRUE:FALSE);
14775   gtk_tree_view_get_background_area (tree_view,
14776                                      cursor_path,
14777                                      tree_view->priv->focus_column,
14778                                      &background_area);
14779   gtk_tree_view_get_cell_area (tree_view,
14780                                cursor_path,
14781                                tree_view->priv->focus_column,
14782                                &cell_area);
14783
14784   if (_gtk_tree_view_column_cell_event (tree_view->priv->focus_column,
14785                                         &editable_widget,
14786                                         NULL,
14787                                         path_string,
14788                                         &background_area,
14789                                         &cell_area,
14790                                         flags))
14791     {
14792       retval = TRUE;
14793       if (editable_widget != NULL)
14794         {
14795           gint left, right;
14796           GdkRectangle area;
14797           GtkCellRenderer *cell;
14798
14799           area = cell_area;
14800           cell = _gtk_tree_view_column_get_edited_cell (tree_view->priv->focus_column);
14801
14802           _gtk_tree_view_column_get_neighbor_sizes (tree_view->priv->focus_column, cell, &left, &right);
14803
14804           area.x += left;
14805           area.width -= right + left;
14806
14807           gtk_tree_view_real_start_editing (tree_view,
14808                                             tree_view->priv->focus_column,
14809                                             cursor_path,
14810                                             editable_widget,
14811                                             &area,
14812                                             NULL,
14813                                             flags);
14814         }
14815
14816     }
14817   g_free (path_string);
14818   return retval;
14819 }
14820
14821 static void
14822 gtk_tree_view_real_start_editing (GtkTreeView       *tree_view,
14823                                   GtkTreeViewColumn *column,
14824                                   GtkTreePath       *path,
14825                                   GtkCellEditable   *cell_editable,
14826                                   GdkRectangle      *cell_area,
14827                                   GdkEvent          *event,
14828                                   guint              flags)
14829 {
14830   gint pre_val = tree_view->priv->vadjustment->value;
14831   GtkRequisition requisition;
14832
14833   tree_view->priv->edited_column = column;
14834   _gtk_tree_view_column_start_editing (column, GTK_CELL_EDITABLE (cell_editable));
14835
14836   gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
14837   cell_area->y += pre_val - (int)tree_view->priv->vadjustment->value;
14838
14839   gtk_widget_size_request (GTK_WIDGET (cell_editable), &requisition);
14840
14841   GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
14842
14843   if (requisition.height < cell_area->height)
14844     {
14845       gint diff = cell_area->height - requisition.height;
14846       gtk_tree_view_put (tree_view,
14847                          GTK_WIDGET (cell_editable),
14848                          cell_area->x, cell_area->y + diff/2,
14849                          cell_area->width, requisition.height);
14850     }
14851   else
14852     {
14853       gtk_tree_view_put (tree_view,
14854                          GTK_WIDGET (cell_editable),
14855                          cell_area->x, cell_area->y,
14856                          cell_area->width, cell_area->height);
14857     }
14858
14859   gtk_cell_editable_start_editing (GTK_CELL_EDITABLE (cell_editable),
14860                                    (GdkEvent *)event);
14861
14862   gtk_widget_grab_focus (GTK_WIDGET (cell_editable));
14863   g_signal_connect (cell_editable, "remove-widget",
14864                     G_CALLBACK (gtk_tree_view_remove_widget), tree_view);
14865 }
14866
14867 static void
14868 gtk_tree_view_stop_editing (GtkTreeView *tree_view,
14869                             gboolean     cancel_editing)
14870 {
14871   GtkTreeViewColumn *column;
14872   GtkCellRenderer *cell;
14873
14874   if (tree_view->priv->edited_column == NULL)
14875     return;
14876
14877   /*
14878    * This is very evil. We need to do this, because
14879    * gtk_cell_editable_editing_done may trigger gtk_tree_view_row_changed
14880    * later on. If gtk_tree_view_row_changed notices
14881    * tree_view->priv->edited_column != NULL, it'll call
14882    * gtk_tree_view_stop_editing again. Bad things will happen then.
14883    *
14884    * Please read that again if you intend to modify anything here.
14885    */
14886
14887   column = tree_view->priv->edited_column;
14888   tree_view->priv->edited_column = NULL;
14889
14890   cell = _gtk_tree_view_column_get_edited_cell (column);
14891   gtk_cell_renderer_stop_editing (cell, cancel_editing);
14892
14893   if (!cancel_editing)
14894     gtk_cell_editable_editing_done (column->editable_widget);
14895
14896   tree_view->priv->edited_column = column;
14897
14898   gtk_cell_editable_remove_widget (column->editable_widget);
14899 }
14900
14901
14902 /**
14903  * gtk_tree_view_set_hover_selection:
14904  * @tree_view: a #GtkTreeView
14905  * @hover: %TRUE to enable hover selection mode
14906  *
14907  * Enables of disables the hover selection mode of @tree_view.
14908  * Hover selection makes the selected row follow the pointer.
14909  * Currently, this works only for the selection modes 
14910  * %GTK_SELECTION_SINGLE and %GTK_SELECTION_BROWSE.
14911  * 
14912  * Since: 2.6
14913  **/
14914 void     
14915 gtk_tree_view_set_hover_selection (GtkTreeView *tree_view,
14916                                    gboolean     hover)
14917 {
14918   hover = hover != FALSE;
14919
14920   if (hover != tree_view->priv->hover_selection)
14921     {
14922       tree_view->priv->hover_selection = hover;
14923
14924       g_object_notify (G_OBJECT (tree_view), "hover-selection");
14925     }
14926 }
14927
14928 /**
14929  * gtk_tree_view_get_hover_selection:
14930  * @tree_view: a #GtkTreeView
14931  * 
14932  * Returns whether hover selection mode is turned on for @tree_view.
14933  * 
14934  * Return value: %TRUE if @tree_view is in hover selection mode
14935  *
14936  * Since: 2.6 
14937  **/
14938 gboolean 
14939 gtk_tree_view_get_hover_selection (GtkTreeView *tree_view)
14940 {
14941   return tree_view->priv->hover_selection;
14942 }
14943
14944 /**
14945  * gtk_tree_view_set_hover_expand:
14946  * @tree_view: a #GtkTreeView
14947  * @expand: %TRUE to enable hover selection mode
14948  *
14949  * Enables of disables the hover expansion mode of @tree_view.
14950  * Hover expansion makes rows expand or collapse if the pointer 
14951  * moves over them.
14952  * 
14953  * Since: 2.6
14954  **/
14955 void     
14956 gtk_tree_view_set_hover_expand (GtkTreeView *tree_view,
14957                                 gboolean     expand)
14958 {
14959   expand = expand != FALSE;
14960
14961   if (expand != tree_view->priv->hover_expand)
14962     {
14963       tree_view->priv->hover_expand = expand;
14964
14965       g_object_notify (G_OBJECT (tree_view), "hover-expand");
14966     }
14967 }
14968
14969 /**
14970  * gtk_tree_view_get_hover_expand:
14971  * @tree_view: a #GtkTreeView
14972  * 
14973  * Returns whether hover expansion mode is turned on for @tree_view.
14974  * 
14975  * Return value: %TRUE if @tree_view is in hover expansion mode
14976  *
14977  * Since: 2.6 
14978  **/
14979 gboolean 
14980 gtk_tree_view_get_hover_expand (GtkTreeView *tree_view)
14981 {
14982   return tree_view->priv->hover_expand;
14983 }
14984
14985 /**
14986  * gtk_tree_view_set_rubber_banding:
14987  * @tree_view: a #GtkTreeView
14988  * @enable: %TRUE to enable rubber banding
14989  *
14990  * Enables or disables rubber banding in @tree_view.  If the selection mode
14991  * is #GTK_SELECTION_MULTIPLE, rubber banding will allow the user to select
14992  * multiple rows by dragging the mouse.
14993  * 
14994  * Since: 2.10
14995  **/
14996 void
14997 gtk_tree_view_set_rubber_banding (GtkTreeView *tree_view,
14998                                   gboolean     enable)
14999 {
15000   enable = enable != FALSE;
15001
15002   if (enable != tree_view->priv->rubber_banding_enable)
15003     {
15004       tree_view->priv->rubber_banding_enable = enable;
15005
15006       g_object_notify (G_OBJECT (tree_view), "rubber-banding");
15007     }
15008 }
15009
15010 /**
15011  * gtk_tree_view_get_rubber_banding:
15012  * @tree_view: a #GtkTreeView
15013  * 
15014  * Returns whether rubber banding is turned on for @tree_view.  If the
15015  * selection mode is #GTK_SELECTION_MULTIPLE, rubber banding will allow the
15016  * user to select multiple rows by dragging the mouse.
15017  * 
15018  * Return value: %TRUE if rubber banding in @tree_view is enabled.
15019  *
15020  * Since: 2.10
15021  **/
15022 gboolean
15023 gtk_tree_view_get_rubber_banding (GtkTreeView *tree_view)
15024 {
15025   return tree_view->priv->rubber_banding_enable;
15026 }
15027
15028 /**
15029  * gtk_tree_view_is_rubber_banding_active:
15030  * @tree_view: a #GtkTreeView
15031  * 
15032  * Returns whether a rubber banding operation is currently being done
15033  * in @tree_view.
15034  *
15035  * Return value: %TRUE if a rubber banding operation is currently being
15036  * done in @tree_view.
15037  *
15038  * Since: 2.12
15039  **/
15040 gboolean
15041 gtk_tree_view_is_rubber_banding_active (GtkTreeView *tree_view)
15042 {
15043   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15044
15045   if (tree_view->priv->rubber_banding_enable
15046       && tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
15047     return TRUE;
15048
15049   return FALSE;
15050 }
15051
15052 /**
15053  * gtk_tree_view_get_row_separator_func:
15054  * @tree_view: a #GtkTreeView
15055  * 
15056  * Returns the current row separator function.
15057  * 
15058  * Return value: the current row separator function.
15059  *
15060  * Since: 2.6
15061  **/
15062 GtkTreeViewRowSeparatorFunc 
15063 gtk_tree_view_get_row_separator_func (GtkTreeView *tree_view)
15064 {
15065   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
15066
15067   return tree_view->priv->row_separator_func;
15068 }
15069
15070 /**
15071  * gtk_tree_view_set_row_separator_func:
15072  * @tree_view: a #GtkTreeView
15073  * @func: a #GtkTreeViewRowSeparatorFunc
15074  * @data: user data to pass to @func, or %NULL
15075  * @destroy: destroy notifier for @data, or %NULL
15076  * 
15077  * Sets the row separator function, which is used to determine
15078  * whether a row should be drawn as a separator. If the row separator
15079  * function is %NULL, no separators are drawn. This is the default value.
15080  *
15081  * Since: 2.6
15082  **/
15083 void
15084 gtk_tree_view_set_row_separator_func (GtkTreeView                 *tree_view,
15085                                       GtkTreeViewRowSeparatorFunc  func,
15086                                       gpointer                     data,
15087                                       GDestroyNotify               destroy)
15088 {
15089   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15090
15091   if (tree_view->priv->row_separator_destroy)
15092     tree_view->priv->row_separator_destroy (tree_view->priv->row_separator_data);
15093
15094   tree_view->priv->row_separator_func = func;
15095   tree_view->priv->row_separator_data = data;
15096   tree_view->priv->row_separator_destroy = destroy;
15097 }
15098
15099   
15100 static void
15101 gtk_tree_view_grab_notify (GtkWidget *widget,
15102                            gboolean   was_grabbed)
15103 {
15104   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
15105
15106   tree_view->priv->in_grab = !was_grabbed;
15107
15108   if (!was_grabbed)
15109     {
15110       tree_view->priv->pressed_button = -1;
15111
15112       if (tree_view->priv->rubber_band_status)
15113         gtk_tree_view_stop_rubber_band (tree_view);
15114     }
15115 }
15116
15117 static void
15118 gtk_tree_view_state_changed (GtkWidget      *widget,
15119                              GtkStateType    previous_state)
15120 {
15121   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
15122
15123   if (GTK_WIDGET_REALIZED (widget))
15124     {
15125       gdk_window_set_back_pixmap (widget->window, NULL, FALSE);
15126       gdk_window_set_background (tree_view->priv->bin_window, &widget->style->base[widget->state]);
15127     }
15128
15129   gtk_widget_queue_draw (widget);
15130 }
15131
15132 /**
15133  * gtk_tree_view_get_grid_lines:
15134  * @tree_view: a #GtkTreeView
15135  *
15136  * Returns which grid lines are enabled in @tree_view.
15137  *
15138  * Return value: a #GtkTreeViewGridLines value indicating which grid lines
15139  * are enabled.
15140  *
15141  * Since: 2.10
15142  */
15143 GtkTreeViewGridLines
15144 gtk_tree_view_get_grid_lines (GtkTreeView *tree_view)
15145 {
15146   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
15147
15148   return tree_view->priv->grid_lines;
15149 }
15150
15151 /**
15152  * gtk_tree_view_set_grid_lines:
15153  * @tree_view: a #GtkTreeView
15154  * @grid_lines: a #GtkTreeViewGridLines value indicating which grid lines to
15155  * enable.
15156  *
15157  * Sets which grid lines to draw in @tree_view.
15158  *
15159  * Since: 2.10
15160  */
15161 void
15162 gtk_tree_view_set_grid_lines (GtkTreeView           *tree_view,
15163                               GtkTreeViewGridLines   grid_lines)
15164 {
15165   GtkTreeViewPrivate *priv;
15166   GtkWidget *widget;
15167   GtkTreeViewGridLines old_grid_lines;
15168
15169   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15170
15171   priv = tree_view->priv;
15172   widget = GTK_WIDGET (tree_view);
15173
15174   old_grid_lines = priv->grid_lines;
15175   priv->grid_lines = grid_lines;
15176   
15177   if (GTK_WIDGET_REALIZED (widget))
15178     {
15179       if (grid_lines == GTK_TREE_VIEW_GRID_LINES_NONE &&
15180           priv->grid_line_gc)
15181         {
15182           g_object_unref (priv->grid_line_gc);
15183           priv->grid_line_gc = NULL;
15184         }
15185       
15186       if (grid_lines != GTK_TREE_VIEW_GRID_LINES_NONE && 
15187           !priv->grid_line_gc)
15188         {
15189           gint line_width;
15190           gint8 *dash_list;
15191
15192           gtk_widget_style_get (widget,
15193                                 "grid-line-width", &line_width,
15194                                 "grid-line-pattern", (gchar *)&dash_list,
15195                                 NULL);
15196       
15197           priv->grid_line_gc = gdk_gc_new (widget->window);
15198           gdk_gc_copy (priv->grid_line_gc, widget->style->black_gc);
15199           
15200           gdk_gc_set_line_attributes (priv->grid_line_gc, line_width,
15201                                       GDK_LINE_ON_OFF_DASH,
15202                                       GDK_CAP_BUTT, GDK_JOIN_MITER);
15203           gdk_gc_set_dashes (priv->grid_line_gc, 0, dash_list, 2);
15204
15205           g_free (dash_list);
15206         }      
15207     }
15208
15209   if (old_grid_lines != grid_lines)
15210     {
15211       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15212       
15213       g_object_notify (G_OBJECT (tree_view), "enable-grid-lines");
15214     }
15215 }
15216
15217 /**
15218  * gtk_tree_view_get_enable_tree_lines:
15219  * @tree_view: a #GtkTreeView.
15220  *
15221  * Returns whether or not tree lines are drawn in @tree_view.
15222  *
15223  * Return value: %TRUE if tree lines are drawn in @tree_view, %FALSE
15224  * otherwise.
15225  *
15226  * Since: 2.10
15227  */
15228 gboolean
15229 gtk_tree_view_get_enable_tree_lines (GtkTreeView *tree_view)
15230 {
15231   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15232
15233   return tree_view->priv->tree_lines_enabled;
15234 }
15235
15236 /**
15237  * gtk_tree_view_set_enable_tree_lines:
15238  * @tree_view: a #GtkTreeView
15239  * @enabled: %TRUE to enable tree line drawing, %FALSE otherwise.
15240  *
15241  * Sets whether to draw lines interconnecting the expanders in @tree_view.
15242  * This does not have any visible effects for lists.
15243  *
15244  * Since: 2.10
15245  */
15246 void
15247 gtk_tree_view_set_enable_tree_lines (GtkTreeView *tree_view,
15248                                      gboolean     enabled)
15249 {
15250   GtkTreeViewPrivate *priv;
15251   GtkWidget *widget;
15252   gboolean was_enabled;
15253
15254   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15255
15256   enabled = enabled != FALSE;
15257
15258   priv = tree_view->priv;
15259   widget = GTK_WIDGET (tree_view);
15260
15261   was_enabled = priv->tree_lines_enabled;
15262
15263   priv->tree_lines_enabled = enabled;
15264
15265   if (GTK_WIDGET_REALIZED (widget))
15266     {
15267       if (!enabled && priv->tree_line_gc)
15268         {
15269           g_object_unref (priv->tree_line_gc);
15270           priv->tree_line_gc = NULL;
15271         }
15272       
15273       if (enabled && !priv->tree_line_gc)
15274         {
15275           gint line_width;
15276           gint8 *dash_list;
15277           gtk_widget_style_get (widget,
15278                                 "tree-line-width", &line_width,
15279                                 "tree-line-pattern", (gchar *)&dash_list,
15280                                 NULL);
15281           
15282           priv->tree_line_gc = gdk_gc_new (widget->window);
15283           gdk_gc_copy (priv->tree_line_gc, widget->style->black_gc);
15284           
15285           gdk_gc_set_line_attributes (priv->tree_line_gc, line_width,
15286                                       GDK_LINE_ON_OFF_DASH,
15287                                       GDK_CAP_BUTT, GDK_JOIN_MITER);
15288           gdk_gc_set_dashes (priv->tree_line_gc, 0, dash_list, 2);
15289
15290           g_free (dash_list);
15291         }
15292     }
15293
15294   if (was_enabled != enabled)
15295     {
15296       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15297
15298       g_object_notify (G_OBJECT (tree_view), "enable-tree-lines");
15299     }
15300 }
15301
15302
15303 /**
15304  * gtk_tree_view_set_show_expanders:
15305  * @tree_view: a #GtkTreeView
15306  * @enabled: %TRUE to enable expander drawing, %FALSE otherwise.
15307  *
15308  * Sets whether to draw and enable expanders and indent child rows in
15309  * @tree_view.  When disabled there will be no expanders visible in trees
15310  * and there will be no way to expand and collapse rows by default.  Also
15311  * note that hiding the expanders will disable the default indentation.  You
15312  * can set a custom indentation in this case using
15313  * gtk_tree_view_set_level_indentation().
15314  * This does not have any visible effects for lists.
15315  *
15316  * Since: 2.12
15317  */
15318 void
15319 gtk_tree_view_set_show_expanders (GtkTreeView *tree_view,
15320                                   gboolean     enabled)
15321 {
15322   gboolean was_enabled;
15323
15324   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15325
15326   enabled = enabled != FALSE;
15327   was_enabled = GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS);
15328
15329   if (enabled)
15330     GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS);
15331   else
15332     GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS);
15333
15334   if (enabled != was_enabled)
15335     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15336 }
15337
15338 /**
15339  * gtk_tree_view_get_show_expanders:
15340  * @tree_view: a #GtkTreeView.
15341  *
15342  * Returns whether or not expanders are drawn in @tree_view.
15343  *
15344  * Return value: %TRUE if expanders are drawn in @tree_view, %FALSE
15345  * otherwise.
15346  *
15347  * Since: 2.12
15348  */
15349 gboolean
15350 gtk_tree_view_get_show_expanders (GtkTreeView *tree_view)
15351 {
15352   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15353
15354   return GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS);
15355 }
15356
15357 /**
15358  * gtk_tree_view_set_level_indentation:
15359  * @tree_view: a #GtkTreeView
15360  * @indentation: the amount, in pixels, of extra indentation in @tree_view.
15361  *
15362  * Sets the amount of extra indentation for child levels to use in @tree_view
15363  * in addition to the default indentation.  The value should be specified in
15364  * pixels, a value of 0 disables this feature and in this case only the default
15365  * indentation will be used.
15366  * This does not have any visible effects for lists.
15367  *
15368  * Since: 2.12
15369  */
15370 void
15371 gtk_tree_view_set_level_indentation (GtkTreeView *tree_view,
15372                                      gint         indentation)
15373 {
15374   tree_view->priv->level_indentation = indentation;
15375
15376   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15377 }
15378
15379 /**
15380  * gtk_tree_view_get_level_indentation:
15381  * @tree_view: a #GtkTreeView.
15382  *
15383  * Returns the amount, in pixels, of extra indentation for child levels
15384  * in @tree_view.
15385  *
15386  * Return value: the amount of extra indentation for child levels in
15387  * @tree_view.  A return value of 0 means that this feature is disabled.
15388  *
15389  * Since: 2.12
15390  */
15391 gint
15392 gtk_tree_view_get_level_indentation (GtkTreeView *tree_view)
15393 {
15394   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
15395
15396   return tree_view->priv->level_indentation;
15397 }
15398
15399 /**
15400  * gtk_tree_view_set_tooltip_row:
15401  * @tree_view: a #GtkTreeView
15402  * @tooltip: a #GtkTooltip
15403  * @path: a #GtkTreePath
15404  *
15405  * Sets the tip area of @tooltip to be the area covered by the row at @path.
15406  * See also gtk_tree_view_set_tooltip_column() for a simpler alternative.
15407  * See also gtk_tooltip_set_tip_area().
15408  *
15409  * Since: 2.12
15410  */
15411 void
15412 gtk_tree_view_set_tooltip_row (GtkTreeView *tree_view,
15413                                GtkTooltip  *tooltip,
15414                                GtkTreePath *path)
15415 {
15416   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15417   g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
15418
15419   gtk_tree_view_set_tooltip_cell (tree_view, tooltip, path, NULL, NULL);
15420 }
15421
15422 /**
15423  * gtk_tree_view_set_tooltip_cell:
15424  * @tree_view: a #GtkTreeView
15425  * @tooltip: a #GtkTooltip
15426  * @path: a #GtkTreePath or %NULL
15427  * @column: a #GtkTreeViewColumn or %NULL
15428  * @cell: a #GtkCellRenderer or %NULL
15429  *
15430  * Sets the tip area of @tooltip to the area @path, @column and @cell have
15431  * in common.  For example if @path is %NULL and @column is set, the tip
15432  * area will be set to the full area covered by @column.  See also
15433  * gtk_tooltip_set_tip_area().
15434  *
15435  * Note that if @path is not specified and @cell is set and part of a column
15436  * containing the expander, the tooltip might not show and hide at the correct
15437  * position.  In such cases @path must be set to the current node under the
15438  * mouse cursor for this function to operate correctly.
15439  *
15440  * See also gtk_tree_view_set_tooltip_column() for a simpler alternative.
15441  *
15442  * Since: 2.12
15443  */
15444 void
15445 gtk_tree_view_set_tooltip_cell (GtkTreeView       *tree_view,
15446                                 GtkTooltip        *tooltip,
15447                                 GtkTreePath       *path,
15448                                 GtkTreeViewColumn *column,
15449                                 GtkCellRenderer   *cell)
15450 {
15451   GdkRectangle rect;
15452
15453   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15454   g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
15455   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
15456   g_return_if_fail (cell == NULL || GTK_IS_CELL_RENDERER (cell));
15457
15458   /* Determine x values. */
15459   if (column && cell)
15460     {
15461       GdkRectangle tmp;
15462       gint start, width;
15463
15464       /* We always pass in path here, whether it is NULL or not.
15465        * For cells in expander columns path must be specified so that
15466        * we can correctly account for the indentation.  This also means
15467        * that the tooltip is constrained vertically by the "Determine y
15468        * values" code below; this is not a real problem since cells actually
15469        * don't stretch vertically in constrast to columns.
15470        */
15471       gtk_tree_view_get_cell_area (tree_view, path, column, &tmp);
15472       gtk_tree_view_column_cell_get_position (column, cell, &start, &width);
15473
15474       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
15475                                                          tmp.x + start, 0,
15476                                                          &rect.x, NULL);
15477       rect.width = width;
15478     }
15479   else if (column)
15480     {
15481       GdkRectangle tmp;
15482
15483       gtk_tree_view_get_background_area (tree_view, NULL, column, &tmp);
15484       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
15485                                                          tmp.x, 0,
15486                                                          &rect.x, NULL);
15487       rect.width = tmp.width;
15488     }
15489   else
15490     {
15491       rect.x = 0;
15492       rect.width = GTK_WIDGET (tree_view)->allocation.width;
15493     }
15494
15495   /* Determine y values. */
15496   if (path)
15497     {
15498       GdkRectangle tmp;
15499
15500       gtk_tree_view_get_background_area (tree_view, path, NULL, &tmp);
15501       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
15502                                                          0, tmp.y,
15503                                                          NULL, &rect.y);
15504       rect.height = tmp.height;
15505     }
15506   else
15507     {
15508       rect.y = 0;
15509       rect.height = tree_view->priv->vadjustment->page_size;
15510     }
15511
15512   gtk_tooltip_set_tip_area (tooltip, &rect);
15513 }
15514
15515 /**
15516  * gtk_tree_view_get_tooltip_context:
15517  * @tree_view: a #GtkTreeView
15518  * @x: the x coordinate (relative to widget coordinates)
15519  * @y: the y coordinate (relative to widget coordinates)
15520  * @keyboard_tip: whether this is a keyboard tooltip or not
15521  * @model: a pointer to receive a #GtkTreeModel or %NULL
15522  * @path: a pointer to receive a #GtkTreePath or %NULL
15523  * @iter: a pointer to receive a #GtkTreeIter or %NULL
15524  *
15525  * This function is supposed to be used in a #GtkWidget::query-tooltip
15526  * signal handler for #GtkTreeView.  The @x, @y and @keyboard_tip values
15527  * which are received in the signal handler, should be passed to this
15528  * function without modification.
15529  *
15530  * The return value indicates whether there is a tree view row at the given
15531  * coordinates (%TRUE) or not (%FALSE) for mouse tooltips.  For keyboard
15532  * tooltips the row returned will be the cursor row.  When %TRUE, then any of
15533  * @model, @path and @iter which have been provided will be set to point to
15534  * that row and the corresponding model.  @x and @y will always be converted
15535  * to be relative to @tree_view's bin_window if @keyboard_tooltip is %FALSE.
15536  *
15537  * Return value: whether or not the given tooltip context points to a row.
15538  *
15539  * Since: 2.12
15540  */
15541 gboolean
15542 gtk_tree_view_get_tooltip_context (GtkTreeView   *tree_view,
15543                                    gint          *x,
15544                                    gint          *y,
15545                                    gboolean       keyboard_tip,
15546                                    GtkTreeModel **model,
15547                                    GtkTreePath  **path,
15548                                    GtkTreeIter   *iter)
15549 {
15550   GtkTreePath *tmppath = NULL;
15551
15552   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15553   g_return_val_if_fail (x != NULL, FALSE);
15554   g_return_val_if_fail (y != NULL, FALSE);
15555
15556   if (keyboard_tip)
15557     {
15558       gtk_tree_view_get_cursor (tree_view, &tmppath, NULL);
15559
15560       if (!tmppath)
15561         return FALSE;
15562     }
15563   else
15564     {
15565       gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, *x, *y,
15566                                                          x, y);
15567
15568       if (!gtk_tree_view_get_path_at_pos (tree_view, *x, *y,
15569                                           &tmppath, NULL, NULL, NULL))
15570         return FALSE;
15571     }
15572
15573   if (model)
15574     *model = gtk_tree_view_get_model (tree_view);
15575
15576   if (iter)
15577     gtk_tree_model_get_iter (gtk_tree_view_get_model (tree_view),
15578                              iter, tmppath);
15579
15580   if (path)
15581     *path = tmppath;
15582   else
15583     gtk_tree_path_free (tmppath);
15584
15585   return TRUE;
15586 }
15587
15588 static gboolean
15589 gtk_tree_view_set_tooltip_query_cb (GtkWidget  *widget,
15590                                     gint        x,
15591                                     gint        y,
15592                                     gboolean    keyboard_tip,
15593                                     GtkTooltip *tooltip,
15594                                     gpointer    data)
15595 {
15596   GValue value = { 0, };
15597   GValue transformed = { 0, };
15598   GtkTreeIter iter;
15599   GtkTreePath *path;
15600   GtkTreeModel *model;
15601   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
15602
15603   if (!gtk_tree_view_get_tooltip_context (GTK_TREE_VIEW (widget),
15604                                           &x, &y,
15605                                           keyboard_tip,
15606                                           &model, &path, &iter))
15607     return FALSE;
15608
15609   gtk_tree_model_get_value (model, &iter,
15610                             tree_view->priv->tooltip_column, &value);
15611
15612   g_value_init (&transformed, G_TYPE_STRING);
15613
15614   if (!g_value_transform (&value, &transformed))
15615     {
15616       g_value_unset (&value);
15617       gtk_tree_path_free (path);
15618
15619       return FALSE;
15620     }
15621
15622   g_value_unset (&value);
15623
15624   if (!g_value_get_string (&transformed))
15625     {
15626       g_value_unset (&transformed);
15627       gtk_tree_path_free (path);
15628
15629       return FALSE;
15630     }
15631
15632   gtk_tooltip_set_markup (tooltip, g_value_get_string (&transformed));
15633   gtk_tree_view_set_tooltip_row (tree_view, tooltip, path);
15634
15635   gtk_tree_path_free (path);
15636   g_value_unset (&transformed);
15637
15638   return TRUE;
15639 }
15640
15641 /**
15642  * gtk_tree_view_set_tooltip_column:
15643  * @tree_view: a #GtkTreeView
15644  * @column: an integer, which is a valid column number for @tree_view's model
15645  *
15646  * If you only plan to have simple (text-only) tooltips on full rows, you
15647  * can use this function to have #GtkTreeView handle these automatically
15648  * for you. @column should be set to the column in @tree_view's model
15649  * containing the tooltip texts, or -1 to disable this feature.
15650  *
15651  * When enabled, #GtkWidget::has-tooltip will be set to %TRUE and
15652  * @tree_view will connect a #GtkWidget::query-tooltip signal handler.
15653  *
15654  * Note that the signal handler sets the text with gtk_tooltip_set_markup(),
15655  * so &amp;, &lt;, etc have to be escaped in the text.
15656  *
15657  * Since: 2.12
15658  */
15659 void
15660 gtk_tree_view_set_tooltip_column (GtkTreeView *tree_view,
15661                                   gint         column)
15662 {
15663   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15664
15665   if (column == tree_view->priv->tooltip_column)
15666     return;
15667
15668   if (column == -1)
15669     {
15670       g_signal_handlers_disconnect_by_func (tree_view,
15671                                             gtk_tree_view_set_tooltip_query_cb,
15672                                             NULL);
15673       gtk_widget_set_has_tooltip (GTK_WIDGET (tree_view), FALSE);
15674     }
15675   else
15676     {
15677       if (tree_view->priv->tooltip_column == -1)
15678         {
15679           g_signal_connect (tree_view, "query-tooltip",
15680                             G_CALLBACK (gtk_tree_view_set_tooltip_query_cb), NULL);
15681           gtk_widget_set_has_tooltip (GTK_WIDGET (tree_view), TRUE);
15682         }
15683     }
15684
15685   tree_view->priv->tooltip_column = column;
15686   g_object_notify (G_OBJECT (tree_view), "tooltip-column");
15687 }
15688
15689 /**
15690  * gtk_tree_view_get_tooltip_column:
15691  * @tree_view: a #GtkTreeView
15692  *
15693  * Returns the column of @tree_view's model which is being used for
15694  * displaying tooltips on @tree_view's rows.
15695  *
15696  * Return value: the index of the tooltip column that is currently being
15697  * used, or -1 if this is disabled.
15698  *
15699  * Since: 2.12
15700  */
15701 gint
15702 gtk_tree_view_get_tooltip_column (GtkTreeView *tree_view)
15703 {
15704   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
15705
15706   return tree_view->priv->tooltip_column;
15707 }
15708
15709 #define __GTK_TREE_VIEW_C__
15710 #include "gtkaliasdef.c"