]> Pileus Git - ~andy/gtk/blob - gtk/gtktreeview.c
treeview: Draw lines with Cairo
[~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
48 #define GTK_TREE_VIEW_PRIORITY_VALIDATE (GDK_PRIORITY_REDRAW + 5)
49 #define GTK_TREE_VIEW_PRIORITY_SCROLL_SYNC (GTK_TREE_VIEW_PRIORITY_VALIDATE + 2)
50 #define GTK_TREE_VIEW_TIME_MS_PER_IDLE 30
51 #define SCROLL_EDGE_SIZE 15
52 #define EXPANDER_EXTRA_PADDING 4
53 #define GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT 5000
54 #define AUTO_EXPAND_TIMEOUT 500
55
56 /* The "background" areas of all rows/cells add up to cover the entire tree.
57  * The background includes all inter-row and inter-cell spacing.
58  * The "cell" areas are the cell_area passed in to gtk_cell_renderer_render(),
59  * i.e. just the cells, no spacing.
60  */
61
62 #define BACKGROUND_HEIGHT(node) (GTK_RBNODE_GET_HEIGHT (node))
63 #define CELL_HEIGHT(node, separator) ((BACKGROUND_HEIGHT (node)) - (separator))
64
65 /* Translate from bin_window coordinates to rbtree (tree coordinates) and
66  * vice versa.
67  */
68 #define TREE_WINDOW_Y_TO_RBTREE_Y(tree_view,y) ((y) + tree_view->priv->dy)
69 #define RBTREE_Y_TO_TREE_WINDOW_Y(tree_view,y) ((y) - tree_view->priv->dy)
70
71 /* This is in bin_window coordinates */
72 #define BACKGROUND_FIRST_PIXEL(tree_view,tree,node) (RBTREE_Y_TO_TREE_WINDOW_Y (tree_view, _gtk_rbtree_node_find_offset ((tree), (node))))
73 #define CELL_FIRST_PIXEL(tree_view,tree,node,separator) (BACKGROUND_FIRST_PIXEL (tree_view,tree,node) + separator/2)
74
75 #define ROW_HEIGHT(tree_view,height) \
76   ((height > 0) ? (height) : (tree_view)->priv->expander_size)
77
78
79 typedef struct _GtkTreeViewChild GtkTreeViewChild;
80 struct _GtkTreeViewChild
81 {
82   GtkWidget *widget;
83   gint x;
84   gint y;
85   gint width;
86   gint height;
87 };
88
89
90 typedef struct _TreeViewDragInfo TreeViewDragInfo;
91 struct _TreeViewDragInfo
92 {
93   GdkModifierType start_button_mask;
94   GtkTargetList *_unused_source_target_list;
95   GdkDragAction source_actions;
96
97   GtkTargetList *_unused_dest_target_list;
98
99   guint source_set : 1;
100   guint dest_set : 1;
101 };
102
103
104 /* Signals */
105 enum
106 {
107   ROW_ACTIVATED,
108   TEST_EXPAND_ROW,
109   TEST_COLLAPSE_ROW,
110   ROW_EXPANDED,
111   ROW_COLLAPSED,
112   COLUMNS_CHANGED,
113   CURSOR_CHANGED,
114   MOVE_CURSOR,
115   SELECT_ALL,
116   UNSELECT_ALL,
117   SELECT_CURSOR_ROW,
118   TOGGLE_CURSOR_ROW,
119   EXPAND_COLLAPSE_CURSOR_ROW,
120   SELECT_CURSOR_PARENT,
121   START_INTERACTIVE_SEARCH,
122   LAST_SIGNAL
123 };
124
125 /* Properties */
126 enum {
127   PROP_0,
128   PROP_MODEL,
129   PROP_HADJUSTMENT,
130   PROP_VADJUSTMENT,
131   PROP_HEADERS_VISIBLE,
132   PROP_HEADERS_CLICKABLE,
133   PROP_EXPANDER_COLUMN,
134   PROP_REORDERABLE,
135   PROP_RULES_HINT,
136   PROP_ENABLE_SEARCH,
137   PROP_SEARCH_COLUMN,
138   PROP_FIXED_HEIGHT_MODE,
139   PROP_HOVER_SELECTION,
140   PROP_HOVER_EXPAND,
141   PROP_SHOW_EXPANDERS,
142   PROP_LEVEL_INDENTATION,
143   PROP_RUBBER_BANDING,
144   PROP_ENABLE_GRID_LINES,
145   PROP_ENABLE_TREE_LINES,
146   PROP_TOOLTIP_COLUMN
147 };
148
149 /* object signals */
150 static void     gtk_tree_view_finalize             (GObject          *object);
151 static void     gtk_tree_view_set_property         (GObject         *object,
152                                                     guint            prop_id,
153                                                     const GValue    *value,
154                                                     GParamSpec      *pspec);
155 static void     gtk_tree_view_get_property         (GObject         *object,
156                                                     guint            prop_id,
157                                                     GValue          *value,
158                                                     GParamSpec      *pspec);
159
160 /* gtkobject signals */
161 static void     gtk_tree_view_destroy              (GtkObject        *object);
162
163 /* gtkwidget signals */
164 static void     gtk_tree_view_realize              (GtkWidget        *widget);
165 static void     gtk_tree_view_unrealize            (GtkWidget        *widget);
166 static void     gtk_tree_view_map                  (GtkWidget        *widget);
167 static void     gtk_tree_view_size_request         (GtkWidget        *widget,
168                                                     GtkRequisition   *requisition);
169 static void     gtk_tree_view_size_allocate        (GtkWidget        *widget,
170                                                     GtkAllocation    *allocation);
171 static gboolean gtk_tree_view_expose               (GtkWidget        *widget,
172                                                     GdkEventExpose   *event);
173 static gboolean gtk_tree_view_key_press            (GtkWidget        *widget,
174                                                     GdkEventKey      *event);
175 static gboolean gtk_tree_view_key_release          (GtkWidget        *widget,
176                                                     GdkEventKey      *event);
177 static gboolean gtk_tree_view_motion               (GtkWidget        *widget,
178                                                     GdkEventMotion   *event);
179 static gboolean gtk_tree_view_enter_notify         (GtkWidget        *widget,
180                                                     GdkEventCrossing *event);
181 static gboolean gtk_tree_view_leave_notify         (GtkWidget        *widget,
182                                                     GdkEventCrossing *event);
183 static gboolean gtk_tree_view_button_press         (GtkWidget        *widget,
184                                                     GdkEventButton   *event);
185 static gboolean gtk_tree_view_button_release       (GtkWidget        *widget,
186                                                     GdkEventButton   *event);
187 static gboolean gtk_tree_view_grab_broken          (GtkWidget          *widget,
188                                                     GdkEventGrabBroken *event);
189 #if 0
190 static gboolean gtk_tree_view_configure            (GtkWidget         *widget,
191                                                     GdkEventConfigure *event);
192 #endif
193
194 static void     gtk_tree_view_set_focus_child      (GtkContainer     *container,
195                                                     GtkWidget        *child);
196 static gint     gtk_tree_view_focus_out            (GtkWidget        *widget,
197                                                     GdkEventFocus    *event);
198 static gint     gtk_tree_view_focus                (GtkWidget        *widget,
199                                                     GtkDirectionType  direction);
200 static void     gtk_tree_view_grab_focus           (GtkWidget        *widget);
201 static void     gtk_tree_view_style_set            (GtkWidget        *widget,
202                                                     GtkStyle         *previous_style);
203 static void     gtk_tree_view_grab_notify          (GtkWidget        *widget,
204                                                     gboolean          was_grabbed);
205 static void     gtk_tree_view_state_changed        (GtkWidget        *widget,
206                                                     GtkStateType      previous_state);
207
208 /* container signals */
209 static void     gtk_tree_view_remove               (GtkContainer     *container,
210                                                     GtkWidget        *widget);
211 static void     gtk_tree_view_forall               (GtkContainer     *container,
212                                                     gboolean          include_internals,
213                                                     GtkCallback       callback,
214                                                     gpointer          callback_data);
215
216 /* Source side drag signals */
217 static void gtk_tree_view_drag_begin       (GtkWidget        *widget,
218                                             GdkDragContext   *context);
219 static void gtk_tree_view_drag_end         (GtkWidget        *widget,
220                                             GdkDragContext   *context);
221 static void gtk_tree_view_drag_data_get    (GtkWidget        *widget,
222                                             GdkDragContext   *context,
223                                             GtkSelectionData *selection_data,
224                                             guint             info,
225                                             guint             time);
226 static void gtk_tree_view_drag_data_delete (GtkWidget        *widget,
227                                             GdkDragContext   *context);
228
229 /* Target side drag signals */
230 static void     gtk_tree_view_drag_leave         (GtkWidget        *widget,
231                                                   GdkDragContext   *context,
232                                                   guint             time);
233 static gboolean gtk_tree_view_drag_motion        (GtkWidget        *widget,
234                                                   GdkDragContext   *context,
235                                                   gint              x,
236                                                   gint              y,
237                                                   guint             time);
238 static gboolean gtk_tree_view_drag_drop          (GtkWidget        *widget,
239                                                   GdkDragContext   *context,
240                                                   gint              x,
241                                                   gint              y,
242                                                   guint             time);
243 static void     gtk_tree_view_drag_data_received (GtkWidget        *widget,
244                                                   GdkDragContext   *context,
245                                                   gint              x,
246                                                   gint              y,
247                                                   GtkSelectionData *selection_data,
248                                                   guint             info,
249                                                   guint             time);
250
251 /* tree_model signals */
252 static void gtk_tree_view_set_adjustments                 (GtkTreeView     *tree_view,
253                                                            GtkAdjustment   *hadj,
254                                                            GtkAdjustment   *vadj);
255 static gboolean gtk_tree_view_real_move_cursor            (GtkTreeView     *tree_view,
256                                                            GtkMovementStep  step,
257                                                            gint             count);
258 static gboolean gtk_tree_view_real_select_all             (GtkTreeView     *tree_view);
259 static gboolean gtk_tree_view_real_unselect_all           (GtkTreeView     *tree_view);
260 static gboolean gtk_tree_view_real_select_cursor_row      (GtkTreeView     *tree_view,
261                                                            gboolean         start_editing);
262 static gboolean gtk_tree_view_real_toggle_cursor_row      (GtkTreeView     *tree_view);
263 static gboolean gtk_tree_view_real_expand_collapse_cursor_row (GtkTreeView     *tree_view,
264                                                                gboolean         logical,
265                                                                gboolean         expand,
266                                                                gboolean         open_all);
267 static gboolean gtk_tree_view_real_select_cursor_parent   (GtkTreeView     *tree_view);
268 static void gtk_tree_view_row_changed                     (GtkTreeModel    *model,
269                                                            GtkTreePath     *path,
270                                                            GtkTreeIter     *iter,
271                                                            gpointer         data);
272 static void gtk_tree_view_row_inserted                    (GtkTreeModel    *model,
273                                                            GtkTreePath     *path,
274                                                            GtkTreeIter     *iter,
275                                                            gpointer         data);
276 static void gtk_tree_view_row_has_child_toggled           (GtkTreeModel    *model,
277                                                            GtkTreePath     *path,
278                                                            GtkTreeIter     *iter,
279                                                            gpointer         data);
280 static void gtk_tree_view_row_deleted                     (GtkTreeModel    *model,
281                                                            GtkTreePath     *path,
282                                                            gpointer         data);
283 static void gtk_tree_view_rows_reordered                  (GtkTreeModel    *model,
284                                                            GtkTreePath     *parent,
285                                                            GtkTreeIter     *iter,
286                                                            gint            *new_order,
287                                                            gpointer         data);
288
289 /* Incremental reflow */
290 static gboolean validate_row             (GtkTreeView *tree_view,
291                                           GtkRBTree   *tree,
292                                           GtkRBNode   *node,
293                                           GtkTreeIter *iter,
294                                           GtkTreePath *path);
295 static void     validate_visible_area    (GtkTreeView *tree_view);
296 static gboolean validate_rows_handler    (GtkTreeView *tree_view);
297 static gboolean do_validate_rows         (GtkTreeView *tree_view,
298                                           gboolean     size_request);
299 static gboolean validate_rows            (GtkTreeView *tree_view);
300 static gboolean presize_handler_callback (gpointer     data);
301 static void     install_presize_handler  (GtkTreeView *tree_view);
302 static void     install_scroll_sync_handler (GtkTreeView *tree_view);
303 static void     gtk_tree_view_set_top_row   (GtkTreeView *tree_view,
304                                              GtkTreePath *path,
305                                              gint         offset);
306 static void     gtk_tree_view_dy_to_top_row (GtkTreeView *tree_view);
307 static void     gtk_tree_view_top_row_to_dy (GtkTreeView *tree_view);
308 static void     invalidate_empty_focus      (GtkTreeView *tree_view);
309
310 /* Internal functions */
311 static gboolean gtk_tree_view_is_expander_column             (GtkTreeView        *tree_view,
312                                                               GtkTreeViewColumn  *column);
313 static void     gtk_tree_view_add_move_binding               (GtkBindingSet      *binding_set,
314                                                               guint               keyval,
315                                                               guint               modmask,
316                                                               gboolean            add_shifted_binding,
317                                                               GtkMovementStep     step,
318                                                               gint                count);
319 static gint     gtk_tree_view_unref_and_check_selection_tree (GtkTreeView        *tree_view,
320                                                               GtkRBTree          *tree);
321 static void     gtk_tree_view_queue_draw_path                (GtkTreeView        *tree_view,
322                                                               GtkTreePath        *path,
323                                                               const GdkRectangle *clip_rect);
324 static void     gtk_tree_view_queue_draw_arrow               (GtkTreeView        *tree_view,
325                                                               GtkRBTree          *tree,
326                                                               GtkRBNode          *node,
327                                                               const GdkRectangle *clip_rect);
328 static void     gtk_tree_view_draw_arrow                     (GtkTreeView        *tree_view,
329                                                               GtkRBTree          *tree,
330                                                               GtkRBNode          *node,
331                                                               gint                x,
332                                                               gint                y);
333 static void     gtk_tree_view_get_arrow_xrange               (GtkTreeView        *tree_view,
334                                                               GtkRBTree          *tree,
335                                                               gint               *x1,
336                                                               gint               *x2);
337 static gint     gtk_tree_view_new_column_width               (GtkTreeView        *tree_view,
338                                                               gint                i,
339                                                               gint               *x);
340 static void     gtk_tree_view_adjustment_changed             (GtkAdjustment      *adjustment,
341                                                               GtkTreeView        *tree_view);
342 static void     gtk_tree_view_build_tree                     (GtkTreeView        *tree_view,
343                                                               GtkRBTree          *tree,
344                                                               GtkTreeIter        *iter,
345                                                               gint                depth,
346                                                               gboolean            recurse);
347 static void     gtk_tree_view_clamp_node_visible             (GtkTreeView        *tree_view,
348                                                               GtkRBTree          *tree,
349                                                               GtkRBNode          *node);
350 static void     gtk_tree_view_clamp_column_visible           (GtkTreeView        *tree_view,
351                                                               GtkTreeViewColumn  *column,
352                                                               gboolean            focus_to_cell);
353 static gboolean gtk_tree_view_maybe_begin_dragging_row       (GtkTreeView        *tree_view,
354                                                               GdkEventMotion     *event);
355 static void     gtk_tree_view_focus_to_cursor                (GtkTreeView        *tree_view);
356 static void     gtk_tree_view_move_cursor_up_down            (GtkTreeView        *tree_view,
357                                                               gint                count);
358 static void     gtk_tree_view_move_cursor_page_up_down       (GtkTreeView        *tree_view,
359                                                               gint                count);
360 static void     gtk_tree_view_move_cursor_left_right         (GtkTreeView        *tree_view,
361                                                               gint                count);
362 static void     gtk_tree_view_move_cursor_start_end          (GtkTreeView        *tree_view,
363                                                               gint                count);
364 static gboolean gtk_tree_view_real_collapse_row              (GtkTreeView        *tree_view,
365                                                               GtkTreePath        *path,
366                                                               GtkRBTree          *tree,
367                                                               GtkRBNode          *node,
368                                                               gboolean            animate);
369 static gboolean gtk_tree_view_real_expand_row                (GtkTreeView        *tree_view,
370                                                               GtkTreePath        *path,
371                                                               GtkRBTree          *tree,
372                                                               GtkRBNode          *node,
373                                                               gboolean            open_all,
374                                                               gboolean            animate);
375 static void     gtk_tree_view_real_set_cursor                (GtkTreeView        *tree_view,
376                                                               GtkTreePath        *path,
377                                                               gboolean            clear_and_select,
378                                                               gboolean            clamp_node);
379 static gboolean gtk_tree_view_has_special_cell               (GtkTreeView        *tree_view);
380 static void     column_sizing_notify                         (GObject            *object,
381                                                               GParamSpec         *pspec,
382                                                               gpointer            data);
383 static gboolean expand_collapse_timeout                      (gpointer            data);
384 static void     add_expand_collapse_timeout                  (GtkTreeView        *tree_view,
385                                                               GtkRBTree          *tree,
386                                                               GtkRBNode          *node,
387                                                               gboolean            expand);
388 static void     remove_expand_collapse_timeout               (GtkTreeView        *tree_view);
389 static void     cancel_arrow_animation                       (GtkTreeView        *tree_view);
390 static gboolean do_expand_collapse                           (GtkTreeView        *tree_view);
391 static void     gtk_tree_view_stop_rubber_band               (GtkTreeView        *tree_view);
392 static void     update_prelight                              (GtkTreeView        *tree_view,
393                                                               int                 x,
394                                                               int                 y);
395
396 /* interactive search */
397 static void     gtk_tree_view_ensure_interactive_directory (GtkTreeView *tree_view);
398 static void     gtk_tree_view_search_dialog_hide        (GtkWidget        *search_dialog,
399                                                          GtkTreeView      *tree_view,
400                                                          GdkDevice        *device);
401 static void     gtk_tree_view_search_position_func      (GtkTreeView      *tree_view,
402                                                          GtkWidget        *search_dialog,
403                                                          gpointer          user_data);
404 static void     gtk_tree_view_search_disable_popdown    (GtkEntry         *entry,
405                                                          GtkMenu          *menu,
406                                                          gpointer          data);
407 static void     gtk_tree_view_search_preedit_changed    (GtkIMContext     *im_context,
408                                                          GtkTreeView      *tree_view);
409 static void     gtk_tree_view_search_activate           (GtkEntry         *entry,
410                                                          GtkTreeView      *tree_view);
411 static gboolean gtk_tree_view_real_search_enable_popdown(gpointer          data);
412 static void     gtk_tree_view_search_enable_popdown     (GtkWidget        *widget,
413                                                          gpointer          data);
414 static gboolean gtk_tree_view_search_delete_event       (GtkWidget        *widget,
415                                                          GdkEventAny      *event,
416                                                          GtkTreeView      *tree_view);
417 static gboolean gtk_tree_view_search_button_press_event (GtkWidget        *widget,
418                                                          GdkEventButton   *event,
419                                                          GtkTreeView      *tree_view);
420 static gboolean gtk_tree_view_search_scroll_event       (GtkWidget        *entry,
421                                                          GdkEventScroll   *event,
422                                                          GtkTreeView      *tree_view);
423 static gboolean gtk_tree_view_search_key_press_event    (GtkWidget        *entry,
424                                                          GdkEventKey      *event,
425                                                          GtkTreeView      *tree_view);
426 static gboolean gtk_tree_view_search_move               (GtkWidget        *window,
427                                                          GtkTreeView      *tree_view,
428                                                          gboolean          up);
429 static gboolean gtk_tree_view_search_equal_func         (GtkTreeModel     *model,
430                                                          gint              column,
431                                                          const gchar      *key,
432                                                          GtkTreeIter      *iter,
433                                                          gpointer          search_data);
434 static gboolean gtk_tree_view_search_iter               (GtkTreeModel     *model,
435                                                          GtkTreeSelection *selection,
436                                                          GtkTreeIter      *iter,
437                                                          const gchar      *text,
438                                                          gint             *count,
439                                                          gint              n);
440 static void     gtk_tree_view_search_init               (GtkWidget        *entry,
441                                                          GtkTreeView      *tree_view);
442 static void     gtk_tree_view_put                       (GtkTreeView      *tree_view,
443                                                          GtkWidget        *child_widget,
444                                                          gint              x,
445                                                          gint              y,
446                                                          gint              width,
447                                                          gint              height);
448 static gboolean gtk_tree_view_start_editing             (GtkTreeView      *tree_view,
449                                                          GtkTreePath      *cursor_path);
450 static void gtk_tree_view_real_start_editing (GtkTreeView       *tree_view,
451                                               GtkTreeViewColumn *column,
452                                               GtkTreePath       *path,
453                                               GtkCellEditable   *cell_editable,
454                                               GdkRectangle      *cell_area,
455                                               GdkEvent          *event,
456                                               guint              flags);
457 static void gtk_tree_view_stop_editing                  (GtkTreeView *tree_view,
458                                                          gboolean     cancel_editing);
459 static gboolean gtk_tree_view_real_start_interactive_search (GtkTreeView *tree_view,
460                                                              GdkDevice   *device,
461                                                              gboolean     keybinding);
462 static gboolean gtk_tree_view_start_interactive_search      (GtkTreeView *tree_view);
463 static GtkTreeViewColumn *gtk_tree_view_get_drop_column (GtkTreeView       *tree_view,
464                                                          GtkTreeViewColumn *column,
465                                                          gint               drop_position);
466
467 /* GtkBuildable */
468 static void     gtk_tree_view_buildable_add_child          (GtkBuildable      *tree_view,
469                                                             GtkBuilder        *builder,
470                                                             GObject           *child,
471                                                             const gchar       *type);
472 static GObject *gtk_tree_view_buildable_get_internal_child (GtkBuildable      *buildable,
473                                                             GtkBuilder        *builder,
474                                                             const gchar       *childname);
475 static void     gtk_tree_view_buildable_init               (GtkBuildableIface *iface);
476
477
478 static gboolean scroll_row_timeout                   (gpointer     data);
479 static void     add_scroll_timeout                   (GtkTreeView *tree_view);
480 static void     remove_scroll_timeout                (GtkTreeView *tree_view);
481
482 static guint tree_view_signals [LAST_SIGNAL] = { 0 };
483
484 \f
485
486 /* GType Methods
487  */
488
489 G_DEFINE_TYPE_WITH_CODE (GtkTreeView, gtk_tree_view, GTK_TYPE_CONTAINER,
490                          G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
491                                                 gtk_tree_view_buildable_init))
492
493 static void
494 gtk_tree_view_class_init (GtkTreeViewClass *class)
495 {
496   GObjectClass *o_class;
497   GtkObjectClass *object_class;
498   GtkWidgetClass *widget_class;
499   GtkContainerClass *container_class;
500   GtkBindingSet *binding_set;
501
502   binding_set = gtk_binding_set_by_class (class);
503
504   o_class = (GObjectClass *) class;
505   object_class = (GtkObjectClass *) class;
506   widget_class = (GtkWidgetClass *) class;
507   container_class = (GtkContainerClass *) class;
508
509   /* GObject signals */
510   o_class->set_property = gtk_tree_view_set_property;
511   o_class->get_property = gtk_tree_view_get_property;
512   o_class->finalize = gtk_tree_view_finalize;
513
514   /* GtkObject signals */
515   object_class->destroy = gtk_tree_view_destroy;
516
517   /* GtkWidget signals */
518   widget_class->map = gtk_tree_view_map;
519   widget_class->realize = gtk_tree_view_realize;
520   widget_class->unrealize = gtk_tree_view_unrealize;
521   widget_class->size_request = gtk_tree_view_size_request;
522   widget_class->size_allocate = gtk_tree_view_size_allocate;
523   widget_class->button_press_event = gtk_tree_view_button_press;
524   widget_class->button_release_event = gtk_tree_view_button_release;
525   widget_class->grab_broken_event = gtk_tree_view_grab_broken;
526   /*widget_class->configure_event = gtk_tree_view_configure;*/
527   widget_class->motion_notify_event = gtk_tree_view_motion;
528   widget_class->expose_event = gtk_tree_view_expose;
529   widget_class->key_press_event = gtk_tree_view_key_press;
530   widget_class->key_release_event = gtk_tree_view_key_release;
531   widget_class->enter_notify_event = gtk_tree_view_enter_notify;
532   widget_class->leave_notify_event = gtk_tree_view_leave_notify;
533   widget_class->focus_out_event = gtk_tree_view_focus_out;
534   widget_class->drag_begin = gtk_tree_view_drag_begin;
535   widget_class->drag_end = gtk_tree_view_drag_end;
536   widget_class->drag_data_get = gtk_tree_view_drag_data_get;
537   widget_class->drag_data_delete = gtk_tree_view_drag_data_delete;
538   widget_class->drag_leave = gtk_tree_view_drag_leave;
539   widget_class->drag_motion = gtk_tree_view_drag_motion;
540   widget_class->drag_drop = gtk_tree_view_drag_drop;
541   widget_class->drag_data_received = gtk_tree_view_drag_data_received;
542   widget_class->focus = gtk_tree_view_focus;
543   widget_class->grab_focus = gtk_tree_view_grab_focus;
544   widget_class->style_set = gtk_tree_view_style_set;
545   widget_class->grab_notify = gtk_tree_view_grab_notify;
546   widget_class->state_changed = gtk_tree_view_state_changed;
547
548   /* GtkContainer signals */
549   container_class->remove = gtk_tree_view_remove;
550   container_class->forall = gtk_tree_view_forall;
551   container_class->set_focus_child = gtk_tree_view_set_focus_child;
552
553   class->set_scroll_adjustments = gtk_tree_view_set_adjustments;
554   class->move_cursor = gtk_tree_view_real_move_cursor;
555   class->select_all = gtk_tree_view_real_select_all;
556   class->unselect_all = gtk_tree_view_real_unselect_all;
557   class->select_cursor_row = gtk_tree_view_real_select_cursor_row;
558   class->toggle_cursor_row = gtk_tree_view_real_toggle_cursor_row;
559   class->expand_collapse_cursor_row = gtk_tree_view_real_expand_collapse_cursor_row;
560   class->select_cursor_parent = gtk_tree_view_real_select_cursor_parent;
561   class->start_interactive_search = gtk_tree_view_start_interactive_search;
562
563   /* Properties */
564
565   g_object_class_install_property (o_class,
566                                    PROP_MODEL,
567                                    g_param_spec_object ("model",
568                                                         P_("TreeView Model"),
569                                                         P_("The model for the tree view"),
570                                                         GTK_TYPE_TREE_MODEL,
571                                                         GTK_PARAM_READWRITE));
572
573   g_object_class_install_property (o_class,
574                                    PROP_HADJUSTMENT,
575                                    g_param_spec_object ("hadjustment",
576                                                         P_("Horizontal Adjustment"),
577                                                         P_("Horizontal Adjustment for the widget"),
578                                                         GTK_TYPE_ADJUSTMENT,
579                                                         GTK_PARAM_READWRITE));
580
581   g_object_class_install_property (o_class,
582                                    PROP_VADJUSTMENT,
583                                    g_param_spec_object ("vadjustment",
584                                                         P_("Vertical Adjustment"),
585                                                         P_("Vertical Adjustment for the widget"),
586                                                         GTK_TYPE_ADJUSTMENT,
587                                                         GTK_PARAM_READWRITE));
588
589   g_object_class_install_property (o_class,
590                                    PROP_HEADERS_VISIBLE,
591                                    g_param_spec_boolean ("headers-visible",
592                                                          P_("Headers Visible"),
593                                                          P_("Show the column header buttons"),
594                                                          TRUE,
595                                                          GTK_PARAM_READWRITE));
596
597   g_object_class_install_property (o_class,
598                                    PROP_HEADERS_CLICKABLE,
599                                    g_param_spec_boolean ("headers-clickable",
600                                                          P_("Headers Clickable"),
601                                                          P_("Column headers respond to click events"),
602                                                          TRUE,
603                                                          GTK_PARAM_READWRITE));
604
605   g_object_class_install_property (o_class,
606                                    PROP_EXPANDER_COLUMN,
607                                    g_param_spec_object ("expander-column",
608                                                         P_("Expander Column"),
609                                                         P_("Set the column for the expander column"),
610                                                         GTK_TYPE_TREE_VIEW_COLUMN,
611                                                         GTK_PARAM_READWRITE));
612
613   g_object_class_install_property (o_class,
614                                    PROP_REORDERABLE,
615                                    g_param_spec_boolean ("reorderable",
616                                                          P_("Reorderable"),
617                                                          P_("View is reorderable"),
618                                                          FALSE,
619                                                          GTK_PARAM_READWRITE));
620
621   g_object_class_install_property (o_class,
622                                    PROP_RULES_HINT,
623                                    g_param_spec_boolean ("rules-hint",
624                                                          P_("Rules Hint"),
625                                                          P_("Set a hint to the theme engine to draw rows in alternating colors"),
626                                                          FALSE,
627                                                          GTK_PARAM_READWRITE));
628
629     g_object_class_install_property (o_class,
630                                      PROP_ENABLE_SEARCH,
631                                      g_param_spec_boolean ("enable-search",
632                                                            P_("Enable Search"),
633                                                            P_("View allows user to search through columns interactively"),
634                                                            TRUE,
635                                                            GTK_PARAM_READWRITE));
636
637     g_object_class_install_property (o_class,
638                                      PROP_SEARCH_COLUMN,
639                                      g_param_spec_int ("search-column",
640                                                        P_("Search Column"),
641                                                        P_("Model column to search through during interactive search"),
642                                                        -1,
643                                                        G_MAXINT,
644                                                        -1,
645                                                        GTK_PARAM_READWRITE));
646
647     /**
648      * GtkTreeView:fixed-height-mode:
649      *
650      * Setting the ::fixed-height-mode property to %TRUE speeds up 
651      * #GtkTreeView by assuming that all rows have the same height. 
652      * Only enable this option if all rows are the same height.  
653      * Please see gtk_tree_view_set_fixed_height_mode() for more 
654      * information on this option.
655      *
656      * Since: 2.4
657      **/
658     g_object_class_install_property (o_class,
659                                      PROP_FIXED_HEIGHT_MODE,
660                                      g_param_spec_boolean ("fixed-height-mode",
661                                                            P_("Fixed Height Mode"),
662                                                            P_("Speeds up GtkTreeView by assuming that all rows have the same height"),
663                                                            FALSE,
664                                                            GTK_PARAM_READWRITE));
665     
666     /**
667      * GtkTreeView:hover-selection:
668      * 
669      * Enables of disables the hover selection mode of @tree_view.
670      * Hover selection makes the selected row follow the pointer.
671      * Currently, this works only for the selection modes 
672      * %GTK_SELECTION_SINGLE and %GTK_SELECTION_BROWSE.
673      *
674      * This mode is primarily intended for treeviews in popups, e.g.
675      * in #GtkComboBox or #GtkEntryCompletion.
676      *
677      * Since: 2.6
678      */
679     g_object_class_install_property (o_class,
680                                      PROP_HOVER_SELECTION,
681                                      g_param_spec_boolean ("hover-selection",
682                                                            P_("Hover Selection"),
683                                                            P_("Whether the selection should follow the pointer"),
684                                                            FALSE,
685                                                            GTK_PARAM_READWRITE));
686
687     /**
688      * GtkTreeView:hover-expand:
689      * 
690      * Enables of disables the hover expansion mode of @tree_view.
691      * Hover expansion makes rows expand or collapse if the pointer moves 
692      * over them.
693      *
694      * This mode is primarily intended for treeviews in popups, e.g.
695      * in #GtkComboBox or #GtkEntryCompletion.
696      *
697      * Since: 2.6
698      */
699     g_object_class_install_property (o_class,
700                                      PROP_HOVER_EXPAND,
701                                      g_param_spec_boolean ("hover-expand",
702                                                            P_("Hover Expand"),
703                                                            P_("Whether rows should be expanded/collapsed when the pointer moves over them"),
704                                                            FALSE,
705                                                            GTK_PARAM_READWRITE));
706
707     /**
708      * GtkTreeView:show-expanders:
709      *
710      * %TRUE if the view has expanders.
711      *
712      * Since: 2.12
713      */
714     g_object_class_install_property (o_class,
715                                      PROP_SHOW_EXPANDERS,
716                                      g_param_spec_boolean ("show-expanders",
717                                                            P_("Show Expanders"),
718                                                            P_("View has expanders"),
719                                                            TRUE,
720                                                            GTK_PARAM_READWRITE));
721
722     /**
723      * GtkTreeView:level-indentation:
724      *
725      * Extra indentation for each level.
726      *
727      * Since: 2.12
728      */
729     g_object_class_install_property (o_class,
730                                      PROP_LEVEL_INDENTATION,
731                                      g_param_spec_int ("level-indentation",
732                                                        P_("Level Indentation"),
733                                                        P_("Extra indentation for each level"),
734                                                        0,
735                                                        G_MAXINT,
736                                                        0,
737                                                        GTK_PARAM_READWRITE));
738
739     g_object_class_install_property (o_class,
740                                      PROP_RUBBER_BANDING,
741                                      g_param_spec_boolean ("rubber-banding",
742                                                            P_("Rubber Banding"),
743                                                            P_("Whether to enable selection of multiple items by dragging the mouse pointer"),
744                                                            FALSE,
745                                                            GTK_PARAM_READWRITE));
746
747     g_object_class_install_property (o_class,
748                                      PROP_ENABLE_GRID_LINES,
749                                      g_param_spec_enum ("enable-grid-lines",
750                                                         P_("Enable Grid Lines"),
751                                                         P_("Whether grid lines should be drawn in the tree view"),
752                                                         GTK_TYPE_TREE_VIEW_GRID_LINES,
753                                                         GTK_TREE_VIEW_GRID_LINES_NONE,
754                                                         GTK_PARAM_READWRITE));
755
756     g_object_class_install_property (o_class,
757                                      PROP_ENABLE_TREE_LINES,
758                                      g_param_spec_boolean ("enable-tree-lines",
759                                                            P_("Enable Tree Lines"),
760                                                            P_("Whether tree lines should be drawn in the tree view"),
761                                                            FALSE,
762                                                            GTK_PARAM_READWRITE));
763
764     g_object_class_install_property (o_class,
765                                      PROP_TOOLTIP_COLUMN,
766                                      g_param_spec_int ("tooltip-column",
767                                                        P_("Tooltip Column"),
768                                                        P_("The column in the model containing the tooltip texts for the rows"),
769                                                        -1,
770                                                        G_MAXINT,
771                                                        -1,
772                                                        GTK_PARAM_READWRITE));
773
774   /* Style properties */
775 #define _TREE_VIEW_EXPANDER_SIZE 12
776 #define _TREE_VIEW_VERTICAL_SEPARATOR 2
777 #define _TREE_VIEW_HORIZONTAL_SEPARATOR 2
778
779   gtk_widget_class_install_style_property (widget_class,
780                                            g_param_spec_int ("expander-size",
781                                                              P_("Expander Size"),
782                                                              P_("Size of the expander arrow"),
783                                                              0,
784                                                              G_MAXINT,
785                                                              _TREE_VIEW_EXPANDER_SIZE,
786                                                              GTK_PARAM_READABLE));
787
788   gtk_widget_class_install_style_property (widget_class,
789                                            g_param_spec_int ("vertical-separator",
790                                                              P_("Vertical Separator Width"),
791                                                              P_("Vertical space between cells.  Must be an even number"),
792                                                              0,
793                                                              G_MAXINT,
794                                                              _TREE_VIEW_VERTICAL_SEPARATOR,
795                                                              GTK_PARAM_READABLE));
796
797   gtk_widget_class_install_style_property (widget_class,
798                                            g_param_spec_int ("horizontal-separator",
799                                                              P_("Horizontal Separator Width"),
800                                                              P_("Horizontal space between cells.  Must be an even number"),
801                                                              0,
802                                                              G_MAXINT,
803                                                              _TREE_VIEW_HORIZONTAL_SEPARATOR,
804                                                              GTK_PARAM_READABLE));
805
806   gtk_widget_class_install_style_property (widget_class,
807                                            g_param_spec_boolean ("allow-rules",
808                                                                  P_("Allow Rules"),
809                                                                  P_("Allow drawing of alternating color rows"),
810                                                                  TRUE,
811                                                                  GTK_PARAM_READABLE));
812
813   gtk_widget_class_install_style_property (widget_class,
814                                            g_param_spec_boolean ("indent-expanders",
815                                                                  P_("Indent Expanders"),
816                                                                  P_("Make the expanders indented"),
817                                                                  TRUE,
818                                                                  GTK_PARAM_READABLE));
819
820   gtk_widget_class_install_style_property (widget_class,
821                                            g_param_spec_boxed ("even-row-color",
822                                                                P_("Even Row Color"),
823                                                                P_("Color to use for even rows"),
824                                                                GDK_TYPE_COLOR,
825                                                                GTK_PARAM_READABLE));
826
827   gtk_widget_class_install_style_property (widget_class,
828                                            g_param_spec_boxed ("odd-row-color",
829                                                                P_("Odd Row Color"),
830                                                                P_("Color to use for odd rows"),
831                                                                GDK_TYPE_COLOR,
832                                                                GTK_PARAM_READABLE));
833
834   gtk_widget_class_install_style_property (widget_class,
835                                            g_param_spec_boolean ("row-ending-details",
836                                                                  P_("Row Ending details"),
837                                                                  P_("Enable extended row background theming"),
838                                                                  FALSE,
839                                                                  GTK_PARAM_READABLE));
840
841   gtk_widget_class_install_style_property (widget_class,
842                                            g_param_spec_int ("grid-line-width",
843                                                              P_("Grid line width"),
844                                                              P_("Width, in pixels, of the tree view grid lines"),
845                                                              0, G_MAXINT, 1,
846                                                              GTK_PARAM_READABLE));
847
848   gtk_widget_class_install_style_property (widget_class,
849                                            g_param_spec_int ("tree-line-width",
850                                                              P_("Tree line width"),
851                                                              P_("Width, in pixels, of the tree view lines"),
852                                                              0, G_MAXINT, 1,
853                                                              GTK_PARAM_READABLE));
854
855   gtk_widget_class_install_style_property (widget_class,
856                                            g_param_spec_string ("grid-line-pattern",
857                                                                 P_("Grid line pattern"),
858                                                                 P_("Dash pattern used to draw the tree view grid lines"),
859                                                                 "\1\1",
860                                                                 GTK_PARAM_READABLE));
861
862   gtk_widget_class_install_style_property (widget_class,
863                                            g_param_spec_string ("tree-line-pattern",
864                                                                 P_("Tree line pattern"),
865                                                                 P_("Dash pattern used to draw the tree view lines"),
866                                                                 "\1\1",
867                                                                 GTK_PARAM_READABLE));
868
869   /* Signals */
870   /**
871    * GtkTreeView::set-scroll-adjustments
872    * @horizontal: the horizontal #GtkAdjustment
873    * @vertical: the vertical #GtkAdjustment
874    *
875    * Set the scroll adjustments for the tree view. Usually scrolled containers
876    * like #GtkScrolledWindow will emit this signal to connect two instances
877    * of #GtkScrollbar to the scroll directions of the #GtkTreeView.
878    */
879   widget_class->set_scroll_adjustments_signal =
880     g_signal_new (I_("set-scroll-adjustments"),
881                   G_TYPE_FROM_CLASS (o_class),
882                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
883                   G_STRUCT_OFFSET (GtkTreeViewClass, set_scroll_adjustments),
884                   NULL, NULL,
885                   _gtk_marshal_VOID__OBJECT_OBJECT,
886                   G_TYPE_NONE, 2,
887                   GTK_TYPE_ADJUSTMENT,
888                   GTK_TYPE_ADJUSTMENT);
889
890   /**
891    * GtkTreeView::row-activated:
892    * @tree_view: the object on which the signal is emitted
893    * @path: the #GtkTreePath for the activated row
894    * @column: the #GtkTreeViewColumn in which the activation occurred
895    *
896    * The "row-activated" signal is emitted when the method
897    * gtk_tree_view_row_activated() is called or the user double clicks 
898    * a treeview row. It is also emitted when a non-editable row is 
899    * selected and one of the keys: Space, Shift+Space, Return or 
900    * Enter is pressed.
901    * 
902    * For selection handling refer to the <link linkend="TreeWidget">tree 
903    * widget conceptual overview</link> as well as #GtkTreeSelection.
904    */
905   tree_view_signals[ROW_ACTIVATED] =
906     g_signal_new (I_("row-activated"),
907                   G_TYPE_FROM_CLASS (o_class),
908                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
909                   G_STRUCT_OFFSET (GtkTreeViewClass, row_activated),
910                   NULL, NULL,
911                   _gtk_marshal_VOID__BOXED_OBJECT,
912                   G_TYPE_NONE, 2,
913                   GTK_TYPE_TREE_PATH,
914                   GTK_TYPE_TREE_VIEW_COLUMN);
915
916   /**
917    * GtkTreeView::test-expand-row:
918    * @tree_view: the object on which the signal is emitted
919    * @iter: the tree iter of the row to expand
920    * @path: a tree path that points to the row 
921    * 
922    * The given row is about to be expanded (show its children nodes). Use this
923    * signal if you need to control the expandability of individual rows.
924    *
925    * Returns: %FALSE to allow expansion, %TRUE to reject
926    */
927   tree_view_signals[TEST_EXPAND_ROW] =
928     g_signal_new (I_("test-expand-row"),
929                   G_TYPE_FROM_CLASS (o_class),
930                   G_SIGNAL_RUN_LAST,
931                   G_STRUCT_OFFSET (GtkTreeViewClass, test_expand_row),
932                   _gtk_boolean_handled_accumulator, NULL,
933                   _gtk_marshal_BOOLEAN__BOXED_BOXED,
934                   G_TYPE_BOOLEAN, 2,
935                   GTK_TYPE_TREE_ITER,
936                   GTK_TYPE_TREE_PATH);
937
938   /**
939    * GtkTreeView::test-collapse-row:
940    * @tree_view: the object on which the signal is emitted
941    * @iter: the tree iter of the row to collapse
942    * @path: a tree path that points to the row 
943    * 
944    * The given row is about to be collapsed (hide its children nodes). Use this
945    * signal if you need to control the collapsibility of individual rows.
946    *
947    * Returns: %FALSE to allow collapsing, %TRUE to reject
948    */
949   tree_view_signals[TEST_COLLAPSE_ROW] =
950     g_signal_new (I_("test-collapse-row"),
951                   G_TYPE_FROM_CLASS (o_class),
952                   G_SIGNAL_RUN_LAST,
953                   G_STRUCT_OFFSET (GtkTreeViewClass, test_collapse_row),
954                   _gtk_boolean_handled_accumulator, NULL,
955                   _gtk_marshal_BOOLEAN__BOXED_BOXED,
956                   G_TYPE_BOOLEAN, 2,
957                   GTK_TYPE_TREE_ITER,
958                   GTK_TYPE_TREE_PATH);
959
960   /**
961    * GtkTreeView::row-expanded:
962    * @tree_view: the object on which the signal is emitted
963    * @iter: the tree iter of the expanded row
964    * @path: a tree path that points to the row 
965    * 
966    * The given row has been expanded (child nodes are shown).
967    */
968   tree_view_signals[ROW_EXPANDED] =
969     g_signal_new (I_("row-expanded"),
970                   G_TYPE_FROM_CLASS (o_class),
971                   G_SIGNAL_RUN_LAST,
972                   G_STRUCT_OFFSET (GtkTreeViewClass, row_expanded),
973                   NULL, NULL,
974                   _gtk_marshal_VOID__BOXED_BOXED,
975                   G_TYPE_NONE, 2,
976                   GTK_TYPE_TREE_ITER,
977                   GTK_TYPE_TREE_PATH);
978
979   /**
980    * GtkTreeView::row-collapsed:
981    * @tree_view: the object on which the signal is emitted
982    * @iter: the tree iter of the collapsed row
983    * @path: a tree path that points to the row 
984    * 
985    * The given row has been collapsed (child nodes are hidden).
986    */
987   tree_view_signals[ROW_COLLAPSED] =
988     g_signal_new (I_("row-collapsed"),
989                   G_TYPE_FROM_CLASS (o_class),
990                   G_SIGNAL_RUN_LAST,
991                   G_STRUCT_OFFSET (GtkTreeViewClass, row_collapsed),
992                   NULL, NULL,
993                   _gtk_marshal_VOID__BOXED_BOXED,
994                   G_TYPE_NONE, 2,
995                   GTK_TYPE_TREE_ITER,
996                   GTK_TYPE_TREE_PATH);
997
998   /**
999    * GtkTreeView::columns-changed:
1000    * @tree_view: the object on which the signal is emitted 
1001    * 
1002    * The number of columns of the treeview has changed.
1003    */
1004   tree_view_signals[COLUMNS_CHANGED] =
1005     g_signal_new (I_("columns-changed"),
1006                   G_TYPE_FROM_CLASS (o_class),
1007                   G_SIGNAL_RUN_LAST,
1008                   G_STRUCT_OFFSET (GtkTreeViewClass, columns_changed),
1009                   NULL, NULL,
1010                   _gtk_marshal_VOID__VOID,
1011                   G_TYPE_NONE, 0);
1012
1013   /**
1014    * GtkTreeView::cursor-changed:
1015    * @tree_view: the object on which the signal is emitted
1016    * 
1017    * The position of the cursor (focused cell) has changed.
1018    */
1019   tree_view_signals[CURSOR_CHANGED] =
1020     g_signal_new (I_("cursor-changed"),
1021                   G_TYPE_FROM_CLASS (o_class),
1022                   G_SIGNAL_RUN_LAST,
1023                   G_STRUCT_OFFSET (GtkTreeViewClass, cursor_changed),
1024                   NULL, NULL,
1025                   _gtk_marshal_VOID__VOID,
1026                   G_TYPE_NONE, 0);
1027
1028   tree_view_signals[MOVE_CURSOR] =
1029     g_signal_new (I_("move-cursor"),
1030                   G_TYPE_FROM_CLASS (object_class),
1031                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1032                   G_STRUCT_OFFSET (GtkTreeViewClass, move_cursor),
1033                   NULL, NULL,
1034                   _gtk_marshal_BOOLEAN__ENUM_INT,
1035                   G_TYPE_BOOLEAN, 2,
1036                   GTK_TYPE_MOVEMENT_STEP,
1037                   G_TYPE_INT);
1038
1039   tree_view_signals[SELECT_ALL] =
1040     g_signal_new (I_("select-all"),
1041                   G_TYPE_FROM_CLASS (object_class),
1042                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1043                   G_STRUCT_OFFSET (GtkTreeViewClass, select_all),
1044                   NULL, NULL,
1045                   _gtk_marshal_BOOLEAN__VOID,
1046                   G_TYPE_BOOLEAN, 0);
1047
1048   tree_view_signals[UNSELECT_ALL] =
1049     g_signal_new (I_("unselect-all"),
1050                   G_TYPE_FROM_CLASS (object_class),
1051                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1052                   G_STRUCT_OFFSET (GtkTreeViewClass, unselect_all),
1053                   NULL, NULL,
1054                   _gtk_marshal_BOOLEAN__VOID,
1055                   G_TYPE_BOOLEAN, 0);
1056
1057   tree_view_signals[SELECT_CURSOR_ROW] =
1058     g_signal_new (I_("select-cursor-row"),
1059                   G_TYPE_FROM_CLASS (object_class),
1060                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1061                   G_STRUCT_OFFSET (GtkTreeViewClass, select_cursor_row),
1062                   NULL, NULL,
1063                   _gtk_marshal_BOOLEAN__BOOLEAN,
1064                   G_TYPE_BOOLEAN, 1,
1065                   G_TYPE_BOOLEAN);
1066
1067   tree_view_signals[TOGGLE_CURSOR_ROW] =
1068     g_signal_new (I_("toggle-cursor-row"),
1069                   G_TYPE_FROM_CLASS (object_class),
1070                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1071                   G_STRUCT_OFFSET (GtkTreeViewClass, toggle_cursor_row),
1072                   NULL, NULL,
1073                   _gtk_marshal_BOOLEAN__VOID,
1074                   G_TYPE_BOOLEAN, 0);
1075
1076   tree_view_signals[EXPAND_COLLAPSE_CURSOR_ROW] =
1077     g_signal_new (I_("expand-collapse-cursor-row"),
1078                   G_TYPE_FROM_CLASS (object_class),
1079                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1080                   G_STRUCT_OFFSET (GtkTreeViewClass, expand_collapse_cursor_row),
1081                   NULL, NULL,
1082                   _gtk_marshal_BOOLEAN__BOOLEAN_BOOLEAN_BOOLEAN,
1083                   G_TYPE_BOOLEAN, 3,
1084                   G_TYPE_BOOLEAN,
1085                   G_TYPE_BOOLEAN,
1086                   G_TYPE_BOOLEAN);
1087
1088   tree_view_signals[SELECT_CURSOR_PARENT] =
1089     g_signal_new (I_("select-cursor-parent"),
1090                   G_TYPE_FROM_CLASS (object_class),
1091                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1092                   G_STRUCT_OFFSET (GtkTreeViewClass, select_cursor_parent),
1093                   NULL, NULL,
1094                   _gtk_marshal_BOOLEAN__VOID,
1095                   G_TYPE_BOOLEAN, 0);
1096
1097   tree_view_signals[START_INTERACTIVE_SEARCH] =
1098     g_signal_new (I_("start-interactive-search"),
1099                   G_TYPE_FROM_CLASS (object_class),
1100                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1101                   G_STRUCT_OFFSET (GtkTreeViewClass, start_interactive_search),
1102                   NULL, NULL,
1103                   _gtk_marshal_BOOLEAN__VOID,
1104                   G_TYPE_BOOLEAN, 0);
1105
1106   /* Key bindings */
1107   gtk_tree_view_add_move_binding (binding_set, GDK_Up, 0, TRUE,
1108                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
1109   gtk_tree_view_add_move_binding (binding_set, GDK_KP_Up, 0, TRUE,
1110                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
1111
1112   gtk_tree_view_add_move_binding (binding_set, GDK_Down, 0, TRUE,
1113                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
1114   gtk_tree_view_add_move_binding (binding_set, GDK_KP_Down, 0, TRUE,
1115                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
1116
1117   gtk_tree_view_add_move_binding (binding_set, GDK_p, GDK_CONTROL_MASK, FALSE,
1118                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
1119
1120   gtk_tree_view_add_move_binding (binding_set, GDK_n, GDK_CONTROL_MASK, FALSE,
1121                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
1122
1123   gtk_tree_view_add_move_binding (binding_set, GDK_Home, 0, TRUE,
1124                                   GTK_MOVEMENT_BUFFER_ENDS, -1);
1125   gtk_tree_view_add_move_binding (binding_set, GDK_KP_Home, 0, TRUE,
1126                                   GTK_MOVEMENT_BUFFER_ENDS, -1);
1127
1128   gtk_tree_view_add_move_binding (binding_set, GDK_End, 0, TRUE,
1129                                   GTK_MOVEMENT_BUFFER_ENDS, 1);
1130   gtk_tree_view_add_move_binding (binding_set, GDK_KP_End, 0, TRUE,
1131                                   GTK_MOVEMENT_BUFFER_ENDS, 1);
1132
1133   gtk_tree_view_add_move_binding (binding_set, GDK_Page_Up, 0, TRUE,
1134                                   GTK_MOVEMENT_PAGES, -1);
1135   gtk_tree_view_add_move_binding (binding_set, GDK_KP_Page_Up, 0, TRUE,
1136                                   GTK_MOVEMENT_PAGES, -1);
1137
1138   gtk_tree_view_add_move_binding (binding_set, GDK_Page_Down, 0, TRUE,
1139                                   GTK_MOVEMENT_PAGES, 1);
1140   gtk_tree_view_add_move_binding (binding_set, GDK_KP_Page_Down, 0, TRUE,
1141                                   GTK_MOVEMENT_PAGES, 1);
1142
1143
1144   gtk_binding_entry_add_signal (binding_set, GDK_Right, 0, "move-cursor", 2,
1145                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1146                                 G_TYPE_INT, 1);
1147
1148   gtk_binding_entry_add_signal (binding_set, GDK_Left, 0, "move-cursor", 2,
1149                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1150                                 G_TYPE_INT, -1);
1151
1152   gtk_binding_entry_add_signal (binding_set, GDK_KP_Right, 0, "move-cursor", 2,
1153                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1154                                 G_TYPE_INT, 1);
1155
1156   gtk_binding_entry_add_signal (binding_set, GDK_KP_Left, 0, "move-cursor", 2,
1157                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1158                                 G_TYPE_INT, -1);
1159
1160   gtk_binding_entry_add_signal (binding_set, GDK_Right, GDK_CONTROL_MASK,
1161                                 "move-cursor", 2,
1162                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1163                                 G_TYPE_INT, 1);
1164
1165   gtk_binding_entry_add_signal (binding_set, GDK_Left, GDK_CONTROL_MASK,
1166                                 "move-cursor", 2,
1167                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1168                                 G_TYPE_INT, -1);
1169
1170   gtk_binding_entry_add_signal (binding_set, GDK_KP_Right, GDK_CONTROL_MASK,
1171                                 "move-cursor", 2,
1172                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1173                                 G_TYPE_INT, 1);
1174
1175   gtk_binding_entry_add_signal (binding_set, GDK_KP_Left, GDK_CONTROL_MASK,
1176                                 "move-cursor", 2,
1177                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1178                                 G_TYPE_INT, -1);
1179
1180   gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_CONTROL_MASK, "toggle-cursor-row", 0);
1181   gtk_binding_entry_add_signal (binding_set, GDK_KP_Space, GDK_CONTROL_MASK, "toggle-cursor-row", 0);
1182
1183   gtk_binding_entry_add_signal (binding_set, GDK_a, GDK_CONTROL_MASK, "select-all", 0);
1184   gtk_binding_entry_add_signal (binding_set, GDK_slash, GDK_CONTROL_MASK, "select-all", 0);
1185
1186   gtk_binding_entry_add_signal (binding_set, GDK_A, GDK_CONTROL_MASK | GDK_SHIFT_MASK, "unselect-all", 0);
1187   gtk_binding_entry_add_signal (binding_set, GDK_backslash, GDK_CONTROL_MASK, "unselect-all", 0);
1188
1189   gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_SHIFT_MASK, "select-cursor-row", 1,
1190                                 G_TYPE_BOOLEAN, TRUE);
1191   gtk_binding_entry_add_signal (binding_set, GDK_KP_Space, GDK_SHIFT_MASK, "select-cursor-row", 1,
1192                                 G_TYPE_BOOLEAN, TRUE);
1193
1194   gtk_binding_entry_add_signal (binding_set, GDK_space, 0, "select-cursor-row", 1,
1195                                 G_TYPE_BOOLEAN, TRUE);
1196   gtk_binding_entry_add_signal (binding_set, GDK_KP_Space, 0, "select-cursor-row", 1,
1197                                 G_TYPE_BOOLEAN, TRUE);
1198   gtk_binding_entry_add_signal (binding_set, GDK_Return, 0, "select-cursor-row", 1,
1199                                 G_TYPE_BOOLEAN, TRUE);
1200   gtk_binding_entry_add_signal (binding_set, GDK_ISO_Enter, 0, "select-cursor-row", 1,
1201                                 G_TYPE_BOOLEAN, TRUE);
1202   gtk_binding_entry_add_signal (binding_set, GDK_KP_Enter, 0, "select-cursor-row", 1,
1203                                 G_TYPE_BOOLEAN, TRUE);
1204
1205   /* expand and collapse rows */
1206   gtk_binding_entry_add_signal (binding_set, GDK_plus, 0, "expand-collapse-cursor-row", 3,
1207                                 G_TYPE_BOOLEAN, TRUE,
1208                                 G_TYPE_BOOLEAN, TRUE,
1209                                 G_TYPE_BOOLEAN, FALSE);
1210
1211   gtk_binding_entry_add_signal (binding_set, GDK_asterisk, 0,
1212                                 "expand-collapse-cursor-row", 3,
1213                                 G_TYPE_BOOLEAN, TRUE,
1214                                 G_TYPE_BOOLEAN, TRUE,
1215                                 G_TYPE_BOOLEAN, TRUE);
1216   gtk_binding_entry_add_signal (binding_set, GDK_KP_Multiply, 0,
1217                                 "expand-collapse-cursor-row", 3,
1218                                 G_TYPE_BOOLEAN, TRUE,
1219                                 G_TYPE_BOOLEAN, TRUE,
1220                                 G_TYPE_BOOLEAN, TRUE);
1221
1222   gtk_binding_entry_add_signal (binding_set, GDK_slash, 0,
1223                                 "expand-collapse-cursor-row", 3,
1224                                 G_TYPE_BOOLEAN, TRUE,
1225                                 G_TYPE_BOOLEAN, FALSE,
1226                                 G_TYPE_BOOLEAN, FALSE);
1227   gtk_binding_entry_add_signal (binding_set, GDK_KP_Divide, 0,
1228                                 "expand-collapse-cursor-row", 3,
1229                                 G_TYPE_BOOLEAN, TRUE,
1230                                 G_TYPE_BOOLEAN, FALSE,
1231                                 G_TYPE_BOOLEAN, FALSE);
1232
1233   /* Not doable on US keyboards */
1234   gtk_binding_entry_add_signal (binding_set, GDK_plus, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1235                                 G_TYPE_BOOLEAN, TRUE,
1236                                 G_TYPE_BOOLEAN, TRUE,
1237                                 G_TYPE_BOOLEAN, TRUE);
1238   gtk_binding_entry_add_signal (binding_set, GDK_KP_Add, 0, "expand-collapse-cursor-row", 3,
1239                                 G_TYPE_BOOLEAN, TRUE,
1240                                 G_TYPE_BOOLEAN, TRUE,
1241                                 G_TYPE_BOOLEAN, FALSE);
1242   gtk_binding_entry_add_signal (binding_set, GDK_KP_Add, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1243                                 G_TYPE_BOOLEAN, TRUE,
1244                                 G_TYPE_BOOLEAN, TRUE,
1245                                 G_TYPE_BOOLEAN, TRUE);
1246   gtk_binding_entry_add_signal (binding_set, GDK_KP_Add, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1247                                 G_TYPE_BOOLEAN, TRUE,
1248                                 G_TYPE_BOOLEAN, TRUE,
1249                                 G_TYPE_BOOLEAN, TRUE);
1250   gtk_binding_entry_add_signal (binding_set, GDK_Right, GDK_SHIFT_MASK,
1251                                 "expand-collapse-cursor-row", 3,
1252                                 G_TYPE_BOOLEAN, FALSE,
1253                                 G_TYPE_BOOLEAN, TRUE,
1254                                 G_TYPE_BOOLEAN, TRUE);
1255   gtk_binding_entry_add_signal (binding_set, GDK_KP_Right, GDK_SHIFT_MASK,
1256                                 "expand-collapse-cursor-row", 3,
1257                                 G_TYPE_BOOLEAN, FALSE,
1258                                 G_TYPE_BOOLEAN, TRUE,
1259                                 G_TYPE_BOOLEAN, TRUE);
1260   gtk_binding_entry_add_signal (binding_set, GDK_Right,
1261                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1262                                 "expand-collapse-cursor-row", 3,
1263                                 G_TYPE_BOOLEAN, FALSE,
1264                                 G_TYPE_BOOLEAN, TRUE,
1265                                 G_TYPE_BOOLEAN, TRUE);
1266   gtk_binding_entry_add_signal (binding_set, GDK_KP_Right,
1267                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1268                                 "expand-collapse-cursor-row", 3,
1269                                 G_TYPE_BOOLEAN, FALSE,
1270                                 G_TYPE_BOOLEAN, TRUE,
1271                                 G_TYPE_BOOLEAN, TRUE);
1272
1273   gtk_binding_entry_add_signal (binding_set, GDK_minus, 0, "expand-collapse-cursor-row", 3,
1274                                 G_TYPE_BOOLEAN, TRUE,
1275                                 G_TYPE_BOOLEAN, FALSE,
1276                                 G_TYPE_BOOLEAN, FALSE);
1277   gtk_binding_entry_add_signal (binding_set, GDK_minus, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1278                                 G_TYPE_BOOLEAN, TRUE,
1279                                 G_TYPE_BOOLEAN, FALSE,
1280                                 G_TYPE_BOOLEAN, TRUE);
1281   gtk_binding_entry_add_signal (binding_set, GDK_KP_Subtract, 0, "expand-collapse-cursor-row", 3,
1282                                 G_TYPE_BOOLEAN, TRUE,
1283                                 G_TYPE_BOOLEAN, FALSE,
1284                                 G_TYPE_BOOLEAN, FALSE);
1285   gtk_binding_entry_add_signal (binding_set, GDK_KP_Subtract, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1286                                 G_TYPE_BOOLEAN, TRUE,
1287                                 G_TYPE_BOOLEAN, FALSE,
1288                                 G_TYPE_BOOLEAN, TRUE);
1289   gtk_binding_entry_add_signal (binding_set, GDK_Left, GDK_SHIFT_MASK,
1290                                 "expand-collapse-cursor-row", 3,
1291                                 G_TYPE_BOOLEAN, FALSE,
1292                                 G_TYPE_BOOLEAN, FALSE,
1293                                 G_TYPE_BOOLEAN, TRUE);
1294   gtk_binding_entry_add_signal (binding_set, GDK_KP_Left, GDK_SHIFT_MASK,
1295                                 "expand-collapse-cursor-row", 3,
1296                                 G_TYPE_BOOLEAN, FALSE,
1297                                 G_TYPE_BOOLEAN, FALSE,
1298                                 G_TYPE_BOOLEAN, TRUE);
1299   gtk_binding_entry_add_signal (binding_set, GDK_Left,
1300                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1301                                 "expand-collapse-cursor-row", 3,
1302                                 G_TYPE_BOOLEAN, FALSE,
1303                                 G_TYPE_BOOLEAN, FALSE,
1304                                 G_TYPE_BOOLEAN, TRUE);
1305   gtk_binding_entry_add_signal (binding_set, GDK_KP_Left,
1306                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1307                                 "expand-collapse-cursor-row", 3,
1308                                 G_TYPE_BOOLEAN, FALSE,
1309                                 G_TYPE_BOOLEAN, FALSE,
1310                                 G_TYPE_BOOLEAN, TRUE);
1311
1312   gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, 0, "select-cursor-parent", 0);
1313   gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, GDK_CONTROL_MASK, "select-cursor-parent", 0);
1314
1315   gtk_binding_entry_add_signal (binding_set, GDK_f, GDK_CONTROL_MASK, "start-interactive-search", 0);
1316
1317   gtk_binding_entry_add_signal (binding_set, GDK_F, GDK_CONTROL_MASK, "start-interactive-search", 0);
1318
1319   g_type_class_add_private (o_class, sizeof (GtkTreeViewPrivate));
1320 }
1321
1322 static void
1323 gtk_tree_view_init (GtkTreeView *tree_view)
1324 {
1325   tree_view->priv = G_TYPE_INSTANCE_GET_PRIVATE (tree_view, GTK_TYPE_TREE_VIEW, GtkTreeViewPrivate);
1326
1327   gtk_widget_set_can_focus (GTK_WIDGET (tree_view), TRUE);
1328   gtk_widget_set_redraw_on_allocate (GTK_WIDGET (tree_view), FALSE);
1329
1330   tree_view->priv->flags =  GTK_TREE_VIEW_SHOW_EXPANDERS
1331                             | GTK_TREE_VIEW_DRAW_KEYFOCUS
1332                             | GTK_TREE_VIEW_HEADERS_VISIBLE;
1333
1334   /* We need some padding */
1335   tree_view->priv->dy = 0;
1336   tree_view->priv->cursor_offset = 0;
1337   tree_view->priv->n_columns = 0;
1338   tree_view->priv->header_height = 1;
1339   tree_view->priv->x_drag = 0;
1340   tree_view->priv->drag_pos = -1;
1341   tree_view->priv->header_has_focus = FALSE;
1342   tree_view->priv->pressed_button = -1;
1343   tree_view->priv->press_start_x = -1;
1344   tree_view->priv->press_start_y = -1;
1345   tree_view->priv->reorderable = FALSE;
1346   tree_view->priv->presize_handler_timer = 0;
1347   tree_view->priv->scroll_sync_timer = 0;
1348   tree_view->priv->fixed_height = -1;
1349   tree_view->priv->fixed_height_mode = FALSE;
1350   tree_view->priv->fixed_height_check = 0;
1351   gtk_tree_view_set_adjustments (tree_view, NULL, NULL);
1352   tree_view->priv->selection = _gtk_tree_selection_new_with_tree_view (tree_view);
1353   tree_view->priv->enable_search = TRUE;
1354   tree_view->priv->search_column = -1;
1355   tree_view->priv->search_position_func = gtk_tree_view_search_position_func;
1356   tree_view->priv->search_equal_func = gtk_tree_view_search_equal_func;
1357   tree_view->priv->search_custom_entry_set = FALSE;
1358   tree_view->priv->typeselect_flush_timeout = 0;
1359   tree_view->priv->init_hadjust_value = TRUE;    
1360   tree_view->priv->width = 0;
1361           
1362   tree_view->priv->hover_selection = FALSE;
1363   tree_view->priv->hover_expand = FALSE;
1364
1365   tree_view->priv->level_indentation = 0;
1366
1367   tree_view->priv->rubber_banding_enable = FALSE;
1368
1369   tree_view->priv->grid_lines = GTK_TREE_VIEW_GRID_LINES_NONE;
1370   tree_view->priv->tree_lines_enabled = FALSE;
1371
1372   tree_view->priv->tooltip_column = -1;
1373
1374   tree_view->priv->post_validation_flag = FALSE;
1375
1376   tree_view->priv->last_button_x = -1;
1377   tree_view->priv->last_button_y = -1;
1378
1379   tree_view->priv->event_last_x = -10000;
1380   tree_view->priv->event_last_y = -10000;
1381 }
1382
1383 \f
1384
1385 /* GObject Methods
1386  */
1387
1388 static void
1389 gtk_tree_view_set_property (GObject         *object,
1390                             guint            prop_id,
1391                             const GValue    *value,
1392                             GParamSpec      *pspec)
1393 {
1394   GtkTreeView *tree_view;
1395
1396   tree_view = GTK_TREE_VIEW (object);
1397
1398   switch (prop_id)
1399     {
1400     case PROP_MODEL:
1401       gtk_tree_view_set_model (tree_view, g_value_get_object (value));
1402       break;
1403     case PROP_HADJUSTMENT:
1404       gtk_tree_view_set_hadjustment (tree_view, g_value_get_object (value));
1405       break;
1406     case PROP_VADJUSTMENT:
1407       gtk_tree_view_set_vadjustment (tree_view, g_value_get_object (value));
1408       break;
1409     case PROP_HEADERS_VISIBLE:
1410       gtk_tree_view_set_headers_visible (tree_view, g_value_get_boolean (value));
1411       break;
1412     case PROP_HEADERS_CLICKABLE:
1413       gtk_tree_view_set_headers_clickable (tree_view, g_value_get_boolean (value));
1414       break;
1415     case PROP_EXPANDER_COLUMN:
1416       gtk_tree_view_set_expander_column (tree_view, g_value_get_object (value));
1417       break;
1418     case PROP_REORDERABLE:
1419       gtk_tree_view_set_reorderable (tree_view, g_value_get_boolean (value));
1420       break;
1421     case PROP_RULES_HINT:
1422       gtk_tree_view_set_rules_hint (tree_view, g_value_get_boolean (value));
1423       break;
1424     case PROP_ENABLE_SEARCH:
1425       gtk_tree_view_set_enable_search (tree_view, g_value_get_boolean (value));
1426       break;
1427     case PROP_SEARCH_COLUMN:
1428       gtk_tree_view_set_search_column (tree_view, g_value_get_int (value));
1429       break;
1430     case PROP_FIXED_HEIGHT_MODE:
1431       gtk_tree_view_set_fixed_height_mode (tree_view, g_value_get_boolean (value));
1432       break;
1433     case PROP_HOVER_SELECTION:
1434       tree_view->priv->hover_selection = g_value_get_boolean (value);
1435       break;
1436     case PROP_HOVER_EXPAND:
1437       tree_view->priv->hover_expand = g_value_get_boolean (value);
1438       break;
1439     case PROP_SHOW_EXPANDERS:
1440       gtk_tree_view_set_show_expanders (tree_view, g_value_get_boolean (value));
1441       break;
1442     case PROP_LEVEL_INDENTATION:
1443       tree_view->priv->level_indentation = g_value_get_int (value);
1444       break;
1445     case PROP_RUBBER_BANDING:
1446       tree_view->priv->rubber_banding_enable = g_value_get_boolean (value);
1447       break;
1448     case PROP_ENABLE_GRID_LINES:
1449       gtk_tree_view_set_grid_lines (tree_view, g_value_get_enum (value));
1450       break;
1451     case PROP_ENABLE_TREE_LINES:
1452       gtk_tree_view_set_enable_tree_lines (tree_view, g_value_get_boolean (value));
1453       break;
1454     case PROP_TOOLTIP_COLUMN:
1455       gtk_tree_view_set_tooltip_column (tree_view, g_value_get_int (value));
1456       break;
1457     default:
1458       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1459       break;
1460     }
1461 }
1462
1463 static void
1464 gtk_tree_view_get_property (GObject    *object,
1465                             guint       prop_id,
1466                             GValue     *value,
1467                             GParamSpec *pspec)
1468 {
1469   GtkTreeView *tree_view;
1470
1471   tree_view = GTK_TREE_VIEW (object);
1472
1473   switch (prop_id)
1474     {
1475     case PROP_MODEL:
1476       g_value_set_object (value, tree_view->priv->model);
1477       break;
1478     case PROP_HADJUSTMENT:
1479       g_value_set_object (value, tree_view->priv->hadjustment);
1480       break;
1481     case PROP_VADJUSTMENT:
1482       g_value_set_object (value, tree_view->priv->vadjustment);
1483       break;
1484     case PROP_HEADERS_VISIBLE:
1485       g_value_set_boolean (value, gtk_tree_view_get_headers_visible (tree_view));
1486       break;
1487     case PROP_HEADERS_CLICKABLE:
1488       g_value_set_boolean (value, gtk_tree_view_get_headers_clickable (tree_view));
1489       break;
1490     case PROP_EXPANDER_COLUMN:
1491       g_value_set_object (value, tree_view->priv->expander_column);
1492       break;
1493     case PROP_REORDERABLE:
1494       g_value_set_boolean (value, tree_view->priv->reorderable);
1495       break;
1496     case PROP_RULES_HINT:
1497       g_value_set_boolean (value, tree_view->priv->has_rules);
1498       break;
1499     case PROP_ENABLE_SEARCH:
1500       g_value_set_boolean (value, tree_view->priv->enable_search);
1501       break;
1502     case PROP_SEARCH_COLUMN:
1503       g_value_set_int (value, tree_view->priv->search_column);
1504       break;
1505     case PROP_FIXED_HEIGHT_MODE:
1506       g_value_set_boolean (value, tree_view->priv->fixed_height_mode);
1507       break;
1508     case PROP_HOVER_SELECTION:
1509       g_value_set_boolean (value, tree_view->priv->hover_selection);
1510       break;
1511     case PROP_HOVER_EXPAND:
1512       g_value_set_boolean (value, tree_view->priv->hover_expand);
1513       break;
1514     case PROP_SHOW_EXPANDERS:
1515       g_value_set_boolean (value, GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS));
1516       break;
1517     case PROP_LEVEL_INDENTATION:
1518       g_value_set_int (value, tree_view->priv->level_indentation);
1519       break;
1520     case PROP_RUBBER_BANDING:
1521       g_value_set_boolean (value, tree_view->priv->rubber_banding_enable);
1522       break;
1523     case PROP_ENABLE_GRID_LINES:
1524       g_value_set_enum (value, tree_view->priv->grid_lines);
1525       break;
1526     case PROP_ENABLE_TREE_LINES:
1527       g_value_set_boolean (value, tree_view->priv->tree_lines_enabled);
1528       break;
1529     case PROP_TOOLTIP_COLUMN:
1530       g_value_set_int (value, tree_view->priv->tooltip_column);
1531       break;
1532     default:
1533       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1534       break;
1535     }
1536 }
1537
1538 static void
1539 gtk_tree_view_finalize (GObject *object)
1540 {
1541   G_OBJECT_CLASS (gtk_tree_view_parent_class)->finalize (object);
1542 }
1543
1544
1545 static GtkBuildableIface *parent_buildable_iface;
1546
1547 static void
1548 gtk_tree_view_buildable_init (GtkBuildableIface *iface)
1549 {
1550   parent_buildable_iface = g_type_interface_peek_parent (iface);
1551   iface->add_child = gtk_tree_view_buildable_add_child;
1552   iface->get_internal_child = gtk_tree_view_buildable_get_internal_child;
1553 }
1554
1555 static void
1556 gtk_tree_view_buildable_add_child (GtkBuildable *tree_view,
1557                                    GtkBuilder  *builder,
1558                                    GObject     *child,
1559                                    const gchar *type)
1560 {
1561   gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), GTK_TREE_VIEW_COLUMN (child));
1562 }
1563
1564 static GObject *
1565 gtk_tree_view_buildable_get_internal_child (GtkBuildable      *buildable,
1566                                             GtkBuilder        *builder,
1567                                             const gchar       *childname)
1568 {
1569     if (strcmp (childname, "selection") == 0)
1570       return G_OBJECT (GTK_TREE_VIEW (buildable)->priv->selection);
1571     
1572     return parent_buildable_iface->get_internal_child (buildable,
1573                                                        builder,
1574                                                        childname);
1575 }
1576
1577 /* GtkObject Methods
1578  */
1579
1580 static void
1581 gtk_tree_view_free_rbtree (GtkTreeView *tree_view)
1582 {
1583   _gtk_rbtree_free (tree_view->priv->tree);
1584   
1585   tree_view->priv->tree = NULL;
1586   tree_view->priv->button_pressed_node = NULL;
1587   tree_view->priv->button_pressed_tree = NULL;
1588   tree_view->priv->prelight_tree = NULL;
1589   tree_view->priv->prelight_node = NULL;
1590   tree_view->priv->expanded_collapsed_node = NULL;
1591   tree_view->priv->expanded_collapsed_tree = NULL;
1592 }
1593
1594 static void
1595 gtk_tree_view_destroy (GtkObject *object)
1596 {
1597   GtkTreeView *tree_view = GTK_TREE_VIEW (object);
1598   GList *list;
1599
1600   gtk_tree_view_stop_editing (tree_view, TRUE);
1601
1602   if (tree_view->priv->columns != NULL)
1603     {
1604       list = tree_view->priv->columns;
1605       while (list)
1606         {
1607           GtkTreeViewColumn *column;
1608           column = GTK_TREE_VIEW_COLUMN (list->data);
1609           list = list->next;
1610           gtk_tree_view_remove_column (tree_view, column);
1611         }
1612       tree_view->priv->columns = NULL;
1613     }
1614
1615   if (tree_view->priv->tree != NULL)
1616     {
1617       gtk_tree_view_unref_and_check_selection_tree (tree_view, tree_view->priv->tree);
1618
1619       gtk_tree_view_free_rbtree (tree_view);
1620     }
1621
1622   if (tree_view->priv->selection != NULL)
1623     {
1624       _gtk_tree_selection_set_tree_view (tree_view->priv->selection, NULL);
1625       g_object_unref (tree_view->priv->selection);
1626       tree_view->priv->selection = NULL;
1627     }
1628
1629   if (tree_view->priv->scroll_to_path != NULL)
1630     {
1631       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
1632       tree_view->priv->scroll_to_path = NULL;
1633     }
1634
1635   if (tree_view->priv->drag_dest_row != NULL)
1636     {
1637       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
1638       tree_view->priv->drag_dest_row = NULL;
1639     }
1640
1641   if (tree_view->priv->top_row != NULL)
1642     {
1643       gtk_tree_row_reference_free (tree_view->priv->top_row);
1644       tree_view->priv->top_row = NULL;
1645     }
1646
1647   if (tree_view->priv->column_drop_func_data &&
1648       tree_view->priv->column_drop_func_data_destroy)
1649     {
1650       tree_view->priv->column_drop_func_data_destroy (tree_view->priv->column_drop_func_data);
1651       tree_view->priv->column_drop_func_data = NULL;
1652     }
1653
1654   if (tree_view->priv->destroy_count_destroy &&
1655       tree_view->priv->destroy_count_data)
1656     {
1657       tree_view->priv->destroy_count_destroy (tree_view->priv->destroy_count_data);
1658       tree_view->priv->destroy_count_data = NULL;
1659     }
1660
1661   gtk_tree_row_reference_free (tree_view->priv->cursor);
1662   tree_view->priv->cursor = NULL;
1663
1664   gtk_tree_row_reference_free (tree_view->priv->anchor);
1665   tree_view->priv->anchor = NULL;
1666
1667   /* destroy interactive search dialog */
1668   if (tree_view->priv->search_window)
1669     {
1670       gtk_widget_destroy (tree_view->priv->search_window);
1671       tree_view->priv->search_window = NULL;
1672       tree_view->priv->search_entry = NULL;
1673       if (tree_view->priv->typeselect_flush_timeout)
1674         {
1675           g_source_remove (tree_view->priv->typeselect_flush_timeout);
1676           tree_view->priv->typeselect_flush_timeout = 0;
1677         }
1678     }
1679
1680   if (tree_view->priv->search_destroy && tree_view->priv->search_user_data)
1681     {
1682       tree_view->priv->search_destroy (tree_view->priv->search_user_data);
1683       tree_view->priv->search_user_data = NULL;
1684     }
1685
1686   if (tree_view->priv->search_position_destroy && tree_view->priv->search_position_user_data)
1687     {
1688       tree_view->priv->search_position_destroy (tree_view->priv->search_position_user_data);
1689       tree_view->priv->search_position_user_data = NULL;
1690     }
1691
1692   if (tree_view->priv->row_separator_destroy && tree_view->priv->row_separator_data)
1693     {
1694       tree_view->priv->row_separator_destroy (tree_view->priv->row_separator_data);
1695       tree_view->priv->row_separator_data = NULL;
1696     }
1697   
1698   gtk_tree_view_set_model (tree_view, NULL);
1699
1700   if (tree_view->priv->hadjustment)
1701     {
1702       g_object_unref (tree_view->priv->hadjustment);
1703       tree_view->priv->hadjustment = NULL;
1704     }
1705   if (tree_view->priv->vadjustment)
1706     {
1707       g_object_unref (tree_view->priv->vadjustment);
1708       tree_view->priv->vadjustment = NULL;
1709     }
1710
1711   GTK_OBJECT_CLASS (gtk_tree_view_parent_class)->destroy (object);
1712 }
1713
1714 \f
1715
1716 /* GtkWidget Methods
1717  */
1718
1719 /* GtkWidget::map helper */
1720 static void
1721 gtk_tree_view_map_buttons (GtkTreeView *tree_view)
1722 {
1723   GList *list;
1724
1725   g_return_if_fail (gtk_widget_get_mapped (GTK_WIDGET (tree_view)));
1726
1727   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
1728     {
1729       GtkTreeViewColumn *column;
1730
1731       for (list = tree_view->priv->columns; list; list = list->next)
1732         {
1733           column = list->data;
1734           if (gtk_widget_get_visible (column->button) &&
1735               !gtk_widget_get_mapped (column->button))
1736             gtk_widget_map (column->button);
1737         }
1738       for (list = tree_view->priv->columns; list; list = list->next)
1739         {
1740           column = list->data;
1741           if (column->visible == FALSE)
1742             continue;
1743           if (column->resizable)
1744             {
1745               gdk_window_raise (column->window);
1746               gdk_window_show (column->window);
1747             }
1748           else
1749             gdk_window_hide (column->window);
1750         }
1751       gdk_window_show (tree_view->priv->header_window);
1752     }
1753 }
1754
1755 static void
1756 gtk_tree_view_map (GtkWidget *widget)
1757 {
1758   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
1759   GList *tmp_list;
1760
1761   gtk_widget_set_mapped (widget, TRUE);
1762
1763   tmp_list = tree_view->priv->children;
1764   while (tmp_list)
1765     {
1766       GtkTreeViewChild *child = tmp_list->data;
1767       tmp_list = tmp_list->next;
1768
1769       if (gtk_widget_get_visible (child->widget))
1770         {
1771           if (!gtk_widget_get_mapped (child->widget))
1772             gtk_widget_map (child->widget);
1773         }
1774     }
1775   gdk_window_show (tree_view->priv->bin_window);
1776
1777   gtk_tree_view_map_buttons (tree_view);
1778
1779   gdk_window_show (widget->window);
1780 }
1781
1782 static void
1783 gtk_tree_view_realize (GtkWidget *widget)
1784 {
1785   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
1786   GList *tmp_list;
1787   GdkWindowAttr attributes;
1788   gint attributes_mask;
1789
1790   gtk_widget_set_realized (widget, TRUE);
1791
1792   /* Make the main, clipping window */
1793   attributes.window_type = GDK_WINDOW_CHILD;
1794   attributes.x = widget->allocation.x;
1795   attributes.y = widget->allocation.y;
1796   attributes.width = widget->allocation.width;
1797   attributes.height = widget->allocation.height;
1798   attributes.wclass = GDK_INPUT_OUTPUT;
1799   attributes.visual = gtk_widget_get_visual (widget);
1800   attributes.colormap = gtk_widget_get_colormap (widget);
1801   attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK;
1802
1803   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
1804
1805   widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
1806                                    &attributes, attributes_mask);
1807   gdk_window_set_user_data (widget->window, widget);
1808
1809   /* Make the window for the tree */
1810   attributes.x = 0;
1811   attributes.y = TREE_VIEW_HEADER_HEIGHT (tree_view);
1812   attributes.width = MAX (tree_view->priv->width, widget->allocation.width);
1813   attributes.height = widget->allocation.height;
1814   attributes.event_mask = (GDK_EXPOSURE_MASK |
1815                            GDK_SCROLL_MASK |
1816                            GDK_POINTER_MOTION_MASK |
1817                            GDK_ENTER_NOTIFY_MASK |
1818                            GDK_LEAVE_NOTIFY_MASK |
1819                            GDK_BUTTON_PRESS_MASK |
1820                            GDK_BUTTON_RELEASE_MASK |
1821                            gtk_widget_get_events (widget));
1822
1823   tree_view->priv->bin_window = gdk_window_new (widget->window,
1824                                                 &attributes, attributes_mask);
1825   gdk_window_set_user_data (tree_view->priv->bin_window, widget);
1826
1827   /* Make the column header window */
1828   attributes.x = 0;
1829   attributes.y = 0;
1830   attributes.width = MAX (tree_view->priv->width, widget->allocation.width);
1831   attributes.height = tree_view->priv->header_height;
1832   attributes.event_mask = (GDK_EXPOSURE_MASK |
1833                            GDK_SCROLL_MASK |
1834                            GDK_ENTER_NOTIFY_MASK |
1835                            GDK_LEAVE_NOTIFY_MASK |
1836                            GDK_BUTTON_PRESS_MASK |
1837                            GDK_BUTTON_RELEASE_MASK |
1838                            GDK_KEY_PRESS_MASK |
1839                            GDK_KEY_RELEASE_MASK |
1840                            gtk_widget_get_events (widget));
1841
1842   tree_view->priv->header_window = gdk_window_new (widget->window,
1843                                                    &attributes, attributes_mask);
1844   gdk_window_set_user_data (tree_view->priv->header_window, widget);
1845
1846   /* Add them all up. */
1847   widget->style = gtk_style_attach (widget->style, widget->window);
1848   gdk_window_set_back_pixmap (widget->window, NULL, FALSE);
1849   gdk_window_set_background (tree_view->priv->bin_window, &widget->style->base[widget->state]);
1850   gtk_style_set_background (widget->style, tree_view->priv->header_window, GTK_STATE_NORMAL);
1851
1852   tmp_list = tree_view->priv->children;
1853   while (tmp_list)
1854     {
1855       GtkTreeViewChild *child = tmp_list->data;
1856       tmp_list = tmp_list->next;
1857
1858       gtk_widget_set_parent_window (child->widget, tree_view->priv->bin_window);
1859     }
1860
1861   for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
1862     _gtk_tree_view_column_realize_button (GTK_TREE_VIEW_COLUMN (tmp_list->data));
1863
1864   /* Need to call those here, since they create GCs */
1865   gtk_tree_view_set_grid_lines (tree_view, tree_view->priv->grid_lines);
1866   gtk_tree_view_set_enable_tree_lines (tree_view, tree_view->priv->tree_lines_enabled);
1867
1868   install_presize_handler (tree_view); 
1869 }
1870
1871 static void
1872 gtk_tree_view_unrealize (GtkWidget *widget)
1873 {
1874   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
1875   GtkTreeViewPrivate *priv = tree_view->priv;
1876   GList *list;
1877
1878   if (priv->scroll_timeout != 0)
1879     {
1880       g_source_remove (priv->scroll_timeout);
1881       priv->scroll_timeout = 0;
1882     }
1883
1884   if (priv->auto_expand_timeout != 0)
1885     {
1886       g_source_remove (priv->auto_expand_timeout);
1887       priv->auto_expand_timeout = 0;
1888     }
1889
1890   if (priv->open_dest_timeout != 0)
1891     {
1892       g_source_remove (priv->open_dest_timeout);
1893       priv->open_dest_timeout = 0;
1894     }
1895
1896   remove_expand_collapse_timeout (tree_view);
1897   
1898   if (priv->presize_handler_timer != 0)
1899     {
1900       g_source_remove (priv->presize_handler_timer);
1901       priv->presize_handler_timer = 0;
1902     }
1903
1904   if (priv->validate_rows_timer != 0)
1905     {
1906       g_source_remove (priv->validate_rows_timer);
1907       priv->validate_rows_timer = 0;
1908     }
1909
1910   if (priv->scroll_sync_timer != 0)
1911     {
1912       g_source_remove (priv->scroll_sync_timer);
1913       priv->scroll_sync_timer = 0;
1914     }
1915
1916   if (priv->typeselect_flush_timeout)
1917     {
1918       g_source_remove (priv->typeselect_flush_timeout);
1919       priv->typeselect_flush_timeout = 0;
1920     }
1921   
1922   for (list = priv->columns; list; list = list->next)
1923     _gtk_tree_view_column_unrealize_button (GTK_TREE_VIEW_COLUMN (list->data));
1924
1925   gdk_window_set_user_data (priv->bin_window, NULL);
1926   gdk_window_destroy (priv->bin_window);
1927   priv->bin_window = NULL;
1928
1929   gdk_window_set_user_data (priv->header_window, NULL);
1930   gdk_window_destroy (priv->header_window);
1931   priv->header_window = NULL;
1932
1933   if (priv->drag_window)
1934     {
1935       gdk_window_set_user_data (priv->drag_window, NULL);
1936       gdk_window_destroy (priv->drag_window);
1937       priv->drag_window = NULL;
1938     }
1939
1940   if (priv->drag_highlight_window)
1941     {
1942       gdk_window_set_user_data (priv->drag_highlight_window, NULL);
1943       gdk_window_destroy (priv->drag_highlight_window);
1944       priv->drag_highlight_window = NULL;
1945     }
1946
1947   GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->unrealize (widget);
1948 }
1949
1950 /* GtkWidget::size_request helper */
1951 static void
1952 gtk_tree_view_size_request_columns (GtkTreeView *tree_view)
1953 {
1954   GList *list;
1955
1956   tree_view->priv->header_height = 0;
1957
1958   if (tree_view->priv->model)
1959     {
1960       for (list = tree_view->priv->columns; list; list = list->next)
1961         {
1962           GtkRequisition requisition;
1963           GtkTreeViewColumn *column = list->data;
1964
1965           if (column->button == NULL)
1966             continue;
1967
1968           column = list->data;
1969           
1970           gtk_widget_size_request (column->button, &requisition);
1971           column->button_request = requisition.width;
1972           tree_view->priv->header_height = MAX (tree_view->priv->header_height, requisition.height);
1973         }
1974     }
1975 }
1976
1977
1978 /* Called only by ::size_request */
1979 static void
1980 gtk_tree_view_update_size (GtkTreeView *tree_view)
1981 {
1982   GList *list;
1983   GtkTreeViewColumn *column;
1984   gint i;
1985
1986   if (tree_view->priv->model == NULL)
1987     {
1988       tree_view->priv->width = 0;
1989       tree_view->priv->prev_width = 0;                   
1990       tree_view->priv->height = 0;
1991       return;
1992     }
1993
1994   tree_view->priv->prev_width = tree_view->priv->width;  
1995   tree_view->priv->width = 0;
1996
1997   /* keep this in sync with size_allocate below */
1998   for (list = tree_view->priv->columns, i = 0; list; list = list->next, i++)
1999     {
2000       gint real_requested_width = 0;
2001       column = list->data;
2002       if (!column->visible)
2003         continue;
2004
2005       if (column->use_resized_width)
2006         {
2007           real_requested_width = column->resized_width;
2008         }
2009       else if (column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
2010         {
2011           real_requested_width = column->fixed_width;
2012         }
2013       else if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
2014         {
2015           real_requested_width = MAX (column->requested_width, column->button_request);
2016         }
2017       else
2018         {
2019           real_requested_width = column->requested_width;
2020         }
2021
2022       if (column->min_width != -1)
2023         real_requested_width = MAX (real_requested_width, column->min_width);
2024       if (column->max_width != -1)
2025         real_requested_width = MIN (real_requested_width, column->max_width);
2026
2027       tree_view->priv->width += real_requested_width;
2028     }
2029
2030   if (tree_view->priv->tree == NULL)
2031     tree_view->priv->height = 0;
2032   else
2033     tree_view->priv->height = tree_view->priv->tree->root->offset;
2034 }
2035
2036 static void
2037 gtk_tree_view_size_request (GtkWidget      *widget,
2038                             GtkRequisition *requisition)
2039 {
2040   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2041   GList *tmp_list;
2042
2043   /* we validate some rows initially just to make sure we have some size. 
2044    * In practice, with a lot of static lists, this should get a good width.
2045    */
2046   do_validate_rows (tree_view, FALSE);
2047   gtk_tree_view_size_request_columns (tree_view);
2048   gtk_tree_view_update_size (GTK_TREE_VIEW (widget));
2049
2050   requisition->width = tree_view->priv->width;
2051   requisition->height = tree_view->priv->height + TREE_VIEW_HEADER_HEIGHT (tree_view);
2052
2053   tmp_list = tree_view->priv->children;
2054
2055   while (tmp_list)
2056     {
2057       GtkTreeViewChild *child = tmp_list->data;
2058       GtkRequisition child_requisition;
2059
2060       tmp_list = tmp_list->next;
2061
2062       if (gtk_widget_get_visible (child->widget))
2063         gtk_widget_size_request (child->widget, &child_requisition);
2064     }
2065 }
2066
2067 static int
2068 gtk_tree_view_calculate_width_before_expander (GtkTreeView *tree_view)
2069 {
2070   int width = 0;
2071   GList *list;
2072   gboolean rtl;
2073
2074   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2075   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
2076        list->data != tree_view->priv->expander_column;
2077        list = (rtl ? list->prev : list->next))
2078     {
2079       GtkTreeViewColumn *column = list->data;
2080
2081       width += column->width;
2082     }
2083
2084   return width;
2085 }
2086
2087 static void
2088 invalidate_column (GtkTreeView       *tree_view,
2089                    GtkTreeViewColumn *column)
2090 {
2091   gint column_offset = 0;
2092   GList *list;
2093   GtkWidget *widget = GTK_WIDGET (tree_view);
2094   gboolean rtl;
2095
2096   if (!gtk_widget_get_realized (widget))
2097     return;
2098
2099   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2100   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
2101        list;
2102        list = (rtl ? list->prev : list->next))
2103     {
2104       GtkTreeViewColumn *tmpcolumn = list->data;
2105       if (tmpcolumn == column)
2106         {
2107           GdkRectangle invalid_rect;
2108           
2109           invalid_rect.x = column_offset;
2110           invalid_rect.y = 0;
2111           invalid_rect.width = column->width;
2112           invalid_rect.height = widget->allocation.height;
2113           
2114           gdk_window_invalidate_rect (widget->window, &invalid_rect, TRUE);
2115           break;
2116         }
2117       
2118       column_offset += tmpcolumn->width;
2119     }
2120 }
2121
2122 static void
2123 invalidate_last_column (GtkTreeView *tree_view)
2124 {
2125   GList *last_column;
2126   gboolean rtl;
2127
2128   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2129
2130   for (last_column = (rtl ? g_list_first (tree_view->priv->columns) : g_list_last (tree_view->priv->columns));
2131        last_column;
2132        last_column = (rtl ? last_column->next : last_column->prev))
2133     {
2134       if (GTK_TREE_VIEW_COLUMN (last_column->data)->visible)
2135         {
2136           invalidate_column (tree_view, last_column->data);
2137           return;
2138         }
2139     }
2140 }
2141
2142 static gint
2143 gtk_tree_view_get_real_requested_width_from_column (GtkTreeView       *tree_view,
2144                                                     GtkTreeViewColumn *column)
2145 {
2146   gint real_requested_width;
2147
2148   if (column->use_resized_width)
2149     {
2150       real_requested_width = column->resized_width;
2151     }
2152   else if (column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
2153     {
2154       real_requested_width = column->fixed_width;
2155     }
2156   else if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
2157     {
2158       real_requested_width = MAX (column->requested_width, column->button_request);
2159     }
2160   else
2161     {
2162       real_requested_width = column->requested_width;
2163       if (real_requested_width < 0)
2164         real_requested_width = 0;
2165     }
2166
2167   if (column->min_width != -1)
2168     real_requested_width = MAX (real_requested_width, column->min_width);
2169   if (column->max_width != -1)
2170     real_requested_width = MIN (real_requested_width, column->max_width);
2171
2172   return real_requested_width;
2173 }
2174
2175 /* GtkWidget::size_allocate helper */
2176 static void
2177 gtk_tree_view_size_allocate_columns (GtkWidget *widget,
2178                                      gboolean  *width_changed)
2179 {
2180   GtkTreeView *tree_view;
2181   GList *list, *first_column, *last_column;
2182   GtkTreeViewColumn *column;
2183   GtkAllocation allocation;
2184   gint width = 0;
2185   gint extra, extra_per_column, extra_for_last;
2186   gint full_requested_width = 0;
2187   gint number_of_expand_columns = 0;
2188   gboolean column_changed = FALSE;
2189   gboolean rtl;
2190   gboolean update_expand;
2191   
2192   tree_view = GTK_TREE_VIEW (widget);
2193
2194   for (last_column = g_list_last (tree_view->priv->columns);
2195        last_column && !(GTK_TREE_VIEW_COLUMN (last_column->data)->visible);
2196        last_column = last_column->prev)
2197     ;
2198   if (last_column == NULL)
2199     return;
2200
2201   for (first_column = g_list_first (tree_view->priv->columns);
2202        first_column && !(GTK_TREE_VIEW_COLUMN (first_column->data)->visible);
2203        first_column = first_column->next)
2204     ;
2205
2206   allocation.y = 0;
2207   allocation.height = tree_view->priv->header_height;
2208
2209   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
2210
2211   /* find out how many extra space and expandable columns we have */
2212   for (list = tree_view->priv->columns; list != last_column->next; list = list->next)
2213     {
2214       column = (GtkTreeViewColumn *)list->data;
2215
2216       if (!column->visible)
2217         continue;
2218
2219       full_requested_width += gtk_tree_view_get_real_requested_width_from_column (tree_view, column);
2220
2221       if (column->expand)
2222         number_of_expand_columns++;
2223     }
2224
2225   /* Only update the expand value if the width of the widget has changed,
2226    * or the number of expand columns has changed, or if there are no expand
2227    * columns, or if we didn't have an size-allocation yet after the
2228    * last validated node.
2229    */
2230   update_expand = (width_changed && *width_changed == TRUE)
2231       || number_of_expand_columns != tree_view->priv->last_number_of_expand_columns
2232       || number_of_expand_columns == 0
2233       || tree_view->priv->post_validation_flag == TRUE;
2234
2235   tree_view->priv->post_validation_flag = FALSE;
2236
2237   if (!update_expand)
2238     {
2239       extra = tree_view->priv->last_extra_space;
2240       extra_for_last = MAX (widget->allocation.width - full_requested_width - extra, 0);
2241     }
2242   else
2243     {
2244       extra = MAX (widget->allocation.width - full_requested_width, 0);
2245       extra_for_last = 0;
2246
2247       tree_view->priv->last_extra_space = extra;
2248     }
2249
2250   if (number_of_expand_columns > 0)
2251     extra_per_column = extra/number_of_expand_columns;
2252   else
2253     extra_per_column = 0;
2254
2255   if (update_expand)
2256     {
2257       tree_view->priv->last_extra_space_per_column = extra_per_column;
2258       tree_view->priv->last_number_of_expand_columns = number_of_expand_columns;
2259     }
2260
2261   for (list = (rtl ? last_column : first_column); 
2262        list != (rtl ? first_column->prev : last_column->next);
2263        list = (rtl ? list->prev : list->next)) 
2264     {
2265       gint real_requested_width = 0;
2266       gint old_width;
2267
2268       column = list->data;
2269       old_width = column->width;
2270
2271       if (!column->visible)
2272         continue;
2273
2274       /* We need to handle the dragged button specially.
2275        */
2276       if (column == tree_view->priv->drag_column)
2277         {
2278           GtkAllocation drag_allocation;
2279           gdk_drawable_get_size (tree_view->priv->drag_window,
2280                                  &(drag_allocation.width),
2281                                  &(drag_allocation.height));
2282           drag_allocation.x = 0;
2283           drag_allocation.y = 0;
2284           gtk_widget_size_allocate (tree_view->priv->drag_column->button,
2285                                     &drag_allocation);
2286           width += drag_allocation.width;
2287           continue;
2288         }
2289
2290       real_requested_width = gtk_tree_view_get_real_requested_width_from_column (tree_view, column);
2291
2292       allocation.x = width;
2293       column->width = real_requested_width;
2294
2295       if (column->expand)
2296         {
2297           if (number_of_expand_columns == 1)
2298             {
2299               /* We add the remander to the last column as
2300                * */
2301               column->width += extra;
2302             }
2303           else
2304             {
2305               column->width += extra_per_column;
2306               extra -= extra_per_column;
2307               number_of_expand_columns --;
2308             }
2309         }
2310       else if (number_of_expand_columns == 0 &&
2311                list == last_column)
2312         {
2313           column->width += extra;
2314         }
2315
2316       /* In addition to expand, the last column can get even more
2317        * extra space so all available space is filled up.
2318        */
2319       if (extra_for_last > 0 && list == last_column)
2320         column->width += extra_for_last;
2321
2322       g_object_notify (G_OBJECT (column), "width");
2323
2324       allocation.width = column->width;
2325       width += column->width;
2326
2327       if (column->width > old_width)
2328         column_changed = TRUE;
2329
2330       gtk_widget_size_allocate (column->button, &allocation);
2331
2332       if (column->window)
2333         gdk_window_move_resize (column->window,
2334                                 allocation.x + (rtl ? 0 : allocation.width) - TREE_VIEW_DRAG_WIDTH/2,
2335                                 allocation.y,
2336                                 TREE_VIEW_DRAG_WIDTH, allocation.height);
2337     }
2338
2339   /* We change the width here.  The user might have been resizing columns,
2340    * so the total width of the tree view changes.
2341    */
2342   tree_view->priv->width = width;
2343   if (width_changed)
2344     *width_changed = TRUE;
2345
2346   if (column_changed)
2347     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
2348 }
2349
2350
2351 static void
2352 gtk_tree_view_size_allocate (GtkWidget     *widget,
2353                              GtkAllocation *allocation)
2354 {
2355   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2356   GList *tmp_list;
2357   gboolean width_changed = FALSE;
2358   gint old_width = widget->allocation.width;
2359
2360   if (allocation->width != widget->allocation.width)
2361     width_changed = TRUE;
2362
2363   widget->allocation = *allocation;
2364
2365   tmp_list = tree_view->priv->children;
2366
2367   while (tmp_list)
2368     {
2369       GtkAllocation allocation;
2370
2371       GtkTreeViewChild *child = tmp_list->data;
2372       tmp_list = tmp_list->next;
2373
2374       /* totally ignore our child's requisition */
2375       allocation.x = child->x;
2376       allocation.y = child->y;
2377       allocation.width = child->width;
2378       allocation.height = child->height;
2379       gtk_widget_size_allocate (child->widget, &allocation);
2380     }
2381
2382   /* We size-allocate the columns first because the width of the
2383    * tree view (used in updating the adjustments below) might change.
2384    */
2385   gtk_tree_view_size_allocate_columns (widget, &width_changed);
2386
2387   tree_view->priv->hadjustment->page_size = allocation->width;
2388   tree_view->priv->hadjustment->page_increment = allocation->width * 0.9;
2389   tree_view->priv->hadjustment->step_increment = allocation->width * 0.1;
2390   tree_view->priv->hadjustment->lower = 0;
2391   tree_view->priv->hadjustment->upper = MAX (tree_view->priv->hadjustment->page_size, tree_view->priv->width);
2392
2393   if (gtk_widget_get_direction(widget) == GTK_TEXT_DIR_RTL)   
2394     {
2395       if (allocation->width < tree_view->priv->width)
2396         {
2397           if (tree_view->priv->init_hadjust_value)
2398             {
2399               tree_view->priv->hadjustment->value = MAX (tree_view->priv->width - allocation->width, 0);
2400               tree_view->priv->init_hadjust_value = FALSE;
2401             }
2402           else if (allocation->width != old_width)
2403             {
2404               tree_view->priv->hadjustment->value = CLAMP (tree_view->priv->hadjustment->value - allocation->width + old_width, 0, tree_view->priv->width - allocation->width);
2405             }
2406           else
2407             tree_view->priv->hadjustment->value = CLAMP (tree_view->priv->width - (tree_view->priv->prev_width - tree_view->priv->hadjustment->value), 0, tree_view->priv->width - allocation->width);
2408         }
2409       else
2410         {
2411           tree_view->priv->hadjustment->value = 0;
2412           tree_view->priv->init_hadjust_value = TRUE;
2413         }
2414     }
2415   else
2416     if (tree_view->priv->hadjustment->value + allocation->width > tree_view->priv->width)
2417       tree_view->priv->hadjustment->value = MAX (tree_view->priv->width - allocation->width, 0);
2418
2419   gtk_adjustment_changed (tree_view->priv->hadjustment);
2420
2421   tree_view->priv->vadjustment->page_size = allocation->height - TREE_VIEW_HEADER_HEIGHT (tree_view);
2422   tree_view->priv->vadjustment->step_increment = tree_view->priv->vadjustment->page_size * 0.1;
2423   tree_view->priv->vadjustment->page_increment = tree_view->priv->vadjustment->page_size * 0.9;
2424   tree_view->priv->vadjustment->lower = 0;
2425   tree_view->priv->vadjustment->upper = MAX (tree_view->priv->vadjustment->page_size, tree_view->priv->height);
2426
2427   gtk_adjustment_changed (tree_view->priv->vadjustment);
2428
2429   /* now the adjustments and window sizes are in sync, we can sync toprow/dy again */
2430   if (tree_view->priv->height <= tree_view->priv->vadjustment->page_size)
2431     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
2432   else if (tree_view->priv->vadjustment->value + tree_view->priv->vadjustment->page_size > tree_view->priv->height)
2433     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment),
2434                               tree_view->priv->height - tree_view->priv->vadjustment->page_size);
2435   else if (gtk_tree_row_reference_valid (tree_view->priv->top_row))
2436     gtk_tree_view_top_row_to_dy (tree_view);
2437   else
2438     gtk_tree_view_dy_to_top_row (tree_view);
2439   
2440   if (gtk_widget_get_realized (widget))
2441     {
2442       gdk_window_move_resize (widget->window,
2443                               allocation->x, allocation->y,
2444                               allocation->width, allocation->height);
2445       gdk_window_move_resize (tree_view->priv->header_window,
2446                               - (gint) tree_view->priv->hadjustment->value,
2447                               0,
2448                               MAX (tree_view->priv->width, allocation->width),
2449                               tree_view->priv->header_height);
2450       gdk_window_move_resize (tree_view->priv->bin_window,
2451                               - (gint) tree_view->priv->hadjustment->value,
2452                               TREE_VIEW_HEADER_HEIGHT (tree_view),
2453                               MAX (tree_view->priv->width, allocation->width),
2454                               allocation->height - TREE_VIEW_HEADER_HEIGHT (tree_view));
2455     }
2456
2457   if (tree_view->priv->tree == NULL)
2458     invalidate_empty_focus (tree_view);
2459
2460   if (gtk_widget_get_realized (widget))
2461     {
2462       gboolean has_expand_column = FALSE;
2463       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
2464         {
2465           if (gtk_tree_view_column_get_expand (GTK_TREE_VIEW_COLUMN (tmp_list->data)))
2466             {
2467               has_expand_column = TRUE;
2468               break;
2469             }
2470         }
2471
2472       if (width_changed && tree_view->priv->expander_column)
2473         {
2474           /* Might seem awkward, but is the best heuristic I could come up
2475            * with.  Only if the width of the columns before the expander
2476            * changes, we will update the prelight status.  It is this
2477            * width that makes the expander move vertically.  Always updating
2478            * prelight status causes trouble with hover selections.
2479            */
2480           gint width_before_expander;
2481
2482           width_before_expander = gtk_tree_view_calculate_width_before_expander (tree_view);
2483
2484           if (tree_view->priv->prev_width_before_expander
2485               != width_before_expander)
2486               update_prelight (tree_view,
2487                                tree_view->priv->event_last_x,
2488                                tree_view->priv->event_last_y);
2489
2490           tree_view->priv->prev_width_before_expander = width_before_expander;
2491         }
2492
2493       /* This little hack only works if we have an LTR locale, and no column has the  */
2494       if (width_changed)
2495         {
2496           if (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_LTR &&
2497               ! has_expand_column)
2498             invalidate_last_column (tree_view);
2499           else
2500             gtk_widget_queue_draw (widget);
2501         }
2502     }
2503 }
2504
2505 /* Grabs the focus and unsets the GTK_TREE_VIEW_DRAW_KEYFOCUS flag */
2506 static void
2507 grab_focus_and_unset_draw_keyfocus (GtkTreeView *tree_view)
2508 {
2509   GtkWidget *widget = GTK_WIDGET (tree_view);
2510
2511   if (gtk_widget_get_can_focus (widget) && !gtk_widget_has_focus (widget))
2512     gtk_widget_grab_focus (widget);
2513   GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
2514 }
2515
2516 static inline gboolean
2517 row_is_separator (GtkTreeView *tree_view,
2518                   GtkTreeIter *iter,
2519                   GtkTreePath *path)
2520 {
2521   gboolean is_separator = FALSE;
2522
2523   if (tree_view->priv->row_separator_func)
2524     {
2525       GtkTreeIter tmpiter;
2526
2527       if (iter)
2528         tmpiter = *iter;
2529       else
2530         gtk_tree_model_get_iter (tree_view->priv->model, &tmpiter, path);
2531
2532       is_separator = tree_view->priv->row_separator_func (tree_view->priv->model,
2533                                                           &tmpiter,
2534                                                           tree_view->priv->row_separator_data);
2535     }
2536
2537   return is_separator;
2538 }
2539
2540 static gboolean
2541 gtk_tree_view_button_press (GtkWidget      *widget,
2542                             GdkEventButton *event)
2543 {
2544   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2545   GList *list;
2546   GtkTreeViewColumn *column = NULL;
2547   gint i;
2548   GdkRectangle background_area;
2549   GdkRectangle cell_area;
2550   gint vertical_separator;
2551   gint horizontal_separator;
2552   gboolean path_is_selectable;
2553   gboolean rtl;
2554
2555   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
2556   gtk_tree_view_stop_editing (tree_view, FALSE);
2557   gtk_widget_style_get (widget,
2558                         "vertical-separator", &vertical_separator,
2559                         "horizontal-separator", &horizontal_separator,
2560                         NULL);
2561
2562
2563   /* Because grab_focus can cause reentrancy, we delay grab_focus until after
2564    * we're done handling the button press.
2565    */
2566
2567   if (event->window == tree_view->priv->bin_window)
2568     {
2569       GtkRBNode *node;
2570       GtkRBTree *tree;
2571       GtkTreePath *path;
2572       gchar *path_string;
2573       gint depth;
2574       gint new_y;
2575       gint y_offset;
2576       gint dval;
2577       gint pre_val, aft_val;
2578       GtkTreeViewColumn *column = NULL;
2579       GtkCellRenderer *focus_cell = NULL;
2580       gint column_handled_click = FALSE;
2581       gboolean row_double_click = FALSE;
2582       gboolean rtl;
2583       gboolean node_selected;
2584
2585       /* Empty tree? */
2586       if (tree_view->priv->tree == NULL)
2587         {
2588           grab_focus_and_unset_draw_keyfocus (tree_view);
2589           return TRUE;
2590         }
2591
2592       /* are we in an arrow? */
2593       if (tree_view->priv->prelight_node &&
2594           GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT) &&
2595           TREE_VIEW_DRAW_EXPANDERS (tree_view))
2596         {
2597           if (event->button == 1)
2598             {
2599               gtk_grab_add (widget);
2600               tree_view->priv->button_pressed_node = tree_view->priv->prelight_node;
2601               tree_view->priv->button_pressed_tree = tree_view->priv->prelight_tree;
2602               gtk_tree_view_draw_arrow (GTK_TREE_VIEW (widget),
2603                                         tree_view->priv->prelight_tree,
2604                                         tree_view->priv->prelight_node,
2605                                         event->x,
2606                                         event->y);
2607             }
2608
2609           grab_focus_and_unset_draw_keyfocus (tree_view);
2610           return TRUE;
2611         }
2612
2613       /* find the node that was clicked */
2614       new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
2615       if (new_y < 0)
2616         new_y = 0;
2617       y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
2618
2619       if (node == NULL)
2620         {
2621           /* We clicked in dead space */
2622           grab_focus_and_unset_draw_keyfocus (tree_view);
2623           return TRUE;
2624         }
2625
2626       /* Get the path and the node */
2627       path = _gtk_tree_view_find_path (tree_view, tree, node);
2628       path_is_selectable = !row_is_separator (tree_view, NULL, path);
2629
2630       if (!path_is_selectable)
2631         {
2632           gtk_tree_path_free (path);
2633           grab_focus_and_unset_draw_keyfocus (tree_view);
2634           return TRUE;
2635         }
2636
2637       depth = gtk_tree_path_get_depth (path);
2638       background_area.y = y_offset + event->y;
2639       background_area.height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
2640       background_area.x = 0;
2641
2642
2643       /* Let the column have a chance at selecting it. */
2644       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2645       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
2646            list; list = (rtl ? list->prev : list->next))
2647         {
2648           GtkTreeViewColumn *candidate = list->data;
2649
2650           if (!candidate->visible)
2651             continue;
2652
2653           background_area.width = candidate->width;
2654           if ((background_area.x > (gint) event->x) ||
2655               (background_area.x + background_area.width <= (gint) event->x))
2656             {
2657               background_area.x += background_area.width;
2658               continue;
2659             }
2660
2661           /* we found the focus column */
2662           column = candidate;
2663           cell_area = background_area;
2664           cell_area.width -= horizontal_separator;
2665           cell_area.height -= vertical_separator;
2666           cell_area.x += horizontal_separator/2;
2667           cell_area.y += vertical_separator/2;
2668           if (gtk_tree_view_is_expander_column (tree_view, column))
2669             {
2670               if (!rtl)
2671                 cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
2672               cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
2673
2674               if (TREE_VIEW_DRAW_EXPANDERS (tree_view))
2675                 {
2676                   if (!rtl)
2677                     cell_area.x += depth * tree_view->priv->expander_size;
2678                   cell_area.width -= depth * tree_view->priv->expander_size;
2679                 }
2680             }
2681           break;
2682         }
2683
2684       if (column == NULL)
2685         {
2686           gtk_tree_path_free (path);
2687           grab_focus_and_unset_draw_keyfocus (tree_view);
2688           return FALSE;
2689         }
2690
2691       tree_view->priv->focus_column = column;
2692
2693       /* decide if we edit */
2694       if (event->type == GDK_BUTTON_PRESS && event->button == 1 &&
2695           !(event->state & gtk_accelerator_get_default_mod_mask ()))
2696         {
2697           GtkTreePath *anchor;
2698           GtkTreeIter iter;
2699
2700           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
2701           gtk_tree_view_column_cell_set_cell_data (column,
2702                                                    tree_view->priv->model,
2703                                                    &iter,
2704                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
2705                                                    node->children?TRUE:FALSE);
2706
2707           if (tree_view->priv->anchor)
2708             anchor = gtk_tree_row_reference_get_path (tree_view->priv->anchor);
2709           else
2710             anchor = NULL;
2711
2712           if ((anchor && !gtk_tree_path_compare (anchor, path))
2713               || !_gtk_tree_view_column_has_editable_cell (column))
2714             {
2715               GtkCellEditable *cell_editable = NULL;
2716
2717               /* FIXME: get the right flags */
2718               guint flags = 0;
2719
2720               path_string = gtk_tree_path_to_string (path);
2721
2722               if (_gtk_tree_view_column_cell_event (column,
2723                                                     &cell_editable,
2724                                                     (GdkEvent *)event,
2725                                                     path_string,
2726                                                     &background_area,
2727                                                     &cell_area, flags))
2728                 {
2729                   if (cell_editable != NULL)
2730                     {
2731                       gint left, right;
2732                       GdkRectangle area;
2733
2734                       area = cell_area;
2735                       _gtk_tree_view_column_get_neighbor_sizes (column, _gtk_tree_view_column_get_edited_cell (column), &left, &right);
2736
2737                       area.x += left;
2738                       area.width -= right + left;
2739
2740                       gtk_tree_view_real_start_editing (tree_view,
2741                                                         column,
2742                                                         path,
2743                                                         cell_editable,
2744                                                         &area,
2745                                                         (GdkEvent *)event,
2746                                                         flags);
2747                       g_free (path_string);
2748                       gtk_tree_path_free (path);
2749                       gtk_tree_path_free (anchor);
2750                       return TRUE;
2751                     }
2752                   column_handled_click = TRUE;
2753                 }
2754               g_free (path_string);
2755             }
2756           if (anchor)
2757             gtk_tree_path_free (anchor);
2758         }
2759
2760       /* select */
2761       node_selected = GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED);
2762       pre_val = tree_view->priv->vadjustment->value;
2763
2764       /* we only handle selection modifications on the first button press
2765        */
2766       if (event->type == GDK_BUTTON_PRESS)
2767         {
2768           if ((event->state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
2769             tree_view->priv->ctrl_pressed = TRUE;
2770           if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
2771             tree_view->priv->shift_pressed = TRUE;
2772
2773           focus_cell = _gtk_tree_view_column_get_cell_at_pos (column, event->x - background_area.x);
2774           if (focus_cell)
2775             gtk_tree_view_column_focus_cell (column, focus_cell);
2776
2777           if (event->state & GDK_CONTROL_MASK)
2778             {
2779               gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
2780               gtk_tree_view_real_toggle_cursor_row (tree_view);
2781             }
2782           else if (event->state & GDK_SHIFT_MASK)
2783             {
2784               gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
2785               gtk_tree_view_real_select_cursor_row (tree_view, FALSE);
2786             }
2787           else
2788             {
2789               gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
2790             }
2791
2792           tree_view->priv->ctrl_pressed = FALSE;
2793           tree_view->priv->shift_pressed = FALSE;
2794         }
2795
2796       /* the treeview may have been scrolled because of _set_cursor,
2797        * correct here
2798        */
2799
2800       aft_val = tree_view->priv->vadjustment->value;
2801       dval = pre_val - aft_val;
2802
2803       cell_area.y += dval;
2804       background_area.y += dval;
2805
2806       /* Save press to possibly begin a drag
2807        */
2808       if (!column_handled_click &&
2809           !tree_view->priv->in_grab &&
2810           tree_view->priv->pressed_button < 0)
2811         {
2812           tree_view->priv->pressed_button = event->button;
2813           tree_view->priv->press_start_x = event->x;
2814           tree_view->priv->press_start_y = event->y;
2815
2816           if (tree_view->priv->rubber_banding_enable
2817               && !node_selected
2818               && tree_view->priv->selection->type == GTK_SELECTION_MULTIPLE)
2819             {
2820               tree_view->priv->press_start_y += tree_view->priv->dy;
2821               tree_view->priv->rubber_band_x = event->x;
2822               tree_view->priv->rubber_band_y = event->y + tree_view->priv->dy;
2823               tree_view->priv->rubber_band_status = RUBBER_BAND_MAYBE_START;
2824
2825               if ((event->state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
2826                 tree_view->priv->rubber_band_ctrl = TRUE;
2827               if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
2828                 tree_view->priv->rubber_band_shift = TRUE;
2829             }
2830         }
2831
2832       /* Test if a double click happened on the same row. */
2833       if (event->button == 1 && event->type == GDK_BUTTON_PRESS)
2834         {
2835           int double_click_time, double_click_distance;
2836
2837           g_object_get (gtk_settings_get_default (),
2838                         "gtk-double-click-time", &double_click_time,
2839                         "gtk-double-click-distance", &double_click_distance,
2840                         NULL);
2841
2842           /* Same conditions as _gdk_event_button_generate */
2843           if (tree_view->priv->last_button_x != -1 &&
2844               (event->time < tree_view->priv->last_button_time + double_click_time) &&
2845               (ABS (event->x - tree_view->priv->last_button_x) <= double_click_distance) &&
2846               (ABS (event->y - tree_view->priv->last_button_y) <= double_click_distance))
2847             {
2848               /* We do no longer compare paths of this row and the
2849                * row clicked previously.  We use the double click
2850                * distance to decide whether this is a valid click,
2851                * allowing the mouse to slightly move over another row.
2852                */
2853               row_double_click = TRUE;
2854
2855               tree_view->priv->last_button_time = 0;
2856               tree_view->priv->last_button_x = -1;
2857               tree_view->priv->last_button_y = -1;
2858             }
2859           else
2860             {
2861               tree_view->priv->last_button_time = event->time;
2862               tree_view->priv->last_button_x = event->x;
2863               tree_view->priv->last_button_y = event->y;
2864             }
2865         }
2866
2867       if (row_double_click)
2868         {
2869           gtk_grab_remove (widget);
2870           gtk_tree_view_row_activated (tree_view, path, column);
2871
2872           if (tree_view->priv->pressed_button == event->button)
2873             tree_view->priv->pressed_button = -1;
2874         }
2875
2876       gtk_tree_path_free (path);
2877
2878       /* If we activated the row through a double click we don't want to grab
2879        * focus back, as moving focus to another widget is pretty common.
2880        */
2881       if (!row_double_click)
2882         grab_focus_and_unset_draw_keyfocus (tree_view);
2883
2884       return TRUE;
2885     }
2886
2887   /* We didn't click in the window.  Let's check to see if we clicked on a column resize window.
2888    */
2889   for (i = 0, list = tree_view->priv->columns; list; list = list->next, i++)
2890     {
2891       column = list->data;
2892       if (event->window == column->window &&
2893           column->resizable &&
2894           column->window)
2895         {
2896           gpointer drag_data;
2897
2898           if (event->type == GDK_2BUTTON_PRESS &&
2899               gtk_tree_view_column_get_sizing (column) != GTK_TREE_VIEW_COLUMN_AUTOSIZE)
2900             {
2901               column->use_resized_width = FALSE;
2902               _gtk_tree_view_column_autosize (tree_view, column);
2903               return TRUE;
2904             }
2905
2906           if (gdk_pointer_grab (column->window, FALSE,
2907                                 GDK_POINTER_MOTION_HINT_MASK |
2908                                 GDK_BUTTON1_MOTION_MASK |
2909                                 GDK_BUTTON_RELEASE_MASK,
2910                                 NULL, NULL, event->time))
2911             return FALSE;
2912
2913           gtk_grab_add (widget);
2914           GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE);
2915           column->resized_width = column->width - tree_view->priv->last_extra_space_per_column;
2916
2917           /* block attached dnd signal handler */
2918           drag_data = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
2919           if (drag_data)
2920             g_signal_handlers_block_matched (widget,
2921                                              G_SIGNAL_MATCH_DATA,
2922                                              0, 0, NULL, NULL,
2923                                              drag_data);
2924
2925           tree_view->priv->drag_pos = i;
2926           tree_view->priv->x_drag = column->button->allocation.x + (rtl ? 0 : column->button->allocation.width);
2927
2928           if (!gtk_widget_has_focus (widget))
2929             gtk_widget_grab_focus (widget);
2930
2931           return TRUE;
2932         }
2933     }
2934   return FALSE;
2935 }
2936
2937 /* GtkWidget::button_release_event helper */
2938 static gboolean
2939 gtk_tree_view_button_release_drag_column (GtkWidget      *widget,
2940                                           GdkEventButton *event)
2941 {
2942   GtkTreeView *tree_view;
2943   GList *l;
2944   gboolean rtl;
2945
2946   tree_view = GTK_TREE_VIEW (widget);
2947
2948   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
2949   gdk_display_pointer_ungrab (gtk_widget_get_display (widget), GDK_CURRENT_TIME);
2950   gdk_display_keyboard_ungrab (gtk_widget_get_display (widget), GDK_CURRENT_TIME);
2951
2952   /* Move the button back */
2953   g_object_ref (tree_view->priv->drag_column->button);
2954   gtk_container_remove (GTK_CONTAINER (tree_view), tree_view->priv->drag_column->button);
2955   gtk_widget_set_parent_window (tree_view->priv->drag_column->button, tree_view->priv->header_window);
2956   gtk_widget_set_parent (tree_view->priv->drag_column->button, GTK_WIDGET (tree_view));
2957   g_object_unref (tree_view->priv->drag_column->button);
2958   gtk_widget_queue_resize (widget);
2959   if (tree_view->priv->drag_column->resizable)
2960     {
2961       gdk_window_raise (tree_view->priv->drag_column->window);
2962       gdk_window_show (tree_view->priv->drag_column->window);
2963     }
2964   else
2965     gdk_window_hide (tree_view->priv->drag_column->window);
2966
2967   gtk_widget_grab_focus (tree_view->priv->drag_column->button);
2968
2969   if (rtl)
2970     {
2971       if (tree_view->priv->cur_reorder &&
2972           tree_view->priv->cur_reorder->right_column != tree_view->priv->drag_column)
2973         gtk_tree_view_move_column_after (tree_view, tree_view->priv->drag_column,
2974                                          tree_view->priv->cur_reorder->right_column);
2975     }
2976   else
2977     {
2978       if (tree_view->priv->cur_reorder &&
2979           tree_view->priv->cur_reorder->left_column != tree_view->priv->drag_column)
2980         gtk_tree_view_move_column_after (tree_view, tree_view->priv->drag_column,
2981                                          tree_view->priv->cur_reorder->left_column);
2982     }
2983   tree_view->priv->drag_column = NULL;
2984   gdk_window_hide (tree_view->priv->drag_window);
2985
2986   for (l = tree_view->priv->column_drag_info; l != NULL; l = l->next)
2987     g_slice_free (GtkTreeViewColumnReorder, l->data);
2988   g_list_free (tree_view->priv->column_drag_info);
2989   tree_view->priv->column_drag_info = NULL;
2990   tree_view->priv->cur_reorder = NULL;
2991
2992   if (tree_view->priv->drag_highlight_window)
2993     gdk_window_hide (tree_view->priv->drag_highlight_window);
2994
2995   /* Reset our flags */
2996   tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_UNSET;
2997   GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG);
2998
2999   return TRUE;
3000 }
3001
3002 /* GtkWidget::button_release_event helper */
3003 static gboolean
3004 gtk_tree_view_button_release_column_resize (GtkWidget      *widget,
3005                                             GdkEventButton *event)
3006 {
3007   GtkTreeView *tree_view;
3008   gpointer drag_data;
3009
3010   tree_view = GTK_TREE_VIEW (widget);
3011
3012   tree_view->priv->drag_pos = -1;
3013
3014   /* unblock attached dnd signal handler */
3015   drag_data = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
3016   if (drag_data)
3017     g_signal_handlers_unblock_matched (widget,
3018                                        G_SIGNAL_MATCH_DATA,
3019                                        0, 0, NULL, NULL,
3020                                        drag_data);
3021
3022   GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE);
3023   gtk_grab_remove (widget);
3024   gdk_display_pointer_ungrab (gdk_drawable_get_display (event->window),
3025                               event->time);
3026   return TRUE;
3027 }
3028
3029 static gboolean
3030 gtk_tree_view_button_release (GtkWidget      *widget,
3031                               GdkEventButton *event)
3032 {
3033   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
3034
3035   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
3036     return gtk_tree_view_button_release_drag_column (widget, event);
3037
3038   if (tree_view->priv->rubber_band_status)
3039     gtk_tree_view_stop_rubber_band (tree_view);
3040
3041   if (tree_view->priv->pressed_button == event->button)
3042     tree_view->priv->pressed_button = -1;
3043
3044   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE))
3045     return gtk_tree_view_button_release_column_resize (widget, event);
3046
3047   if (tree_view->priv->button_pressed_node == NULL)
3048     return FALSE;
3049
3050   if (event->button == 1)
3051     {
3052       gtk_grab_remove (widget);
3053       if (tree_view->priv->button_pressed_node == tree_view->priv->prelight_node &&
3054           GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT))
3055         {
3056           GtkTreePath *path = NULL;
3057
3058           path = _gtk_tree_view_find_path (tree_view,
3059                                            tree_view->priv->button_pressed_tree,
3060                                            tree_view->priv->button_pressed_node);
3061           /* Actually activate the node */
3062           if (tree_view->priv->button_pressed_node->children == NULL)
3063             gtk_tree_view_real_expand_row (tree_view, path,
3064                                            tree_view->priv->button_pressed_tree,
3065                                            tree_view->priv->button_pressed_node,
3066                                            FALSE, TRUE);
3067           else
3068             gtk_tree_view_real_collapse_row (GTK_TREE_VIEW (widget), path,
3069                                              tree_view->priv->button_pressed_tree,
3070                                              tree_view->priv->button_pressed_node, TRUE);
3071           gtk_tree_path_free (path);
3072         }
3073
3074       tree_view->priv->button_pressed_tree = NULL;
3075       tree_view->priv->button_pressed_node = NULL;
3076     }
3077
3078   return TRUE;
3079 }
3080
3081 static gboolean
3082 gtk_tree_view_grab_broken (GtkWidget          *widget,
3083                            GdkEventGrabBroken *event)
3084 {
3085   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
3086
3087   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
3088     gtk_tree_view_button_release_drag_column (widget, (GdkEventButton *)event);
3089
3090   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE))
3091     gtk_tree_view_button_release_column_resize (widget, (GdkEventButton *)event);
3092
3093   return TRUE;
3094 }
3095
3096 #if 0
3097 static gboolean
3098 gtk_tree_view_configure (GtkWidget *widget,
3099                          GdkEventConfigure *event)
3100 {
3101   GtkTreeView *tree_view;
3102
3103   tree_view = GTK_TREE_VIEW (widget);
3104   tree_view->priv->search_position_func (tree_view, tree_view->priv->search_window);
3105
3106   return FALSE;
3107 }
3108 #endif
3109
3110 /* GtkWidget::motion_event function set.
3111  */
3112
3113 static gboolean
3114 coords_are_over_arrow (GtkTreeView *tree_view,
3115                        GtkRBTree   *tree,
3116                        GtkRBNode   *node,
3117                        /* these are in bin window coords */
3118                        gint         x,
3119                        gint         y)
3120 {
3121   GdkRectangle arrow;
3122   gint x2;
3123
3124   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
3125     return FALSE;
3126
3127   if ((node->flags & GTK_RBNODE_IS_PARENT) == 0)
3128     return FALSE;
3129
3130   arrow.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
3131
3132   arrow.height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
3133
3134   gtk_tree_view_get_arrow_xrange (tree_view, tree, &arrow.x, &x2);
3135
3136   arrow.width = x2 - arrow.x;
3137
3138   return (x >= arrow.x &&
3139           x < (arrow.x + arrow.width) &&
3140           y >= arrow.y &&
3141           y < (arrow.y + arrow.height));
3142 }
3143
3144 static gboolean
3145 auto_expand_timeout (gpointer data)
3146 {
3147   GtkTreeView *tree_view = GTK_TREE_VIEW (data);
3148   GtkTreePath *path;
3149
3150   if (tree_view->priv->prelight_node)
3151     {
3152       path = _gtk_tree_view_find_path (tree_view,
3153                                        tree_view->priv->prelight_tree,
3154                                        tree_view->priv->prelight_node);   
3155
3156       if (tree_view->priv->prelight_node->children)
3157         gtk_tree_view_collapse_row (tree_view, path);
3158       else
3159         gtk_tree_view_expand_row (tree_view, path, FALSE);
3160
3161       gtk_tree_path_free (path);
3162     }
3163
3164   tree_view->priv->auto_expand_timeout = 0;
3165
3166   return FALSE;
3167 }
3168
3169 static void
3170 remove_auto_expand_timeout (GtkTreeView *tree_view)
3171 {
3172   if (tree_view->priv->auto_expand_timeout != 0)
3173     {
3174       g_source_remove (tree_view->priv->auto_expand_timeout);
3175       tree_view->priv->auto_expand_timeout = 0;
3176     }
3177 }
3178
3179 static void
3180 do_prelight (GtkTreeView *tree_view,
3181              GtkRBTree   *tree,
3182              GtkRBNode   *node,
3183              /* these are in bin_window coords */
3184              gint         x,
3185              gint         y)
3186 {
3187   if (tree_view->priv->prelight_tree == tree &&
3188       tree_view->priv->prelight_node == node)
3189     {
3190       /*  We are still on the same node,
3191           but we might need to take care of the arrow  */
3192
3193       if (tree && node && TREE_VIEW_DRAW_EXPANDERS (tree_view))
3194         {
3195           gboolean over_arrow;
3196           gboolean flag_set;
3197
3198           over_arrow = coords_are_over_arrow (tree_view, tree, node, x, y);
3199           flag_set = GTK_TREE_VIEW_FLAG_SET (tree_view,
3200                                              GTK_TREE_VIEW_ARROW_PRELIT);
3201
3202           if (over_arrow != flag_set)
3203             {
3204               if (over_arrow)
3205                 GTK_TREE_VIEW_SET_FLAG (tree_view,
3206                                         GTK_TREE_VIEW_ARROW_PRELIT);
3207               else
3208                 GTK_TREE_VIEW_UNSET_FLAG (tree_view,
3209                                           GTK_TREE_VIEW_ARROW_PRELIT);
3210
3211               gtk_tree_view_draw_arrow (tree_view, tree, node, x, y);
3212             }
3213         }
3214
3215       return;
3216     }
3217
3218   if (tree_view->priv->prelight_tree && tree_view->priv->prelight_node)
3219     {
3220       /*  Unprelight the old node and arrow  */
3221
3222       GTK_RBNODE_UNSET_FLAG (tree_view->priv->prelight_node,
3223                              GTK_RBNODE_IS_PRELIT);
3224
3225       if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT)
3226           && TREE_VIEW_DRAW_EXPANDERS (tree_view))
3227         {
3228           GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_ARROW_PRELIT);
3229           
3230           gtk_tree_view_draw_arrow (tree_view,
3231                                     tree_view->priv->prelight_tree,
3232                                     tree_view->priv->prelight_node,
3233                                     x,
3234                                     y);
3235         }
3236
3237       _gtk_tree_view_queue_draw_node (tree_view,
3238                                       tree_view->priv->prelight_tree,
3239                                       tree_view->priv->prelight_node,
3240                                       NULL);
3241     }
3242
3243
3244   if (tree_view->priv->hover_expand)
3245     remove_auto_expand_timeout (tree_view);
3246
3247   /*  Set the new prelight values  */
3248   tree_view->priv->prelight_node = node;
3249   tree_view->priv->prelight_tree = tree;
3250
3251   if (!node || !tree)
3252     return;
3253
3254   /*  Prelight the new node and arrow  */
3255
3256   if (TREE_VIEW_DRAW_EXPANDERS (tree_view)
3257       && coords_are_over_arrow (tree_view, tree, node, x, y))
3258     {
3259       GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_ARROW_PRELIT);
3260
3261       gtk_tree_view_draw_arrow (tree_view, tree, node, x, y);
3262     }
3263
3264   GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_PRELIT);
3265
3266   _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
3267
3268   if (tree_view->priv->hover_expand)
3269     {
3270       tree_view->priv->auto_expand_timeout = 
3271         gdk_threads_add_timeout (AUTO_EXPAND_TIMEOUT, auto_expand_timeout, tree_view);
3272     }
3273 }
3274
3275 static void
3276 prelight_or_select (GtkTreeView *tree_view,
3277                     GtkRBTree   *tree,
3278                     GtkRBNode   *node,
3279                     /* these are in bin_window coords */
3280                     gint         x,
3281                     gint         y)
3282 {
3283   GtkSelectionMode mode = gtk_tree_selection_get_mode (tree_view->priv->selection);
3284   
3285   if (tree_view->priv->hover_selection &&
3286       (mode == GTK_SELECTION_SINGLE || mode == GTK_SELECTION_BROWSE) &&
3287       !(tree_view->priv->edited_column &&
3288         tree_view->priv->edited_column->editable_widget))
3289     {
3290       if (node)
3291         {
3292           if (!GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
3293             {
3294               GtkTreePath *path;
3295               
3296               path = _gtk_tree_view_find_path (tree_view, tree, node);
3297               gtk_tree_selection_select_path (tree_view->priv->selection, path);
3298               if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
3299                 {
3300                   GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
3301                   gtk_tree_view_real_set_cursor (tree_view, path, FALSE, FALSE);
3302                 }
3303               gtk_tree_path_free (path);
3304             }
3305         }
3306
3307       else if (mode == GTK_SELECTION_SINGLE)
3308         gtk_tree_selection_unselect_all (tree_view->priv->selection);
3309     }
3310
3311     do_prelight (tree_view, tree, node, x, y);
3312 }
3313
3314 static void
3315 ensure_unprelighted (GtkTreeView *tree_view)
3316 {
3317   do_prelight (tree_view,
3318                NULL, NULL,
3319                -1000, -1000); /* coords not possibly over an arrow */
3320
3321   g_assert (tree_view->priv->prelight_node == NULL);
3322 }
3323
3324 static void
3325 update_prelight (GtkTreeView *tree_view,
3326                  gint         x,
3327                  gint         y)
3328 {
3329   int new_y;
3330   GtkRBTree *tree;
3331   GtkRBNode *node;
3332
3333   if (tree_view->priv->tree == NULL)
3334     return;
3335
3336   if (x == -10000)
3337     {
3338       ensure_unprelighted (tree_view);
3339       return;
3340     }
3341
3342   new_y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, y);
3343   if (new_y < 0)
3344     new_y = 0;
3345
3346   _gtk_rbtree_find_offset (tree_view->priv->tree,
3347                            new_y, &tree, &node);
3348
3349   if (node)
3350     prelight_or_select (tree_view, tree, node, x, y);
3351 }
3352
3353
3354
3355
3356 /* Our motion arrow is either a box (in the case of the original spot)
3357  * or an arrow.  It is expander_size wide.
3358  */
3359 /*
3360  * 11111111111111
3361  * 01111111111110
3362  * 00111111111100
3363  * 00011111111000
3364  * 00001111110000
3365  * 00000111100000
3366  * 00000111100000
3367  * 00000111100000
3368  * ~ ~ ~ ~ ~ ~ ~
3369  * 00000111100000
3370  * 00000111100000
3371  * 00000111100000
3372  * 00001111110000
3373  * 00011111111000
3374  * 00111111111100
3375  * 01111111111110
3376  * 11111111111111
3377  */
3378
3379 static void
3380 gtk_tree_view_motion_draw_column_motion_arrow (GtkTreeView *tree_view)
3381 {
3382   GtkTreeViewColumnReorder *reorder = tree_view->priv->cur_reorder;
3383   GtkWidget *widget = GTK_WIDGET (tree_view);
3384   GdkBitmap *mask = NULL;
3385   gint x;
3386   gint y;
3387   gint width;
3388   gint height;
3389   gint arrow_type = DRAG_COLUMN_WINDOW_STATE_UNSET;
3390   GdkWindowAttr attributes;
3391   guint attributes_mask;
3392   cairo_t *cr;
3393
3394   if (!reorder ||
3395       reorder->left_column == tree_view->priv->drag_column ||
3396       reorder->right_column == tree_view->priv->drag_column)
3397     arrow_type = DRAG_COLUMN_WINDOW_STATE_ORIGINAL;
3398   else if (reorder->left_column || reorder->right_column)
3399     {
3400       GdkRectangle visible_rect;
3401       gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
3402       if (reorder->left_column)
3403         x = reorder->left_column->button->allocation.x + reorder->left_column->button->allocation.width;
3404       else
3405         x = reorder->right_column->button->allocation.x;
3406
3407       if (x < visible_rect.x)
3408         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT;
3409       else if (x > visible_rect.x + visible_rect.width)
3410         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT;
3411       else
3412         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW;
3413     }
3414
3415   /* We want to draw the rectangle over the initial location. */
3416   if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ORIGINAL)
3417     {
3418       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ORIGINAL)
3419         {
3420           if (tree_view->priv->drag_highlight_window)
3421             {
3422               gdk_window_set_user_data (tree_view->priv->drag_highlight_window,
3423                                         NULL);
3424               gdk_window_destroy (tree_view->priv->drag_highlight_window);
3425             }
3426
3427           attributes.window_type = GDK_WINDOW_CHILD;
3428           attributes.wclass = GDK_INPUT_OUTPUT;
3429           attributes.x = tree_view->priv->drag_column_x;
3430           attributes.y = 0;
3431           width = attributes.width = tree_view->priv->drag_column->button->allocation.width;
3432           height = attributes.height = tree_view->priv->drag_column->button->allocation.height;
3433           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
3434           attributes.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
3435           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3436           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
3437           tree_view->priv->drag_highlight_window = gdk_window_new (tree_view->priv->header_window, &attributes, attributes_mask);
3438           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
3439
3440           mask = gdk_pixmap_new (tree_view->priv->drag_highlight_window, width, height, 1);
3441           cr = gdk_cairo_create (mask);
3442
3443           cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
3444           cairo_paint (cr);
3445           cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
3446           cairo_rectangle (cr, 1, 1, width - 2, height - 2);
3447           cairo_stroke (cr);
3448           cairo_destroy (cr);
3449
3450           gdk_window_shape_combine_mask (tree_view->priv->drag_highlight_window,
3451                                          mask, 0, 0);
3452           if (mask) g_object_unref (mask);
3453           tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_ORIGINAL;
3454         }
3455     }
3456   else if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW)
3457     {
3458       gint i, j = 1;
3459
3460       width = tree_view->priv->expander_size;
3461
3462       /* Get x, y, width, height of arrow */
3463       gdk_window_get_origin (tree_view->priv->header_window, &x, &y);
3464       if (reorder->left_column)
3465         {
3466           x += reorder->left_column->button->allocation.x + reorder->left_column->button->allocation.width - width/2;
3467           height = reorder->left_column->button->allocation.height;
3468         }
3469       else
3470         {
3471           x += reorder->right_column->button->allocation.x - width/2;
3472           height = reorder->right_column->button->allocation.height;
3473         }
3474       y -= tree_view->priv->expander_size/2; /* The arrow takes up only half the space */
3475       height += tree_view->priv->expander_size;
3476
3477       /* Create the new window */
3478       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW)
3479         {
3480           if (tree_view->priv->drag_highlight_window)
3481             {
3482               gdk_window_set_user_data (tree_view->priv->drag_highlight_window,
3483                                         NULL);
3484               gdk_window_destroy (tree_view->priv->drag_highlight_window);
3485             }
3486
3487           attributes.window_type = GDK_WINDOW_TEMP;
3488           attributes.wclass = GDK_INPUT_OUTPUT;
3489           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
3490           attributes.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
3491           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3492           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
3493           attributes.x = x;
3494           attributes.y = y;
3495           attributes.width = width;
3496           attributes.height = height;
3497           tree_view->priv->drag_highlight_window = gdk_window_new (gtk_widget_get_root_window (widget),
3498                                                                    &attributes, attributes_mask);
3499           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
3500
3501           mask = gdk_pixmap_new (tree_view->priv->drag_highlight_window, width, height, 1);
3502           cr = gdk_cairo_create (mask);
3503
3504           cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
3505           cairo_paint (cr);
3506           cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
3507           cairo_move_to (cr, 0, 0);
3508           cairo_line_to (cr, width, 0);
3509           cairo_line_to (cr, width / 2., width / 2);
3510           cairo_move_to (cr, 0, height);
3511           cairo_line_to (cr, width, height);
3512           cairo_line_to (cr, width / 2., height - width / 2.);
3513           cairo_fill (cr);
3514
3515           cairo_destroy (cr);
3516           gdk_window_shape_combine_mask (tree_view->priv->drag_highlight_window,
3517                                          mask, 0, 0);
3518           if (mask) g_object_unref (mask);
3519         }
3520
3521       tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_ARROW;
3522       gdk_window_move (tree_view->priv->drag_highlight_window, x, y);
3523     }
3524   else if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT ||
3525            arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
3526     {
3527       gint i, j = 1;
3528
3529       width = tree_view->priv->expander_size;
3530
3531       /* Get x, y, width, height of arrow */
3532       width = width/2; /* remember, the arrow only takes half the available width */
3533       gdk_window_get_origin (widget->window, &x, &y);
3534       if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
3535         x += widget->allocation.width - width;
3536
3537       if (reorder->left_column)
3538         height = reorder->left_column->button->allocation.height;
3539       else
3540         height = reorder->right_column->button->allocation.height;
3541
3542       y -= tree_view->priv->expander_size;
3543       height += 2*tree_view->priv->expander_size;
3544
3545       /* Create the new window */
3546       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT &&
3547           tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
3548         {
3549           if (tree_view->priv->drag_highlight_window)
3550             {
3551               gdk_window_set_user_data (tree_view->priv->drag_highlight_window,
3552                                         NULL);
3553               gdk_window_destroy (tree_view->priv->drag_highlight_window);
3554             }
3555
3556           attributes.window_type = GDK_WINDOW_TEMP;
3557           attributes.wclass = GDK_INPUT_OUTPUT;
3558           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
3559           attributes.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
3560           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3561           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
3562           attributes.x = x;
3563           attributes.y = y;
3564           attributes.width = width;
3565           attributes.height = height;
3566           tree_view->priv->drag_highlight_window = gdk_window_new (NULL, &attributes, attributes_mask);
3567           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
3568
3569           mask = gdk_pixmap_new (tree_view->priv->drag_highlight_window, width, height, 1);
3570           cr = gdk_cairo_create (mask);
3571
3572           cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
3573           cairo_paint (cr);
3574           cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
3575           /* mirror if we're on the left */
3576           if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT)
3577             {
3578               cairo_translate (cr, width, 0);
3579               cairo_scale (cr, -1, 1);
3580             }
3581           cairo_move_to (cr, 0, 0);
3582           cairo_line_to (cr, width, width);
3583           cairo_line_to (cr, 0, tree_view->priv->expander_size);
3584           cairo_move_to (cr, 0, height);
3585           cairo_line_to (cr, width, height - width);
3586           cairo_line_to (cr, 0, height - tree_view->priv->expander_size);
3587           cairo_fill (cr);
3588
3589           cairo_destroy (cr);
3590           gdk_window_shape_combine_mask (tree_view->priv->drag_highlight_window,
3591                                          mask, 0, 0);
3592           if (mask) g_object_unref (mask);
3593         }
3594
3595       tree_view->priv->drag_column_window_state = arrow_type;
3596       gdk_window_move (tree_view->priv->drag_highlight_window, x, y);
3597    }
3598   else
3599     {
3600       g_warning (G_STRLOC"Invalid GtkTreeViewColumnReorder struct");
3601       gdk_window_hide (tree_view->priv->drag_highlight_window);
3602       return;
3603     }
3604
3605   gdk_window_show (tree_view->priv->drag_highlight_window);
3606   gdk_window_raise (tree_view->priv->drag_highlight_window);
3607 }
3608
3609 static gboolean
3610 gtk_tree_view_motion_resize_column (GtkWidget      *widget,
3611                                     GdkEventMotion *event)
3612 {
3613   gint x;
3614   gint new_width;
3615   GtkTreeViewColumn *column;
3616   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
3617
3618   column = gtk_tree_view_get_column (tree_view, tree_view->priv->drag_pos);
3619
3620   if (event->is_hint || event->window != widget->window)
3621     gtk_widget_get_pointer (widget, &x, NULL);
3622   else
3623     x = event->x;
3624
3625   if (tree_view->priv->hadjustment)
3626     x += tree_view->priv->hadjustment->value;
3627
3628   new_width = gtk_tree_view_new_column_width (tree_view,
3629                                               tree_view->priv->drag_pos, &x);
3630   if (x != tree_view->priv->x_drag &&
3631       (new_width != column->fixed_width))
3632     {
3633       column->use_resized_width = TRUE;
3634       column->resized_width = new_width;
3635       if (column->expand)
3636         column->resized_width -= tree_view->priv->last_extra_space_per_column;
3637       gtk_widget_queue_resize (widget);
3638     }
3639
3640   return FALSE;
3641 }
3642
3643
3644 static void
3645 gtk_tree_view_update_current_reorder (GtkTreeView *tree_view)
3646 {
3647   GtkTreeViewColumnReorder *reorder = NULL;
3648   GList *list;
3649   gint mouse_x;
3650
3651   gdk_window_get_pointer (tree_view->priv->header_window, &mouse_x, NULL, NULL);
3652   for (list = tree_view->priv->column_drag_info; list; list = list->next)
3653     {
3654       reorder = (GtkTreeViewColumnReorder *) list->data;
3655       if (mouse_x >= reorder->left_align && mouse_x < reorder->right_align)
3656         break;
3657       reorder = NULL;
3658     }
3659
3660   /*  if (reorder && reorder == tree_view->priv->cur_reorder)
3661       return;*/
3662
3663   tree_view->priv->cur_reorder = reorder;
3664   gtk_tree_view_motion_draw_column_motion_arrow (tree_view);
3665 }
3666
3667 static void
3668 gtk_tree_view_vertical_autoscroll (GtkTreeView *tree_view)
3669 {
3670   GdkRectangle visible_rect;
3671   gint y;
3672   gint offset;
3673
3674   gdk_window_get_pointer (tree_view->priv->bin_window, NULL, &y, NULL);
3675   y += tree_view->priv->dy;
3676
3677   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
3678
3679   /* see if we are near the edge. */
3680   offset = y - (visible_rect.y + 2 * SCROLL_EDGE_SIZE);
3681   if (offset > 0)
3682     {
3683       offset = y - (visible_rect.y + visible_rect.height - 2 * SCROLL_EDGE_SIZE);
3684       if (offset < 0)
3685         return;
3686     }
3687
3688   gtk_adjustment_set_value (tree_view->priv->vadjustment,
3689                             MAX (tree_view->priv->vadjustment->value + offset, 0.0));
3690 }
3691
3692 static gboolean
3693 gtk_tree_view_horizontal_autoscroll (GtkTreeView *tree_view)
3694 {
3695   GdkRectangle visible_rect;
3696   gint x;
3697   gint offset;
3698
3699   gdk_window_get_pointer (tree_view->priv->bin_window, &x, NULL, NULL);
3700
3701   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
3702
3703   /* See if we are near the edge. */
3704   offset = x - (visible_rect.x + SCROLL_EDGE_SIZE);
3705   if (offset > 0)
3706     {
3707       offset = x - (visible_rect.x + visible_rect.width - SCROLL_EDGE_SIZE);
3708       if (offset < 0)
3709         return TRUE;
3710     }
3711   offset = offset/3;
3712
3713   gtk_adjustment_set_value (tree_view->priv->hadjustment,
3714                             MAX (tree_view->priv->hadjustment->value + offset, 0.0));
3715
3716   return TRUE;
3717
3718 }
3719
3720 static gboolean
3721 gtk_tree_view_motion_drag_column (GtkWidget      *widget,
3722                                   GdkEventMotion *event)
3723 {
3724   GtkTreeView *tree_view = (GtkTreeView *) widget;
3725   GtkTreeViewColumn *column = tree_view->priv->drag_column;
3726   gint x, y;
3727
3728   /* Sanity Check */
3729   if ((column == NULL) ||
3730       (event->window != tree_view->priv->drag_window))
3731     return FALSE;
3732
3733   /* Handle moving the header */
3734   gdk_window_get_position (tree_view->priv->drag_window, &x, &y);
3735   x = CLAMP (x + (gint)event->x - column->drag_x, 0,
3736              MAX (tree_view->priv->width, GTK_WIDGET (tree_view)->allocation.width) - column->button->allocation.width);
3737   gdk_window_move (tree_view->priv->drag_window, x, y);
3738   
3739   /* autoscroll, if needed */
3740   gtk_tree_view_horizontal_autoscroll (tree_view);
3741   /* Update the current reorder position and arrow; */
3742   gtk_tree_view_update_current_reorder (tree_view);
3743
3744   return TRUE;
3745 }
3746
3747 static void
3748 gtk_tree_view_stop_rubber_band (GtkTreeView *tree_view)
3749 {
3750   remove_scroll_timeout (tree_view);
3751   gtk_grab_remove (GTK_WIDGET (tree_view));
3752
3753   if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
3754     {
3755       GtkTreePath *tmp_path;
3756
3757       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
3758
3759       /* The anchor path should be set to the start path */
3760       tmp_path = _gtk_tree_view_find_path (tree_view,
3761                                            tree_view->priv->rubber_band_start_tree,
3762                                            tree_view->priv->rubber_band_start_node);
3763
3764       if (tree_view->priv->anchor)
3765         gtk_tree_row_reference_free (tree_view->priv->anchor);
3766
3767       tree_view->priv->anchor =
3768         gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
3769                                           tree_view->priv->model,
3770                                           tmp_path);
3771
3772       gtk_tree_path_free (tmp_path);
3773
3774       /* ... and the cursor to the end path */
3775       tmp_path = _gtk_tree_view_find_path (tree_view,
3776                                            tree_view->priv->rubber_band_end_tree,
3777                                            tree_view->priv->rubber_band_end_node);
3778       gtk_tree_view_real_set_cursor (GTK_TREE_VIEW (tree_view), tmp_path, FALSE, FALSE);
3779       gtk_tree_path_free (tmp_path);
3780
3781       _gtk_tree_selection_emit_changed (tree_view->priv->selection);
3782     }
3783
3784   /* Clear status variables */
3785   tree_view->priv->rubber_band_status = RUBBER_BAND_OFF;
3786   tree_view->priv->rubber_band_shift = 0;
3787   tree_view->priv->rubber_band_ctrl = 0;
3788
3789   tree_view->priv->rubber_band_start_node = NULL;
3790   tree_view->priv->rubber_band_start_tree = NULL;
3791   tree_view->priv->rubber_band_end_node = NULL;
3792   tree_view->priv->rubber_band_end_tree = NULL;
3793 }
3794
3795 static void
3796 gtk_tree_view_update_rubber_band_selection_range (GtkTreeView *tree_view,
3797                                                  GtkRBTree   *start_tree,
3798                                                  GtkRBNode   *start_node,
3799                                                  GtkRBTree   *end_tree,
3800                                                  GtkRBNode   *end_node,
3801                                                  gboolean     select,
3802                                                  gboolean     skip_start,
3803                                                  gboolean     skip_end)
3804 {
3805   if (start_node == end_node)
3806     return;
3807
3808   /* We skip the first node and jump inside the loop */
3809   if (skip_start)
3810     goto skip_first;
3811
3812   do
3813     {
3814       /* Small optimization by assuming insensitive nodes are never
3815        * selected.
3816        */
3817       if (!GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
3818         {
3819           GtkTreePath *path;
3820           gboolean selectable;
3821
3822           path = _gtk_tree_view_find_path (tree_view, start_tree, start_node);
3823           selectable = _gtk_tree_selection_row_is_selectable (tree_view->priv->selection, start_node, path);
3824           gtk_tree_path_free (path);
3825
3826           if (!selectable)
3827             goto node_not_selectable;
3828         }
3829
3830       if (select)
3831         {
3832           if (tree_view->priv->rubber_band_shift)
3833             GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3834           else if (tree_view->priv->rubber_band_ctrl)
3835             {
3836               /* Toggle the selection state */
3837               if (GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
3838                 GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3839               else
3840                 GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3841             }
3842           else
3843             GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3844         }
3845       else
3846         {
3847           /* Mirror the above */
3848           if (tree_view->priv->rubber_band_shift)
3849             GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3850           else if (tree_view->priv->rubber_band_ctrl)
3851             {
3852               /* Toggle the selection state */
3853               if (GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
3854                 GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3855               else
3856                 GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3857             }
3858           else
3859             GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3860         }
3861
3862       _gtk_tree_view_queue_draw_node (tree_view, start_tree, start_node, NULL);
3863
3864 node_not_selectable:
3865       if (start_node == end_node)
3866         break;
3867
3868 skip_first:
3869
3870       if (start_node->children)
3871         {
3872           start_tree = start_node->children;
3873           start_node = start_tree->root;
3874           while (start_node->left != start_tree->nil)
3875             start_node = start_node->left;
3876         }
3877       else
3878         {
3879           _gtk_rbtree_next_full (start_tree, start_node, &start_tree, &start_node);
3880
3881           if (!start_tree)
3882             /* Ran out of tree */
3883             break;
3884         }
3885
3886       if (skip_end && start_node == end_node)
3887         break;
3888     }
3889   while (TRUE);
3890 }
3891
3892 static void
3893 gtk_tree_view_update_rubber_band_selection (GtkTreeView *tree_view)
3894 {
3895   GtkRBTree *start_tree, *end_tree;
3896   GtkRBNode *start_node, *end_node;
3897
3898   _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);
3899   _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);
3900
3901   /* Handle the start area first */
3902   if (!tree_view->priv->rubber_band_start_node)
3903     {
3904       gtk_tree_view_update_rubber_band_selection_range (tree_view,
3905                                                        start_tree,
3906                                                        start_node,
3907                                                        end_tree,
3908                                                        end_node,
3909                                                        TRUE,
3910                                                        FALSE,
3911                                                        FALSE);
3912     }
3913   else if (_gtk_rbtree_node_find_offset (start_tree, start_node) <
3914            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_start_tree, tree_view->priv->rubber_band_start_node))
3915     {
3916       /* New node is above the old one; selection became bigger */
3917       gtk_tree_view_update_rubber_band_selection_range (tree_view,
3918                                                        start_tree,
3919                                                        start_node,
3920                                                        tree_view->priv->rubber_band_start_tree,
3921                                                        tree_view->priv->rubber_band_start_node,
3922                                                        TRUE,
3923                                                        FALSE,
3924                                                        TRUE);
3925     }
3926   else if (_gtk_rbtree_node_find_offset (start_tree, start_node) >
3927            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_start_tree, tree_view->priv->rubber_band_start_node))
3928     {
3929       /* New node is below the old one; selection became smaller */
3930       gtk_tree_view_update_rubber_band_selection_range (tree_view,
3931                                                        tree_view->priv->rubber_band_start_tree,
3932                                                        tree_view->priv->rubber_band_start_node,
3933                                                        start_tree,
3934                                                        start_node,
3935                                                        FALSE,
3936                                                        FALSE,
3937                                                        TRUE);
3938     }
3939
3940   tree_view->priv->rubber_band_start_tree = start_tree;
3941   tree_view->priv->rubber_band_start_node = start_node;
3942
3943   /* Next, handle the end area */
3944   if (!tree_view->priv->rubber_band_end_node)
3945     {
3946       /* In the event this happens, start_node was also NULL; this case is
3947        * handled above.
3948        */
3949     }
3950   else if (!end_node)
3951     {
3952       /* Find the last node in the tree */
3953       _gtk_rbtree_find_offset (tree_view->priv->tree, tree_view->priv->height - 1,
3954                                &end_tree, &end_node);
3955
3956       /* Selection reached end of the tree */
3957       gtk_tree_view_update_rubber_band_selection_range (tree_view,
3958                                                        tree_view->priv->rubber_band_end_tree,
3959                                                        tree_view->priv->rubber_band_end_node,
3960                                                        end_tree,
3961                                                        end_node,
3962                                                        TRUE,
3963                                                        TRUE,
3964                                                        FALSE);
3965     }
3966   else if (_gtk_rbtree_node_find_offset (end_tree, end_node) >
3967            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_end_tree, tree_view->priv->rubber_band_end_node))
3968     {
3969       /* New node is below the old one; selection became bigger */
3970       gtk_tree_view_update_rubber_band_selection_range (tree_view,
3971                                                        tree_view->priv->rubber_band_end_tree,
3972                                                        tree_view->priv->rubber_band_end_node,
3973                                                        end_tree,
3974                                                        end_node,
3975                                                        TRUE,
3976                                                        TRUE,
3977                                                        FALSE);
3978     }
3979   else if (_gtk_rbtree_node_find_offset (end_tree, end_node) <
3980            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_end_tree, tree_view->priv->rubber_band_end_node))
3981     {
3982       /* New node is above the old one; selection became smaller */
3983       gtk_tree_view_update_rubber_band_selection_range (tree_view,
3984                                                        end_tree,
3985                                                        end_node,
3986                                                        tree_view->priv->rubber_band_end_tree,
3987                                                        tree_view->priv->rubber_band_end_node,
3988                                                        FALSE,
3989                                                        TRUE,
3990                                                        FALSE);
3991     }
3992
3993   tree_view->priv->rubber_band_end_tree = end_tree;
3994   tree_view->priv->rubber_band_end_node = end_node;
3995 }
3996
3997 static void
3998 gtk_tree_view_update_rubber_band (GtkTreeView *tree_view)
3999 {
4000   gint x, y;
4001   GdkRectangle old_area;
4002   GdkRectangle new_area;
4003   GdkRectangle common;
4004   cairo_region_t *invalid_region;
4005
4006   old_area.x = MIN (tree_view->priv->press_start_x, tree_view->priv->rubber_band_x);
4007   old_area.y = MIN (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y) - tree_view->priv->dy;
4008   old_area.width = ABS (tree_view->priv->rubber_band_x - tree_view->priv->press_start_x) + 1;
4009   old_area.height = ABS (tree_view->priv->rubber_band_y - tree_view->priv->press_start_y) + 1;
4010
4011   gdk_window_get_pointer (tree_view->priv->bin_window, &x, &y, NULL);
4012
4013   x = MAX (x, 0);
4014   y = MAX (y, 0) + tree_view->priv->dy;
4015
4016   new_area.x = MIN (tree_view->priv->press_start_x, x);
4017   new_area.y = MIN (tree_view->priv->press_start_y, y) - tree_view->priv->dy;
4018   new_area.width = ABS (x - tree_view->priv->press_start_x) + 1;
4019   new_area.height = ABS (y - tree_view->priv->press_start_y) + 1;
4020
4021   invalid_region = cairo_region_create_rectangle (&old_area);
4022   cairo_region_union_rectangle (invalid_region, &new_area);
4023
4024   gdk_rectangle_intersect (&old_area, &new_area, &common);
4025   if (common.width > 2 && common.height > 2)
4026     {
4027       cairo_region_t *common_region;
4028
4029       /* make sure the border is invalidated */
4030       common.x += 1;
4031       common.y += 1;
4032       common.width -= 2;
4033       common.height -= 2;
4034
4035       common_region = cairo_region_create_rectangle (&common);
4036
4037       cairo_region_subtract (invalid_region, common_region);
4038       cairo_region_destroy (common_region);
4039     }
4040
4041   gdk_window_invalidate_region (tree_view->priv->bin_window, invalid_region, TRUE);
4042
4043   cairo_region_destroy (invalid_region);
4044
4045   tree_view->priv->rubber_band_x = x;
4046   tree_view->priv->rubber_band_y = y;
4047
4048   gtk_tree_view_update_rubber_band_selection (tree_view);
4049 }
4050
4051 static void
4052 gtk_tree_view_paint_rubber_band (GtkTreeView  *tree_view,
4053                                 GdkRectangle *area)
4054 {
4055   cairo_t *cr;
4056   GdkRectangle rect;
4057   GdkRectangle rubber_rect;
4058
4059   rubber_rect.x = MIN (tree_view->priv->press_start_x, tree_view->priv->rubber_band_x);
4060   rubber_rect.y = MIN (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y) - tree_view->priv->dy;
4061   rubber_rect.width = ABS (tree_view->priv->press_start_x - tree_view->priv->rubber_band_x) + 1;
4062   rubber_rect.height = ABS (tree_view->priv->press_start_y - tree_view->priv->rubber_band_y) + 1;
4063
4064   if (!gdk_rectangle_intersect (&rubber_rect, area, &rect))
4065     return;
4066
4067   cr = gdk_cairo_create (tree_view->priv->bin_window);
4068   cairo_set_line_width (cr, 1.0);
4069
4070   cairo_set_source_rgba (cr,
4071                          GTK_WIDGET (tree_view)->style->fg[GTK_STATE_NORMAL].red / 65535.,
4072                          GTK_WIDGET (tree_view)->style->fg[GTK_STATE_NORMAL].green / 65535.,
4073                          GTK_WIDGET (tree_view)->style->fg[GTK_STATE_NORMAL].blue / 65535.,
4074                          .25);
4075
4076   gdk_cairo_rectangle (cr, &rect);
4077   cairo_clip (cr);
4078   cairo_paint (cr);
4079
4080   cairo_set_source_rgb (cr,
4081                         GTK_WIDGET (tree_view)->style->fg[GTK_STATE_NORMAL].red / 65535.,
4082                         GTK_WIDGET (tree_view)->style->fg[GTK_STATE_NORMAL].green / 65535.,
4083                         GTK_WIDGET (tree_view)->style->fg[GTK_STATE_NORMAL].blue / 65535.);
4084
4085   cairo_rectangle (cr,
4086                    rubber_rect.x + 0.5, rubber_rect.y + 0.5,
4087                    rubber_rect.width - 1, rubber_rect.height - 1);
4088   cairo_stroke (cr);
4089
4090   cairo_destroy (cr);
4091 }
4092
4093 static gboolean
4094 gtk_tree_view_motion_bin_window (GtkWidget      *widget,
4095                                  GdkEventMotion *event)
4096 {
4097   GtkTreeView *tree_view;
4098   GtkRBTree *tree;
4099   GtkRBNode *node;
4100   gint new_y;
4101
4102   tree_view = (GtkTreeView *) widget;
4103
4104   if (tree_view->priv->tree == NULL)
4105     return FALSE;
4106
4107   if (tree_view->priv->rubber_band_status == RUBBER_BAND_MAYBE_START)
4108     {
4109       gtk_grab_add (GTK_WIDGET (tree_view));
4110       gtk_tree_view_update_rubber_band (tree_view);
4111
4112       tree_view->priv->rubber_band_status = RUBBER_BAND_ACTIVE;
4113     }
4114   else if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
4115     {
4116       gtk_tree_view_update_rubber_band (tree_view);
4117
4118       add_scroll_timeout (tree_view);
4119     }
4120
4121   /* only check for an initiated drag when a button is pressed */
4122   if (tree_view->priv->pressed_button >= 0
4123       && !tree_view->priv->rubber_band_status)
4124     gtk_tree_view_maybe_begin_dragging_row (tree_view, event);
4125
4126   new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
4127   if (new_y < 0)
4128     new_y = 0;
4129
4130   _gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
4131
4132   /* If we are currently pressing down a button, we don't want to prelight anything else. */
4133   if ((tree_view->priv->button_pressed_node != NULL) &&
4134       (tree_view->priv->button_pressed_node != node))
4135     node = NULL;
4136
4137   tree_view->priv->event_last_x = event->x;
4138   tree_view->priv->event_last_y = event->y;
4139
4140   prelight_or_select (tree_view, tree, node, event->x, event->y);
4141
4142   return TRUE;
4143 }
4144
4145 static gboolean
4146 gtk_tree_view_motion (GtkWidget      *widget,
4147                       GdkEventMotion *event)
4148 {
4149   GtkTreeView *tree_view;
4150
4151   tree_view = (GtkTreeView *) widget;
4152
4153   /* Resizing a column */
4154   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE))
4155     return gtk_tree_view_motion_resize_column (widget, event);
4156
4157   /* Drag column */
4158   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
4159     return gtk_tree_view_motion_drag_column (widget, event);
4160
4161   /* Sanity check it */
4162   if (event->window == tree_view->priv->bin_window)
4163     return gtk_tree_view_motion_bin_window (widget, event);
4164
4165   return FALSE;
4166 }
4167
4168 /* Invalidate the focus rectangle near the edge of the bin_window; used when
4169  * the tree is empty.
4170  */
4171 static void
4172 invalidate_empty_focus (GtkTreeView *tree_view)
4173 {
4174   GdkRectangle area;
4175
4176   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
4177     return;
4178
4179   area.x = 0;
4180   area.y = 0;
4181   gdk_drawable_get_size (tree_view->priv->bin_window, &area.width, &area.height);
4182   gdk_window_invalidate_rect (tree_view->priv->bin_window, &area, FALSE);
4183 }
4184
4185 /* Draws a focus rectangle near the edge of the bin_window; used when the tree
4186  * is empty.
4187  */
4188 static void
4189 draw_empty_focus (GtkTreeView *tree_view, GdkRectangle *clip_area)
4190 {
4191   GtkWidget *widget = GTK_WIDGET (tree_view);
4192   gint w, h;
4193
4194   if (!gtk_widget_has_focus (widget))
4195     return;
4196
4197   gdk_drawable_get_size (tree_view->priv->bin_window, &w, &h);
4198
4199   w -= 2;
4200   h -= 2;
4201
4202   if (w > 0 && h > 0)
4203     gtk_paint_focus (gtk_widget_get_style (widget),
4204                      tree_view->priv->bin_window,
4205                      gtk_widget_get_state (widget),
4206                      clip_area,
4207                      widget,
4208                      NULL,
4209                      1, 1, w, h);
4210 }
4211
4212 typedef enum {
4213   GTK_TREE_VIEW_GRID_LINE,
4214   GTK_TREE_VIEW_TREE_LINE,
4215   GTK_TREE_VIEW_FOREGROUND_LINE
4216 } GtkTreeViewLineType;
4217
4218 static void
4219 gtk_tree_view_draw_line (GtkTreeView         *tree_view,
4220                          GdkWindow           *window,
4221                          GtkTreeViewLineType  type,
4222                          int                  x1,
4223                          int                  y1,
4224                          int                  x2,
4225                          int                  y2)
4226 {
4227   cairo_t *cr;
4228   int line_width;
4229
4230   cr = gdk_cairo_create (window);
4231
4232   switch (type)
4233     {
4234     case GTK_TREE_VIEW_TREE_LINE:
4235       cairo_set_source_rgb (cr, 0, 0, 0);
4236       cairo_set_line_width (cr, tree_view->priv->tree_line_width);
4237       if (tree_view->priv->tree_line_dashes[0])
4238         cairo_set_dash (cr, 
4239                         tree_view->priv->tree_line_dashes,
4240                         2, 0.5);
4241       break;
4242     case GTK_TREE_VIEW_GRID_LINE:
4243       cairo_set_source_rgb (cr, 0, 0, 0);
4244       cairo_set_line_width (cr, tree_view->priv->grid_line_width);
4245       if (tree_view->priv->grid_line_dashes[0])
4246         cairo_set_dash (cr, 
4247                         tree_view->priv->grid_line_dashes,
4248                         2, 0.5);
4249       break;
4250     default:
4251       g_assert_not_reached ();
4252       /* fall through */
4253     case GTK_TREE_VIEW_FOREGROUND_LINE:
4254       cairo_set_line_width (cr, 1.0);
4255       gdk_cairo_set_source_color (cr,
4256           &GTK_WIDGET (tree_view)->style->fg[gtk_widget_get_state (GTK_WIDGET (tree_view))]);
4257       break;
4258     }
4259
4260   cairo_move_to (cr, x1 + 0.5, y1 + 0.5);
4261   cairo_line_to (cr, x2 + 0.5, y2 + 0.5);
4262   cairo_stroke (cr);
4263
4264   cairo_destroy (cr);
4265 }
4266                          
4267 static void
4268 gtk_tree_view_draw_grid_lines (GtkTreeView    *tree_view,
4269                                GdkEventExpose *event,
4270                                gint            n_visible_columns)
4271 {
4272   GList *list = tree_view->priv->columns;
4273   gint i = 0;
4274   gint current_x = 0;
4275
4276   if (tree_view->priv->grid_lines != GTK_TREE_VIEW_GRID_LINES_VERTICAL
4277       && tree_view->priv->grid_lines != GTK_TREE_VIEW_GRID_LINES_BOTH)
4278     return;
4279
4280   /* Only draw the lines for visible rows and columns */
4281   for (list = tree_view->priv->columns; list; list = list->next, i++)
4282     {
4283       GtkTreeViewColumn *column = list->data;
4284
4285       /* We don't want a line for the last column */
4286       if (i == n_visible_columns - 1)
4287         break;
4288
4289       if (! column->visible)
4290         continue;
4291
4292       current_x += column->width;
4293
4294       gtk_tree_view_draw_line (tree_view, event->window,
4295                                GTK_TREE_VIEW_GRID_LINE,
4296                                current_x - 1, 0,
4297                                current_x - 1, tree_view->priv->height);
4298     }
4299 }
4300
4301 /* Warning: Very scary function.
4302  * Modify at your own risk
4303  *
4304  * KEEP IN SYNC WITH gtk_tree_view_create_row_drag_icon()!
4305  * FIXME: It's not...
4306  */
4307 static gboolean
4308 gtk_tree_view_bin_expose (GtkWidget      *widget,
4309                           GdkEventExpose *event)
4310 {
4311   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
4312   GtkTreePath *path;
4313   GtkRBTree *tree;
4314   GList *list;
4315   GtkRBNode *node;
4316   GtkRBNode *cursor = NULL;
4317   GtkRBTree *cursor_tree = NULL;
4318   GtkRBNode *drag_highlight = NULL;
4319   GtkRBTree *drag_highlight_tree = NULL;
4320   GtkTreeIter iter;
4321   gint new_y;
4322   gint y_offset, cell_offset;
4323   gint max_height;
4324   gint depth;
4325   GdkRectangle background_area;
4326   GdkRectangle cell_area;
4327   guint flags;
4328   gint highlight_x;
4329   gint expander_cell_width;
4330   gint bin_window_width;
4331   gint bin_window_height;
4332   GtkTreePath *cursor_path;
4333   GtkTreePath *drag_dest_path;
4334   GList *first_column, *last_column;
4335   gint vertical_separator;
4336   gint horizontal_separator;
4337   gint focus_line_width;
4338   gboolean allow_rules;
4339   gboolean has_special_cell;
4340   gboolean rtl;
4341   gint n_visible_columns;
4342   gint pointer_x, pointer_y;
4343   gint grid_line_width;
4344   gboolean got_pointer = FALSE;
4345   gboolean row_ending_details;
4346   gboolean draw_vgrid_lines, draw_hgrid_lines;
4347
4348   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
4349
4350   gtk_widget_style_get (widget,
4351                         "horizontal-separator", &horizontal_separator,
4352                         "vertical-separator", &vertical_separator,
4353                         "allow-rules", &allow_rules,
4354                         "focus-line-width", &focus_line_width,
4355                         "row-ending-details", &row_ending_details,
4356                         NULL);
4357
4358   if (tree_view->priv->tree == NULL)
4359     {
4360       draw_empty_focus (tree_view, &event->area);
4361       return TRUE;
4362     }
4363
4364   /* clip event->area to the visible area */
4365   if (event->area.height < 0)
4366     return TRUE;
4367
4368   validate_visible_area (tree_view);
4369
4370   new_y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, event->area.y);
4371
4372   if (new_y < 0)
4373     new_y = 0;
4374   y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
4375   gdk_drawable_get_size (tree_view->priv->bin_window,
4376                          &bin_window_width, &bin_window_height);
4377
4378   if (tree_view->priv->height < bin_window_height)
4379     {
4380       gtk_paint_flat_box (widget->style,
4381                           event->window,
4382                           widget->state,
4383                           GTK_SHADOW_NONE,
4384                           &event->area,
4385                           widget,
4386                           "cell_even",
4387                           0, tree_view->priv->height,
4388                           bin_window_width,
4389                           bin_window_height - tree_view->priv->height);
4390     }
4391
4392   if (node == NULL)
4393     return TRUE;
4394
4395   /* find the path for the node */
4396   path = _gtk_tree_view_find_path ((GtkTreeView *)widget,
4397                                    tree,
4398                                    node);
4399   gtk_tree_model_get_iter (tree_view->priv->model,
4400                            &iter,
4401                            path);
4402   depth = gtk_tree_path_get_depth (path);
4403   gtk_tree_path_free (path);
4404   
4405   cursor_path = NULL;
4406   drag_dest_path = NULL;
4407
4408   if (tree_view->priv->cursor)
4409     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
4410
4411   if (cursor_path)
4412     _gtk_tree_view_find_node (tree_view, cursor_path,
4413                               &cursor_tree, &cursor);
4414
4415   if (tree_view->priv->drag_dest_row)
4416     drag_dest_path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
4417
4418   if (drag_dest_path)
4419     _gtk_tree_view_find_node (tree_view, drag_dest_path,
4420                               &drag_highlight_tree, &drag_highlight);
4421
4422   draw_vgrid_lines =
4423     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_VERTICAL
4424     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
4425   draw_hgrid_lines =
4426     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_HORIZONTAL
4427     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
4428
4429   if (draw_vgrid_lines || draw_hgrid_lines)
4430     gtk_widget_style_get (widget, "grid-line-width", &grid_line_width, NULL);
4431   
4432   n_visible_columns = 0;
4433   for (list = tree_view->priv->columns; list; list = list->next)
4434     {
4435       if (! GTK_TREE_VIEW_COLUMN (list->data)->visible)
4436         continue;
4437       n_visible_columns ++;
4438     }
4439
4440   /* Find the last column */
4441   for (last_column = g_list_last (tree_view->priv->columns);
4442        last_column && !(GTK_TREE_VIEW_COLUMN (last_column->data)->visible);
4443        last_column = last_column->prev)
4444     ;
4445
4446   /* and the first */
4447   for (first_column = g_list_first (tree_view->priv->columns);
4448        first_column && !(GTK_TREE_VIEW_COLUMN (first_column->data)->visible);
4449        first_column = first_column->next)
4450     ;
4451
4452   /* Actually process the expose event.  To do this, we want to
4453    * start at the first node of the event, and walk the tree in
4454    * order, drawing each successive node.
4455    */
4456
4457   do
4458     {
4459       gboolean parity;
4460       gboolean is_separator = FALSE;
4461       gboolean is_first = FALSE;
4462       gboolean is_last = FALSE;
4463       
4464       is_separator = row_is_separator (tree_view, &iter, NULL);
4465
4466       max_height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
4467
4468       cell_offset = 0;
4469       highlight_x = 0; /* should match x coord of first cell */
4470       expander_cell_width = 0;
4471
4472       background_area.y = y_offset + event->area.y;
4473       background_area.height = max_height;
4474
4475       flags = 0;
4476
4477       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PRELIT))
4478         flags |= GTK_CELL_RENDERER_PRELIT;
4479
4480       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
4481         flags |= GTK_CELL_RENDERER_SELECTED;
4482
4483       parity = _gtk_rbtree_node_find_parity (tree, node);
4484
4485       /* we *need* to set cell data on all cells before the call
4486        * to _has_special_cell, else _has_special_cell() does not
4487        * return a correct value.
4488        */
4489       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
4490            list;
4491            list = (rtl ? list->prev : list->next))
4492         {
4493           GtkTreeViewColumn *column = list->data;
4494           gtk_tree_view_column_cell_set_cell_data (column,
4495                                                    tree_view->priv->model,
4496                                                    &iter,
4497                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
4498                                                    node->children?TRUE:FALSE);
4499         }
4500
4501       has_special_cell = gtk_tree_view_has_special_cell (tree_view);
4502
4503       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
4504            list;
4505            list = (rtl ? list->prev : list->next))
4506         {
4507           GtkTreeViewColumn *column = list->data;
4508           const gchar *detail = NULL;
4509           GtkStateType state;
4510
4511           if (!column->visible)
4512             continue;
4513
4514           if (cell_offset > event->area.x + event->area.width ||
4515               cell_offset + column->width < event->area.x)
4516             {
4517               cell_offset += column->width;
4518               continue;
4519             }
4520
4521           if (column->show_sort_indicator)
4522             flags |= GTK_CELL_RENDERER_SORTED;
4523           else
4524             flags &= ~GTK_CELL_RENDERER_SORTED;
4525
4526           if (cursor == node)
4527             flags |= GTK_CELL_RENDERER_FOCUSED;
4528           else
4529             flags &= ~GTK_CELL_RENDERER_FOCUSED;
4530
4531           background_area.x = cell_offset;
4532           background_area.width = column->width;
4533
4534           cell_area = background_area;
4535           cell_area.y += vertical_separator / 2;
4536           cell_area.x += horizontal_separator / 2;
4537           cell_area.height -= vertical_separator;
4538           cell_area.width -= horizontal_separator;
4539
4540           if (draw_vgrid_lines)
4541             {
4542               if (list == first_column)
4543                 {
4544                   cell_area.width -= grid_line_width / 2;
4545                 }
4546               else if (list == last_column)
4547                 {
4548                   cell_area.x += grid_line_width / 2;
4549                   cell_area.width -= grid_line_width / 2;
4550                 }
4551               else
4552                 {
4553                   cell_area.x += grid_line_width / 2;
4554                   cell_area.width -= grid_line_width;
4555                 }
4556             }
4557
4558           if (draw_hgrid_lines)
4559             {
4560               cell_area.y += grid_line_width / 2;
4561               cell_area.height -= grid_line_width;
4562             }
4563
4564           if (cairo_region_contains_rectangle (event->region, &background_area) == CAIRO_REGION_OVERLAP_OUT)
4565             {
4566               cell_offset += column->width;
4567               continue;
4568             }
4569
4570           gtk_tree_view_column_cell_set_cell_data (column,
4571                                                    tree_view->priv->model,
4572                                                    &iter,
4573                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
4574                                                    node->children?TRUE:FALSE);
4575
4576           /* Select the detail for drawing the cell.  relevant
4577            * factors are parity, sortedness, and whether to
4578            * display rules.
4579            */
4580           if (allow_rules && tree_view->priv->has_rules)
4581             {
4582               if ((flags & GTK_CELL_RENDERER_SORTED) &&
4583                   n_visible_columns >= 3)
4584                 {
4585                   if (parity)
4586                     detail = "cell_odd_ruled_sorted";
4587                   else
4588                     detail = "cell_even_ruled_sorted";
4589                 }
4590               else
4591                 {
4592                   if (parity)
4593                     detail = "cell_odd_ruled";
4594                   else
4595                     detail = "cell_even_ruled";
4596                 }
4597             }
4598           else
4599             {
4600               if ((flags & GTK_CELL_RENDERER_SORTED) &&
4601                   n_visible_columns >= 3)
4602                 {
4603                   if (parity)
4604                     detail = "cell_odd_sorted";
4605                   else
4606                     detail = "cell_even_sorted";
4607                 }
4608               else
4609                 {
4610                   if (parity)
4611                     detail = "cell_odd";
4612                   else
4613                     detail = "cell_even";
4614                 }
4615             }
4616
4617           g_assert (detail);
4618
4619           if (widget->state == GTK_STATE_INSENSITIVE)
4620             state = GTK_STATE_INSENSITIVE;          
4621           else if (flags & GTK_CELL_RENDERER_SELECTED)
4622             state = GTK_STATE_SELECTED;
4623           else
4624             state = GTK_STATE_NORMAL;
4625
4626           /* Draw background */
4627           if (row_ending_details)
4628             {
4629               char new_detail[128];
4630
4631               is_first = (rtl ? !list->next : !list->prev);
4632               is_last = (rtl ? !list->prev : !list->next);
4633
4634               /* (I don't like the snprintfs either, but couldn't find a
4635                * less messy way).
4636                */
4637               if (is_first && is_last)
4638                 g_snprintf (new_detail, 127, "%s", detail);
4639               else if (is_first)
4640                 g_snprintf (new_detail, 127, "%s_start", detail);
4641               else if (is_last)
4642                 g_snprintf (new_detail, 127, "%s_end", detail);
4643               else
4644                 g_snprintf (new_detail, 128, "%s_middle", detail);
4645
4646               gtk_paint_flat_box (widget->style,
4647                                   event->window,
4648                                   state,
4649                                   GTK_SHADOW_NONE,
4650                                   &event->area,
4651                                   widget,
4652                                   new_detail,
4653                                   background_area.x,
4654                                   background_area.y,
4655                                   background_area.width,
4656                                   background_area.height);
4657             }
4658           else
4659             {
4660               gtk_paint_flat_box (widget->style,
4661                                   event->window,
4662                                   state,
4663                                   GTK_SHADOW_NONE,
4664                                   &event->area,
4665                                   widget,
4666                                   detail,
4667                                   background_area.x,
4668                                   background_area.y,
4669                                   background_area.width,
4670                                   background_area.height);
4671             }
4672
4673           if (gtk_tree_view_is_expander_column (tree_view, column))
4674             {
4675               if (!rtl)
4676                 cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
4677               cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
4678
4679               if (TREE_VIEW_DRAW_EXPANDERS(tree_view))
4680                 {
4681                   if (!rtl)
4682                     cell_area.x += depth * tree_view->priv->expander_size;
4683                   cell_area.width -= depth * tree_view->priv->expander_size;
4684                 }
4685
4686               /* If we have an expander column, the highlight underline
4687                * starts with that column, so that it indicates which
4688                * level of the tree we're dropping at.
4689                */
4690               highlight_x = cell_area.x;
4691               expander_cell_width = cell_area.width;
4692
4693               if (is_separator)
4694                 gtk_paint_hline (widget->style,
4695                                  event->window,
4696                                  state,
4697                                  &cell_area,
4698                                  widget,
4699                                  NULL,
4700                                  cell_area.x,
4701                                  cell_area.x + cell_area.width,
4702                                  cell_area.y + cell_area.height / 2);
4703               else
4704                 _gtk_tree_view_column_cell_render (column,
4705                                                    event->window,
4706                                                    &background_area,
4707                                                    &cell_area,
4708                                                    &event->area,
4709                                                    flags);
4710               if (TREE_VIEW_DRAW_EXPANDERS(tree_view)
4711                   && (node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT)
4712                 {
4713                   if (!got_pointer)
4714                     {
4715                       gdk_window_get_pointer (tree_view->priv->bin_window, 
4716                                               &pointer_x, &pointer_y, NULL);
4717                       got_pointer = TRUE;
4718                     }
4719
4720                   gtk_tree_view_draw_arrow (GTK_TREE_VIEW (widget),
4721                                             tree,
4722                                             node,
4723                                             pointer_x, pointer_y);
4724                 }
4725             }
4726           else
4727             {
4728               if (is_separator)
4729                 gtk_paint_hline (widget->style,
4730                                  event->window,
4731                                  state,
4732                                  &cell_area,
4733                                  widget,
4734                                  NULL,
4735                                  cell_area.x,
4736                                  cell_area.x + cell_area.width,
4737                                  cell_area.y + cell_area.height / 2);
4738               else
4739                 _gtk_tree_view_column_cell_render (column,
4740                                                    event->window,
4741                                                    &background_area,
4742                                                    &cell_area,
4743                                                    &event->area,
4744                                                    flags);
4745             }
4746
4747           if (draw_hgrid_lines)
4748             {
4749               if (background_area.y > 0)
4750                 gtk_tree_view_draw_line (tree_view, event->window,
4751                                          GTK_TREE_VIEW_GRID_LINE,
4752                                          background_area.x, background_area.y,
4753                                          background_area.x + background_area.width,
4754                                          background_area.y);
4755
4756               if (y_offset + max_height >= event->area.height)
4757                 gtk_tree_view_draw_line (tree_view, event->window,
4758                                          GTK_TREE_VIEW_GRID_LINE,
4759                                          background_area.x, background_area.y + max_height,
4760                                          background_area.x + background_area.width,
4761                                          background_area.y + max_height);
4762             }
4763
4764           if (gtk_tree_view_is_expander_column (tree_view, column) &&
4765               tree_view->priv->tree_lines_enabled)
4766             {
4767               gint x = background_area.x;
4768               gint mult = rtl ? -1 : 1;
4769               gint y0 = background_area.y;
4770               gint y1 = background_area.y + background_area.height/2;
4771               gint y2 = background_area.y + background_area.height;
4772
4773               if (rtl)
4774                 x += background_area.width - 1;
4775
4776               if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT
4777                   && depth > 1)
4778                 {
4779                   gtk_tree_view_draw_line (tree_view, event->window,
4780                                            GTK_TREE_VIEW_TREE_LINE,
4781                                            x + tree_view->priv->expander_size * (depth - 1.5) * mult,
4782                                            y1,
4783                                            x + tree_view->priv->expander_size * (depth - 1.1) * mult,
4784                                            y1);
4785                 }
4786               else if (depth > 1)
4787                 {
4788                   gtk_tree_view_draw_line (tree_view, event->window,
4789                                            GTK_TREE_VIEW_TREE_LINE,
4790                                            x + tree_view->priv->expander_size * (depth - 1.5) * mult,
4791                                            y1,
4792                                            x + tree_view->priv->expander_size * (depth - 0.5) * mult,
4793                                            y1);
4794                 }
4795
4796               if (depth > 1)
4797                 {
4798                   gint i;
4799                   GtkRBNode *tmp_node;
4800                   GtkRBTree *tmp_tree;
4801
4802                   if (!_gtk_rbtree_next (tree, node))
4803                     gtk_tree_view_draw_line (tree_view, event->window,
4804                                              GTK_TREE_VIEW_TREE_LINE,
4805                                              x + tree_view->priv->expander_size * (depth - 1.5) * mult,
4806                                              y0,
4807                                              x + tree_view->priv->expander_size * (depth - 1.5) * mult,
4808                                              y1);
4809                   else
4810                     gtk_tree_view_draw_line (tree_view, event->window,
4811                                              GTK_TREE_VIEW_TREE_LINE,
4812                                              x + tree_view->priv->expander_size * (depth - 1.5) * mult,
4813                                              y0,
4814                                              x + tree_view->priv->expander_size * (depth - 1.5) * mult,
4815                                              y2);
4816
4817                   tmp_node = tree->parent_node;
4818                   tmp_tree = tree->parent_tree;
4819
4820                   for (i = depth - 2; i > 0; i--)
4821                     {
4822                       if (_gtk_rbtree_next (tmp_tree, tmp_node))
4823                         gtk_tree_view_draw_line (tree_view, event->window,
4824                                                  GTK_TREE_VIEW_TREE_LINE,
4825                                                  x + tree_view->priv->expander_size * (i - 0.5) * mult,
4826                                                  y0,
4827                                                  x + tree_view->priv->expander_size * (i - 0.5) * mult,
4828                                                  y2);
4829
4830                       tmp_node = tmp_tree->parent_node;
4831                       tmp_tree = tmp_tree->parent_tree;
4832                     }
4833                 }
4834             }
4835
4836           if (node == cursor && has_special_cell &&
4837               ((column == tree_view->priv->focus_column &&
4838                 GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS) &&
4839                 gtk_widget_has_focus (widget)) ||
4840                (column == tree_view->priv->edited_column)))
4841             {
4842               _gtk_tree_view_column_cell_draw_focus (column,
4843                                                      event->window,
4844                                                      &background_area,
4845                                                      &cell_area,
4846                                                      &event->area,
4847                                                      flags);
4848             }
4849
4850           cell_offset += column->width;
4851         }
4852
4853       if (node == drag_highlight)
4854         {
4855           /* Draw indicator for the drop
4856            */
4857           gint highlight_y = -1;
4858           GtkRBTree *tree = NULL;
4859           GtkRBNode *node = NULL;
4860           gint width;
4861
4862           switch (tree_view->priv->drag_dest_pos)
4863             {
4864             case GTK_TREE_VIEW_DROP_BEFORE:
4865               highlight_y = background_area.y - 1;
4866               if (highlight_y < 0)
4867                       highlight_y = 0;
4868               break;
4869
4870             case GTK_TREE_VIEW_DROP_AFTER:
4871               highlight_y = background_area.y + background_area.height - 1;
4872               break;
4873
4874             case GTK_TREE_VIEW_DROP_INTO_OR_BEFORE:
4875             case GTK_TREE_VIEW_DROP_INTO_OR_AFTER:
4876               _gtk_tree_view_find_node (tree_view, drag_dest_path, &tree, &node);
4877
4878               if (tree == NULL)
4879                 break;
4880               gdk_drawable_get_size (tree_view->priv->bin_window,
4881                                      &width, NULL);
4882
4883               if (row_ending_details)
4884                 gtk_paint_focus (widget->style,
4885                                  tree_view->priv->bin_window,
4886                                  gtk_widget_get_state (widget),
4887                                  &event->area,
4888                                  widget,
4889                                  (is_first
4890                                   ? (is_last ? "treeview-drop-indicator" : "treeview-drop-indicator-left" )
4891                                   : (is_last ? "treeview-drop-indicator-right" : "tree-view-drop-indicator-middle" )),
4892                                  0, BACKGROUND_FIRST_PIXEL (tree_view, tree, node)
4893                                  - focus_line_width / 2,
4894                                  width, ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node))
4895                                - focus_line_width + 1);
4896               else
4897                 gtk_paint_focus (widget->style,
4898                                  tree_view->priv->bin_window,
4899                                  gtk_widget_get_state (widget),
4900                                  &event->area,
4901                                  widget,
4902                                  "treeview-drop-indicator",
4903                                  0, BACKGROUND_FIRST_PIXEL (tree_view, tree, node)
4904                                  - focus_line_width / 2,
4905                                  width, ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node))
4906                                  - focus_line_width + 1);
4907               break;
4908             }
4909
4910           if (highlight_y >= 0)
4911             {
4912               gtk_tree_view_draw_line (tree_view, event->window,
4913                                        GTK_TREE_VIEW_FOREGROUND_LINE,
4914                                        rtl ? highlight_x + expander_cell_width : highlight_x,
4915                                        highlight_y,
4916                                        rtl ? 0 : bin_window_width,
4917                                        highlight_y);
4918             }
4919         }
4920
4921       /* draw the big row-spanning focus rectangle, if needed */
4922       if (!has_special_cell && node == cursor &&
4923           GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS) &&
4924           gtk_widget_has_focus (widget))
4925         {
4926           gint tmp_y, tmp_height;
4927           gint width;
4928           GtkStateType focus_rect_state;
4929
4930           focus_rect_state =
4931             flags & GTK_CELL_RENDERER_SELECTED ? GTK_STATE_SELECTED :
4932             (flags & GTK_CELL_RENDERER_PRELIT ? GTK_STATE_PRELIGHT :
4933              (flags & GTK_CELL_RENDERER_INSENSITIVE ? GTK_STATE_INSENSITIVE :
4934               GTK_STATE_NORMAL));
4935
4936           gdk_drawable_get_size (tree_view->priv->bin_window,
4937                                  &width, NULL);
4938           
4939           if (draw_hgrid_lines)
4940             {
4941               tmp_y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node) + grid_line_width / 2;
4942               tmp_height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node)) - grid_line_width;
4943             }
4944           else
4945             {
4946               tmp_y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
4947               tmp_height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
4948             }
4949
4950           if (row_ending_details)
4951             gtk_paint_focus (widget->style,
4952                              tree_view->priv->bin_window,
4953                              focus_rect_state,
4954                              &event->area,
4955                              widget,
4956                              (is_first
4957                               ? (is_last ? "treeview" : "treeview-left" )
4958                               : (is_last ? "treeview-right" : "treeview-middle" )),
4959                              0, tmp_y,
4960                              width, tmp_height);
4961           else
4962             gtk_paint_focus (widget->style,
4963                              tree_view->priv->bin_window,
4964                              focus_rect_state,
4965                              &event->area,
4966                              widget,
4967                              "treeview",
4968                              0, tmp_y,
4969                              width, tmp_height);
4970         }
4971
4972       y_offset += max_height;
4973       if (node->children)
4974         {
4975           GtkTreeIter parent = iter;
4976           gboolean has_child;
4977
4978           tree = node->children;
4979           node = tree->root;
4980
4981           g_assert (node != tree->nil);
4982
4983           while (node->left != tree->nil)
4984             node = node->left;
4985           has_child = gtk_tree_model_iter_children (tree_view->priv->model,
4986                                                     &iter,
4987                                                     &parent);
4988           depth++;
4989
4990           /* Sanity Check! */
4991           TREE_VIEW_INTERNAL_ASSERT (has_child, FALSE);
4992         }
4993       else
4994         {
4995           gboolean done = FALSE;
4996
4997           do
4998             {
4999               node = _gtk_rbtree_next (tree, node);
5000               if (node != NULL)
5001                 {
5002                   gboolean has_next = gtk_tree_model_iter_next (tree_view->priv->model, &iter);
5003                   done = TRUE;
5004
5005                   /* Sanity Check! */
5006                   TREE_VIEW_INTERNAL_ASSERT (has_next, FALSE);
5007                 }
5008               else
5009                 {
5010                   GtkTreeIter parent_iter = iter;
5011                   gboolean has_parent;
5012
5013                   node = tree->parent_node;
5014                   tree = tree->parent_tree;
5015                   if (tree == NULL)
5016                     /* we should go to done to free some memory */
5017                     goto done;
5018                   has_parent = gtk_tree_model_iter_parent (tree_view->priv->model,
5019                                                            &iter,
5020                                                            &parent_iter);
5021                   depth--;
5022
5023                   /* Sanity check */
5024                   TREE_VIEW_INTERNAL_ASSERT (has_parent, FALSE);
5025                 }
5026             }
5027           while (!done);
5028         }
5029     }
5030   while (y_offset < event->area.height);
5031
5032 done:
5033   gtk_tree_view_draw_grid_lines (tree_view, event, n_visible_columns);
5034
5035   if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
5036     {
5037       GdkRectangle rectangle;
5038       gint n_rectangles;
5039  
5040       n_rectangles = cairo_region_num_rectangles (event->region);
5041  
5042       while (n_rectangles--)
5043         {
5044           cairo_region_get_rectangle (event->region, n_rectangles, &rectangle);
5045           gtk_tree_view_paint_rubber_band (tree_view, &rectangle);
5046         }
5047     }
5048
5049   if (cursor_path)
5050     gtk_tree_path_free (cursor_path);
5051
5052   if (drag_dest_path)
5053     gtk_tree_path_free (drag_dest_path);
5054
5055   return FALSE;
5056 }
5057
5058 static gboolean
5059 gtk_tree_view_expose (GtkWidget      *widget,
5060                       GdkEventExpose *event)
5061 {
5062   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
5063
5064   if (event->window == tree_view->priv->bin_window)
5065     {
5066       gboolean retval;
5067       GList *tmp_list;
5068
5069       retval = gtk_tree_view_bin_expose (widget, event);
5070
5071       /* We can't just chain up to Container::expose as it will try to send the
5072        * event to the headers, so we handle propagating it to our children
5073        * (eg. widgets being edited) ourselves.
5074        */
5075       tmp_list = tree_view->priv->children;
5076       while (tmp_list)
5077         {
5078           GtkTreeViewChild *child = tmp_list->data;
5079           tmp_list = tmp_list->next;
5080
5081           gtk_container_propagate_expose (GTK_CONTAINER (tree_view), child->widget, event);
5082         }
5083
5084       return retval;
5085     }
5086
5087   else if (event->window == tree_view->priv->header_window)
5088     {
5089       GList *list;
5090       
5091       for (list = tree_view->priv->columns; list != NULL; list = list->next)
5092         {
5093           GtkTreeViewColumn *column = list->data;
5094
5095           if (column == tree_view->priv->drag_column)
5096             continue;
5097
5098           if (column->visible)
5099             gtk_container_propagate_expose (GTK_CONTAINER (tree_view),
5100                                             column->button,
5101                                             event);
5102         }
5103     }
5104   else if (event->window == tree_view->priv->drag_window)
5105     {
5106       gtk_container_propagate_expose (GTK_CONTAINER (tree_view),
5107                                       tree_view->priv->drag_column->button,
5108                                       event);
5109     }
5110   return TRUE;
5111 }
5112
5113 enum
5114 {
5115   DROP_HOME,
5116   DROP_RIGHT,
5117   DROP_LEFT,
5118   DROP_END
5119 };
5120
5121 /* returns 0x1 when no column has been found -- yes it's hackish */
5122 static GtkTreeViewColumn *
5123 gtk_tree_view_get_drop_column (GtkTreeView       *tree_view,
5124                                GtkTreeViewColumn *column,
5125                                gint               drop_position)
5126 {
5127   GtkTreeViewColumn *left_column = NULL;
5128   GtkTreeViewColumn *cur_column = NULL;
5129   GList *tmp_list;
5130
5131   if (!column->reorderable)
5132     return (GtkTreeViewColumn *)0x1;
5133
5134   switch (drop_position)
5135     {
5136       case DROP_HOME:
5137         /* find first column where we can drop */
5138         tmp_list = tree_view->priv->columns;
5139         if (column == GTK_TREE_VIEW_COLUMN (tmp_list->data))
5140           return (GtkTreeViewColumn *)0x1;
5141
5142         while (tmp_list)
5143           {
5144             g_assert (tmp_list);
5145
5146             cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5147             tmp_list = tmp_list->next;
5148
5149             if (left_column && left_column->visible == FALSE)
5150               continue;
5151
5152             if (!tree_view->priv->column_drop_func)
5153               return left_column;
5154
5155             if (!tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5156               {
5157                 left_column = cur_column;
5158                 continue;
5159               }
5160
5161             return left_column;
5162           }
5163
5164         if (!tree_view->priv->column_drop_func)
5165           return left_column;
5166
5167         if (tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data))
5168           return left_column;
5169         else
5170           return (GtkTreeViewColumn *)0x1;
5171         break;
5172
5173       case DROP_RIGHT:
5174         /* find first column after column where we can drop */
5175         tmp_list = tree_view->priv->columns;
5176
5177         for (; tmp_list; tmp_list = tmp_list->next)
5178           if (GTK_TREE_VIEW_COLUMN (tmp_list->data) == column)
5179             break;
5180
5181         if (!tmp_list || !tmp_list->next)
5182           return (GtkTreeViewColumn *)0x1;
5183
5184         tmp_list = tmp_list->next;
5185         left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5186         tmp_list = tmp_list->next;
5187
5188         while (tmp_list)
5189           {
5190             g_assert (tmp_list);
5191
5192             cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5193             tmp_list = tmp_list->next;
5194
5195             if (left_column && left_column->visible == FALSE)
5196               {
5197                 left_column = cur_column;
5198                 if (tmp_list)
5199                   tmp_list = tmp_list->next;
5200                 continue;
5201               }
5202
5203             if (!tree_view->priv->column_drop_func)
5204               return left_column;
5205
5206             if (!tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5207               {
5208                 left_column = cur_column;
5209                 continue;
5210               }
5211
5212             return left_column;
5213           }
5214
5215         if (!tree_view->priv->column_drop_func)
5216           return left_column;
5217
5218         if (tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data))
5219           return left_column;
5220         else
5221           return (GtkTreeViewColumn *)0x1;
5222         break;
5223
5224       case DROP_LEFT:
5225         /* find first column before column where we can drop */
5226         tmp_list = tree_view->priv->columns;
5227
5228         for (; tmp_list; tmp_list = tmp_list->next)
5229           if (GTK_TREE_VIEW_COLUMN (tmp_list->data) == column)
5230             break;
5231
5232         if (!tmp_list || !tmp_list->prev)
5233           return (GtkTreeViewColumn *)0x1;
5234
5235         tmp_list = tmp_list->prev;
5236         cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5237         tmp_list = tmp_list->prev;
5238
5239         while (tmp_list)
5240           {
5241             g_assert (tmp_list);
5242
5243             left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5244
5245             if (left_column && !left_column->visible)
5246               {
5247                 /*if (!tmp_list->prev)
5248                   return (GtkTreeViewColumn *)0x1;
5249                   */
5250 /*
5251                 cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->prev->data);
5252                 tmp_list = tmp_list->prev->prev;
5253                 continue;*/
5254
5255                 cur_column = left_column;
5256                 if (tmp_list)
5257                   tmp_list = tmp_list->prev;
5258                 continue;
5259               }
5260
5261             if (!tree_view->priv->column_drop_func)
5262               return left_column;
5263
5264             if (tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5265               return left_column;
5266
5267             cur_column = left_column;
5268             tmp_list = tmp_list->prev;
5269           }
5270
5271         if (!tree_view->priv->column_drop_func)
5272           return NULL;
5273
5274         if (tree_view->priv->column_drop_func (tree_view, column, NULL, cur_column, tree_view->priv->column_drop_func_data))
5275           return NULL;
5276         else
5277           return (GtkTreeViewColumn *)0x1;
5278         break;
5279
5280       case DROP_END:
5281         /* same as DROP_HOME case, but doing it backwards */
5282         tmp_list = g_list_last (tree_view->priv->columns);
5283         cur_column = NULL;
5284
5285         if (column == GTK_TREE_VIEW_COLUMN (tmp_list->data))
5286           return (GtkTreeViewColumn *)0x1;
5287
5288         while (tmp_list)
5289           {
5290             g_assert (tmp_list);
5291
5292             left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5293
5294             if (left_column && !left_column->visible)
5295               {
5296                 cur_column = left_column;
5297                 tmp_list = tmp_list->prev;
5298               }
5299
5300             if (!tree_view->priv->column_drop_func)
5301               return left_column;
5302
5303             if (tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5304               return left_column;
5305
5306             cur_column = left_column;
5307             tmp_list = tmp_list->prev;
5308           }
5309
5310         if (!tree_view->priv->column_drop_func)
5311           return NULL;
5312
5313         if (tree_view->priv->column_drop_func (tree_view, column, NULL, cur_column, tree_view->priv->column_drop_func_data))
5314           return NULL;
5315         else
5316           return (GtkTreeViewColumn *)0x1;
5317         break;
5318     }
5319
5320   return (GtkTreeViewColumn *)0x1;
5321 }
5322
5323 static gboolean
5324 gtk_tree_view_key_press (GtkWidget   *widget,
5325                          GdkEventKey *event)
5326 {
5327   GtkTreeView *tree_view = (GtkTreeView *) widget;
5328
5329   if (tree_view->priv->rubber_band_status)
5330     {
5331       if (event->keyval == GDK_Escape)
5332         gtk_tree_view_stop_rubber_band (tree_view);
5333
5334       return TRUE;
5335     }
5336
5337   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
5338     {
5339       if (event->keyval == GDK_Escape)
5340         {
5341           tree_view->priv->cur_reorder = NULL;
5342           gtk_tree_view_button_release_drag_column (widget, NULL);
5343         }
5344       return TRUE;
5345     }
5346
5347   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
5348     {
5349       GList *focus_column;
5350       gboolean rtl;
5351
5352       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
5353
5354       for (focus_column = tree_view->priv->columns;
5355            focus_column;
5356            focus_column = focus_column->next)
5357         {
5358           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
5359
5360           if (gtk_widget_has_focus (column->button))
5361             break;
5362         }
5363
5364       if (focus_column &&
5365           (event->state & GDK_SHIFT_MASK) && (event->state & GDK_MOD1_MASK) &&
5366           (event->keyval == GDK_Left || event->keyval == GDK_KP_Left
5367            || event->keyval == GDK_Right || event->keyval == GDK_KP_Right))
5368         {
5369           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
5370
5371           if (!column->resizable)
5372             {
5373               gtk_widget_error_bell (widget);
5374               return TRUE;
5375             }
5376
5377           if (event->keyval == (rtl ? GDK_Right : GDK_Left)
5378               || event->keyval == (rtl ? GDK_KP_Right : GDK_KP_Left))
5379             {
5380               gint old_width = column->resized_width;
5381
5382               column->resized_width = MAX (column->resized_width,
5383                                            column->width);
5384               column->resized_width -= 2;
5385               if (column->resized_width < 0)
5386                 column->resized_width = 0;
5387
5388               if (column->min_width == -1)
5389                 column->resized_width = MAX (column->button->requisition.width,
5390                                              column->resized_width);
5391               else
5392                 column->resized_width = MAX (column->min_width,
5393                                              column->resized_width);
5394
5395               if (column->max_width != -1)
5396                 column->resized_width = MIN (column->resized_width,
5397                                              column->max_width);
5398
5399               column->use_resized_width = TRUE;
5400
5401               if (column->resized_width != old_width)
5402                 gtk_widget_queue_resize (widget);
5403               else
5404                 gtk_widget_error_bell (widget);
5405             }
5406           else if (event->keyval == (rtl ? GDK_Left : GDK_Right)
5407                    || event->keyval == (rtl ? GDK_KP_Left : GDK_KP_Right))
5408             {
5409               gint old_width = column->resized_width;
5410
5411               column->resized_width = MAX (column->resized_width,
5412                                            column->width);
5413               column->resized_width += 2;
5414
5415               if (column->max_width != -1)
5416                 column->resized_width = MIN (column->resized_width,
5417                                              column->max_width);
5418
5419               column->use_resized_width = TRUE;
5420
5421               if (column->resized_width != old_width)
5422                 gtk_widget_queue_resize (widget);
5423               else
5424                 gtk_widget_error_bell (widget);
5425             }
5426
5427           return TRUE;
5428         }
5429
5430       if (focus_column &&
5431           (event->state & GDK_MOD1_MASK) &&
5432           (event->keyval == GDK_Left || event->keyval == GDK_KP_Left
5433            || event->keyval == GDK_Right || event->keyval == GDK_KP_Right
5434            || event->keyval == GDK_Home || event->keyval == GDK_KP_Home
5435            || event->keyval == GDK_End || event->keyval == GDK_KP_End))
5436         {
5437           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
5438
5439           if (event->keyval == (rtl ? GDK_Right : GDK_Left)
5440               || event->keyval == (rtl ? GDK_KP_Right : GDK_KP_Left))
5441             {
5442               GtkTreeViewColumn *col;
5443               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_LEFT);
5444               if (col != (GtkTreeViewColumn *)0x1)
5445                 gtk_tree_view_move_column_after (tree_view, column, col);
5446               else
5447                 gtk_widget_error_bell (widget);
5448             }
5449           else if (event->keyval == (rtl ? GDK_Left : GDK_Right)
5450                    || event->keyval == (rtl ? GDK_KP_Left : GDK_KP_Right))
5451             {
5452               GtkTreeViewColumn *col;
5453               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_RIGHT);
5454               if (col != (GtkTreeViewColumn *)0x1)
5455                 gtk_tree_view_move_column_after (tree_view, column, col);
5456               else
5457                 gtk_widget_error_bell (widget);
5458             }
5459           else if (event->keyval == GDK_Home || event->keyval == GDK_KP_Home)
5460             {
5461               GtkTreeViewColumn *col;
5462               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_HOME);
5463               if (col != (GtkTreeViewColumn *)0x1)
5464                 gtk_tree_view_move_column_after (tree_view, column, col);
5465               else
5466                 gtk_widget_error_bell (widget);
5467             }
5468           else if (event->keyval == GDK_End || event->keyval == GDK_KP_End)
5469             {
5470               GtkTreeViewColumn *col;
5471               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_END);
5472               if (col != (GtkTreeViewColumn *)0x1)
5473                 gtk_tree_view_move_column_after (tree_view, column, col);
5474               else
5475                 gtk_widget_error_bell (widget);
5476             }
5477
5478           return TRUE;
5479         }
5480     }
5481
5482   /* Chain up to the parent class.  It handles the keybindings. */
5483   if (GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->key_press_event (widget, event))
5484     return TRUE;
5485
5486   if (tree_view->priv->search_entry_avoid_unhandled_binding)
5487     {
5488       tree_view->priv->search_entry_avoid_unhandled_binding = FALSE;
5489       return FALSE;
5490     }
5491
5492   /* We pass the event to the search_entry.  If its text changes, then we start
5493    * the typeahead find capabilities. */
5494   if (gtk_widget_has_focus (GTK_WIDGET (tree_view))
5495       && tree_view->priv->enable_search
5496       && !tree_view->priv->search_custom_entry_set)
5497     {
5498       GdkEvent *new_event;
5499       char *old_text;
5500       const char *new_text;
5501       gboolean retval;
5502       GdkScreen *screen;
5503       gboolean text_modified;
5504       gulong popup_menu_id;
5505
5506       gtk_tree_view_ensure_interactive_directory (tree_view);
5507
5508       /* Make a copy of the current text */
5509       old_text = g_strdup (gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry)));
5510       new_event = gdk_event_copy ((GdkEvent *) event);
5511       g_object_unref (((GdkEventKey *) new_event)->window);
5512       ((GdkEventKey *) new_event)->window = g_object_ref (tree_view->priv->search_window->window);
5513       gtk_widget_realize (tree_view->priv->search_window);
5514
5515       popup_menu_id = g_signal_connect (tree_view->priv->search_entry, 
5516                                         "popup-menu", G_CALLBACK (gtk_true),
5517                                         NULL);
5518
5519       /* Move the entry off screen */
5520       screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
5521       gtk_window_move (GTK_WINDOW (tree_view->priv->search_window),
5522                        gdk_screen_get_width (screen) + 1,
5523                        gdk_screen_get_height (screen) + 1);
5524       gtk_widget_show (tree_view->priv->search_window);
5525
5526       /* Send the event to the window.  If the preedit_changed signal is emitted
5527        * during this event, we will set priv->imcontext_changed  */
5528       tree_view->priv->imcontext_changed = FALSE;
5529       retval = gtk_widget_event (tree_view->priv->search_window, new_event);
5530       gdk_event_free (new_event);
5531       gtk_widget_hide (tree_view->priv->search_window);
5532
5533       g_signal_handler_disconnect (tree_view->priv->search_entry, 
5534                                    popup_menu_id);
5535
5536       /* We check to make sure that the entry tried to handle the text, and that
5537        * the text has changed.
5538        */
5539       new_text = gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry));
5540       text_modified = strcmp (old_text, new_text) != 0;
5541       g_free (old_text);
5542       if (tree_view->priv->imcontext_changed ||    /* we're in a preedit */
5543           (retval && text_modified))               /* ...or the text was modified */
5544         {
5545           if (gtk_tree_view_real_start_interactive_search (tree_view,
5546                                                            gdk_event_get_device ((GdkEvent *) event),
5547                                                            FALSE))
5548             {
5549               gtk_widget_grab_focus (GTK_WIDGET (tree_view));
5550               return TRUE;
5551             }
5552           else
5553             {
5554               gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
5555               return FALSE;
5556             }
5557         }
5558     }
5559
5560   return FALSE;
5561 }
5562
5563 static gboolean
5564 gtk_tree_view_key_release (GtkWidget   *widget,
5565                            GdkEventKey *event)
5566 {
5567   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
5568
5569   if (tree_view->priv->rubber_band_status)
5570     return TRUE;
5571
5572   return GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->key_release_event (widget, event);
5573 }
5574
5575 /* FIXME Is this function necessary? Can I get an enter_notify event
5576  * w/o either an expose event or a mouse motion event?
5577  */
5578 static gboolean
5579 gtk_tree_view_enter_notify (GtkWidget        *widget,
5580                             GdkEventCrossing *event)
5581 {
5582   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
5583   GtkRBTree *tree;
5584   GtkRBNode *node;
5585   gint new_y;
5586
5587   /* Sanity check it */
5588   if (event->window != tree_view->priv->bin_window)
5589     return FALSE;
5590
5591   if (tree_view->priv->tree == NULL)
5592     return FALSE;
5593
5594   if (event->mode == GDK_CROSSING_GRAB ||
5595       event->mode == GDK_CROSSING_GTK_GRAB ||
5596       event->mode == GDK_CROSSING_GTK_UNGRAB ||
5597       event->mode == GDK_CROSSING_STATE_CHANGED)
5598     return TRUE;
5599
5600   /* find the node internally */
5601   new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
5602   if (new_y < 0)
5603     new_y = 0;
5604   _gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
5605
5606   tree_view->priv->event_last_x = event->x;
5607   tree_view->priv->event_last_y = event->y;
5608
5609   if ((tree_view->priv->button_pressed_node == NULL) ||
5610       (tree_view->priv->button_pressed_node == node))
5611     prelight_or_select (tree_view, tree, node, event->x, event->y);
5612
5613   return TRUE;
5614 }
5615
5616 static gboolean
5617 gtk_tree_view_leave_notify (GtkWidget        *widget,
5618                             GdkEventCrossing *event)
5619 {
5620   GtkTreeView *tree_view;
5621
5622   if (event->mode == GDK_CROSSING_GRAB)
5623     return TRUE;
5624
5625   tree_view = GTK_TREE_VIEW (widget);
5626
5627   if (tree_view->priv->prelight_node)
5628     _gtk_tree_view_queue_draw_node (tree_view,
5629                                    tree_view->priv->prelight_tree,
5630                                    tree_view->priv->prelight_node,
5631                                    NULL);
5632
5633   tree_view->priv->event_last_x = -10000;
5634   tree_view->priv->event_last_y = -10000;
5635
5636   prelight_or_select (tree_view,
5637                       NULL, NULL,
5638                       -1000, -1000); /* coords not possibly over an arrow */
5639
5640   return TRUE;
5641 }
5642
5643
5644 static gint
5645 gtk_tree_view_focus_out (GtkWidget     *widget,
5646                          GdkEventFocus *event)
5647 {
5648   GtkTreeView *tree_view;
5649
5650   tree_view = GTK_TREE_VIEW (widget);
5651
5652   gtk_widget_queue_draw (widget);
5653
5654   /* destroy interactive search dialog */
5655   if (tree_view->priv->search_window)
5656     gtk_tree_view_search_dialog_hide (tree_view->priv->search_window, tree_view,
5657                                       gdk_event_get_device ((GdkEvent *) event));
5658
5659   return FALSE;
5660 }
5661
5662
5663 /* Incremental Reflow
5664  */
5665
5666 static void
5667 gtk_tree_view_node_queue_redraw (GtkTreeView *tree_view,
5668                                  GtkRBTree   *tree,
5669                                  GtkRBNode   *node)
5670 {
5671   gint y;
5672
5673   y = _gtk_rbtree_node_find_offset (tree, node)
5674     - tree_view->priv->vadjustment->value
5675     + TREE_VIEW_HEADER_HEIGHT (tree_view);
5676
5677   gtk_widget_queue_draw_area (GTK_WIDGET (tree_view),
5678                               0, y,
5679                               GTK_WIDGET (tree_view)->allocation.width,
5680                               GTK_RBNODE_GET_HEIGHT (node));
5681 }
5682
5683 static gboolean
5684 node_is_visible (GtkTreeView *tree_view,
5685                  GtkRBTree   *tree,
5686                  GtkRBNode   *node)
5687 {
5688   int y;
5689   int height;
5690
5691   y = _gtk_rbtree_node_find_offset (tree, node);
5692   height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
5693
5694   if (y >= tree_view->priv->vadjustment->value &&
5695       y + height <= (tree_view->priv->vadjustment->value
5696                      + tree_view->priv->vadjustment->page_size))
5697     return TRUE;
5698
5699   return FALSE;
5700 }
5701
5702 /* Returns TRUE if it updated the size
5703  */
5704 static gboolean
5705 validate_row (GtkTreeView *tree_view,
5706               GtkRBTree   *tree,
5707               GtkRBNode   *node,
5708               GtkTreeIter *iter,
5709               GtkTreePath *path)
5710 {
5711   GtkTreeViewColumn *column;
5712   GList *list, *first_column, *last_column;
5713   gint height = 0;
5714   gint horizontal_separator;
5715   gint vertical_separator;
5716   gint focus_line_width;
5717   gint depth = gtk_tree_path_get_depth (path);
5718   gboolean retval = FALSE;
5719   gboolean is_separator = FALSE;
5720   gboolean draw_vgrid_lines, draw_hgrid_lines;
5721   gint focus_pad;
5722   gint grid_line_width;
5723   gboolean wide_separators;
5724   gint separator_height;
5725
5726   /* double check the row needs validating */
5727   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) &&
5728       ! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
5729     return FALSE;
5730
5731   is_separator = row_is_separator (tree_view, iter, NULL);
5732
5733   gtk_widget_style_get (GTK_WIDGET (tree_view),
5734                         "focus-padding", &focus_pad,
5735                         "focus-line-width", &focus_line_width,
5736                         "horizontal-separator", &horizontal_separator,
5737                         "vertical-separator", &vertical_separator,
5738                         "grid-line-width", &grid_line_width,
5739                         "wide-separators",  &wide_separators,
5740                         "separator-height", &separator_height,
5741                         NULL);
5742   
5743   draw_vgrid_lines =
5744     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_VERTICAL
5745     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
5746   draw_hgrid_lines =
5747     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_HORIZONTAL
5748     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
5749
5750   for (last_column = g_list_last (tree_view->priv->columns);
5751        last_column && !(GTK_TREE_VIEW_COLUMN (last_column->data)->visible);
5752        last_column = last_column->prev)
5753     ;
5754
5755   for (first_column = g_list_first (tree_view->priv->columns);
5756        first_column && !(GTK_TREE_VIEW_COLUMN (first_column->data)->visible);
5757        first_column = first_column->next)
5758     ;
5759
5760   for (list = tree_view->priv->columns; list; list = list->next)
5761     {
5762       gint tmp_width;
5763       gint tmp_height;
5764
5765       column = list->data;
5766
5767       if (! column->visible)
5768         continue;
5769
5770       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID) && !column->dirty)
5771         continue;
5772
5773       gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, iter,
5774                                                GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
5775                                                node->children?TRUE:FALSE);
5776       gtk_tree_view_column_cell_get_size (column,
5777                                           NULL, NULL, NULL,
5778                                           &tmp_width, &tmp_height);
5779
5780       if (!is_separator)
5781         {
5782           tmp_height += vertical_separator;
5783           height = MAX (height, tmp_height);
5784           height = MAX (height, tree_view->priv->expander_size);
5785         }
5786       else
5787         {
5788           if (wide_separators)
5789             height = separator_height + 2 * focus_pad;
5790           else
5791             height = 2 + 2 * focus_pad;
5792         }
5793
5794       if (gtk_tree_view_is_expander_column (tree_view, column))
5795         {
5796           tmp_width = tmp_width + horizontal_separator + (depth - 1) * tree_view->priv->level_indentation;
5797
5798           if (TREE_VIEW_DRAW_EXPANDERS (tree_view))
5799             tmp_width += depth * tree_view->priv->expander_size;
5800         }
5801       else
5802         tmp_width = tmp_width + horizontal_separator;
5803
5804       if (draw_vgrid_lines)
5805         {
5806           if (list->data == first_column || list->data == last_column)
5807             tmp_width += grid_line_width / 2.0;
5808           else
5809             tmp_width += grid_line_width;
5810         }
5811
5812       if (tmp_width > column->requested_width)
5813         {
5814           retval = TRUE;
5815           column->requested_width = tmp_width;
5816         }
5817     }
5818
5819   if (draw_hgrid_lines)
5820     height += grid_line_width;
5821
5822   if (height != GTK_RBNODE_GET_HEIGHT (node))
5823     {
5824       retval = TRUE;
5825       _gtk_rbtree_node_set_height (tree, node, height);
5826     }
5827   _gtk_rbtree_node_mark_valid (tree, node);
5828   tree_view->priv->post_validation_flag = TRUE;
5829
5830   return retval;
5831 }
5832
5833
5834 static void
5835 validate_visible_area (GtkTreeView *tree_view)
5836 {
5837   GtkTreePath *path = NULL;
5838   GtkTreePath *above_path = NULL;
5839   GtkTreeIter iter;
5840   GtkRBTree *tree = NULL;
5841   GtkRBNode *node = NULL;
5842   gboolean need_redraw = FALSE;
5843   gboolean size_changed = FALSE;
5844   gint total_height;
5845   gint area_above = 0;
5846   gint area_below = 0;
5847
5848   if (tree_view->priv->tree == NULL)
5849     return;
5850
5851   if (! GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID) &&
5852       tree_view->priv->scroll_to_path == NULL)
5853     return;
5854
5855   total_height = GTK_WIDGET (tree_view)->allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view);
5856
5857   if (total_height == 0)
5858     return;
5859
5860   /* First, we check to see if we need to scroll anywhere
5861    */
5862   if (tree_view->priv->scroll_to_path)
5863     {
5864       path = gtk_tree_row_reference_get_path (tree_view->priv->scroll_to_path);
5865       if (path && !_gtk_tree_view_find_node (tree_view, path, &tree, &node))
5866         {
5867           /* we are going to scroll, and will update dy */
5868           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
5869           if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
5870               GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
5871             {
5872               _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
5873               if (validate_row (tree_view, tree, node, &iter, path))
5874                 size_changed = TRUE;
5875             }
5876
5877           if (tree_view->priv->scroll_to_use_align)
5878             {
5879               gint height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
5880               area_above = (total_height - height) *
5881                 tree_view->priv->scroll_to_row_align;
5882               area_below = total_height - area_above - height;
5883               area_above = MAX (area_above, 0);
5884               area_below = MAX (area_below, 0);
5885             }
5886           else
5887             {
5888               /* two cases:
5889                * 1) row not visible
5890                * 2) row visible
5891                */
5892               gint dy;
5893               gint height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
5894
5895               dy = _gtk_rbtree_node_find_offset (tree, node);
5896
5897               if (dy >= tree_view->priv->vadjustment->value &&
5898                   dy + height <= (tree_view->priv->vadjustment->value
5899                                   + tree_view->priv->vadjustment->page_size))
5900                 {
5901                   /* row visible: keep the row at the same position */
5902                   area_above = dy - tree_view->priv->vadjustment->value;
5903                   area_below = (tree_view->priv->vadjustment->value +
5904                                 tree_view->priv->vadjustment->page_size)
5905                                - dy - height;
5906                 }
5907               else
5908                 {
5909                   /* row not visible */
5910                   if (dy >= 0
5911                       && dy + height <= tree_view->priv->vadjustment->page_size)
5912                     {
5913                       /* row at the beginning -- fixed */
5914                       area_above = dy;
5915                       area_below = tree_view->priv->vadjustment->page_size
5916                                    - area_above - height;
5917                     }
5918                   else if (dy >= (tree_view->priv->vadjustment->upper -
5919                                   tree_view->priv->vadjustment->page_size))
5920                     {
5921                       /* row at the end -- fixed */
5922                       area_above = dy - (tree_view->priv->vadjustment->upper -
5923                                    tree_view->priv->vadjustment->page_size);
5924                       area_below = tree_view->priv->vadjustment->page_size -
5925                                    area_above - height;
5926
5927                       if (area_below < 0)
5928                         {
5929                           area_above = tree_view->priv->vadjustment->page_size - height;
5930                           area_below = 0;
5931                         }
5932                     }
5933                   else
5934                     {
5935                       /* row somewhere in the middle, bring it to the top
5936                        * of the view
5937                        */
5938                       area_above = 0;
5939                       area_below = total_height - height;
5940                     }
5941                 }
5942             }
5943         }
5944       else
5945         /* the scroll to isn't valid; ignore it.
5946          */
5947         {
5948           if (tree_view->priv->scroll_to_path && !path)
5949             {
5950               gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
5951               tree_view->priv->scroll_to_path = NULL;
5952             }
5953           if (path)
5954             gtk_tree_path_free (path);
5955           path = NULL;
5956         }      
5957     }
5958
5959   /* We didn't have a scroll_to set, so we just handle things normally
5960    */
5961   if (path == NULL)
5962     {
5963       gint offset;
5964
5965       offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
5966                                         TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, 0),
5967                                         &tree, &node);
5968       if (node == NULL)
5969         {
5970           /* In this case, nothing has been validated */
5971           path = gtk_tree_path_new_first ();
5972           _gtk_tree_view_find_node (tree_view, path, &tree, &node);
5973         }
5974       else
5975         {
5976           path = _gtk_tree_view_find_path (tree_view, tree, node);
5977           total_height += offset;
5978         }
5979
5980       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
5981
5982       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
5983           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
5984         {
5985           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
5986           if (validate_row (tree_view, tree, node, &iter, path))
5987             size_changed = TRUE;
5988         }
5989       area_above = 0;
5990       area_below = total_height - ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
5991     }
5992
5993   above_path = gtk_tree_path_copy (path);
5994
5995   /* if we do not validate any row above the new top_row, we will make sure
5996    * that the row immediately above top_row has been validated. (if we do not
5997    * do this, _gtk_rbtree_find_offset will find the row above top_row, because
5998    * when invalidated that row's height will be zero. and this will mess up
5999    * scrolling).
6000    */
6001   if (area_above == 0)
6002     {
6003       GtkRBTree *tmptree;
6004       GtkRBNode *tmpnode;
6005
6006       _gtk_tree_view_find_node (tree_view, above_path, &tmptree, &tmpnode);
6007       _gtk_rbtree_prev_full (tmptree, tmpnode, &tmptree, &tmpnode);
6008
6009       if (tmpnode)
6010         {
6011           GtkTreePath *tmppath;
6012           GtkTreeIter tmpiter;
6013
6014           tmppath = _gtk_tree_view_find_path (tree_view, tmptree, tmpnode);
6015           gtk_tree_model_get_iter (tree_view->priv->model, &tmpiter, tmppath);
6016
6017           if (GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_INVALID) ||
6018               GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_COLUMN_INVALID))
6019             {
6020               _gtk_tree_view_queue_draw_node (tree_view, tmptree, tmpnode, NULL);
6021               if (validate_row (tree_view, tmptree, tmpnode, &tmpiter, tmppath))
6022                 size_changed = TRUE;
6023             }
6024
6025           gtk_tree_path_free (tmppath);
6026         }
6027     }
6028
6029   /* Now, we walk forwards and backwards, measuring rows. Unfortunately,
6030    * backwards is much slower then forward, as there is no iter_prev function.
6031    * We go forwards first in case we run out of tree.  Then we go backwards to
6032    * fill out the top.
6033    */
6034   while (node && area_below > 0)
6035     {
6036       if (node->children)
6037         {
6038           GtkTreeIter parent = iter;
6039           gboolean has_child;
6040
6041           tree = node->children;
6042           node = tree->root;
6043
6044           g_assert (node != tree->nil);
6045
6046           while (node->left != tree->nil)
6047             node = node->left;
6048           has_child = gtk_tree_model_iter_children (tree_view->priv->model,
6049                                                     &iter,
6050                                                     &parent);
6051           TREE_VIEW_INTERNAL_ASSERT_VOID (has_child);
6052           gtk_tree_path_down (path);
6053         }
6054       else
6055         {
6056           gboolean done = FALSE;
6057           do
6058             {
6059               node = _gtk_rbtree_next (tree, node);
6060               if (node != NULL)
6061                 {
6062                   gboolean has_next = gtk_tree_model_iter_next (tree_view->priv->model, &iter);
6063                   done = TRUE;
6064                   gtk_tree_path_next (path);
6065
6066                   /* Sanity Check! */
6067                   TREE_VIEW_INTERNAL_ASSERT_VOID (has_next);
6068                 }
6069               else
6070                 {
6071                   GtkTreeIter parent_iter = iter;
6072                   gboolean has_parent;
6073
6074                   node = tree->parent_node;
6075                   tree = tree->parent_tree;
6076                   if (tree == NULL)
6077                     break;
6078                   has_parent = gtk_tree_model_iter_parent (tree_view->priv->model,
6079                                                            &iter,
6080                                                            &parent_iter);
6081                   gtk_tree_path_up (path);
6082
6083                   /* Sanity check */
6084                   TREE_VIEW_INTERNAL_ASSERT_VOID (has_parent);
6085                 }
6086             }
6087           while (!done);
6088         }
6089
6090       if (!node)
6091         break;
6092
6093       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6094           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6095         {
6096           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
6097           if (validate_row (tree_view, tree, node, &iter, path))
6098               size_changed = TRUE;
6099         }
6100
6101       area_below -= ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
6102     }
6103   gtk_tree_path_free (path);
6104
6105   /* If we ran out of tree, and have extra area_below left, we need to add it
6106    * to area_above */
6107   if (area_below > 0)
6108     area_above += area_below;
6109
6110   _gtk_tree_view_find_node (tree_view, above_path, &tree, &node);
6111
6112   /* We walk backwards */
6113   while (area_above > 0)
6114     {
6115       _gtk_rbtree_prev_full (tree, node, &tree, &node);
6116
6117       /* Always find the new path in the tree.  We cannot just assume
6118        * a gtk_tree_path_prev() is enough here, as there might be children
6119        * in between this node and the previous sibling node.  If this
6120        * appears to be a performance hotspot in profiles, we can look into
6121        * intrigate logic for keeping path, node and iter in sync like
6122        * we do for forward walks.  (Which will be hard because of the lacking
6123        * iter_prev).
6124        */
6125
6126       if (node == NULL)
6127         break;
6128
6129       gtk_tree_path_free (above_path);
6130       above_path = _gtk_tree_view_find_path (tree_view, tree, node);
6131
6132       gtk_tree_model_get_iter (tree_view->priv->model, &iter, above_path);
6133
6134       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6135           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6136         {
6137           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
6138           if (validate_row (tree_view, tree, node, &iter, above_path))
6139             size_changed = TRUE;
6140         }
6141       area_above -= ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
6142     }
6143
6144   /* if we scrolled to a path, we need to set the dy here,
6145    * and sync the top row accordingly
6146    */
6147   if (tree_view->priv->scroll_to_path)
6148     {
6149       gtk_tree_view_set_top_row (tree_view, above_path, -area_above);
6150       gtk_tree_view_top_row_to_dy (tree_view);
6151
6152       need_redraw = TRUE;
6153     }
6154   else if (tree_view->priv->height <= tree_view->priv->vadjustment->page_size)
6155     {
6156       /* when we are not scrolling, we should never set dy to something
6157        * else than zero. we update top_row to be in sync with dy = 0.
6158        */
6159       gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
6160       gtk_tree_view_dy_to_top_row (tree_view);
6161     }
6162   else if (tree_view->priv->vadjustment->value + tree_view->priv->vadjustment->page_size > tree_view->priv->height)
6163     {
6164       gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), tree_view->priv->height - tree_view->priv->vadjustment->page_size);
6165       gtk_tree_view_dy_to_top_row (tree_view);
6166     }
6167   else
6168     gtk_tree_view_top_row_to_dy (tree_view);
6169
6170   /* update width/height and queue a resize */
6171   if (size_changed)
6172     {
6173       GtkRequisition requisition;
6174
6175       /* We temporarily guess a size, under the assumption that it will be the
6176        * same when we get our next size_allocate.  If we don't do this, we'll be
6177        * in an inconsistent state if we call top_row_to_dy. */
6178
6179       gtk_widget_size_request (GTK_WIDGET (tree_view), &requisition);
6180       tree_view->priv->hadjustment->upper = MAX (tree_view->priv->hadjustment->upper, (gfloat)requisition.width);
6181       tree_view->priv->vadjustment->upper = MAX (tree_view->priv->vadjustment->upper, (gfloat)requisition.height);
6182       gtk_adjustment_changed (tree_view->priv->hadjustment);
6183       gtk_adjustment_changed (tree_view->priv->vadjustment);
6184       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6185     }
6186
6187   if (tree_view->priv->scroll_to_path)
6188     {
6189       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
6190       tree_view->priv->scroll_to_path = NULL;
6191     }
6192
6193   if (above_path)
6194     gtk_tree_path_free (above_path);
6195
6196   if (tree_view->priv->scroll_to_column)
6197     {
6198       tree_view->priv->scroll_to_column = NULL;
6199     }
6200   if (need_redraw)
6201     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
6202 }
6203
6204 static void
6205 initialize_fixed_height_mode (GtkTreeView *tree_view)
6206 {
6207   if (!tree_view->priv->tree)
6208     return;
6209
6210   if (tree_view->priv->fixed_height < 0)
6211     {
6212       GtkTreeIter iter;
6213       GtkTreePath *path;
6214
6215       GtkRBTree *tree = NULL;
6216       GtkRBNode *node = NULL;
6217
6218       tree = tree_view->priv->tree;
6219       node = tree->root;
6220
6221       path = _gtk_tree_view_find_path (tree_view, tree, node);
6222       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6223
6224       validate_row (tree_view, tree, node, &iter, path);
6225
6226       gtk_tree_path_free (path);
6227
6228       tree_view->priv->fixed_height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
6229     }
6230
6231    _gtk_rbtree_set_fixed_height (tree_view->priv->tree,
6232                                  tree_view->priv->fixed_height, TRUE);
6233 }
6234
6235 /* Our strategy for finding nodes to validate is a little convoluted.  We find
6236  * the left-most uninvalidated node.  We then try walking right, validating
6237  * nodes.  Once we find a valid node, we repeat the previous process of finding
6238  * the first invalid node.
6239  */
6240
6241 static gboolean
6242 do_validate_rows (GtkTreeView *tree_view, gboolean queue_resize)
6243 {
6244   GtkRBTree *tree = NULL;
6245   GtkRBNode *node = NULL;
6246   gboolean validated_area = FALSE;
6247   gint retval = TRUE;
6248   GtkTreePath *path = NULL;
6249   GtkTreeIter iter;
6250   GTimer *timer;
6251   gint i = 0;
6252
6253   gint prev_height = -1;
6254   gboolean fixed_height = TRUE;
6255
6256   g_assert (tree_view);
6257
6258   if (tree_view->priv->tree == NULL)
6259       return FALSE;
6260
6261   if (tree_view->priv->fixed_height_mode)
6262     {
6263       if (tree_view->priv->fixed_height < 0)
6264         initialize_fixed_height_mode (tree_view);
6265
6266       return FALSE;
6267     }
6268
6269   timer = g_timer_new ();
6270   g_timer_start (timer);
6271
6272   do
6273     {
6274       if (! GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID))
6275         {
6276           retval = FALSE;
6277           goto done;
6278         }
6279
6280       if (path != NULL)
6281         {
6282           node = _gtk_rbtree_next (tree, node);
6283           if (node != NULL)
6284             {
6285               TREE_VIEW_INTERNAL_ASSERT (gtk_tree_model_iter_next (tree_view->priv->model, &iter), FALSE);
6286               gtk_tree_path_next (path);
6287             }
6288           else
6289             {
6290               gtk_tree_path_free (path);
6291               path = NULL;
6292             }
6293         }
6294
6295       if (path == NULL)
6296         {
6297           tree = tree_view->priv->tree;
6298           node = tree_view->priv->tree->root;
6299
6300           g_assert (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_DESCENDANTS_INVALID));
6301
6302           do
6303             {
6304               if (node->left != tree->nil &&
6305                   GTK_RBNODE_FLAG_SET (node->left, GTK_RBNODE_DESCENDANTS_INVALID))
6306                 {
6307                   node = node->left;
6308                 }
6309               else if (node->right != tree->nil &&
6310                        GTK_RBNODE_FLAG_SET (node->right, GTK_RBNODE_DESCENDANTS_INVALID))
6311                 {
6312                   node = node->right;
6313                 }
6314               else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6315                        GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6316                 {
6317                   break;
6318                 }
6319               else if (node->children != NULL)
6320                 {
6321                   tree = node->children;
6322                   node = tree->root;
6323                 }
6324               else
6325                 /* RBTree corruption!  All bad */
6326                 g_assert_not_reached ();
6327             }
6328           while (TRUE);
6329           path = _gtk_tree_view_find_path (tree_view, tree, node);
6330           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6331         }
6332
6333       validated_area = validate_row (tree_view, tree, node, &iter, path) ||
6334                        validated_area;
6335
6336       if (!tree_view->priv->fixed_height_check)
6337         {
6338           gint height;
6339
6340           height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
6341           if (prev_height < 0)
6342             prev_height = height;
6343           else if (prev_height != height)
6344             fixed_height = FALSE;
6345         }
6346
6347       i++;
6348     }
6349   while (g_timer_elapsed (timer, NULL) < GTK_TREE_VIEW_TIME_MS_PER_IDLE / 1000.);
6350
6351   if (!tree_view->priv->fixed_height_check)
6352    {
6353      if (fixed_height)
6354        _gtk_rbtree_set_fixed_height (tree_view->priv->tree, prev_height, FALSE);
6355
6356      tree_view->priv->fixed_height_check = 1;
6357    }
6358   
6359  done:
6360   if (validated_area)
6361     {
6362       GtkRequisition requisition;
6363       /* We temporarily guess a size, under the assumption that it will be the
6364        * same when we get our next size_allocate.  If we don't do this, we'll be
6365        * in an inconsistent state when we call top_row_to_dy. */
6366
6367       gtk_widget_size_request (GTK_WIDGET (tree_view), &requisition);
6368       tree_view->priv->hadjustment->upper = MAX (tree_view->priv->hadjustment->upper, (gfloat)requisition.width);
6369       tree_view->priv->vadjustment->upper = MAX (tree_view->priv->vadjustment->upper, (gfloat)requisition.height);
6370       gtk_adjustment_changed (tree_view->priv->hadjustment);
6371       gtk_adjustment_changed (tree_view->priv->vadjustment);
6372
6373       if (queue_resize)
6374         gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6375     }
6376
6377   if (path) gtk_tree_path_free (path);
6378   g_timer_destroy (timer);
6379
6380   return retval;
6381 }
6382
6383 static gboolean
6384 validate_rows (GtkTreeView *tree_view)
6385 {
6386   gboolean retval;
6387   
6388   retval = do_validate_rows (tree_view, TRUE);
6389   
6390   if (! retval && tree_view->priv->validate_rows_timer)
6391     {
6392       g_source_remove (tree_view->priv->validate_rows_timer);
6393       tree_view->priv->validate_rows_timer = 0;
6394     }
6395
6396   return retval;
6397 }
6398
6399 static gboolean
6400 validate_rows_handler (GtkTreeView *tree_view)
6401 {
6402   gboolean retval;
6403
6404   retval = do_validate_rows (tree_view, TRUE);
6405   if (! retval && tree_view->priv->validate_rows_timer)
6406     {
6407       g_source_remove (tree_view->priv->validate_rows_timer);
6408       tree_view->priv->validate_rows_timer = 0;
6409     }
6410
6411   return retval;
6412 }
6413
6414 static gboolean
6415 do_presize_handler (GtkTreeView *tree_view)
6416 {
6417   if (tree_view->priv->mark_rows_col_dirty)
6418     {
6419       if (tree_view->priv->tree)
6420         _gtk_rbtree_column_invalid (tree_view->priv->tree);
6421       tree_view->priv->mark_rows_col_dirty = FALSE;
6422     }
6423   validate_visible_area (tree_view);
6424   tree_view->priv->presize_handler_timer = 0;
6425
6426   if (tree_view->priv->fixed_height_mode)
6427     {
6428       GtkRequisition requisition;
6429
6430       gtk_widget_size_request (GTK_WIDGET (tree_view), &requisition);
6431
6432       tree_view->priv->hadjustment->upper = MAX (tree_view->priv->hadjustment->upper, (gfloat)requisition.width);
6433       tree_view->priv->vadjustment->upper = MAX (tree_view->priv->vadjustment->upper, (gfloat)requisition.height);
6434       gtk_adjustment_changed (tree_view->priv->hadjustment);
6435       gtk_adjustment_changed (tree_view->priv->vadjustment);
6436       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6437     }
6438                    
6439   return FALSE;
6440 }
6441
6442 static gboolean
6443 presize_handler_callback (gpointer data)
6444 {
6445   do_presize_handler (GTK_TREE_VIEW (data));
6446                    
6447   return FALSE;
6448 }
6449
6450 static void
6451 install_presize_handler (GtkTreeView *tree_view)
6452 {
6453   if (! gtk_widget_get_realized (GTK_WIDGET (tree_view)))
6454     return;
6455
6456   if (! tree_view->priv->presize_handler_timer)
6457     {
6458       tree_view->priv->presize_handler_timer =
6459         gdk_threads_add_idle_full (GTK_PRIORITY_RESIZE - 2, presize_handler_callback, tree_view, NULL);
6460     }
6461   if (! tree_view->priv->validate_rows_timer)
6462     {
6463       tree_view->priv->validate_rows_timer =
6464         gdk_threads_add_idle_full (GTK_TREE_VIEW_PRIORITY_VALIDATE, (GSourceFunc) validate_rows_handler, tree_view, NULL);
6465     }
6466 }
6467
6468 static gboolean
6469 scroll_sync_handler (GtkTreeView *tree_view)
6470 {
6471   if (tree_view->priv->height <= tree_view->priv->vadjustment->page_size)
6472     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
6473   else if (gtk_tree_row_reference_valid (tree_view->priv->top_row))
6474     gtk_tree_view_top_row_to_dy (tree_view);
6475   else
6476     gtk_tree_view_dy_to_top_row (tree_view);
6477
6478   tree_view->priv->scroll_sync_timer = 0;
6479
6480   return FALSE;
6481 }
6482
6483 static void
6484 install_scroll_sync_handler (GtkTreeView *tree_view)
6485 {
6486   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
6487     return;
6488
6489   if (!tree_view->priv->scroll_sync_timer)
6490     {
6491       tree_view->priv->scroll_sync_timer =
6492         gdk_threads_add_idle_full (GTK_TREE_VIEW_PRIORITY_SCROLL_SYNC, (GSourceFunc) scroll_sync_handler, tree_view, NULL);
6493     }
6494 }
6495
6496 static void
6497 gtk_tree_view_set_top_row (GtkTreeView *tree_view,
6498                            GtkTreePath *path,
6499                            gint         offset)
6500 {
6501   gtk_tree_row_reference_free (tree_view->priv->top_row);
6502
6503   if (!path)
6504     {
6505       tree_view->priv->top_row = NULL;
6506       tree_view->priv->top_row_dy = 0;
6507     }
6508   else
6509     {
6510       tree_view->priv->top_row = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
6511       tree_view->priv->top_row_dy = offset;
6512     }
6513 }
6514
6515 /* Always call this iff dy is in the visible range.  If the tree is empty, then
6516  * it's set to be NULL, and top_row_dy is 0;
6517  */
6518 static void
6519 gtk_tree_view_dy_to_top_row (GtkTreeView *tree_view)
6520 {
6521   gint offset;
6522   GtkTreePath *path;
6523   GtkRBTree *tree;
6524   GtkRBNode *node;
6525
6526   if (tree_view->priv->tree == NULL)
6527     {
6528       gtk_tree_view_set_top_row (tree_view, NULL, 0);
6529     }
6530   else
6531     {
6532       offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
6533                                         tree_view->priv->dy,
6534                                         &tree, &node);
6535
6536       if (tree == NULL)
6537         {
6538           gtk_tree_view_set_top_row (tree_view, NULL, 0);
6539         }
6540       else
6541         {
6542           path = _gtk_tree_view_find_path (tree_view, tree, node);
6543           gtk_tree_view_set_top_row (tree_view, path, offset);
6544           gtk_tree_path_free (path);
6545         }
6546     }
6547 }
6548
6549 static void
6550 gtk_tree_view_top_row_to_dy (GtkTreeView *tree_view)
6551 {
6552   GtkTreePath *path;
6553   GtkRBTree *tree;
6554   GtkRBNode *node;
6555   int new_dy;
6556
6557   /* Avoid recursive calls */
6558   if (tree_view->priv->in_top_row_to_dy)
6559     return;
6560
6561   if (tree_view->priv->top_row)
6562     path = gtk_tree_row_reference_get_path (tree_view->priv->top_row);
6563   else
6564     path = NULL;
6565
6566   if (!path)
6567     tree = NULL;
6568   else
6569     _gtk_tree_view_find_node (tree_view, path, &tree, &node);
6570
6571   if (path)
6572     gtk_tree_path_free (path);
6573
6574   if (tree == NULL)
6575     {
6576       /* keep dy and set new toprow */
6577       gtk_tree_row_reference_free (tree_view->priv->top_row);
6578       tree_view->priv->top_row = NULL;
6579       tree_view->priv->top_row_dy = 0;
6580       /* DO NOT install the idle handler */
6581       gtk_tree_view_dy_to_top_row (tree_view);
6582       return;
6583     }
6584
6585   if (ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node))
6586       < tree_view->priv->top_row_dy)
6587     {
6588       /* new top row -- do NOT install the idle handler */
6589       gtk_tree_view_dy_to_top_row (tree_view);
6590       return;
6591     }
6592
6593   new_dy = _gtk_rbtree_node_find_offset (tree, node);
6594   new_dy += tree_view->priv->top_row_dy;
6595
6596   if (new_dy + tree_view->priv->vadjustment->page_size > tree_view->priv->height)
6597     new_dy = tree_view->priv->height - tree_view->priv->vadjustment->page_size;
6598
6599   new_dy = MAX (0, new_dy);
6600
6601   tree_view->priv->in_top_row_to_dy = TRUE;
6602   gtk_adjustment_set_value (tree_view->priv->vadjustment, (gdouble)new_dy);
6603   tree_view->priv->in_top_row_to_dy = FALSE;
6604 }
6605
6606
6607 void
6608 _gtk_tree_view_install_mark_rows_col_dirty (GtkTreeView *tree_view)
6609 {
6610   tree_view->priv->mark_rows_col_dirty = TRUE;
6611
6612   install_presize_handler (tree_view);
6613 }
6614
6615 /*
6616  * This function works synchronously (due to the while (validate_rows...)
6617  * loop).
6618  *
6619  * There was a check for column_type != GTK_TREE_VIEW_COLUMN_AUTOSIZE
6620  * here. You now need to check that yourself.
6621  */
6622 void
6623 _gtk_tree_view_column_autosize (GtkTreeView *tree_view,
6624                                 GtkTreeViewColumn *column)
6625 {
6626   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
6627   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (column));
6628
6629   _gtk_tree_view_column_cell_set_dirty (column, FALSE);
6630
6631   do_presize_handler (tree_view);
6632   while (validate_rows (tree_view));
6633
6634   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6635 }
6636
6637 /* Drag-and-drop */
6638
6639 static void
6640 set_source_row (GdkDragContext *context,
6641                 GtkTreeModel   *model,
6642                 GtkTreePath    *source_row)
6643 {
6644   g_object_set_data_full (G_OBJECT (context),
6645                           I_("gtk-tree-view-source-row"),
6646                           source_row ? gtk_tree_row_reference_new (model, source_row) : NULL,
6647                           (GDestroyNotify) (source_row ? gtk_tree_row_reference_free : NULL));
6648 }
6649
6650 static GtkTreePath*
6651 get_source_row (GdkDragContext *context)
6652 {
6653   GtkTreeRowReference *ref =
6654     g_object_get_data (G_OBJECT (context), "gtk-tree-view-source-row");
6655
6656   if (ref)
6657     return gtk_tree_row_reference_get_path (ref);
6658   else
6659     return NULL;
6660 }
6661
6662 typedef struct
6663 {
6664   GtkTreeRowReference *dest_row;
6665   guint                path_down_mode   : 1;
6666   guint                empty_view_drop  : 1;
6667   guint                drop_append_mode : 1;
6668 }
6669 DestRow;
6670
6671 static void
6672 dest_row_free (gpointer data)
6673 {
6674   DestRow *dr = (DestRow *)data;
6675
6676   gtk_tree_row_reference_free (dr->dest_row);
6677   g_slice_free (DestRow, dr);
6678 }
6679
6680 static void
6681 set_dest_row (GdkDragContext *context,
6682               GtkTreeModel   *model,
6683               GtkTreePath    *dest_row,
6684               gboolean        path_down_mode,
6685               gboolean        empty_view_drop,
6686               gboolean        drop_append_mode)
6687 {
6688   DestRow *dr;
6689
6690   if (!dest_row)
6691     {
6692       g_object_set_data_full (G_OBJECT (context), I_("gtk-tree-view-dest-row"),
6693                               NULL, NULL);
6694       return;
6695     }
6696
6697   dr = g_slice_new (DestRow);
6698
6699   dr->dest_row = gtk_tree_row_reference_new (model, dest_row);
6700   dr->path_down_mode = path_down_mode != FALSE;
6701   dr->empty_view_drop = empty_view_drop != FALSE;
6702   dr->drop_append_mode = drop_append_mode != FALSE;
6703
6704   g_object_set_data_full (G_OBJECT (context), I_("gtk-tree-view-dest-row"),
6705                           dr, (GDestroyNotify) dest_row_free);
6706 }
6707
6708 static GtkTreePath*
6709 get_dest_row (GdkDragContext *context,
6710               gboolean       *path_down_mode)
6711 {
6712   DestRow *dr =
6713     g_object_get_data (G_OBJECT (context), "gtk-tree-view-dest-row");
6714
6715   if (dr)
6716     {
6717       GtkTreePath *path = NULL;
6718
6719       if (path_down_mode)
6720         *path_down_mode = dr->path_down_mode;
6721
6722       if (dr->dest_row)
6723         path = gtk_tree_row_reference_get_path (dr->dest_row);
6724       else if (dr->empty_view_drop)
6725         path = gtk_tree_path_new_from_indices (0, -1);
6726       else
6727         path = NULL;
6728
6729       if (path && dr->drop_append_mode)
6730         gtk_tree_path_next (path);
6731
6732       return path;
6733     }
6734   else
6735     return NULL;
6736 }
6737
6738 /* Get/set whether drag_motion requested the drag data and
6739  * drag_data_received should thus not actually insert the data,
6740  * since the data doesn't result from a drop.
6741  */
6742 static void
6743 set_status_pending (GdkDragContext *context,
6744                     GdkDragAction   suggested_action)
6745 {
6746   g_object_set_data (G_OBJECT (context),
6747                      I_("gtk-tree-view-status-pending"),
6748                      GINT_TO_POINTER (suggested_action));
6749 }
6750
6751 static GdkDragAction
6752 get_status_pending (GdkDragContext *context)
6753 {
6754   return GPOINTER_TO_INT (g_object_get_data (G_OBJECT (context),
6755                                              "gtk-tree-view-status-pending"));
6756 }
6757
6758 static TreeViewDragInfo*
6759 get_info (GtkTreeView *tree_view)
6760 {
6761   return g_object_get_data (G_OBJECT (tree_view), "gtk-tree-view-drag-info");
6762 }
6763
6764 static void
6765 destroy_info (TreeViewDragInfo *di)
6766 {
6767   g_slice_free (TreeViewDragInfo, di);
6768 }
6769
6770 static TreeViewDragInfo*
6771 ensure_info (GtkTreeView *tree_view)
6772 {
6773   TreeViewDragInfo *di;
6774
6775   di = get_info (tree_view);
6776
6777   if (di == NULL)
6778     {
6779       di = g_slice_new0 (TreeViewDragInfo);
6780
6781       g_object_set_data_full (G_OBJECT (tree_view),
6782                               I_("gtk-tree-view-drag-info"),
6783                               di,
6784                               (GDestroyNotify) destroy_info);
6785     }
6786
6787   return di;
6788 }
6789
6790 static void
6791 remove_info (GtkTreeView *tree_view)
6792 {
6793   g_object_set_data (G_OBJECT (tree_view), I_("gtk-tree-view-drag-info"), NULL);
6794 }
6795
6796 #if 0
6797 static gint
6798 drag_scan_timeout (gpointer data)
6799 {
6800   GtkTreeView *tree_view;
6801   gint x, y;
6802   GdkModifierType state;
6803   GtkTreePath *path = NULL;
6804   GtkTreeViewColumn *column = NULL;
6805   GdkRectangle visible_rect;
6806
6807   GDK_THREADS_ENTER ();
6808
6809   tree_view = GTK_TREE_VIEW (data);
6810
6811   gdk_window_get_pointer (tree_view->priv->bin_window,
6812                           &x, &y, &state);
6813
6814   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
6815
6816   /* See if we are near the edge. */
6817   if ((x - visible_rect.x) < SCROLL_EDGE_SIZE ||
6818       (visible_rect.x + visible_rect.width - x) < SCROLL_EDGE_SIZE ||
6819       (y - visible_rect.y) < SCROLL_EDGE_SIZE ||
6820       (visible_rect.y + visible_rect.height - y) < SCROLL_EDGE_SIZE)
6821     {
6822       gtk_tree_view_get_path_at_pos (tree_view,
6823                                      tree_view->priv->bin_window,
6824                                      x, y,
6825                                      &path,
6826                                      &column,
6827                                      NULL,
6828                                      NULL);
6829
6830       if (path != NULL)
6831         {
6832           gtk_tree_view_scroll_to_cell (tree_view,
6833                                         path,
6834                                         column,
6835                                         TRUE,
6836                                         0.5, 0.5);
6837
6838           gtk_tree_path_free (path);
6839         }
6840     }
6841
6842   GDK_THREADS_LEAVE ();
6843
6844   return TRUE;
6845 }
6846 #endif /* 0 */
6847
6848 static void
6849 add_scroll_timeout (GtkTreeView *tree_view)
6850 {
6851   if (tree_view->priv->scroll_timeout == 0)
6852     {
6853       tree_view->priv->scroll_timeout =
6854         gdk_threads_add_timeout (150, scroll_row_timeout, tree_view);
6855     }
6856 }
6857
6858 static void
6859 remove_scroll_timeout (GtkTreeView *tree_view)
6860 {
6861   if (tree_view->priv->scroll_timeout != 0)
6862     {
6863       g_source_remove (tree_view->priv->scroll_timeout);
6864       tree_view->priv->scroll_timeout = 0;
6865     }
6866 }
6867
6868 static gboolean
6869 check_model_dnd (GtkTreeModel *model,
6870                  GType         required_iface,
6871                  const gchar  *signal)
6872 {
6873   if (model == NULL || !G_TYPE_CHECK_INSTANCE_TYPE ((model), required_iface))
6874     {
6875       g_warning ("You must override the default '%s' handler "
6876                  "on GtkTreeView when using models that don't support "
6877                  "the %s interface and enabling drag-and-drop. The simplest way to do this "
6878                  "is to connect to '%s' and call "
6879                  "g_signal_stop_emission_by_name() in your signal handler to prevent "
6880                  "the default handler from running. Look at the source code "
6881                  "for the default handler in gtktreeview.c to get an idea what "
6882                  "your handler should do. (gtktreeview.c is in the GTK source "
6883                  "code.) If you're using GTK from a language other than C, "
6884                  "there may be a more natural way to override default handlers, e.g. via derivation.",
6885                  signal, g_type_name (required_iface), signal);
6886       return FALSE;
6887     }
6888   else
6889     return TRUE;
6890 }
6891
6892 static void
6893 remove_open_timeout (GtkTreeView *tree_view)
6894 {
6895   if (tree_view->priv->open_dest_timeout != 0)
6896     {
6897       g_source_remove (tree_view->priv->open_dest_timeout);
6898       tree_view->priv->open_dest_timeout = 0;
6899     }
6900 }
6901
6902
6903 static gint
6904 open_row_timeout (gpointer data)
6905 {
6906   GtkTreeView *tree_view = data;
6907   GtkTreePath *dest_path = NULL;
6908   GtkTreeViewDropPosition pos;
6909   gboolean result = FALSE;
6910
6911   gtk_tree_view_get_drag_dest_row (tree_view,
6912                                    &dest_path,
6913                                    &pos);
6914
6915   if (dest_path &&
6916       (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
6917        pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
6918     {
6919       gtk_tree_view_expand_row (tree_view, dest_path, FALSE);
6920       tree_view->priv->open_dest_timeout = 0;
6921
6922       gtk_tree_path_free (dest_path);
6923     }
6924   else
6925     {
6926       if (dest_path)
6927         gtk_tree_path_free (dest_path);
6928
6929       result = TRUE;
6930     }
6931
6932   return result;
6933 }
6934
6935 static gboolean
6936 scroll_row_timeout (gpointer data)
6937 {
6938   GtkTreeView *tree_view = data;
6939
6940   gtk_tree_view_vertical_autoscroll (tree_view);
6941
6942   if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
6943     gtk_tree_view_update_rubber_band (tree_view);
6944
6945   return TRUE;
6946 }
6947
6948 /* Returns TRUE if event should not be propagated to parent widgets */
6949 static gboolean
6950 set_destination_row (GtkTreeView    *tree_view,
6951                      GdkDragContext *context,
6952                      /* coordinates relative to the widget */
6953                      gint            x,
6954                      gint            y,
6955                      GdkDragAction  *suggested_action,
6956                      GdkAtom        *target)
6957 {
6958   GtkTreePath *path = NULL;
6959   GtkTreeViewDropPosition pos;
6960   GtkTreeViewDropPosition old_pos;
6961   TreeViewDragInfo *di;
6962   GtkWidget *widget;
6963   GtkTreePath *old_dest_path = NULL;
6964   gboolean can_drop = FALSE;
6965
6966   *suggested_action = 0;
6967   *target = GDK_NONE;
6968
6969   widget = GTK_WIDGET (tree_view);
6970
6971   di = get_info (tree_view);
6972
6973   if (di == NULL || y - TREE_VIEW_HEADER_HEIGHT (tree_view) < 0)
6974     {
6975       /* someone unset us as a drag dest, note that if
6976        * we return FALSE drag_leave isn't called
6977        */
6978
6979       gtk_tree_view_set_drag_dest_row (tree_view,
6980                                        NULL,
6981                                        GTK_TREE_VIEW_DROP_BEFORE);
6982
6983       remove_scroll_timeout (GTK_TREE_VIEW (widget));
6984       remove_open_timeout (GTK_TREE_VIEW (widget));
6985
6986       return FALSE; /* no longer a drop site */
6987     }
6988
6989   *target = gtk_drag_dest_find_target (widget, context,
6990                                        gtk_drag_dest_get_target_list (widget));
6991   if (*target == GDK_NONE)
6992     {
6993       return FALSE;
6994     }
6995
6996   if (!gtk_tree_view_get_dest_row_at_pos (tree_view,
6997                                           x, y,
6998                                           &path,
6999                                           &pos))
7000     {
7001       gint n_children;
7002       GtkTreeModel *model;
7003
7004       remove_open_timeout (tree_view);
7005
7006       /* the row got dropped on empty space, let's setup a special case
7007        */
7008
7009       if (path)
7010         gtk_tree_path_free (path);
7011
7012       model = gtk_tree_view_get_model (tree_view);
7013
7014       n_children = gtk_tree_model_iter_n_children (model, NULL);
7015       if (n_children)
7016         {
7017           pos = GTK_TREE_VIEW_DROP_AFTER;
7018           path = gtk_tree_path_new_from_indices (n_children - 1, -1);
7019         }
7020       else
7021         {
7022           pos = GTK_TREE_VIEW_DROP_BEFORE;
7023           path = gtk_tree_path_new_from_indices (0, -1);
7024         }
7025
7026       can_drop = TRUE;
7027
7028       goto out;
7029     }
7030
7031   g_assert (path);
7032
7033   /* If we left the current row's "open" zone, unset the timeout for
7034    * opening the row
7035    */
7036   gtk_tree_view_get_drag_dest_row (tree_view,
7037                                    &old_dest_path,
7038                                    &old_pos);
7039
7040   if (old_dest_path &&
7041       (gtk_tree_path_compare (path, old_dest_path) != 0 ||
7042        !(pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
7043          pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE)))
7044     remove_open_timeout (tree_view);
7045
7046   if (old_dest_path)
7047     gtk_tree_path_free (old_dest_path);
7048
7049   if (TRUE /* FIXME if the location droppable predicate */)
7050     {
7051       can_drop = TRUE;
7052     }
7053
7054 out:
7055   if (can_drop)
7056     {
7057       GtkWidget *source_widget;
7058
7059       *suggested_action = context->suggested_action;
7060       source_widget = gtk_drag_get_source_widget (context);
7061
7062       if (source_widget == widget)
7063         {
7064           /* Default to MOVE, unless the user has
7065            * pressed ctrl or shift to affect available actions
7066            */
7067           if ((context->actions & GDK_ACTION_MOVE) != 0)
7068             *suggested_action = GDK_ACTION_MOVE;
7069         }
7070
7071       gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7072                                        path, pos);
7073     }
7074   else
7075     {
7076       /* can't drop here */
7077       remove_open_timeout (tree_view);
7078
7079       gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7080                                        NULL,
7081                                        GTK_TREE_VIEW_DROP_BEFORE);
7082     }
7083
7084   if (path)
7085     gtk_tree_path_free (path);
7086
7087   return TRUE;
7088 }
7089
7090 static GtkTreePath*
7091 get_logical_dest_row (GtkTreeView *tree_view,
7092                       gboolean    *path_down_mode,
7093                       gboolean    *drop_append_mode)
7094 {
7095   /* adjust path to point to the row the drop goes in front of */
7096   GtkTreePath *path = NULL;
7097   GtkTreeViewDropPosition pos;
7098
7099   g_return_val_if_fail (path_down_mode != NULL, NULL);
7100   g_return_val_if_fail (drop_append_mode != NULL, NULL);
7101
7102   *path_down_mode = FALSE;
7103   *drop_append_mode = 0;
7104
7105   gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
7106
7107   if (path == NULL)
7108     return NULL;
7109
7110   if (pos == GTK_TREE_VIEW_DROP_BEFORE)
7111     ; /* do nothing */
7112   else if (pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE ||
7113            pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER)
7114     *path_down_mode = TRUE;
7115   else
7116     {
7117       GtkTreeIter iter;
7118       GtkTreeModel *model = gtk_tree_view_get_model (tree_view);
7119
7120       g_assert (pos == GTK_TREE_VIEW_DROP_AFTER);
7121
7122       if (!gtk_tree_model_get_iter (model, &iter, path) ||
7123           !gtk_tree_model_iter_next (model, &iter))
7124         *drop_append_mode = 1;
7125       else
7126         {
7127           *drop_append_mode = 0;
7128           gtk_tree_path_next (path);
7129         }
7130     }
7131
7132   return path;
7133 }
7134
7135 static gboolean
7136 gtk_tree_view_maybe_begin_dragging_row (GtkTreeView      *tree_view,
7137                                         GdkEventMotion   *event)
7138 {
7139   GtkWidget *widget = GTK_WIDGET (tree_view);
7140   GdkDragContext *context;
7141   TreeViewDragInfo *di;
7142   GtkTreePath *path = NULL;
7143   gint button;
7144   gint cell_x, cell_y;
7145   GtkTreeModel *model;
7146   gboolean retval = FALSE;
7147
7148   di = get_info (tree_view);
7149
7150   if (di == NULL || !di->source_set)
7151     goto out;
7152
7153   if (tree_view->priv->pressed_button < 0)
7154     goto out;
7155
7156   if (!gtk_drag_check_threshold (widget,
7157                                  tree_view->priv->press_start_x,
7158                                  tree_view->priv->press_start_y,
7159                                  event->x, event->y))
7160     goto out;
7161
7162   model = gtk_tree_view_get_model (tree_view);
7163
7164   if (model == NULL)
7165     goto out;
7166
7167   button = tree_view->priv->pressed_button;
7168   tree_view->priv->pressed_button = -1;
7169
7170   gtk_tree_view_get_path_at_pos (tree_view,
7171                                  tree_view->priv->press_start_x,
7172                                  tree_view->priv->press_start_y,
7173                                  &path,
7174                                  NULL,
7175                                  &cell_x,
7176                                  &cell_y);
7177
7178   if (path == NULL)
7179     goto out;
7180
7181   if (!GTK_IS_TREE_DRAG_SOURCE (model) ||
7182       !gtk_tree_drag_source_row_draggable (GTK_TREE_DRAG_SOURCE (model),
7183                                            path))
7184     goto out;
7185
7186   if (!(GDK_BUTTON1_MASK << (button - 1) & di->start_button_mask))
7187     goto out;
7188
7189   /* Now we can begin the drag */
7190
7191   retval = TRUE;
7192
7193   context = gtk_drag_begin (widget,
7194                             gtk_drag_source_get_target_list (widget),
7195                             di->source_actions,
7196                             button,
7197                             (GdkEvent*)event);
7198
7199   set_source_row (context, model, path);
7200
7201  out:
7202   if (path)
7203     gtk_tree_path_free (path);
7204
7205   return retval;
7206 }
7207
7208
7209 static void
7210 gtk_tree_view_drag_begin (GtkWidget      *widget,
7211                           GdkDragContext *context)
7212 {
7213   GtkTreeView *tree_view;
7214   GtkTreePath *path = NULL;
7215   gint cell_x, cell_y;
7216   GdkPixmap *row_pix;
7217   TreeViewDragInfo *di;
7218
7219   tree_view = GTK_TREE_VIEW (widget);
7220
7221   /* if the user uses a custom DND source impl, we don't set the icon here */
7222   di = get_info (tree_view);
7223
7224   if (di == NULL || !di->source_set)
7225     return;
7226
7227   gtk_tree_view_get_path_at_pos (tree_view,
7228                                  tree_view->priv->press_start_x,
7229                                  tree_view->priv->press_start_y,
7230                                  &path,
7231                                  NULL,
7232                                  &cell_x,
7233                                  &cell_y);
7234
7235   g_return_if_fail (path != NULL);
7236
7237   row_pix = gtk_tree_view_create_row_drag_icon (tree_view,
7238                                                 path);
7239
7240   gtk_drag_set_icon_pixmap (context,
7241                             gdk_drawable_get_colormap (row_pix),
7242                             row_pix,
7243                             NULL,
7244                             /* the + 1 is for the black border in the icon */
7245                             tree_view->priv->press_start_x + 1,
7246                             cell_y + 1);
7247
7248   g_object_unref (row_pix);
7249   gtk_tree_path_free (path);
7250 }
7251
7252 static void
7253 gtk_tree_view_drag_end (GtkWidget      *widget,
7254                         GdkDragContext *context)
7255 {
7256   /* do nothing */
7257 }
7258
7259 /* Default signal implementations for the drag signals */
7260 static void
7261 gtk_tree_view_drag_data_get (GtkWidget        *widget,
7262                              GdkDragContext   *context,
7263                              GtkSelectionData *selection_data,
7264                              guint             info,
7265                              guint             time)
7266 {
7267   GtkTreeView *tree_view;
7268   GtkTreeModel *model;
7269   TreeViewDragInfo *di;
7270   GtkTreePath *source_row;
7271
7272   tree_view = GTK_TREE_VIEW (widget);
7273
7274   model = gtk_tree_view_get_model (tree_view);
7275
7276   if (model == NULL)
7277     return;
7278
7279   di = get_info (GTK_TREE_VIEW (widget));
7280
7281   if (di == NULL)
7282     return;
7283
7284   source_row = get_source_row (context);
7285
7286   if (source_row == NULL)
7287     return;
7288
7289   /* We can implement the GTK_TREE_MODEL_ROW target generically for
7290    * any model; for DragSource models there are some other targets
7291    * we also support.
7292    */
7293
7294   if (GTK_IS_TREE_DRAG_SOURCE (model) &&
7295       gtk_tree_drag_source_drag_data_get (GTK_TREE_DRAG_SOURCE (model),
7296                                           source_row,
7297                                           selection_data))
7298     goto done;
7299
7300   /* If drag_data_get does nothing, try providing row data. */
7301   if (selection_data->target == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
7302     {
7303       gtk_tree_set_row_drag_data (selection_data,
7304                                   model,
7305                                   source_row);
7306     }
7307
7308  done:
7309   gtk_tree_path_free (source_row);
7310 }
7311
7312
7313 static void
7314 gtk_tree_view_drag_data_delete (GtkWidget      *widget,
7315                                 GdkDragContext *context)
7316 {
7317   TreeViewDragInfo *di;
7318   GtkTreeModel *model;
7319   GtkTreeView *tree_view;
7320   GtkTreePath *source_row;
7321
7322   tree_view = GTK_TREE_VIEW (widget);
7323   model = gtk_tree_view_get_model (tree_view);
7324
7325   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_SOURCE, "drag_data_delete"))
7326     return;
7327
7328   di = get_info (tree_view);
7329
7330   if (di == NULL)
7331     return;
7332
7333   source_row = get_source_row (context);
7334
7335   if (source_row == NULL)
7336     return;
7337
7338   gtk_tree_drag_source_drag_data_delete (GTK_TREE_DRAG_SOURCE (model),
7339                                          source_row);
7340
7341   gtk_tree_path_free (source_row);
7342
7343   set_source_row (context, NULL, NULL);
7344 }
7345
7346 static void
7347 gtk_tree_view_drag_leave (GtkWidget      *widget,
7348                           GdkDragContext *context,
7349                           guint             time)
7350 {
7351   /* unset any highlight row */
7352   gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7353                                    NULL,
7354                                    GTK_TREE_VIEW_DROP_BEFORE);
7355
7356   remove_scroll_timeout (GTK_TREE_VIEW (widget));
7357   remove_open_timeout (GTK_TREE_VIEW (widget));
7358 }
7359
7360
7361 static gboolean
7362 gtk_tree_view_drag_motion (GtkWidget        *widget,
7363                            GdkDragContext   *context,
7364                            /* coordinates relative to the widget */
7365                            gint              x,
7366                            gint              y,
7367                            guint             time)
7368 {
7369   gboolean empty;
7370   GtkTreePath *path = NULL;
7371   GtkTreeViewDropPosition pos;
7372   GtkTreeView *tree_view;
7373   GdkDragAction suggested_action = 0;
7374   GdkAtom target;
7375
7376   tree_view = GTK_TREE_VIEW (widget);
7377
7378   if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
7379     return FALSE;
7380
7381   gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
7382
7383   /* we only know this *after* set_desination_row */
7384   empty = tree_view->priv->empty_view_drop;
7385
7386   if (path == NULL && !empty)
7387     {
7388       /* Can't drop here. */
7389       gdk_drag_status (context, 0, time);
7390     }
7391   else
7392     {
7393       if (tree_view->priv->open_dest_timeout == 0 &&
7394           (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
7395            pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
7396         {
7397           tree_view->priv->open_dest_timeout =
7398             gdk_threads_add_timeout (AUTO_EXPAND_TIMEOUT, open_row_timeout, tree_view);
7399         }
7400       else
7401         {
7402           add_scroll_timeout (tree_view);
7403         }
7404
7405       if (target == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
7406         {
7407           /* Request data so we can use the source row when
7408            * determining whether to accept the drop
7409            */
7410           set_status_pending (context, suggested_action);
7411           gtk_drag_get_data (widget, context, target, time);
7412         }
7413       else
7414         {
7415           set_status_pending (context, 0);
7416           gdk_drag_status (context, suggested_action, time);
7417         }
7418     }
7419
7420   if (path)
7421     gtk_tree_path_free (path);
7422
7423   return TRUE;
7424 }
7425
7426
7427 static gboolean
7428 gtk_tree_view_drag_drop (GtkWidget        *widget,
7429                          GdkDragContext   *context,
7430                          /* coordinates relative to the widget */
7431                          gint              x,
7432                          gint              y,
7433                          guint             time)
7434 {
7435   GtkTreeView *tree_view;
7436   GtkTreePath *path;
7437   GdkDragAction suggested_action = 0;
7438   GdkAtom target = GDK_NONE;
7439   TreeViewDragInfo *di;
7440   GtkTreeModel *model;
7441   gboolean path_down_mode;
7442   gboolean drop_append_mode;
7443
7444   tree_view = GTK_TREE_VIEW (widget);
7445
7446   model = gtk_tree_view_get_model (tree_view);
7447
7448   remove_scroll_timeout (GTK_TREE_VIEW (widget));
7449   remove_open_timeout (GTK_TREE_VIEW (widget));
7450
7451   di = get_info (tree_view);
7452
7453   if (di == NULL)
7454     return FALSE;
7455
7456   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_drop"))
7457     return FALSE;
7458
7459   if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
7460     return FALSE;
7461
7462   path = get_logical_dest_row (tree_view, &path_down_mode, &drop_append_mode);
7463
7464   if (target != GDK_NONE && path != NULL)
7465     {
7466       /* in case a motion had requested drag data, change things so we
7467        * treat drag data receives as a drop.
7468        */
7469       set_status_pending (context, 0);
7470       set_dest_row (context, model, path,
7471                     path_down_mode, tree_view->priv->empty_view_drop,
7472                     drop_append_mode);
7473     }
7474
7475   if (path)
7476     gtk_tree_path_free (path);
7477
7478   /* Unset this thing */
7479   gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7480                                    NULL,
7481                                    GTK_TREE_VIEW_DROP_BEFORE);
7482
7483   if (target != GDK_NONE)
7484     {
7485       gtk_drag_get_data (widget, context, target, time);
7486       return TRUE;
7487     }
7488   else
7489     return FALSE;
7490 }
7491
7492 static void
7493 gtk_tree_view_drag_data_received (GtkWidget        *widget,
7494                                   GdkDragContext   *context,
7495                                   /* coordinates relative to the widget */
7496                                   gint              x,
7497                                   gint              y,
7498                                   GtkSelectionData *selection_data,
7499                                   guint             info,
7500                                   guint             time)
7501 {
7502   GtkTreePath *path;
7503   TreeViewDragInfo *di;
7504   gboolean accepted = FALSE;
7505   GtkTreeModel *model;
7506   GtkTreeView *tree_view;
7507   GtkTreePath *dest_row;
7508   GdkDragAction suggested_action;
7509   gboolean path_down_mode;
7510   gboolean drop_append_mode;
7511
7512   tree_view = GTK_TREE_VIEW (widget);
7513
7514   model = gtk_tree_view_get_model (tree_view);
7515
7516   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_data_received"))
7517     return;
7518
7519   di = get_info (tree_view);
7520
7521   if (di == NULL)
7522     return;
7523
7524   suggested_action = get_status_pending (context);
7525
7526   if (suggested_action)
7527     {
7528       /* We are getting this data due to a request in drag_motion,
7529        * rather than due to a request in drag_drop, so we are just
7530        * supposed to call drag_status, not actually paste in the
7531        * data.
7532        */
7533       path = get_logical_dest_row (tree_view, &path_down_mode,
7534                                    &drop_append_mode);
7535
7536       if (path == NULL)
7537         suggested_action = 0;
7538       else if (path_down_mode)
7539         gtk_tree_path_down (path);
7540
7541       if (suggested_action)
7542         {
7543           if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
7544                                                      path,
7545                                                      selection_data))
7546             {
7547               if (path_down_mode)
7548                 {
7549                   path_down_mode = FALSE;
7550                   gtk_tree_path_up (path);
7551
7552                   if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
7553                                                              path,
7554                                                              selection_data))
7555                     suggested_action = 0;
7556                 }
7557               else
7558                 suggested_action = 0;
7559             }
7560         }
7561
7562       gdk_drag_status (context, suggested_action, time);
7563
7564       if (path)
7565         gtk_tree_path_free (path);
7566
7567       /* If you can't drop, remove user drop indicator until the next motion */
7568       if (suggested_action == 0)
7569         gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7570                                          NULL,
7571                                          GTK_TREE_VIEW_DROP_BEFORE);
7572
7573       return;
7574     }
7575
7576   dest_row = get_dest_row (context, &path_down_mode);
7577
7578   if (dest_row == NULL)
7579     return;
7580
7581   if (selection_data->length >= 0)
7582     {
7583       if (path_down_mode)
7584         {
7585           gtk_tree_path_down (dest_row);
7586           if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
7587                                                      dest_row, selection_data))
7588             gtk_tree_path_up (dest_row);
7589         }
7590     }
7591
7592   if (selection_data->length >= 0)
7593     {
7594       if (gtk_tree_drag_dest_drag_data_received (GTK_TREE_DRAG_DEST (model),
7595                                                  dest_row,
7596                                                  selection_data))
7597         accepted = TRUE;
7598     }
7599
7600   gtk_drag_finish (context,
7601                    accepted,
7602                    (context->action == GDK_ACTION_MOVE),
7603                    time);
7604
7605   if (gtk_tree_path_get_depth (dest_row) == 1
7606       && gtk_tree_path_get_indices (dest_row)[0] == 0)
7607     {
7608       /* special special case drag to "0", scroll to first item */
7609       if (!tree_view->priv->scroll_to_path)
7610         gtk_tree_view_scroll_to_cell (tree_view, dest_row, NULL, FALSE, 0.0, 0.0);
7611     }
7612
7613   gtk_tree_path_free (dest_row);
7614
7615   /* drop dest_row */
7616   set_dest_row (context, NULL, NULL, FALSE, FALSE, FALSE);
7617 }
7618
7619
7620
7621 /* GtkContainer Methods
7622  */
7623
7624
7625 static void
7626 gtk_tree_view_remove (GtkContainer *container,
7627                       GtkWidget    *widget)
7628 {
7629   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
7630   GtkTreeViewChild *child = NULL;
7631   GList *tmp_list;
7632
7633   tmp_list = tree_view->priv->children;
7634   while (tmp_list)
7635     {
7636       child = tmp_list->data;
7637       if (child->widget == widget)
7638         {
7639           gtk_widget_unparent (widget);
7640
7641           tree_view->priv->children = g_list_remove_link (tree_view->priv->children, tmp_list);
7642           g_list_free_1 (tmp_list);
7643           g_slice_free (GtkTreeViewChild, child);
7644           return;
7645         }
7646
7647       tmp_list = tmp_list->next;
7648     }
7649
7650   tmp_list = tree_view->priv->columns;
7651
7652   while (tmp_list)
7653     {
7654       GtkTreeViewColumn *column;
7655       column = tmp_list->data;
7656       if (column->button == widget)
7657         {
7658           gtk_widget_unparent (widget);
7659           return;
7660         }
7661       tmp_list = tmp_list->next;
7662     }
7663 }
7664
7665 static void
7666 gtk_tree_view_forall (GtkContainer *container,
7667                       gboolean      include_internals,
7668                       GtkCallback   callback,
7669                       gpointer      callback_data)
7670 {
7671   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
7672   GtkTreeViewChild *child = NULL;
7673   GtkTreeViewColumn *column;
7674   GList *tmp_list;
7675
7676   tmp_list = tree_view->priv->children;
7677   while (tmp_list)
7678     {
7679       child = tmp_list->data;
7680       tmp_list = tmp_list->next;
7681
7682       (* callback) (child->widget, callback_data);
7683     }
7684   if (include_internals == FALSE)
7685     return;
7686
7687   for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
7688     {
7689       column = tmp_list->data;
7690
7691       if (column->button)
7692         (* callback) (column->button, callback_data);
7693     }
7694 }
7695
7696 /* Returns TRUE if the treeview contains no "special" (editable or activatable)
7697  * cells. If so we draw one big row-spanning focus rectangle.
7698  */
7699 static gboolean
7700 gtk_tree_view_has_special_cell (GtkTreeView *tree_view)
7701 {
7702   GList *list;
7703
7704   for (list = tree_view->priv->columns; list; list = list->next)
7705     {
7706       if (!((GtkTreeViewColumn *)list->data)->visible)
7707         continue;
7708       if (_gtk_tree_view_column_count_special_cells (list->data))
7709         return TRUE;
7710     }
7711
7712   return FALSE;
7713 }
7714
7715 static void
7716 column_sizing_notify (GObject    *object,
7717                       GParamSpec *pspec,
7718                       gpointer    data)
7719 {
7720   GtkTreeViewColumn *c = GTK_TREE_VIEW_COLUMN (object);
7721
7722   if (gtk_tree_view_column_get_sizing (c) != GTK_TREE_VIEW_COLUMN_FIXED)
7723     /* disable fixed height mode */
7724     g_object_set (data, "fixed-height-mode", FALSE, NULL);
7725 }
7726
7727 /**
7728  * gtk_tree_view_set_fixed_height_mode:
7729  * @tree_view: a #GtkTreeView 
7730  * @enable: %TRUE to enable fixed height mode
7731  * 
7732  * Enables or disables the fixed height mode of @tree_view. 
7733  * Fixed height mode speeds up #GtkTreeView by assuming that all 
7734  * rows have the same height. 
7735  * Only enable this option if all rows are the same height and all
7736  * columns are of type %GTK_TREE_VIEW_COLUMN_FIXED.
7737  *
7738  * Since: 2.6 
7739  **/
7740 void
7741 gtk_tree_view_set_fixed_height_mode (GtkTreeView *tree_view,
7742                                      gboolean     enable)
7743 {
7744   GList *l;
7745   
7746   enable = enable != FALSE;
7747
7748   if (enable == tree_view->priv->fixed_height_mode)
7749     return;
7750
7751   if (!enable)
7752     {
7753       tree_view->priv->fixed_height_mode = 0;
7754       tree_view->priv->fixed_height = -1;
7755
7756       /* force a revalidation */
7757       install_presize_handler (tree_view);
7758     }
7759   else 
7760     {
7761       /* make sure all columns are of type FIXED */
7762       for (l = tree_view->priv->columns; l; l = l->next)
7763         {
7764           GtkTreeViewColumn *c = l->data;
7765           
7766           g_return_if_fail (gtk_tree_view_column_get_sizing (c) == GTK_TREE_VIEW_COLUMN_FIXED);
7767         }
7768       
7769       /* yes, we really have to do this is in a separate loop */
7770       for (l = tree_view->priv->columns; l; l = l->next)
7771         g_signal_connect (l->data, "notify::sizing",
7772                           G_CALLBACK (column_sizing_notify), tree_view);
7773       
7774       tree_view->priv->fixed_height_mode = 1;
7775       tree_view->priv->fixed_height = -1;
7776       
7777       if (tree_view->priv->tree)
7778         initialize_fixed_height_mode (tree_view);
7779     }
7780
7781   g_object_notify (G_OBJECT (tree_view), "fixed-height-mode");
7782 }
7783
7784 /**
7785  * gtk_tree_view_get_fixed_height_mode:
7786  * @tree_view: a #GtkTreeView
7787  * 
7788  * Returns whether fixed height mode is turned on for @tree_view.
7789  * 
7790  * Return value: %TRUE if @tree_view is in fixed height mode
7791  * 
7792  * Since: 2.6
7793  **/
7794 gboolean
7795 gtk_tree_view_get_fixed_height_mode (GtkTreeView *tree_view)
7796 {
7797   return tree_view->priv->fixed_height_mode;
7798 }
7799
7800 /* Returns TRUE if the focus is within the headers, after the focus operation is
7801  * done
7802  */
7803 static gboolean
7804 gtk_tree_view_header_focus (GtkTreeView      *tree_view,
7805                             GtkDirectionType  dir,
7806                             gboolean          clamp_column_visible)
7807 {
7808   GtkWidget *focus_child;
7809
7810   GList *last_column, *first_column;
7811   GList *tmp_list;
7812   gboolean rtl;
7813
7814   if (! GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
7815     return FALSE;
7816
7817   focus_child = gtk_container_get_focus_child (GTK_CONTAINER (tree_view));
7818
7819   first_column = tree_view->priv->columns;
7820   while (first_column)
7821     {
7822       if (gtk_widget_get_can_focus (GTK_TREE_VIEW_COLUMN (first_column->data)->button) &&
7823           GTK_TREE_VIEW_COLUMN (first_column->data)->visible &&
7824           (GTK_TREE_VIEW_COLUMN (first_column->data)->clickable ||
7825            GTK_TREE_VIEW_COLUMN (first_column->data)->reorderable))
7826         break;
7827       first_column = first_column->next;
7828     }
7829
7830   /* No headers are visible, or are focusable.  We can't focus in or out.
7831    */
7832   if (first_column == NULL)
7833     return FALSE;
7834
7835   last_column = g_list_last (tree_view->priv->columns);
7836   while (last_column)
7837     {
7838       if (gtk_widget_get_can_focus (GTK_TREE_VIEW_COLUMN (last_column->data)->button) &&
7839           GTK_TREE_VIEW_COLUMN (last_column->data)->visible &&
7840           (GTK_TREE_VIEW_COLUMN (last_column->data)->clickable ||
7841            GTK_TREE_VIEW_COLUMN (last_column->data)->reorderable))
7842         break;
7843       last_column = last_column->prev;
7844     }
7845
7846
7847   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
7848
7849   switch (dir)
7850     {
7851     case GTK_DIR_TAB_BACKWARD:
7852     case GTK_DIR_TAB_FORWARD:
7853     case GTK_DIR_UP:
7854     case GTK_DIR_DOWN:
7855       if (focus_child == NULL)
7856         {
7857           if (tree_view->priv->focus_column != NULL &&
7858               gtk_widget_get_can_focus (tree_view->priv->focus_column->button))
7859             focus_child = tree_view->priv->focus_column->button;
7860           else
7861             focus_child = GTK_TREE_VIEW_COLUMN (first_column->data)->button;
7862           gtk_widget_grab_focus (focus_child);
7863           break;
7864         }
7865       return FALSE;
7866
7867     case GTK_DIR_LEFT:
7868     case GTK_DIR_RIGHT:
7869       if (focus_child == NULL)
7870         {
7871           if (tree_view->priv->focus_column != NULL)
7872             focus_child = tree_view->priv->focus_column->button;
7873           else if (dir == GTK_DIR_LEFT)
7874             focus_child = GTK_TREE_VIEW_COLUMN (last_column->data)->button;
7875           else
7876             focus_child = GTK_TREE_VIEW_COLUMN (first_column->data)->button;
7877           gtk_widget_grab_focus (focus_child);
7878           break;
7879         }
7880
7881       if (gtk_widget_child_focus (focus_child, dir))
7882         {
7883           /* The focus moves inside the button. */
7884           /* This is probably a great example of bad UI */
7885           break;
7886         }
7887
7888       /* We need to move the focus among the row of buttons. */
7889       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
7890         if (GTK_TREE_VIEW_COLUMN (tmp_list->data)->button == focus_child)
7891           break;
7892
7893       if ((tmp_list == first_column && dir == (rtl ? GTK_DIR_RIGHT : GTK_DIR_LEFT))
7894           || (tmp_list == last_column && dir == (rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT)))
7895         {
7896           gtk_widget_error_bell (GTK_WIDGET (tree_view));
7897           break;
7898         }
7899
7900       while (tmp_list)
7901         {
7902           GtkTreeViewColumn *column;
7903
7904           if (dir == (rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT))
7905             tmp_list = tmp_list->next;
7906           else
7907             tmp_list = tmp_list->prev;
7908
7909           if (tmp_list == NULL)
7910             {
7911               g_warning ("Internal button not found");
7912               break;
7913             }
7914           column = tmp_list->data;
7915           if (column->button &&
7916               column->visible &&
7917               gtk_widget_get_can_focus (column->button))
7918             {
7919               focus_child = column->button;
7920               gtk_widget_grab_focus (column->button);
7921               break;
7922             }
7923         }
7924       break;
7925     default:
7926       g_assert_not_reached ();
7927       break;
7928     }
7929
7930   /* if focus child is non-null, we assume it's been set to the current focus child
7931    */
7932   if (focus_child)
7933     {
7934       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
7935         if (GTK_TREE_VIEW_COLUMN (tmp_list->data)->button == focus_child)
7936           {
7937             tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
7938             break;
7939           }
7940
7941       if (clamp_column_visible)
7942         {
7943           gtk_tree_view_clamp_column_visible (tree_view,
7944                                               tree_view->priv->focus_column,
7945                                               FALSE);
7946         }
7947     }
7948
7949   return (focus_child != NULL);
7950 }
7951
7952 /* This function returns in 'path' the first focusable path, if the given path
7953  * is already focusable, it's the returned one.
7954  */
7955 static gboolean
7956 search_first_focusable_path (GtkTreeView  *tree_view,
7957                              GtkTreePath **path,
7958                              gboolean      search_forward,
7959                              GtkRBTree   **new_tree,
7960                              GtkRBNode   **new_node)
7961 {
7962   GtkRBTree *tree = NULL;
7963   GtkRBNode *node = NULL;
7964
7965   if (!path || !*path)
7966     return FALSE;
7967
7968   _gtk_tree_view_find_node (tree_view, *path, &tree, &node);
7969
7970   if (!tree || !node)
7971     return FALSE;
7972
7973   while (node && row_is_separator (tree_view, NULL, *path))
7974     {
7975       if (search_forward)
7976         _gtk_rbtree_next_full (tree, node, &tree, &node);
7977       else
7978         _gtk_rbtree_prev_full (tree, node, &tree, &node);
7979
7980       if (*path)
7981         gtk_tree_path_free (*path);
7982
7983       if (node)
7984         *path = _gtk_tree_view_find_path (tree_view, tree, node);
7985       else
7986         *path = NULL;
7987     }
7988
7989   if (new_tree)
7990     *new_tree = tree;
7991
7992   if (new_node)
7993     *new_node = node;
7994
7995   return (*path != NULL);
7996 }
7997
7998 static gint
7999 gtk_tree_view_focus (GtkWidget        *widget,
8000                      GtkDirectionType  direction)
8001 {
8002   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
8003   GtkContainer *container = GTK_CONTAINER (widget);
8004   GtkWidget *focus_child;
8005
8006   if (!gtk_widget_is_sensitive (widget) || !gtk_widget_get_can_focus (widget))
8007     return FALSE;
8008
8009   focus_child = gtk_container_get_focus_child (container);
8010
8011   gtk_tree_view_stop_editing (GTK_TREE_VIEW (widget), FALSE);
8012   /* Case 1.  Headers currently have focus. */
8013   if (focus_child)
8014     {
8015       switch (direction)
8016         {
8017         case GTK_DIR_LEFT:
8018         case GTK_DIR_RIGHT:
8019           gtk_tree_view_header_focus (tree_view, direction, TRUE);
8020           return TRUE;
8021         case GTK_DIR_TAB_BACKWARD:
8022         case GTK_DIR_UP:
8023           return FALSE;
8024         case GTK_DIR_TAB_FORWARD:
8025         case GTK_DIR_DOWN:
8026           gtk_widget_grab_focus (widget);
8027           return TRUE;
8028         default:
8029           g_assert_not_reached ();
8030           return FALSE;
8031         }
8032     }
8033
8034   /* Case 2. We don't have focus at all. */
8035   if (!gtk_widget_has_focus (widget))
8036     {
8037       if (!gtk_tree_view_header_focus (tree_view, direction, FALSE))
8038         gtk_widget_grab_focus (widget);
8039       return TRUE;
8040     }
8041
8042   /* Case 3. We have focus already. */
8043   if (direction == GTK_DIR_TAB_BACKWARD)
8044     return (gtk_tree_view_header_focus (tree_view, direction, FALSE));
8045   else if (direction == GTK_DIR_TAB_FORWARD)
8046     return FALSE;
8047
8048   /* Other directions caught by the keybindings */
8049   gtk_widget_grab_focus (widget);
8050   return TRUE;
8051 }
8052
8053 static void
8054 gtk_tree_view_grab_focus (GtkWidget *widget)
8055 {
8056   GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->grab_focus (widget);
8057
8058   gtk_tree_view_focus_to_cursor (GTK_TREE_VIEW (widget));
8059 }
8060
8061 static void
8062 gtk_tree_view_style_set (GtkWidget *widget,
8063                          GtkStyle *previous_style)
8064 {
8065   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
8066   GList *list;
8067   GtkTreeViewColumn *column;
8068
8069   if (gtk_widget_get_realized (widget))
8070     {
8071       gdk_window_set_back_pixmap (widget->window, NULL, FALSE);
8072       gdk_window_set_background (tree_view->priv->bin_window, &widget->style->base[widget->state]);
8073       gtk_style_set_background (widget->style, tree_view->priv->header_window, GTK_STATE_NORMAL);
8074
8075       gtk_tree_view_set_grid_lines (tree_view, tree_view->priv->grid_lines);
8076       gtk_tree_view_set_enable_tree_lines (tree_view, tree_view->priv->tree_lines_enabled);
8077     }
8078
8079   gtk_widget_style_get (widget,
8080                         "expander-size", &tree_view->priv->expander_size,
8081                         NULL);
8082   tree_view->priv->expander_size += EXPANDER_EXTRA_PADDING;
8083
8084   for (list = tree_view->priv->columns; list; list = list->next)
8085     {
8086       column = list->data;
8087       _gtk_tree_view_column_cell_set_dirty (column, TRUE);
8088     }
8089
8090   tree_view->priv->fixed_height = -1;
8091   _gtk_rbtree_mark_invalid (tree_view->priv->tree);
8092
8093   gtk_widget_queue_resize (widget);
8094 }
8095
8096
8097 static void
8098 gtk_tree_view_set_focus_child (GtkContainer *container,
8099                                GtkWidget    *child)
8100 {
8101   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
8102   GList *list;
8103
8104   for (list = tree_view->priv->columns; list; list = list->next)
8105     {
8106       if (GTK_TREE_VIEW_COLUMN (list->data)->button == child)
8107         {
8108           tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (list->data);
8109           break;
8110         }
8111     }
8112
8113   GTK_CONTAINER_CLASS (gtk_tree_view_parent_class)->set_focus_child (container, child);
8114 }
8115
8116 static void
8117 gtk_tree_view_set_adjustments (GtkTreeView   *tree_view,
8118                                GtkAdjustment *hadj,
8119                                GtkAdjustment *vadj)
8120 {
8121   gboolean need_adjust = FALSE;
8122
8123   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8124
8125   if (hadj)
8126     g_return_if_fail (GTK_IS_ADJUSTMENT (hadj));
8127   else
8128     hadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
8129   if (vadj)
8130     g_return_if_fail (GTK_IS_ADJUSTMENT (vadj));
8131   else
8132     vadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
8133
8134   if (tree_view->priv->hadjustment && (tree_view->priv->hadjustment != hadj))
8135     {
8136       g_signal_handlers_disconnect_by_func (tree_view->priv->hadjustment,
8137                                             gtk_tree_view_adjustment_changed,
8138                                             tree_view);
8139       g_object_unref (tree_view->priv->hadjustment);
8140     }
8141
8142   if (tree_view->priv->vadjustment && (tree_view->priv->vadjustment != vadj))
8143     {
8144       g_signal_handlers_disconnect_by_func (tree_view->priv->vadjustment,
8145                                             gtk_tree_view_adjustment_changed,
8146                                             tree_view);
8147       g_object_unref (tree_view->priv->vadjustment);
8148     }
8149
8150   if (tree_view->priv->hadjustment != hadj)
8151     {
8152       tree_view->priv->hadjustment = hadj;
8153       g_object_ref_sink (tree_view->priv->hadjustment);
8154
8155       g_signal_connect (tree_view->priv->hadjustment, "value-changed",
8156                         G_CALLBACK (gtk_tree_view_adjustment_changed),
8157                         tree_view);
8158       need_adjust = TRUE;
8159     }
8160
8161   if (tree_view->priv->vadjustment != vadj)
8162     {
8163       tree_view->priv->vadjustment = vadj;
8164       g_object_ref_sink (tree_view->priv->vadjustment);
8165
8166       g_signal_connect (tree_view->priv->vadjustment, "value-changed",
8167                         G_CALLBACK (gtk_tree_view_adjustment_changed),
8168                         tree_view);
8169       need_adjust = TRUE;
8170     }
8171
8172   if (need_adjust)
8173     gtk_tree_view_adjustment_changed (NULL, tree_view);
8174 }
8175
8176
8177 static gboolean
8178 gtk_tree_view_real_move_cursor (GtkTreeView       *tree_view,
8179                                 GtkMovementStep    step,
8180                                 gint               count)
8181 {
8182   GdkModifierType state;
8183
8184   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
8185   g_return_val_if_fail (step == GTK_MOVEMENT_LOGICAL_POSITIONS ||
8186                         step == GTK_MOVEMENT_VISUAL_POSITIONS ||
8187                         step == GTK_MOVEMENT_DISPLAY_LINES ||
8188                         step == GTK_MOVEMENT_PAGES ||
8189                         step == GTK_MOVEMENT_BUFFER_ENDS, FALSE);
8190
8191   if (tree_view->priv->tree == NULL)
8192     return FALSE;
8193   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
8194     return FALSE;
8195
8196   gtk_tree_view_stop_editing (tree_view, FALSE);
8197   GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
8198   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
8199
8200   if (gtk_get_current_event_state (&state))
8201     {
8202       if ((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
8203         tree_view->priv->ctrl_pressed = TRUE;
8204       if ((state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
8205         tree_view->priv->shift_pressed = TRUE;
8206     }
8207   /* else we assume not pressed */
8208
8209   switch (step)
8210     {
8211       /* currently we make no distinction.  When we go bi-di, we need to */
8212     case GTK_MOVEMENT_LOGICAL_POSITIONS:
8213     case GTK_MOVEMENT_VISUAL_POSITIONS:
8214       gtk_tree_view_move_cursor_left_right (tree_view, count);
8215       break;
8216     case GTK_MOVEMENT_DISPLAY_LINES:
8217       gtk_tree_view_move_cursor_up_down (tree_view, count);
8218       break;
8219     case GTK_MOVEMENT_PAGES:
8220       gtk_tree_view_move_cursor_page_up_down (tree_view, count);
8221       break;
8222     case GTK_MOVEMENT_BUFFER_ENDS:
8223       gtk_tree_view_move_cursor_start_end (tree_view, count);
8224       break;
8225     default:
8226       g_assert_not_reached ();
8227     }
8228
8229   tree_view->priv->ctrl_pressed = FALSE;
8230   tree_view->priv->shift_pressed = FALSE;
8231
8232   return TRUE;
8233 }
8234
8235 static void
8236 gtk_tree_view_put (GtkTreeView *tree_view,
8237                    GtkWidget   *child_widget,
8238                    /* in bin_window coordinates */
8239                    gint         x,
8240                    gint         y,
8241                    gint         width,
8242                    gint         height)
8243 {
8244   GtkTreeViewChild *child;
8245   
8246   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8247   g_return_if_fail (GTK_IS_WIDGET (child_widget));
8248
8249   child = g_slice_new (GtkTreeViewChild);
8250
8251   child->widget = child_widget;
8252   child->x = x;
8253   child->y = y;
8254   child->width = width;
8255   child->height = height;
8256
8257   tree_view->priv->children = g_list_append (tree_view->priv->children, child);
8258
8259   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
8260     gtk_widget_set_parent_window (child->widget, tree_view->priv->bin_window);
8261   
8262   gtk_widget_set_parent (child_widget, GTK_WIDGET (tree_view));
8263 }
8264
8265 void
8266 _gtk_tree_view_child_move_resize (GtkTreeView *tree_view,
8267                                   GtkWidget   *widget,
8268                                   /* in tree coordinates */
8269                                   gint         x,
8270                                   gint         y,
8271                                   gint         width,
8272                                   gint         height)
8273 {
8274   GtkTreeViewChild *child = NULL;
8275   GList *list;
8276   GdkRectangle allocation;
8277
8278   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8279   g_return_if_fail (GTK_IS_WIDGET (widget));
8280
8281   for (list = tree_view->priv->children; list; list = list->next)
8282     {
8283       if (((GtkTreeViewChild *)list->data)->widget == widget)
8284         {
8285           child = list->data;
8286           break;
8287         }
8288     }
8289   if (child == NULL)
8290     return;
8291
8292   allocation.x = child->x = x;
8293   allocation.y = child->y = y;
8294   allocation.width = child->width = width;
8295   allocation.height = child->height = height;
8296
8297   if (gtk_widget_get_realized (widget))
8298     gtk_widget_size_allocate (widget, &allocation);
8299 }
8300
8301
8302 /* TreeModel Callbacks
8303  */
8304
8305 static void
8306 gtk_tree_view_row_changed (GtkTreeModel *model,
8307                            GtkTreePath  *path,
8308                            GtkTreeIter  *iter,
8309                            gpointer      data)
8310 {
8311   GtkTreeView *tree_view = (GtkTreeView *)data;
8312   GtkRBTree *tree;
8313   GtkRBNode *node;
8314   gboolean free_path = FALSE;
8315   GList *list;
8316   GtkTreePath *cursor_path;
8317
8318   g_return_if_fail (path != NULL || iter != NULL);
8319
8320   if (tree_view->priv->cursor != NULL)
8321     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
8322   else
8323     cursor_path = NULL;
8324
8325   if (tree_view->priv->edited_column &&
8326       (cursor_path == NULL || gtk_tree_path_compare (cursor_path, path) == 0))
8327     gtk_tree_view_stop_editing (tree_view, TRUE);
8328
8329   if (cursor_path != NULL)
8330     gtk_tree_path_free (cursor_path);
8331
8332   if (path == NULL)
8333     {
8334       path = gtk_tree_model_get_path (model, iter);
8335       free_path = TRUE;
8336     }
8337   else if (iter == NULL)
8338     gtk_tree_model_get_iter (model, iter, path);
8339
8340   if (_gtk_tree_view_find_node (tree_view,
8341                                 path,
8342                                 &tree,
8343                                 &node))
8344     /* We aren't actually showing the node */
8345     goto done;
8346
8347   if (tree == NULL)
8348     goto done;
8349
8350   if (tree_view->priv->fixed_height_mode
8351       && tree_view->priv->fixed_height >= 0)
8352     {
8353       _gtk_rbtree_node_set_height (tree, node, tree_view->priv->fixed_height);
8354       if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
8355         gtk_tree_view_node_queue_redraw (tree_view, tree, node);
8356     }
8357   else
8358     {
8359       _gtk_rbtree_node_mark_invalid (tree, node);
8360       for (list = tree_view->priv->columns; list; list = list->next)
8361         {
8362           GtkTreeViewColumn *column;
8363
8364           column = list->data;
8365           if (! column->visible)
8366             continue;
8367
8368           if (column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
8369             {
8370               _gtk_tree_view_column_cell_set_dirty (column, TRUE);
8371             }
8372         }
8373     }
8374
8375  done:
8376   if (!tree_view->priv->fixed_height_mode &&
8377       gtk_widget_get_realized (GTK_WIDGET (tree_view)))
8378     install_presize_handler (tree_view);
8379   if (free_path)
8380     gtk_tree_path_free (path);
8381 }
8382
8383 static void
8384 gtk_tree_view_row_inserted (GtkTreeModel *model,
8385                             GtkTreePath  *path,
8386                             GtkTreeIter  *iter,
8387                             gpointer      data)
8388 {
8389   GtkTreeView *tree_view = (GtkTreeView *) data;
8390   gint *indices;
8391   GtkRBTree *tmptree, *tree;
8392   GtkRBNode *tmpnode = NULL;
8393   gint depth;
8394   gint i = 0;
8395   gint height;
8396   gboolean free_path = FALSE;
8397   gboolean node_visible = TRUE;
8398
8399   g_return_if_fail (path != NULL || iter != NULL);
8400
8401   if (tree_view->priv->fixed_height_mode
8402       && tree_view->priv->fixed_height >= 0)
8403     height = tree_view->priv->fixed_height;
8404   else
8405     height = 0;
8406
8407   if (path == NULL)
8408     {
8409       path = gtk_tree_model_get_path (model, iter);
8410       free_path = TRUE;
8411     }
8412   else if (iter == NULL)
8413     gtk_tree_model_get_iter (model, iter, path);
8414
8415   if (tree_view->priv->tree == NULL)
8416     tree_view->priv->tree = _gtk_rbtree_new ();
8417
8418   tmptree = tree = tree_view->priv->tree;
8419
8420   /* Update all row-references */
8421   gtk_tree_row_reference_inserted (G_OBJECT (data), path);
8422   depth = gtk_tree_path_get_depth (path);
8423   indices = gtk_tree_path_get_indices (path);
8424
8425   /* First, find the parent tree */
8426   while (i < depth - 1)
8427     {
8428       if (tmptree == NULL)
8429         {
8430           /* We aren't showing the node */
8431           node_visible = FALSE;
8432           goto done;
8433         }
8434
8435       tmpnode = _gtk_rbtree_find_count (tmptree, indices[i] + 1);
8436       if (tmpnode == NULL)
8437         {
8438           g_warning ("A node was inserted with a parent that's not in the tree.\n" \
8439                      "This possibly means that a GtkTreeModel inserted a child node\n" \
8440                      "before the parent was inserted.");
8441           goto done;
8442         }
8443       else if (!GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_IS_PARENT))
8444         {
8445           /* FIXME enforce correct behavior on model, probably */
8446           /* In theory, the model should have emitted has_child_toggled here.  We
8447            * try to catch it anyway, just to be safe, in case the model hasn't.
8448            */
8449           GtkTreePath *tmppath = _gtk_tree_view_find_path (tree_view,
8450                                                            tree,
8451                                                            tmpnode);
8452           gtk_tree_view_row_has_child_toggled (model, tmppath, NULL, data);
8453           gtk_tree_path_free (tmppath);
8454           goto done;
8455         }
8456
8457       tmptree = tmpnode->children;
8458       tree = tmptree;
8459       i++;
8460     }
8461
8462   if (tree == NULL)
8463     {
8464       node_visible = FALSE;
8465       goto done;
8466     }
8467
8468   /* ref the node */
8469   gtk_tree_model_ref_node (tree_view->priv->model, iter);
8470   if (indices[depth - 1] == 0)
8471     {
8472       tmpnode = _gtk_rbtree_find_count (tree, 1);
8473       tmpnode = _gtk_rbtree_insert_before (tree, tmpnode, height, FALSE);
8474     }
8475   else
8476     {
8477       tmpnode = _gtk_rbtree_find_count (tree, indices[depth - 1]);
8478       tmpnode = _gtk_rbtree_insert_after (tree, tmpnode, height, FALSE);
8479     }
8480
8481  done:
8482   if (height > 0)
8483     {
8484       if (tree)
8485         _gtk_rbtree_node_mark_valid (tree, tmpnode);
8486
8487       if (node_visible && node_is_visible (tree_view, tree, tmpnode))
8488         gtk_widget_queue_resize (GTK_WIDGET (tree_view));
8489       else
8490         gtk_widget_queue_resize_no_redraw (GTK_WIDGET (tree_view));
8491     }
8492   else
8493     install_presize_handler (tree_view);
8494   if (free_path)
8495     gtk_tree_path_free (path);
8496 }
8497
8498 static void
8499 gtk_tree_view_row_has_child_toggled (GtkTreeModel *model,
8500                                      GtkTreePath  *path,
8501                                      GtkTreeIter  *iter,
8502                                      gpointer      data)
8503 {
8504   GtkTreeView *tree_view = (GtkTreeView *)data;
8505   GtkTreeIter real_iter;
8506   gboolean has_child;
8507   GtkRBTree *tree;
8508   GtkRBNode *node;
8509   gboolean free_path = FALSE;
8510
8511   g_return_if_fail (path != NULL || iter != NULL);
8512
8513   if (iter)
8514     real_iter = *iter;
8515
8516   if (path == NULL)
8517     {
8518       path = gtk_tree_model_get_path (model, iter);
8519       free_path = TRUE;
8520     }
8521   else if (iter == NULL)
8522     gtk_tree_model_get_iter (model, &real_iter, path);
8523
8524   if (_gtk_tree_view_find_node (tree_view,
8525                                 path,
8526                                 &tree,
8527                                 &node))
8528     /* We aren't actually showing the node */
8529     goto done;
8530
8531   if (tree == NULL)
8532     goto done;
8533
8534   has_child = gtk_tree_model_iter_has_child (model, &real_iter);
8535   /* Sanity check.
8536    */
8537   if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT) == has_child)
8538     goto done;
8539
8540   if (has_child)
8541     GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_PARENT);
8542   else
8543     GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_PARENT);
8544
8545   if (has_child && GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IS_LIST))
8546     {
8547       GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IS_LIST);
8548       if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS))
8549         {
8550           GList *list;
8551
8552           for (list = tree_view->priv->columns; list; list = list->next)
8553             if (GTK_TREE_VIEW_COLUMN (list->data)->visible)
8554               {
8555                 GTK_TREE_VIEW_COLUMN (list->data)->dirty = TRUE;
8556                 _gtk_tree_view_column_cell_set_dirty (GTK_TREE_VIEW_COLUMN (list->data), TRUE);
8557                 break;
8558               }
8559         }
8560       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
8561     }
8562   else
8563     {
8564       _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
8565     }
8566
8567  done:
8568   if (free_path)
8569     gtk_tree_path_free (path);
8570 }
8571
8572 static void
8573 count_children_helper (GtkRBTree *tree,
8574                        GtkRBNode *node,
8575                        gpointer   data)
8576 {
8577   if (node->children)
8578     _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, data);
8579   (*((gint *)data))++;
8580 }
8581
8582 static void
8583 check_selection_helper (GtkRBTree *tree,
8584                         GtkRBNode *node,
8585                         gpointer   data)
8586 {
8587   gint *value = (gint *)data;
8588
8589   *value = GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED);
8590
8591   if (node->children && !*value)
8592     _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, check_selection_helper, data);
8593 }
8594
8595 static void
8596 gtk_tree_view_row_deleted (GtkTreeModel *model,
8597                            GtkTreePath  *path,
8598                            gpointer      data)
8599 {
8600   GtkTreeView *tree_view = (GtkTreeView *)data;
8601   GtkRBTree *tree;
8602   GtkRBNode *node;
8603   GList *list;
8604   gint selection_changed = FALSE;
8605
8606   g_return_if_fail (path != NULL);
8607
8608   gtk_tree_row_reference_deleted (G_OBJECT (data), path);
8609
8610   if (_gtk_tree_view_find_node (tree_view, path, &tree, &node))
8611     return;
8612
8613   if (tree == NULL)
8614     return;
8615
8616   /* check if the selection has been changed */
8617   _gtk_rbtree_traverse (tree, node, G_POST_ORDER,
8618                         check_selection_helper, &selection_changed);
8619
8620   for (list = tree_view->priv->columns; list; list = list->next)
8621     if (((GtkTreeViewColumn *)list->data)->visible &&
8622         ((GtkTreeViewColumn *)list->data)->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
8623       _gtk_tree_view_column_cell_set_dirty ((GtkTreeViewColumn *)list->data, TRUE);
8624
8625   /* Ensure we don't have a dangling pointer to a dead node */
8626   ensure_unprelighted (tree_view);
8627
8628   /* Cancel editting if we've started */
8629   gtk_tree_view_stop_editing (tree_view, TRUE);
8630
8631   /* If we have a node expanded/collapsed timeout, remove it */
8632   remove_expand_collapse_timeout (tree_view);
8633
8634   if (tree_view->priv->destroy_count_func)
8635     {
8636       gint child_count = 0;
8637       if (node->children)
8638         _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, &child_count);
8639       tree_view->priv->destroy_count_func (tree_view, path, child_count, tree_view->priv->destroy_count_data);
8640     }
8641
8642   if (tree->root->count == 1)
8643     {
8644       if (tree_view->priv->tree == tree)
8645         tree_view->priv->tree = NULL;
8646
8647       _gtk_rbtree_remove (tree);
8648     }
8649   else
8650     {
8651       _gtk_rbtree_remove_node (tree, node);
8652     }
8653
8654   if (! gtk_tree_row_reference_valid (tree_view->priv->top_row))
8655     {
8656       gtk_tree_row_reference_free (tree_view->priv->top_row);
8657       tree_view->priv->top_row = NULL;
8658     }
8659
8660   install_scroll_sync_handler (tree_view);
8661
8662   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
8663
8664   if (selection_changed)
8665     g_signal_emit_by_name (tree_view->priv->selection, "changed");
8666 }
8667
8668 static void
8669 gtk_tree_view_rows_reordered (GtkTreeModel *model,
8670                               GtkTreePath  *parent,
8671                               GtkTreeIter  *iter,
8672                               gint         *new_order,
8673                               gpointer      data)
8674 {
8675   GtkTreeView *tree_view = GTK_TREE_VIEW (data);
8676   GtkRBTree *tree;
8677   GtkRBNode *node;
8678   gint len;
8679
8680   len = gtk_tree_model_iter_n_children (model, iter);
8681
8682   if (len < 2)
8683     return;
8684
8685   gtk_tree_row_reference_reordered (G_OBJECT (data),
8686                                     parent,
8687                                     iter,
8688                                     new_order);
8689
8690   if (_gtk_tree_view_find_node (tree_view,
8691                                 parent,
8692                                 &tree,
8693                                 &node))
8694     return;
8695
8696   /* We need to special case the parent path */
8697   if (tree == NULL)
8698     tree = tree_view->priv->tree;
8699   else
8700     tree = node->children;
8701
8702   if (tree == NULL)
8703     return;
8704
8705   if (tree_view->priv->edited_column)
8706     gtk_tree_view_stop_editing (tree_view, TRUE);
8707
8708   /* we need to be unprelighted */
8709   ensure_unprelighted (tree_view);
8710
8711   /* clear the timeout */
8712   cancel_arrow_animation (tree_view);
8713   
8714   _gtk_rbtree_reorder (tree, new_order, len);
8715
8716   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
8717
8718   gtk_tree_view_dy_to_top_row (tree_view);
8719 }
8720
8721
8722 /* Internal tree functions
8723  */
8724
8725
8726 static void
8727 gtk_tree_view_get_background_xrange (GtkTreeView       *tree_view,
8728                                      GtkRBTree         *tree,
8729                                      GtkTreeViewColumn *column,
8730                                      gint              *x1,
8731                                      gint              *x2)
8732 {
8733   GtkTreeViewColumn *tmp_column = NULL;
8734   gint total_width;
8735   GList *list;
8736   gboolean rtl;
8737
8738   if (x1)
8739     *x1 = 0;
8740
8741   if (x2)
8742     *x2 = 0;
8743
8744   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
8745
8746   total_width = 0;
8747   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
8748        list;
8749        list = (rtl ? list->prev : list->next))
8750     {
8751       tmp_column = list->data;
8752
8753       if (tmp_column == column)
8754         break;
8755
8756       if (tmp_column->visible)
8757         total_width += tmp_column->width;
8758     }
8759
8760   if (tmp_column != column)
8761     {
8762       g_warning (G_STRLOC": passed-in column isn't in the tree");
8763       return;
8764     }
8765
8766   if (x1)
8767     *x1 = total_width;
8768
8769   if (x2)
8770     {
8771       if (column->visible)
8772         *x2 = total_width + column->width;
8773       else
8774         *x2 = total_width; /* width of 0 */
8775     }
8776 }
8777 static void
8778 gtk_tree_view_get_arrow_xrange (GtkTreeView *tree_view,
8779                                 GtkRBTree   *tree,
8780                                 gint        *x1,
8781                                 gint        *x2)
8782 {
8783   gint x_offset = 0;
8784   GList *list;
8785   GtkTreeViewColumn *tmp_column = NULL;
8786   gint total_width;
8787   gboolean indent_expanders;
8788   gboolean rtl;
8789
8790   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
8791
8792   total_width = 0;
8793   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
8794        list;
8795        list = (rtl ? list->prev : list->next))
8796     {
8797       tmp_column = list->data;
8798
8799       if (gtk_tree_view_is_expander_column (tree_view, tmp_column))
8800         {
8801           if (rtl)
8802             x_offset = total_width + tmp_column->width - tree_view->priv->expander_size;
8803           else
8804             x_offset = total_width;
8805           break;
8806         }
8807
8808       if (tmp_column->visible)
8809         total_width += tmp_column->width;
8810     }
8811
8812   gtk_widget_style_get (GTK_WIDGET (tree_view),
8813                         "indent-expanders", &indent_expanders,
8814                         NULL);
8815
8816   if (indent_expanders)
8817     {
8818       if (rtl)
8819         x_offset -= tree_view->priv->expander_size * _gtk_rbtree_get_depth (tree);
8820       else
8821         x_offset += tree_view->priv->expander_size * _gtk_rbtree_get_depth (tree);
8822     }
8823
8824   *x1 = x_offset;
8825   
8826   if (tmp_column && tmp_column->visible)
8827     /* +1 because x2 isn't included in the range. */
8828     *x2 = *x1 + tree_view->priv->expander_size + 1;
8829   else
8830     *x2 = *x1;
8831 }
8832
8833 static void
8834 gtk_tree_view_build_tree (GtkTreeView *tree_view,
8835                           GtkRBTree   *tree,
8836                           GtkTreeIter *iter,
8837                           gint         depth,
8838                           gboolean     recurse)
8839 {
8840   GtkRBNode *temp = NULL;
8841   GtkTreePath *path = NULL;
8842   gboolean is_list = GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IS_LIST);
8843
8844   do
8845     {
8846       gtk_tree_model_ref_node (tree_view->priv->model, iter);
8847       temp = _gtk_rbtree_insert_after (tree, temp, 0, FALSE);
8848
8849       if (tree_view->priv->fixed_height > 0)
8850         {
8851           if (GTK_RBNODE_FLAG_SET (temp, GTK_RBNODE_INVALID))
8852             {
8853               _gtk_rbtree_node_set_height (tree, temp, tree_view->priv->fixed_height);
8854               _gtk_rbtree_node_mark_valid (tree, temp);
8855             }
8856         }
8857
8858       if (is_list)
8859         continue;
8860
8861       if (recurse)
8862         {
8863           GtkTreeIter child;
8864
8865           if (!path)
8866             path = gtk_tree_model_get_path (tree_view->priv->model, iter);
8867           else
8868             gtk_tree_path_next (path);
8869
8870           if (gtk_tree_model_iter_children (tree_view->priv->model, &child, iter))
8871             {
8872               gboolean expand;
8873
8874               g_signal_emit (tree_view, tree_view_signals[TEST_EXPAND_ROW], 0, iter, path, &expand);
8875
8876               if (gtk_tree_model_iter_has_child (tree_view->priv->model, iter)
8877                   && !expand)
8878                 {
8879                   temp->children = _gtk_rbtree_new ();
8880                   temp->children->parent_tree = tree;
8881                   temp->children->parent_node = temp;
8882                   gtk_tree_view_build_tree (tree_view, temp->children, &child, depth + 1, recurse);
8883                 }
8884             }
8885         }
8886
8887       if (gtk_tree_model_iter_has_child (tree_view->priv->model, iter))
8888         {
8889           if ((temp->flags&GTK_RBNODE_IS_PARENT) != GTK_RBNODE_IS_PARENT)
8890             temp->flags ^= GTK_RBNODE_IS_PARENT;
8891         }
8892     }
8893   while (gtk_tree_model_iter_next (tree_view->priv->model, iter));
8894
8895   if (path)
8896     gtk_tree_path_free (path);
8897 }
8898
8899 /* Make sure the node is visible vertically */
8900 static void
8901 gtk_tree_view_clamp_node_visible (GtkTreeView *tree_view,
8902                                   GtkRBTree   *tree,
8903                                   GtkRBNode   *node)
8904 {
8905   gint node_dy, height;
8906   GtkTreePath *path = NULL;
8907
8908   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
8909     return;
8910
8911   /* just return if the node is visible, avoiding a costly expose */
8912   node_dy = _gtk_rbtree_node_find_offset (tree, node);
8913   height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
8914   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID)
8915       && node_dy >= tree_view->priv->vadjustment->value
8916       && node_dy + height <= (tree_view->priv->vadjustment->value
8917                               + tree_view->priv->vadjustment->page_size))
8918     return;
8919
8920   path = _gtk_tree_view_find_path (tree_view, tree, node);
8921   if (path)
8922     {
8923       /* We process updates because we want to clear old selected items when we scroll.
8924        * if this is removed, we get a "selection streak" at the bottom. */
8925       gdk_window_process_updates (tree_view->priv->bin_window, TRUE);
8926       gtk_tree_view_scroll_to_cell (tree_view, path, NULL, FALSE, 0.0, 0.0);
8927       gtk_tree_path_free (path);
8928     }
8929 }
8930
8931 static void
8932 gtk_tree_view_clamp_column_visible (GtkTreeView       *tree_view,
8933                                     GtkTreeViewColumn *column,
8934                                     gboolean           focus_to_cell)
8935 {
8936   gint x, width;
8937
8938   if (column == NULL)
8939     return;
8940
8941   x = column->button->allocation.x;
8942   width = column->button->allocation.width;
8943
8944   if (width > tree_view->priv->hadjustment->page_size)
8945     {
8946       /* The column is larger than the horizontal page size.  If the
8947        * column has cells which can be focussed individually, then we make
8948        * sure the cell which gets focus is fully visible (if even the
8949        * focus cell is bigger than the page size, we make sure the
8950        * left-hand side of the cell is visible).
8951        *
8952        * If the column does not have those so-called special cells, we
8953        * make sure the left-hand side of the column is visible.
8954        */
8955
8956       if (focus_to_cell && gtk_tree_view_has_special_cell (tree_view))
8957         {
8958           GtkTreePath *cursor_path;
8959           GdkRectangle background_area, cell_area, focus_area;
8960
8961           cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
8962
8963           gtk_tree_view_get_cell_area (tree_view,
8964                                        cursor_path, column, &cell_area);
8965           gtk_tree_view_get_background_area (tree_view,
8966                                              cursor_path, column,
8967                                              &background_area);
8968
8969           gtk_tree_path_free (cursor_path);
8970
8971           _gtk_tree_view_column_get_focus_area (column,
8972                                                 &background_area,
8973                                                 &cell_area,
8974                                                 &focus_area);
8975
8976           x = focus_area.x;
8977           width = focus_area.width;
8978
8979           if (width < tree_view->priv->hadjustment->page_size)
8980             {
8981               if ((tree_view->priv->hadjustment->value + tree_view->priv->hadjustment->page_size) < (x + width))
8982                 gtk_adjustment_set_value (tree_view->priv->hadjustment,
8983                                           x + width - tree_view->priv->hadjustment->page_size);
8984               else if (tree_view->priv->hadjustment->value > x)
8985                 gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
8986             }
8987         }
8988
8989       gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
8990     }
8991   else
8992     {
8993       if ((tree_view->priv->hadjustment->value + tree_view->priv->hadjustment->page_size) < (x + width))
8994           gtk_adjustment_set_value (tree_view->priv->hadjustment,
8995                                     x + width - tree_view->priv->hadjustment->page_size);
8996       else if (tree_view->priv->hadjustment->value > x)
8997         gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
8998   }
8999 }
9000
9001 /* This function could be more efficient.  I'll optimize it if profiling seems
9002  * to imply that it is important */
9003 GtkTreePath *
9004 _gtk_tree_view_find_path (GtkTreeView *tree_view,
9005                           GtkRBTree   *tree,
9006                           GtkRBNode   *node)
9007 {
9008   GtkTreePath *path;
9009   GtkRBTree *tmp_tree;
9010   GtkRBNode *tmp_node, *last;
9011   gint count;
9012
9013   path = gtk_tree_path_new ();
9014
9015   g_return_val_if_fail (node != NULL, path);
9016   g_return_val_if_fail (node != tree->nil, path);
9017
9018   count = 1 + node->left->count;
9019
9020   last = node;
9021   tmp_node = node->parent;
9022   tmp_tree = tree;
9023   while (tmp_tree)
9024     {
9025       while (tmp_node != tmp_tree->nil)
9026         {
9027           if (tmp_node->right == last)
9028             count += 1 + tmp_node->left->count;
9029           last = tmp_node;
9030           tmp_node = tmp_node->parent;
9031         }
9032       gtk_tree_path_prepend_index (path, count - 1);
9033       last = tmp_tree->parent_node;
9034       tmp_tree = tmp_tree->parent_tree;
9035       if (last)
9036         {
9037           count = 1 + last->left->count;
9038           tmp_node = last->parent;
9039         }
9040     }
9041   return path;
9042 }
9043
9044 /* Returns TRUE if we ran out of tree before finding the path.  If the path is
9045  * invalid (ie. points to a node that's not in the tree), *tree and *node are
9046  * both set to NULL.
9047  */
9048 gboolean
9049 _gtk_tree_view_find_node (GtkTreeView  *tree_view,
9050                           GtkTreePath  *path,
9051                           GtkRBTree   **tree,
9052                           GtkRBNode   **node)
9053 {
9054   GtkRBNode *tmpnode = NULL;
9055   GtkRBTree *tmptree = tree_view->priv->tree;
9056   gint *indices = gtk_tree_path_get_indices (path);
9057   gint depth = gtk_tree_path_get_depth (path);
9058   gint i = 0;
9059
9060   *node = NULL;
9061   *tree = NULL;
9062
9063   if (depth == 0 || tmptree == NULL)
9064     return FALSE;
9065   do
9066     {
9067       tmpnode = _gtk_rbtree_find_count (tmptree, indices[i] + 1);
9068       ++i;
9069       if (tmpnode == NULL)
9070         {
9071           *tree = NULL;
9072           *node = NULL;
9073           return FALSE;
9074         }
9075       if (i >= depth)
9076         {
9077           *tree = tmptree;
9078           *node = tmpnode;
9079           return FALSE;
9080         }
9081       *tree = tmptree;
9082       *node = tmpnode;
9083       tmptree = tmpnode->children;
9084       if (tmptree == NULL)
9085         return TRUE;
9086     }
9087   while (1);
9088 }
9089
9090 static gboolean
9091 gtk_tree_view_is_expander_column (GtkTreeView       *tree_view,
9092                                   GtkTreeViewColumn *column)
9093 {
9094   GList *list;
9095
9096   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IS_LIST))
9097     return FALSE;
9098
9099   if (tree_view->priv->expander_column != NULL)
9100     {
9101       if (tree_view->priv->expander_column == column)
9102         return TRUE;
9103       return FALSE;
9104     }
9105   else
9106     {
9107       for (list = tree_view->priv->columns;
9108            list;
9109            list = list->next)
9110         if (((GtkTreeViewColumn *)list->data)->visible)
9111           break;
9112       if (list && list->data == column)
9113         return TRUE;
9114     }
9115   return FALSE;
9116 }
9117
9118 static void
9119 gtk_tree_view_add_move_binding (GtkBindingSet  *binding_set,
9120                                 guint           keyval,
9121                                 guint           modmask,
9122                                 gboolean        add_shifted_binding,
9123                                 GtkMovementStep step,
9124                                 gint            count)
9125 {
9126   
9127   gtk_binding_entry_add_signal (binding_set, keyval, modmask,
9128                                 "move-cursor", 2,
9129                                 G_TYPE_ENUM, step,
9130                                 G_TYPE_INT, count);
9131
9132   if (add_shifted_binding)
9133     gtk_binding_entry_add_signal (binding_set, keyval, GDK_SHIFT_MASK,
9134                                   "move-cursor", 2,
9135                                   G_TYPE_ENUM, step,
9136                                   G_TYPE_INT, count);
9137
9138   if ((modmask & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
9139    return;
9140
9141   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK | GDK_SHIFT_MASK,
9142                                 "move-cursor", 2,
9143                                 G_TYPE_ENUM, step,
9144                                 G_TYPE_INT, count);
9145
9146   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK,
9147                                 "move-cursor", 2,
9148                                 G_TYPE_ENUM, step,
9149                                 G_TYPE_INT, count);
9150 }
9151
9152 static gint
9153 gtk_tree_view_unref_tree_helper (GtkTreeModel *model,
9154                                  GtkTreeIter  *iter,
9155                                  GtkRBTree    *tree,
9156                                  GtkRBNode    *node)
9157 {
9158   gint retval = FALSE;
9159   do
9160     {
9161       g_return_val_if_fail (node != NULL, FALSE);
9162
9163       if (node->children)
9164         {
9165           GtkTreeIter child;
9166           GtkRBTree *new_tree;
9167           GtkRBNode *new_node;
9168
9169           new_tree = node->children;
9170           new_node = new_tree->root;
9171
9172           while (new_node && new_node->left != new_tree->nil)
9173             new_node = new_node->left;
9174
9175           if (!gtk_tree_model_iter_children (model, &child, iter))
9176             return FALSE;
9177
9178           retval = retval || gtk_tree_view_unref_tree_helper (model, &child, new_tree, new_node);
9179         }
9180
9181       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
9182         retval = TRUE;
9183       gtk_tree_model_unref_node (model, iter);
9184       node = _gtk_rbtree_next (tree, node);
9185     }
9186   while (gtk_tree_model_iter_next (model, iter));
9187
9188   return retval;
9189 }
9190
9191 static gint
9192 gtk_tree_view_unref_and_check_selection_tree (GtkTreeView *tree_view,
9193                                               GtkRBTree   *tree)
9194 {
9195   GtkTreeIter iter;
9196   GtkTreePath *path;
9197   GtkRBNode *node;
9198   gint retval;
9199
9200   if (!tree)
9201     return FALSE;
9202
9203   node = tree->root;
9204   while (node && node->left != tree->nil)
9205     node = node->left;
9206
9207   g_return_val_if_fail (node != NULL, FALSE);
9208   path = _gtk_tree_view_find_path (tree_view, tree, node);
9209   gtk_tree_model_get_iter (GTK_TREE_MODEL (tree_view->priv->model),
9210                            &iter, path);
9211   retval = gtk_tree_view_unref_tree_helper (GTK_TREE_MODEL (tree_view->priv->model), &iter, tree, node);
9212   gtk_tree_path_free (path);
9213
9214   return retval;
9215 }
9216
9217 static void
9218 gtk_tree_view_set_column_drag_info (GtkTreeView       *tree_view,
9219                                     GtkTreeViewColumn *column)
9220 {
9221   GtkTreeViewColumn *left_column;
9222   GtkTreeViewColumn *cur_column = NULL;
9223   GtkTreeViewColumnReorder *reorder;
9224   gboolean rtl;
9225   GList *tmp_list;
9226   gint left;
9227
9228   /* We want to precalculate the motion list such that we know what column slots
9229    * are available.
9230    */
9231   left_column = NULL;
9232   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
9233
9234   /* First, identify all possible drop spots */
9235   if (rtl)
9236     tmp_list = g_list_last (tree_view->priv->columns);
9237   else
9238     tmp_list = g_list_first (tree_view->priv->columns);
9239
9240   while (tmp_list)
9241     {
9242       cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
9243       tmp_list = rtl?g_list_previous (tmp_list):g_list_next (tmp_list);
9244
9245       if (cur_column->visible == FALSE)
9246         continue;
9247
9248       /* If it's not the column moving and func tells us to skip over the column, we continue. */
9249       if (left_column != column && cur_column != column &&
9250           tree_view->priv->column_drop_func &&
9251           ! tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
9252         {
9253           left_column = cur_column;
9254           continue;
9255         }
9256       reorder = g_slice_new0 (GtkTreeViewColumnReorder);
9257       reorder->left_column = left_column;
9258       left_column = reorder->right_column = cur_column;
9259
9260       tree_view->priv->column_drag_info = g_list_append (tree_view->priv->column_drag_info, reorder);
9261     }
9262
9263   /* Add the last one */
9264   if (tree_view->priv->column_drop_func == NULL ||
9265       ((left_column != column) &&
9266        tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data)))
9267     {
9268       reorder = g_slice_new0 (GtkTreeViewColumnReorder);
9269       reorder->left_column = left_column;
9270       reorder->right_column = NULL;
9271       tree_view->priv->column_drag_info = g_list_append (tree_view->priv->column_drag_info, reorder);
9272     }
9273
9274   /* We quickly check to see if it even makes sense to reorder columns. */
9275   /* If there is nothing that can be moved, then we return */
9276
9277   if (tree_view->priv->column_drag_info == NULL)
9278     return;
9279
9280   /* We know there are always 2 slots possbile, as you can always return column. */
9281   /* If that's all there is, return */
9282   if (tree_view->priv->column_drag_info->next == NULL || 
9283       (tree_view->priv->column_drag_info->next->next == NULL &&
9284        ((GtkTreeViewColumnReorder *)tree_view->priv->column_drag_info->data)->right_column == column &&
9285        ((GtkTreeViewColumnReorder *)tree_view->priv->column_drag_info->next->data)->left_column == column))
9286     {
9287       for (tmp_list = tree_view->priv->column_drag_info; tmp_list; tmp_list = tmp_list->next)
9288         g_slice_free (GtkTreeViewColumnReorder, tmp_list->data);
9289       g_list_free (tree_view->priv->column_drag_info);
9290       tree_view->priv->column_drag_info = NULL;
9291       return;
9292     }
9293   /* We fill in the ranges for the columns, now that we've isolated them */
9294   left = - TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER (tree_view);
9295
9296   for (tmp_list = tree_view->priv->column_drag_info; tmp_list; tmp_list = tmp_list->next)
9297     {
9298       reorder = (GtkTreeViewColumnReorder *) tmp_list->data;
9299
9300       reorder->left_align = left;
9301       if (tmp_list->next != NULL)
9302         {
9303           g_assert (tmp_list->next->data);
9304           left = reorder->right_align = (reorder->right_column->button->allocation.x +
9305                                          reorder->right_column->button->allocation.width +
9306                                          ((GtkTreeViewColumnReorder *)tmp_list->next->data)->left_column->button->allocation.x)/2;
9307         }
9308       else
9309         {
9310           gint width;
9311
9312           gdk_drawable_get_size (tree_view->priv->header_window, &width, NULL);
9313           reorder->right_align = width + TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER (tree_view);
9314         }
9315     }
9316 }
9317
9318 void
9319 _gtk_tree_view_column_start_drag (GtkTreeView       *tree_view,
9320                                   GtkTreeViewColumn *column,
9321                                   GdkDevice         *device)
9322 {
9323   GdkEvent *send_event;
9324   GtkAllocation allocation;
9325   gint x, y, width, height;
9326   GdkScreen *screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
9327   GdkDisplay *display = gdk_screen_get_display (screen);
9328
9329   g_return_if_fail (tree_view->priv->column_drag_info == NULL);
9330   g_return_if_fail (tree_view->priv->cur_reorder == NULL);
9331
9332   gtk_tree_view_set_column_drag_info (tree_view, column);
9333
9334   if (tree_view->priv->column_drag_info == NULL)
9335     return;
9336
9337   if (tree_view->priv->drag_window == NULL)
9338     {
9339       GdkWindowAttr attributes;
9340       guint attributes_mask;
9341
9342       attributes.window_type = GDK_WINDOW_CHILD;
9343       attributes.wclass = GDK_INPUT_OUTPUT;
9344       attributes.x = column->button->allocation.x;
9345       attributes.y = 0;
9346       attributes.width = column->button->allocation.width;
9347       attributes.height = column->button->allocation.height;
9348       attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
9349       attributes.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
9350       attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
9351       attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
9352
9353       tree_view->priv->drag_window = gdk_window_new (tree_view->priv->bin_window,
9354                                                      &attributes,
9355                                                      attributes_mask);
9356       gdk_window_set_user_data (tree_view->priv->drag_window, GTK_WIDGET (tree_view));
9357     }
9358
9359   gdk_display_pointer_ungrab (display, GDK_CURRENT_TIME);
9360   gdk_display_keyboard_ungrab (display, GDK_CURRENT_TIME);
9361
9362   gtk_grab_remove (column->button);
9363
9364   send_event = gdk_event_new (GDK_LEAVE_NOTIFY);
9365   send_event->crossing.send_event = TRUE;
9366   send_event->crossing.window = g_object_ref (GTK_BUTTON (column->button)->event_window);
9367   send_event->crossing.subwindow = NULL;
9368   send_event->crossing.detail = GDK_NOTIFY_ANCESTOR;
9369   send_event->crossing.time = GDK_CURRENT_TIME;
9370   gdk_event_set_device (send_event, device);
9371
9372   gtk_propagate_event (column->button, send_event);
9373   gdk_event_free (send_event);
9374
9375   send_event = gdk_event_new (GDK_BUTTON_RELEASE);
9376   send_event->button.window = g_object_ref (gdk_screen_get_root_window (screen));
9377   send_event->button.send_event = TRUE;
9378   send_event->button.time = GDK_CURRENT_TIME;
9379   send_event->button.x = -1;
9380   send_event->button.y = -1;
9381   send_event->button.axes = NULL;
9382   send_event->button.state = 0;
9383   send_event->button.button = 1;
9384   send_event->button.x_root = 0;
9385   send_event->button.y_root = 0;
9386   gdk_event_set_device (send_event, device);
9387
9388   gtk_propagate_event (column->button, send_event);
9389   gdk_event_free (send_event);
9390
9391   /* Kids, don't try this at home */
9392   g_object_ref (column->button);
9393   gtk_container_remove (GTK_CONTAINER (tree_view), column->button);
9394   gtk_widget_set_parent_window (column->button, tree_view->priv->drag_window);
9395   gtk_widget_set_parent (column->button, GTK_WIDGET (tree_view));
9396   g_object_unref (column->button);
9397
9398   tree_view->priv->drag_column_x = column->button->allocation.x;
9399   allocation = column->button->allocation;
9400   allocation.x = 0;
9401   gtk_widget_size_allocate (column->button, &allocation);
9402   gtk_widget_set_parent_window (column->button, tree_view->priv->drag_window);
9403
9404   tree_view->priv->drag_column = column;
9405   gdk_window_show (tree_view->priv->drag_window);
9406
9407   gdk_window_get_origin (tree_view->priv->header_window, &x, &y);
9408   gdk_drawable_get_size (tree_view->priv->header_window, &width, &height);
9409
9410   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
9411   while (gtk_events_pending ())
9412     gtk_main_iteration ();
9413
9414   GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG);
9415   gdk_pointer_grab (tree_view->priv->drag_window,
9416                     FALSE,
9417                     GDK_POINTER_MOTION_MASK|GDK_BUTTON_RELEASE_MASK,
9418                     NULL, NULL, GDK_CURRENT_TIME);
9419   gdk_keyboard_grab (tree_view->priv->drag_window,
9420                      FALSE,
9421                      GDK_CURRENT_TIME);
9422 }
9423
9424 static void
9425 gtk_tree_view_queue_draw_arrow (GtkTreeView        *tree_view,
9426                                 GtkRBTree          *tree,
9427                                 GtkRBNode          *node,
9428                                 const GdkRectangle *clip_rect)
9429 {
9430   GdkRectangle rect;
9431
9432   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
9433     return;
9434
9435   rect.x = 0;
9436   rect.width = MAX (tree_view->priv->expander_size, MAX (tree_view->priv->width, GTK_WIDGET (tree_view)->allocation.width));
9437
9438   rect.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
9439   rect.height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
9440
9441   if (clip_rect)
9442     {
9443       GdkRectangle new_rect;
9444
9445       gdk_rectangle_intersect (clip_rect, &rect, &new_rect);
9446
9447       gdk_window_invalidate_rect (tree_view->priv->bin_window, &new_rect, TRUE);
9448     }
9449   else
9450     {
9451       gdk_window_invalidate_rect (tree_view->priv->bin_window, &rect, TRUE);
9452     }
9453 }
9454
9455 void
9456 _gtk_tree_view_queue_draw_node (GtkTreeView        *tree_view,
9457                                 GtkRBTree          *tree,
9458                                 GtkRBNode          *node,
9459                                 const GdkRectangle *clip_rect)
9460 {
9461   GdkRectangle rect;
9462
9463   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
9464     return;
9465
9466   rect.x = 0;
9467   rect.width = MAX (tree_view->priv->width, GTK_WIDGET (tree_view)->allocation.width);
9468
9469   rect.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
9470   rect.height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
9471
9472   if (clip_rect)
9473     {
9474       GdkRectangle new_rect;
9475
9476       gdk_rectangle_intersect (clip_rect, &rect, &new_rect);
9477
9478       gdk_window_invalidate_rect (tree_view->priv->bin_window, &new_rect, TRUE);
9479     }
9480   else
9481     {
9482       gdk_window_invalidate_rect (tree_view->priv->bin_window, &rect, TRUE);
9483     }
9484 }
9485
9486 static void
9487 gtk_tree_view_queue_draw_path (GtkTreeView        *tree_view,
9488                                GtkTreePath        *path,
9489                                const GdkRectangle *clip_rect)
9490 {
9491   GtkRBTree *tree = NULL;
9492   GtkRBNode *node = NULL;
9493
9494   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
9495
9496   if (tree)
9497     _gtk_tree_view_queue_draw_node (tree_view, tree, node, clip_rect);
9498 }
9499
9500 /* x and y are the mouse position
9501  */
9502 static void
9503 gtk_tree_view_draw_arrow (GtkTreeView *tree_view,
9504                           GtkRBTree   *tree,
9505                           GtkRBNode   *node,
9506                           /* in bin_window coordinates */
9507                           gint         x,
9508                           gint         y)
9509 {
9510   GdkRectangle area;
9511   GtkStateType state;
9512   GtkWidget *widget;
9513   gint x_offset = 0;
9514   gint x2;
9515   gint vertical_separator;
9516   gint expander_size;
9517   GtkExpanderStyle expander_style;
9518
9519   widget = GTK_WIDGET (tree_view);
9520
9521   gtk_widget_style_get (widget,
9522                         "vertical-separator", &vertical_separator,
9523                         NULL);
9524   expander_size = tree_view->priv->expander_size - EXPANDER_EXTRA_PADDING;
9525
9526   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
9527     return;
9528
9529   gtk_tree_view_get_arrow_xrange (tree_view, tree, &x_offset, &x2);
9530
9531   area.x = x_offset;
9532   area.y = CELL_FIRST_PIXEL (tree_view, tree, node, vertical_separator);
9533   area.width = expander_size + 2;
9534   area.height = MAX (CELL_HEIGHT (node, vertical_separator), (expander_size - vertical_separator));
9535
9536   if (gtk_widget_get_state (widget) == GTK_STATE_INSENSITIVE)
9537     {
9538       state = GTK_STATE_INSENSITIVE;
9539     }
9540   else if (node == tree_view->priv->button_pressed_node)
9541     {
9542       if (x >= area.x && x <= (area.x + area.width) &&
9543           y >= area.y && y <= (area.y + area.height))
9544         state = GTK_STATE_ACTIVE;
9545       else
9546         state = GTK_STATE_NORMAL;
9547     }
9548   else
9549     {
9550       if (node == tree_view->priv->prelight_node &&
9551           GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT))
9552         state = GTK_STATE_PRELIGHT;
9553       else
9554         state = GTK_STATE_NORMAL;
9555     }
9556
9557   if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_EXPANDED))
9558     expander_style = GTK_EXPANDER_SEMI_EXPANDED;
9559   else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_COLLAPSED))
9560     expander_style = GTK_EXPANDER_SEMI_COLLAPSED;
9561   else if (node->children != NULL)
9562     expander_style = GTK_EXPANDER_EXPANDED;
9563   else
9564     expander_style = GTK_EXPANDER_COLLAPSED;
9565
9566   gtk_paint_expander (widget->style,
9567                       tree_view->priv->bin_window,
9568                       state,
9569                       &area,
9570                       widget,
9571                       "treeview",
9572                       area.x + area.width / 2,
9573                       area.y + area.height / 2,
9574                       expander_style);
9575 }
9576
9577 static void
9578 gtk_tree_view_focus_to_cursor (GtkTreeView *tree_view)
9579
9580 {
9581   GtkTreePath *cursor_path;
9582
9583   if ((tree_view->priv->tree == NULL) ||
9584       (! gtk_widget_get_realized (GTK_WIDGET (tree_view))))
9585     return;
9586
9587   cursor_path = NULL;
9588   if (tree_view->priv->cursor)
9589     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
9590
9591   if (cursor_path == NULL)
9592     {
9593       /* Consult the selection before defaulting to the
9594        * first focusable element
9595        */
9596       GList *selected_rows;
9597       GtkTreeModel *model;
9598       GtkTreeSelection *selection;
9599
9600       selection = gtk_tree_view_get_selection (tree_view);
9601       selected_rows = gtk_tree_selection_get_selected_rows (selection, &model);
9602
9603       if (selected_rows)
9604         {
9605           cursor_path = gtk_tree_path_copy((const GtkTreePath *)(selected_rows->data));
9606           g_list_foreach (selected_rows, (GFunc)gtk_tree_path_free, NULL);
9607           g_list_free (selected_rows);
9608         }
9609       else
9610         {
9611           cursor_path = gtk_tree_path_new_first ();
9612           search_first_focusable_path (tree_view, &cursor_path,
9613                                        TRUE, NULL, NULL);
9614         }
9615
9616       gtk_tree_row_reference_free (tree_view->priv->cursor);
9617       tree_view->priv->cursor = NULL;
9618
9619       if (cursor_path)
9620         {
9621           if (tree_view->priv->selection->type == GTK_SELECTION_MULTIPLE)
9622             gtk_tree_view_real_set_cursor (tree_view, cursor_path, FALSE, FALSE);
9623           else
9624             gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE);
9625         }
9626     }
9627
9628   if (cursor_path)
9629     {
9630       GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
9631
9632       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
9633       gtk_tree_path_free (cursor_path);
9634
9635       if (tree_view->priv->focus_column == NULL)
9636         {
9637           GList *list;
9638           for (list = tree_view->priv->columns; list; list = list->next)
9639             {
9640               if (GTK_TREE_VIEW_COLUMN (list->data)->visible)
9641                 {
9642                   tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (list->data);
9643                   break;
9644                 }
9645             }
9646         }
9647     }
9648 }
9649
9650 static void
9651 gtk_tree_view_move_cursor_up_down (GtkTreeView *tree_view,
9652                                    gint         count)
9653 {
9654   gint selection_count;
9655   GtkRBTree *cursor_tree = NULL;
9656   GtkRBNode *cursor_node = NULL;
9657   GtkRBTree *new_cursor_tree = NULL;
9658   GtkRBNode *new_cursor_node = NULL;
9659   GtkTreePath *cursor_path = NULL;
9660   gboolean grab_focus = TRUE;
9661   gboolean selectable;
9662
9663   if (! gtk_widget_has_focus (GTK_WIDGET (tree_view)))
9664     return;
9665
9666   cursor_path = NULL;
9667   if (!gtk_tree_row_reference_valid (tree_view->priv->cursor))
9668     /* FIXME: we lost the cursor; should we get the first? */
9669     return;
9670
9671   cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
9672   _gtk_tree_view_find_node (tree_view, cursor_path,
9673                             &cursor_tree, &cursor_node);
9674
9675   if (cursor_tree == NULL)
9676     /* FIXME: we lost the cursor; should we get the first? */
9677     return;
9678
9679   selection_count = gtk_tree_selection_count_selected_rows (tree_view->priv->selection);
9680   selectable = _gtk_tree_selection_row_is_selectable (tree_view->priv->selection,
9681                                                       cursor_node,
9682                                                       cursor_path);
9683
9684   if (selection_count == 0
9685       && tree_view->priv->selection->type != GTK_SELECTION_NONE
9686       && !tree_view->priv->ctrl_pressed
9687       && selectable)
9688     {
9689       /* Don't move the cursor, but just select the current node */
9690       new_cursor_tree = cursor_tree;
9691       new_cursor_node = cursor_node;
9692     }
9693   else
9694     {
9695       if (count == -1)
9696         _gtk_rbtree_prev_full (cursor_tree, cursor_node,
9697                                &new_cursor_tree, &new_cursor_node);
9698       else
9699         _gtk_rbtree_next_full (cursor_tree, cursor_node,
9700                                &new_cursor_tree, &new_cursor_node);
9701     }
9702
9703   gtk_tree_path_free (cursor_path);
9704
9705   if (new_cursor_node)
9706     {
9707       cursor_path = _gtk_tree_view_find_path (tree_view,
9708                                               new_cursor_tree, new_cursor_node);
9709
9710       search_first_focusable_path (tree_view, &cursor_path,
9711                                    (count != -1),
9712                                    &new_cursor_tree,
9713                                    &new_cursor_node);
9714
9715       if (cursor_path)
9716         gtk_tree_path_free (cursor_path);
9717     }
9718
9719   /*
9720    * If the list has only one item and multi-selection is set then select
9721    * the row (if not yet selected).
9722    */
9723   if (tree_view->priv->selection->type == GTK_SELECTION_MULTIPLE &&
9724       new_cursor_node == NULL)
9725     {
9726       if (count == -1)
9727         _gtk_rbtree_next_full (cursor_tree, cursor_node,
9728                                &new_cursor_tree, &new_cursor_node);
9729       else
9730         _gtk_rbtree_prev_full (cursor_tree, cursor_node,
9731                                &new_cursor_tree, &new_cursor_node);
9732
9733       if (new_cursor_node == NULL
9734           && !GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_SELECTED))
9735         {
9736           new_cursor_node = cursor_node;
9737           new_cursor_tree = cursor_tree;
9738         }
9739       else
9740         {
9741           new_cursor_node = NULL;
9742         }
9743     }
9744
9745   if (new_cursor_node)
9746     {
9747       cursor_path = _gtk_tree_view_find_path (tree_view, new_cursor_tree, new_cursor_node);
9748       gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, TRUE);
9749       gtk_tree_path_free (cursor_path);
9750     }
9751   else
9752     {
9753       gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
9754
9755       if (!tree_view->priv->shift_pressed)
9756         {
9757           if (! gtk_widget_keynav_failed (GTK_WIDGET (tree_view),
9758                                           count < 0 ?
9759                                           GTK_DIR_UP : GTK_DIR_DOWN))
9760             {
9761               GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (tree_view));
9762
9763               if (toplevel)
9764                 gtk_widget_child_focus (toplevel,
9765                                         count < 0 ?
9766                                         GTK_DIR_TAB_BACKWARD :
9767                                         GTK_DIR_TAB_FORWARD);
9768
9769               grab_focus = FALSE;
9770             }
9771         }
9772       else
9773         {
9774           gtk_widget_error_bell (GTK_WIDGET (tree_view));
9775         }
9776     }
9777
9778   if (grab_focus)
9779     gtk_widget_grab_focus (GTK_WIDGET (tree_view));
9780 }
9781
9782 static void
9783 gtk_tree_view_move_cursor_page_up_down (GtkTreeView *tree_view,
9784                                         gint         count)
9785 {
9786   GtkRBTree *cursor_tree = NULL;
9787   GtkRBNode *cursor_node = NULL;
9788   GtkTreePath *old_cursor_path = NULL;
9789   GtkTreePath *cursor_path = NULL;
9790   GtkRBTree *start_cursor_tree = NULL;
9791   GtkRBNode *start_cursor_node = NULL;
9792   gint y;
9793   gint window_y;
9794   gint vertical_separator;
9795
9796   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
9797     return;
9798
9799   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
9800     old_cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
9801   else
9802     /* This is sorta weird.  Focus in should give us a cursor */
9803     return;
9804
9805   gtk_widget_style_get (GTK_WIDGET (tree_view), "vertical-separator", &vertical_separator, NULL);
9806   _gtk_tree_view_find_node (tree_view, old_cursor_path,
9807                             &cursor_tree, &cursor_node);
9808
9809   if (cursor_tree == NULL)
9810     {
9811       /* FIXME: we lost the cursor.  Should we try to get one? */
9812       gtk_tree_path_free (old_cursor_path);
9813       return;
9814     }
9815   g_return_if_fail (cursor_node != NULL);
9816
9817   y = _gtk_rbtree_node_find_offset (cursor_tree, cursor_node);
9818   window_y = RBTREE_Y_TO_TREE_WINDOW_Y (tree_view, y);
9819   y += tree_view->priv->cursor_offset;
9820   y += count * (int)tree_view->priv->vadjustment->page_increment;
9821   y = CLAMP (y, (gint)tree_view->priv->vadjustment->lower,  (gint)tree_view->priv->vadjustment->upper - vertical_separator);
9822
9823   if (y >= tree_view->priv->height)
9824     y = tree_view->priv->height - 1;
9825
9826   tree_view->priv->cursor_offset =
9827     _gtk_rbtree_find_offset (tree_view->priv->tree, y,
9828                              &cursor_tree, &cursor_node);
9829
9830   if (tree_view->priv->cursor_offset > BACKGROUND_HEIGHT (cursor_node))
9831     {
9832       _gtk_rbtree_next_full (cursor_tree, cursor_node,
9833                              &cursor_tree, &cursor_node);
9834       tree_view->priv->cursor_offset -= BACKGROUND_HEIGHT (cursor_node);
9835     }
9836
9837   y -= tree_view->priv->cursor_offset;
9838   cursor_path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
9839
9840   start_cursor_tree = cursor_tree;
9841   start_cursor_node = cursor_node;
9842
9843   if (! search_first_focusable_path (tree_view, &cursor_path,
9844                                      (count != -1),
9845                                      &cursor_tree, &cursor_node))
9846     {
9847       /* It looks like we reached the end of the view without finding
9848        * a focusable row.  We will step backwards to find the last
9849        * focusable row.
9850        */
9851       cursor_tree = start_cursor_tree;
9852       cursor_node = start_cursor_node;
9853       cursor_path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
9854
9855       search_first_focusable_path (tree_view, &cursor_path,
9856                                    (count == -1),
9857                                    &cursor_tree, &cursor_node);
9858     }
9859
9860   if (!cursor_path)
9861     goto cleanup;
9862
9863   /* update y */
9864   y = _gtk_rbtree_node_find_offset (cursor_tree, cursor_node);
9865
9866   gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE);
9867
9868   y -= window_y;
9869   gtk_tree_view_scroll_to_point (tree_view, -1, y);
9870   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
9871   _gtk_tree_view_queue_draw_node (tree_view, cursor_tree, cursor_node, NULL);
9872
9873   if (!gtk_tree_path_compare (old_cursor_path, cursor_path))
9874     gtk_widget_error_bell (GTK_WIDGET (tree_view));
9875
9876   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
9877
9878 cleanup:
9879   gtk_tree_path_free (old_cursor_path);
9880   gtk_tree_path_free (cursor_path);
9881 }
9882
9883 static void
9884 gtk_tree_view_move_cursor_left_right (GtkTreeView *tree_view,
9885                                       gint         count)
9886 {
9887   GtkRBTree *cursor_tree = NULL;
9888   GtkRBNode *cursor_node = NULL;
9889   GtkTreePath *cursor_path = NULL;
9890   GtkTreeViewColumn *column;
9891   GtkTreeIter iter;
9892   GList *list;
9893   gboolean found_column = FALSE;
9894   gboolean rtl;
9895
9896   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
9897
9898   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
9899     return;
9900
9901   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
9902     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
9903   else
9904     return;
9905
9906   _gtk_tree_view_find_node (tree_view, cursor_path, &cursor_tree, &cursor_node);
9907   if (cursor_tree == NULL)
9908     return;
9909   if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path) == FALSE)
9910     {
9911       gtk_tree_path_free (cursor_path);
9912       return;
9913     }
9914   gtk_tree_path_free (cursor_path);
9915
9916   list = rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns);
9917   if (tree_view->priv->focus_column)
9918     {
9919       for (; list; list = (rtl ? list->prev : list->next))
9920         {
9921           if (list->data == tree_view->priv->focus_column)
9922             break;
9923         }
9924     }
9925
9926   while (list)
9927     {
9928       gboolean left, right;
9929
9930       column = list->data;
9931       if (column->visible == FALSE)
9932         goto loop_end;
9933
9934       gtk_tree_view_column_cell_set_cell_data (column,
9935                                                tree_view->priv->model,
9936                                                &iter,
9937                                                GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_PARENT),
9938                                                cursor_node->children?TRUE:FALSE);
9939
9940       if (rtl)
9941         {
9942           right = list->prev ? TRUE : FALSE;
9943           left = list->next ? TRUE : FALSE;
9944         }
9945       else
9946         {
9947           left = list->prev ? TRUE : FALSE;
9948           right = list->next ? TRUE : FALSE;
9949         }
9950
9951       if (_gtk_tree_view_column_cell_focus (column, count, left, right))
9952         {
9953           tree_view->priv->focus_column = column;
9954           found_column = TRUE;
9955           break;
9956         }
9957     loop_end:
9958       if (count == 1)
9959         list = rtl ? list->prev : list->next;
9960       else
9961         list = rtl ? list->next : list->prev;
9962     }
9963
9964   if (found_column)
9965     {
9966       if (!gtk_tree_view_has_special_cell (tree_view))
9967         _gtk_tree_view_queue_draw_node (tree_view,
9968                                         cursor_tree,
9969                                         cursor_node,
9970                                         NULL);
9971       g_signal_emit (tree_view, tree_view_signals[CURSOR_CHANGED], 0);
9972       gtk_widget_grab_focus (GTK_WIDGET (tree_view));
9973     }
9974   else
9975     {
9976       gtk_widget_error_bell (GTK_WIDGET (tree_view));
9977     }
9978
9979   gtk_tree_view_clamp_column_visible (tree_view,
9980                                       tree_view->priv->focus_column, TRUE);
9981 }
9982
9983 static void
9984 gtk_tree_view_move_cursor_start_end (GtkTreeView *tree_view,
9985                                      gint         count)
9986 {
9987   GtkRBTree *cursor_tree;
9988   GtkRBNode *cursor_node;
9989   GtkTreePath *path;
9990   GtkTreePath *old_path;
9991
9992   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
9993     return;
9994
9995   g_return_if_fail (tree_view->priv->tree != NULL);
9996
9997   gtk_tree_view_get_cursor (tree_view, &old_path, NULL);
9998
9999   cursor_tree = tree_view->priv->tree;
10000   cursor_node = cursor_tree->root;
10001
10002   if (count == -1)
10003     {
10004       while (cursor_node && cursor_node->left != cursor_tree->nil)
10005         cursor_node = cursor_node->left;
10006
10007       /* Now go forward to find the first focusable row. */
10008       path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
10009       search_first_focusable_path (tree_view, &path,
10010                                    TRUE, &cursor_tree, &cursor_node);
10011     }
10012   else
10013     {
10014       do
10015         {
10016           while (cursor_node && cursor_node->right != cursor_tree->nil)
10017             cursor_node = cursor_node->right;
10018           if (cursor_node->children == NULL)
10019             break;
10020
10021           cursor_tree = cursor_node->children;
10022           cursor_node = cursor_tree->root;
10023         }
10024       while (1);
10025
10026       /* Now go backwards to find last focusable row. */
10027       path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
10028       search_first_focusable_path (tree_view, &path,
10029                                    FALSE, &cursor_tree, &cursor_node);
10030     }
10031
10032   if (!path)
10033     goto cleanup;
10034
10035   if (gtk_tree_path_compare (old_path, path))
10036     {
10037       gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
10038       gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10039     }
10040   else
10041     {
10042       gtk_widget_error_bell (GTK_WIDGET (tree_view));
10043     }
10044
10045 cleanup:
10046   gtk_tree_path_free (old_path);
10047   gtk_tree_path_free (path);
10048 }
10049
10050 static gboolean
10051 gtk_tree_view_real_select_all (GtkTreeView *tree_view)
10052 {
10053   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10054     return FALSE;
10055
10056   if (tree_view->priv->selection->type != GTK_SELECTION_MULTIPLE)
10057     return FALSE;
10058
10059   gtk_tree_selection_select_all (tree_view->priv->selection);
10060
10061   return TRUE;
10062 }
10063
10064 static gboolean
10065 gtk_tree_view_real_unselect_all (GtkTreeView *tree_view)
10066 {
10067   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10068     return FALSE;
10069
10070   if (tree_view->priv->selection->type != GTK_SELECTION_MULTIPLE)
10071     return FALSE;
10072
10073   gtk_tree_selection_unselect_all (tree_view->priv->selection);
10074
10075   return TRUE;
10076 }
10077
10078 static gboolean
10079 gtk_tree_view_real_select_cursor_row (GtkTreeView *tree_view,
10080                                       gboolean     start_editing)
10081 {
10082   GtkRBTree *new_tree = NULL;
10083   GtkRBNode *new_node = NULL;
10084   GtkRBTree *cursor_tree = NULL;
10085   GtkRBNode *cursor_node = NULL;
10086   GtkTreePath *cursor_path = NULL;
10087   GtkTreeSelectMode mode = 0;
10088
10089   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10090     return FALSE;
10091
10092   if (tree_view->priv->cursor)
10093     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10094
10095   if (cursor_path == NULL)
10096     return FALSE;
10097
10098   _gtk_tree_view_find_node (tree_view, cursor_path,
10099                             &cursor_tree, &cursor_node);
10100
10101   if (cursor_tree == NULL)
10102     {
10103       gtk_tree_path_free (cursor_path);
10104       return FALSE;
10105     }
10106
10107   if (!tree_view->priv->shift_pressed && start_editing &&
10108       tree_view->priv->focus_column)
10109     {
10110       if (gtk_tree_view_start_editing (tree_view, cursor_path))
10111         {
10112           gtk_tree_path_free (cursor_path);
10113           return TRUE;
10114         }
10115     }
10116
10117   if (tree_view->priv->ctrl_pressed)
10118     mode |= GTK_TREE_SELECT_MODE_TOGGLE;
10119   if (tree_view->priv->shift_pressed)
10120     mode |= GTK_TREE_SELECT_MODE_EXTEND;
10121
10122   _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
10123                                             cursor_node,
10124                                             cursor_tree,
10125                                             cursor_path,
10126                                             mode,
10127                                             FALSE);
10128
10129   /* We bail out if the original (tree, node) don't exist anymore after
10130    * handling the selection-changed callback.  We do return TRUE because
10131    * the key press has been handled at this point.
10132    */
10133   _gtk_tree_view_find_node (tree_view, cursor_path, &new_tree, &new_node);
10134
10135   if (cursor_tree != new_tree || cursor_node != new_node)
10136     return FALSE;
10137
10138   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10139
10140   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10141   _gtk_tree_view_queue_draw_node (tree_view, cursor_tree, cursor_node, NULL);
10142
10143   if (!tree_view->priv->shift_pressed)
10144     gtk_tree_view_row_activated (tree_view, cursor_path,
10145                                  tree_view->priv->focus_column);
10146     
10147   gtk_tree_path_free (cursor_path);
10148
10149   return TRUE;
10150 }
10151
10152 static gboolean
10153 gtk_tree_view_real_toggle_cursor_row (GtkTreeView *tree_view)
10154 {
10155   GtkRBTree *new_tree = NULL;
10156   GtkRBNode *new_node = NULL;
10157   GtkRBTree *cursor_tree = NULL;
10158   GtkRBNode *cursor_node = NULL;
10159   GtkTreePath *cursor_path = NULL;
10160
10161   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10162     return FALSE;
10163
10164   cursor_path = NULL;
10165   if (tree_view->priv->cursor)
10166     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10167
10168   if (cursor_path == NULL)
10169     return FALSE;
10170
10171   _gtk_tree_view_find_node (tree_view, cursor_path,
10172                             &cursor_tree, &cursor_node);
10173   if (cursor_tree == NULL)
10174     {
10175       gtk_tree_path_free (cursor_path);
10176       return FALSE;
10177     }
10178
10179   _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
10180                                             cursor_node,
10181                                             cursor_tree,
10182                                             cursor_path,
10183                                             GTK_TREE_SELECT_MODE_TOGGLE,
10184                                             FALSE);
10185
10186   /* We bail out if the original (tree, node) don't exist anymore after
10187    * handling the selection-changed callback.  We do return TRUE because
10188    * the key press has been handled at this point.
10189    */
10190   _gtk_tree_view_find_node (tree_view, cursor_path, &new_tree, &new_node);
10191
10192   if (cursor_tree != new_tree || cursor_node != new_node)
10193     return FALSE;
10194
10195   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10196
10197   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10198   gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10199   gtk_tree_path_free (cursor_path);
10200
10201   return TRUE;
10202 }
10203
10204 static gboolean
10205 gtk_tree_view_real_expand_collapse_cursor_row (GtkTreeView *tree_view,
10206                                                gboolean     logical,
10207                                                gboolean     expand,
10208                                                gboolean     open_all)
10209 {
10210   GtkTreePath *cursor_path = NULL;
10211   GtkRBTree *tree;
10212   GtkRBNode *node;
10213
10214   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10215     return FALSE;
10216
10217   cursor_path = NULL;
10218   if (tree_view->priv->cursor)
10219     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10220
10221   if (cursor_path == NULL)
10222     return FALSE;
10223
10224   if (_gtk_tree_view_find_node (tree_view, cursor_path, &tree, &node))
10225     return FALSE;
10226
10227   /* Don't handle the event if we aren't an expander */
10228   if (!((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT))
10229     return FALSE;
10230
10231   if (!logical
10232       && gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL)
10233     expand = !expand;
10234
10235   if (expand)
10236     gtk_tree_view_real_expand_row (tree_view, cursor_path, tree, node, open_all, TRUE);
10237   else
10238     gtk_tree_view_real_collapse_row (tree_view, cursor_path, tree, node, TRUE);
10239
10240   gtk_tree_path_free (cursor_path);
10241
10242   return TRUE;
10243 }
10244
10245 static gboolean
10246 gtk_tree_view_real_select_cursor_parent (GtkTreeView *tree_view)
10247 {
10248   GtkRBTree *cursor_tree = NULL;
10249   GtkRBNode *cursor_node = NULL;
10250   GtkTreePath *cursor_path = NULL;
10251   GdkModifierType state;
10252
10253   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10254     goto out;
10255
10256   cursor_path = NULL;
10257   if (tree_view->priv->cursor)
10258     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10259
10260   if (cursor_path == NULL)
10261     goto out;
10262
10263   _gtk_tree_view_find_node (tree_view, cursor_path,
10264                             &cursor_tree, &cursor_node);
10265   if (cursor_tree == NULL)
10266     {
10267       gtk_tree_path_free (cursor_path);
10268       goto out;
10269     }
10270
10271   if (cursor_tree->parent_node)
10272     {
10273       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10274       cursor_node = cursor_tree->parent_node;
10275       cursor_tree = cursor_tree->parent_tree;
10276
10277       gtk_tree_path_up (cursor_path);
10278
10279       if (gtk_get_current_event_state (&state))
10280         {
10281           if ((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
10282             tree_view->priv->ctrl_pressed = TRUE;
10283         }
10284
10285       gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE);
10286       gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10287
10288       gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10289       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10290       gtk_tree_path_free (cursor_path);
10291
10292       tree_view->priv->ctrl_pressed = FALSE;
10293
10294       return TRUE;
10295     }
10296
10297  out:
10298
10299   tree_view->priv->search_entry_avoid_unhandled_binding = TRUE;
10300   return FALSE;
10301 }
10302
10303 static gboolean
10304 gtk_tree_view_search_entry_flush_timeout (GtkTreeView *tree_view)
10305 {
10306   gtk_tree_view_search_dialog_hide (tree_view->priv->search_window, tree_view, NULL);
10307   tree_view->priv->typeselect_flush_timeout = 0;
10308
10309   return FALSE;
10310 }
10311
10312 /* Cut and paste from gtkwindow.c */
10313 static void
10314 send_focus_change (GtkWidget *widget,
10315                    GdkDevice *device,
10316                    gboolean   in)
10317 {
10318   GdkDeviceManager *device_manager;
10319   GList *devices, *d;
10320
10321   device_manager = gdk_display_get_device_manager (gtk_widget_get_display (widget));
10322   devices = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER);
10323   devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_SLAVE));
10324   devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_FLOATING));
10325
10326   for (d = devices; d; d = d->next)
10327     {
10328       GdkDevice *dev = d->data;
10329       GdkEvent *fevent;
10330
10331       if (dev->source != GDK_SOURCE_KEYBOARD)
10332         continue;
10333
10334       /* Skip non-master keyboards that haven't
10335        * selected for events from this window
10336        */
10337       if (gdk_device_get_device_type (dev) != GDK_DEVICE_TYPE_MASTER &&
10338           !gdk_window_get_device_events (widget->window, dev))
10339         continue;
10340
10341       fevent = gdk_event_new (GDK_FOCUS_CHANGE);
10342
10343       fevent->focus_change.type = GDK_FOCUS_CHANGE;
10344       fevent->focus_change.window = g_object_ref (widget->window);
10345       fevent->focus_change.in = in;
10346       gdk_event_set_device (fevent, device);
10347
10348       gtk_widget_send_focus_change (widget, fevent);
10349
10350       gdk_event_free (fevent);
10351     }
10352 }
10353
10354 static void
10355 gtk_tree_view_ensure_interactive_directory (GtkTreeView *tree_view)
10356 {
10357   GtkWidget *frame, *vbox, *toplevel;
10358   GdkScreen *screen;
10359
10360   if (tree_view->priv->search_custom_entry_set)
10361     return;
10362
10363   toplevel = gtk_widget_get_toplevel (GTK_WIDGET (tree_view));
10364   screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
10365
10366    if (tree_view->priv->search_window != NULL)
10367      {
10368        if (GTK_WINDOW (toplevel)->group)
10369          gtk_window_group_add_window (GTK_WINDOW (toplevel)->group,
10370                                       GTK_WINDOW (tree_view->priv->search_window));
10371        else if (GTK_WINDOW (tree_view->priv->search_window)->group)
10372          gtk_window_group_remove_window (GTK_WINDOW (tree_view->priv->search_window)->group,
10373                                          GTK_WINDOW (tree_view->priv->search_window));
10374        gtk_window_set_screen (GTK_WINDOW (tree_view->priv->search_window), screen);
10375        return;
10376      }
10377    
10378   tree_view->priv->search_window = gtk_window_new (GTK_WINDOW_POPUP);
10379   gtk_window_set_screen (GTK_WINDOW (tree_view->priv->search_window), screen);
10380
10381   if (GTK_WINDOW (toplevel)->group)
10382     gtk_window_group_add_window (GTK_WINDOW (toplevel)->group,
10383                                  GTK_WINDOW (tree_view->priv->search_window));
10384
10385   gtk_window_set_type_hint (GTK_WINDOW (tree_view->priv->search_window),
10386                             GDK_WINDOW_TYPE_HINT_UTILITY);
10387   gtk_window_set_modal (GTK_WINDOW (tree_view->priv->search_window), TRUE);
10388   g_signal_connect (tree_view->priv->search_window, "delete-event",
10389                     G_CALLBACK (gtk_tree_view_search_delete_event),
10390                     tree_view);
10391   g_signal_connect (tree_view->priv->search_window, "key-press-event",
10392                     G_CALLBACK (gtk_tree_view_search_key_press_event),
10393                     tree_view);
10394   g_signal_connect (tree_view->priv->search_window, "button-press-event",
10395                     G_CALLBACK (gtk_tree_view_search_button_press_event),
10396                     tree_view);
10397   g_signal_connect (tree_view->priv->search_window, "scroll-event",
10398                     G_CALLBACK (gtk_tree_view_search_scroll_event),
10399                     tree_view);
10400
10401   frame = gtk_frame_new (NULL);
10402   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
10403   gtk_widget_show (frame);
10404   gtk_container_add (GTK_CONTAINER (tree_view->priv->search_window), frame);
10405
10406   vbox = gtk_vbox_new (FALSE, 0);
10407   gtk_widget_show (vbox);
10408   gtk_container_add (GTK_CONTAINER (frame), vbox);
10409   gtk_container_set_border_width (GTK_CONTAINER (vbox), 3);
10410
10411   /* add entry */
10412   tree_view->priv->search_entry = gtk_entry_new ();
10413   gtk_widget_show (tree_view->priv->search_entry);
10414   g_signal_connect (tree_view->priv->search_entry, "populate-popup",
10415                     G_CALLBACK (gtk_tree_view_search_disable_popdown),
10416                     tree_view);
10417   g_signal_connect (tree_view->priv->search_entry,
10418                     "activate", G_CALLBACK (gtk_tree_view_search_activate),
10419                     tree_view);
10420   g_signal_connect (GTK_ENTRY (tree_view->priv->search_entry)->im_context,
10421                     "preedit-changed",
10422                     G_CALLBACK (gtk_tree_view_search_preedit_changed),
10423                     tree_view);
10424   gtk_container_add (GTK_CONTAINER (vbox),
10425                      tree_view->priv->search_entry);
10426
10427   gtk_widget_realize (tree_view->priv->search_entry);
10428 }
10429
10430 /* Pops up the interactive search entry.  If keybinding is TRUE then the user
10431  * started this by typing the start_interactive_search keybinding.  Otherwise, it came from 
10432  */
10433 static gboolean
10434 gtk_tree_view_real_start_interactive_search (GtkTreeView *tree_view,
10435                                              GdkDevice   *device,
10436                                              gboolean     keybinding)
10437 {
10438   /* We only start interactive search if we have focus or the columns
10439    * have focus.  If one of our children have focus, we don't want to
10440    * start the search.
10441    */
10442   GList *list;
10443   gboolean found_focus = FALSE;
10444   GtkWidgetClass *entry_parent_class;
10445   
10446   if (!tree_view->priv->enable_search && !keybinding)
10447     return FALSE;
10448
10449   if (tree_view->priv->search_custom_entry_set)
10450     return FALSE;
10451
10452   if (tree_view->priv->search_window != NULL &&
10453       gtk_widget_get_visible (tree_view->priv->search_window))
10454     return TRUE;
10455
10456   for (list = tree_view->priv->columns; list; list = list->next)
10457     {
10458       GtkTreeViewColumn *column;
10459
10460       column = list->data;
10461       if (! column->visible)
10462         continue;
10463
10464       if (gtk_widget_has_focus (column->button))
10465         {
10466           found_focus = TRUE;
10467           break;
10468         }
10469     }
10470   
10471   if (gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10472     found_focus = TRUE;
10473
10474   if (!found_focus)
10475     return FALSE;
10476
10477   if (tree_view->priv->search_column < 0)
10478     return FALSE;
10479
10480   gtk_tree_view_ensure_interactive_directory (tree_view);
10481
10482   if (keybinding)
10483     gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
10484
10485   /* done, show it */
10486   tree_view->priv->search_position_func (tree_view, tree_view->priv->search_window, tree_view->priv->search_position_user_data);
10487   gtk_widget_show (tree_view->priv->search_window);
10488   if (tree_view->priv->search_entry_changed_id == 0)
10489     {
10490       tree_view->priv->search_entry_changed_id =
10491         g_signal_connect (tree_view->priv->search_entry, "changed",
10492                           G_CALLBACK (gtk_tree_view_search_init),
10493                           tree_view);
10494     }
10495
10496   tree_view->priv->typeselect_flush_timeout =
10497     gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
10498                    (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
10499                    tree_view);
10500
10501   /* Grab focus will select all the text.  We don't want that to happen, so we
10502    * call the parent instance and bypass the selection change.  This is probably
10503    * really non-kosher. */
10504   entry_parent_class = g_type_class_peek_parent (GTK_ENTRY_GET_CLASS (tree_view->priv->search_entry));
10505   (entry_parent_class->grab_focus) (tree_view->priv->search_entry);
10506
10507   /* send focus-in event */
10508   send_focus_change (tree_view->priv->search_entry, device, TRUE);
10509
10510   /* search first matching iter */
10511   gtk_tree_view_search_init (tree_view->priv->search_entry, tree_view);
10512
10513   return TRUE;
10514 }
10515
10516 static gboolean
10517 gtk_tree_view_start_interactive_search (GtkTreeView *tree_view)
10518 {
10519   return gtk_tree_view_real_start_interactive_search (tree_view,
10520                                                       gtk_get_current_event_device (),
10521                                                       TRUE);
10522 }
10523
10524 /* this function returns the new width of the column being resized given
10525  * the column and x position of the cursor; the x cursor position is passed
10526  * in as a pointer and automagicly corrected if it's beyond min/max limits
10527  */
10528 static gint
10529 gtk_tree_view_new_column_width (GtkTreeView *tree_view,
10530                                 gint       i,
10531                                 gint      *x)
10532 {
10533   GtkTreeViewColumn *column;
10534   gint width;
10535   gboolean rtl;
10536
10537   /* first translate the x position from widget->window
10538    * to clist->clist_window
10539    */
10540   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
10541   column = g_list_nth (tree_view->priv->columns, i)->data;
10542   width = rtl ? (column->button->allocation.x + column->button->allocation.width - *x) : (*x - column->button->allocation.x);
10543  
10544   /* Clamp down the value */
10545   if (column->min_width == -1)
10546     width = MAX (column->button->requisition.width,
10547                  width);
10548   else
10549     width = MAX (column->min_width,
10550                  width);
10551   if (column->max_width != -1)
10552     width = MIN (width, column->max_width);
10553
10554   *x = rtl ? (column->button->allocation.x + column->button->allocation.width - width) : (column->button->allocation.x + width);
10555  
10556   return width;
10557 }
10558
10559
10560 /* FIXME this adjust_allocation is a big cut-and-paste from
10561  * GtkCList, needs to be some "official" way to do this
10562  * factored out.
10563  */
10564 typedef struct
10565 {
10566   GdkWindow *window;
10567   int dx;
10568   int dy;
10569 } ScrollData;
10570
10571 /* The window to which widget->window is relative */
10572 #define ALLOCATION_WINDOW(widget)               \
10573    (!gtk_widget_get_has_window (widget) ?               \
10574     (widget)->window :                          \
10575      gdk_window_get_parent ((widget)->window))
10576
10577 static void
10578 adjust_allocation_recurse (GtkWidget *widget,
10579                            gpointer   data)
10580 {
10581   ScrollData *scroll_data = data;
10582
10583   /* Need to really size allocate instead of just poking
10584    * into widget->allocation if the widget is not realized.
10585    * FIXME someone figure out why this was.
10586    */
10587   if (!gtk_widget_get_realized (widget))
10588     {
10589       if (gtk_widget_get_visible (widget))
10590         {
10591           GdkRectangle tmp_rectangle = widget->allocation;
10592           tmp_rectangle.x += scroll_data->dx;
10593           tmp_rectangle.y += scroll_data->dy;
10594           
10595           gtk_widget_size_allocate (widget, &tmp_rectangle);
10596         }
10597     }
10598   else
10599     {
10600       if (ALLOCATION_WINDOW (widget) == scroll_data->window)
10601         {
10602           widget->allocation.x += scroll_data->dx;
10603           widget->allocation.y += scroll_data->dy;
10604           
10605           if (GTK_IS_CONTAINER (widget))
10606             gtk_container_forall (GTK_CONTAINER (widget),
10607                                   adjust_allocation_recurse,
10608                                   data);
10609         }
10610     }
10611 }
10612
10613 static void
10614 adjust_allocation (GtkWidget *widget,
10615                    int        dx,
10616                    int        dy)
10617 {
10618   ScrollData scroll_data;
10619
10620   if (gtk_widget_get_realized (widget))
10621     scroll_data.window = ALLOCATION_WINDOW (widget);
10622   else
10623     scroll_data.window = NULL;
10624     
10625   scroll_data.dx = dx;
10626   scroll_data.dy = dy;
10627   
10628   adjust_allocation_recurse (widget, &scroll_data);
10629 }
10630
10631 /* Callbacks */
10632 static void
10633 gtk_tree_view_adjustment_changed (GtkAdjustment *adjustment,
10634                                   GtkTreeView   *tree_view)
10635 {
10636   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
10637     {
10638       gint dy;
10639         
10640       gdk_window_move (tree_view->priv->bin_window,
10641                        - tree_view->priv->hadjustment->value,
10642                        TREE_VIEW_HEADER_HEIGHT (tree_view));
10643       gdk_window_move (tree_view->priv->header_window,
10644                        - tree_view->priv->hadjustment->value,
10645                        0);
10646       dy = tree_view->priv->dy - (int) tree_view->priv->vadjustment->value;
10647       if (dy)
10648         {
10649           update_prelight (tree_view,
10650                            tree_view->priv->event_last_x,
10651                            tree_view->priv->event_last_y - dy);
10652
10653           if (tree_view->priv->edited_column &&
10654               GTK_IS_WIDGET (tree_view->priv->edited_column->editable_widget))
10655             {
10656               GList *list;
10657               GtkWidget *widget;
10658               GtkTreeViewChild *child = NULL;
10659
10660               widget = GTK_WIDGET (tree_view->priv->edited_column->editable_widget);
10661               adjust_allocation (widget, 0, dy); 
10662               
10663               for (list = tree_view->priv->children; list; list = list->next)
10664                 {
10665                   child = (GtkTreeViewChild *)list->data;
10666                   if (child->widget == widget)
10667                     {
10668                       child->y += dy;
10669                       break;
10670                     }
10671                 }
10672             }
10673         }
10674       gdk_window_scroll (tree_view->priv->bin_window, 0, dy);
10675
10676       if (tree_view->priv->dy != (int) tree_view->priv->vadjustment->value)
10677         {
10678           /* update our dy and top_row */
10679           tree_view->priv->dy = (int) tree_view->priv->vadjustment->value;
10680
10681           if (!tree_view->priv->in_top_row_to_dy)
10682             gtk_tree_view_dy_to_top_row (tree_view);
10683         }
10684
10685       gdk_window_process_updates (tree_view->priv->header_window, TRUE);
10686       gdk_window_process_updates (tree_view->priv->bin_window, TRUE);
10687     }
10688 }
10689
10690 \f
10691
10692 /* Public methods
10693  */
10694
10695 /**
10696  * gtk_tree_view_new:
10697  *
10698  * Creates a new #GtkTreeView widget.
10699  *
10700  * Return value: A newly created #GtkTreeView widget.
10701  **/
10702 GtkWidget *
10703 gtk_tree_view_new (void)
10704 {
10705   return g_object_new (GTK_TYPE_TREE_VIEW, NULL);
10706 }
10707
10708 /**
10709  * gtk_tree_view_new_with_model:
10710  * @model: the model.
10711  *
10712  * Creates a new #GtkTreeView widget with the model initialized to @model.
10713  *
10714  * Return value: A newly created #GtkTreeView widget.
10715  **/
10716 GtkWidget *
10717 gtk_tree_view_new_with_model (GtkTreeModel *model)
10718 {
10719   return g_object_new (GTK_TYPE_TREE_VIEW, "model", model, NULL);
10720 }
10721
10722 /* Public Accessors
10723  */
10724
10725 /**
10726  * gtk_tree_view_get_model:
10727  * @tree_view: a #GtkTreeView
10728  *
10729  * Returns the model the #GtkTreeView is based on.  Returns %NULL if the
10730  * model is unset.
10731  *
10732  * Return value: (transfer none): A #GtkTreeModel, or %NULL if none is currently being used.
10733  **/
10734 GtkTreeModel *
10735 gtk_tree_view_get_model (GtkTreeView *tree_view)
10736 {
10737   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
10738
10739   return tree_view->priv->model;
10740 }
10741
10742 /**
10743  * gtk_tree_view_set_model:
10744  * @tree_view: A #GtkTreeNode.
10745  * @model: (allow-none): The model.
10746  *
10747  * Sets the model for a #GtkTreeView.  If the @tree_view already has a model
10748  * set, it will remove it before setting the new model.  If @model is %NULL,
10749  * then it will unset the old model.
10750  **/
10751 void
10752 gtk_tree_view_set_model (GtkTreeView  *tree_view,
10753                          GtkTreeModel *model)
10754 {
10755   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
10756   g_return_if_fail (model == NULL || GTK_IS_TREE_MODEL (model));
10757
10758   if (model == tree_view->priv->model)
10759     return;
10760
10761   if (tree_view->priv->scroll_to_path)
10762     {
10763       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
10764       tree_view->priv->scroll_to_path = NULL;
10765     }
10766
10767   if (tree_view->priv->model)
10768     {
10769       GList *tmplist = tree_view->priv->columns;
10770
10771       gtk_tree_view_unref_and_check_selection_tree (tree_view, tree_view->priv->tree);
10772       gtk_tree_view_stop_editing (tree_view, TRUE);
10773
10774       remove_expand_collapse_timeout (tree_view);
10775
10776       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
10777                                             gtk_tree_view_row_changed,
10778                                             tree_view);
10779       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
10780                                             gtk_tree_view_row_inserted,
10781                                             tree_view);
10782       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
10783                                             gtk_tree_view_row_has_child_toggled,
10784                                             tree_view);
10785       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
10786                                             gtk_tree_view_row_deleted,
10787                                             tree_view);
10788       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
10789                                             gtk_tree_view_rows_reordered,
10790                                             tree_view);
10791
10792       for (; tmplist; tmplist = tmplist->next)
10793         _gtk_tree_view_column_unset_model (tmplist->data,
10794                                            tree_view->priv->model);
10795
10796       if (tree_view->priv->tree)
10797         gtk_tree_view_free_rbtree (tree_view);
10798
10799       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
10800       tree_view->priv->drag_dest_row = NULL;
10801       gtk_tree_row_reference_free (tree_view->priv->cursor);
10802       tree_view->priv->cursor = NULL;
10803       gtk_tree_row_reference_free (tree_view->priv->anchor);
10804       tree_view->priv->anchor = NULL;
10805       gtk_tree_row_reference_free (tree_view->priv->top_row);
10806       tree_view->priv->top_row = NULL;
10807       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
10808       tree_view->priv->scroll_to_path = NULL;
10809
10810       tree_view->priv->scroll_to_column = NULL;
10811
10812       g_object_unref (tree_view->priv->model);
10813
10814       tree_view->priv->search_column = -1;
10815       tree_view->priv->fixed_height_check = 0;
10816       tree_view->priv->fixed_height = -1;
10817       tree_view->priv->dy = tree_view->priv->top_row_dy = 0;
10818       tree_view->priv->last_button_x = -1;
10819       tree_view->priv->last_button_y = -1;
10820     }
10821
10822   tree_view->priv->model = model;
10823
10824   if (tree_view->priv->model)
10825     {
10826       gint i;
10827       GtkTreePath *path;
10828       GtkTreeIter iter;
10829       GtkTreeModelFlags flags;
10830
10831       if (tree_view->priv->search_column == -1)
10832         {
10833           for (i = 0; i < gtk_tree_model_get_n_columns (model); i++)
10834             {
10835               GType type = gtk_tree_model_get_column_type (model, i);
10836
10837               if (g_value_type_transformable (type, G_TYPE_STRING))
10838                 {
10839                   tree_view->priv->search_column = i;
10840                   break;
10841                 }
10842             }
10843         }
10844
10845       g_object_ref (tree_view->priv->model);
10846       g_signal_connect (tree_view->priv->model,
10847                         "row-changed",
10848                         G_CALLBACK (gtk_tree_view_row_changed),
10849                         tree_view);
10850       g_signal_connect (tree_view->priv->model,
10851                         "row-inserted",
10852                         G_CALLBACK (gtk_tree_view_row_inserted),
10853                         tree_view);
10854       g_signal_connect (tree_view->priv->model,
10855                         "row-has-child-toggled",
10856                         G_CALLBACK (gtk_tree_view_row_has_child_toggled),
10857                         tree_view);
10858       g_signal_connect (tree_view->priv->model,
10859                         "row-deleted",
10860                         G_CALLBACK (gtk_tree_view_row_deleted),
10861                         tree_view);
10862       g_signal_connect (tree_view->priv->model,
10863                         "rows-reordered",
10864                         G_CALLBACK (gtk_tree_view_rows_reordered),
10865                         tree_view);
10866
10867       flags = gtk_tree_model_get_flags (tree_view->priv->model);
10868       if ((flags & GTK_TREE_MODEL_LIST_ONLY) == GTK_TREE_MODEL_LIST_ONLY)
10869         GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_IS_LIST);
10870       else
10871         GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IS_LIST);
10872
10873       path = gtk_tree_path_new_first ();
10874       if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, path))
10875         {
10876           tree_view->priv->tree = _gtk_rbtree_new ();
10877           gtk_tree_view_build_tree (tree_view, tree_view->priv->tree, &iter, 1, FALSE);
10878         }
10879       gtk_tree_path_free (path);
10880
10881       /*  FIXME: do I need to do this? gtk_tree_view_create_buttons (tree_view); */
10882       install_presize_handler (tree_view);
10883     }
10884
10885   g_object_notify (G_OBJECT (tree_view), "model");
10886
10887   if (tree_view->priv->selection)
10888   _gtk_tree_selection_emit_changed (tree_view->priv->selection);
10889
10890   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
10891     gtk_widget_queue_resize (GTK_WIDGET (tree_view));
10892 }
10893
10894 /**
10895  * gtk_tree_view_get_selection:
10896  * @tree_view: A #GtkTreeView.
10897  *
10898  * Gets the #GtkTreeSelection associated with @tree_view.
10899  *
10900  * Return value: (transfer none): A #GtkTreeSelection object.
10901  **/
10902 GtkTreeSelection *
10903 gtk_tree_view_get_selection (GtkTreeView *tree_view)
10904 {
10905   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
10906
10907   return tree_view->priv->selection;
10908 }
10909
10910 /**
10911  * gtk_tree_view_get_hadjustment:
10912  * @tree_view: A #GtkTreeView
10913  *
10914  * Gets the #GtkAdjustment currently being used for the horizontal aspect.
10915  *
10916  * Return value: A #GtkAdjustment object, or %NULL if none is currently being
10917  * used.
10918  **/
10919 GtkAdjustment *
10920 gtk_tree_view_get_hadjustment (GtkTreeView *tree_view)
10921 {
10922   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
10923
10924   if (tree_view->priv->hadjustment == NULL)
10925     gtk_tree_view_set_hadjustment (tree_view, NULL);
10926
10927   return tree_view->priv->hadjustment;
10928 }
10929
10930 /**
10931  * gtk_tree_view_set_hadjustment:
10932  * @tree_view: A #GtkTreeView
10933  * @adjustment: (allow-none): The #GtkAdjustment to set, or %NULL
10934  *
10935  * Sets the #GtkAdjustment for the current horizontal aspect.
10936  **/
10937 void
10938 gtk_tree_view_set_hadjustment (GtkTreeView   *tree_view,
10939                                GtkAdjustment *adjustment)
10940 {
10941   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
10942
10943   gtk_tree_view_set_adjustments (tree_view,
10944                                  adjustment,
10945                                  tree_view->priv->vadjustment);
10946
10947   g_object_notify (G_OBJECT (tree_view), "hadjustment");
10948 }
10949
10950 /**
10951  * gtk_tree_view_get_vadjustment:
10952  * @tree_view: A #GtkTreeView
10953  *
10954  * Gets the #GtkAdjustment currently being used for the vertical aspect.
10955  *
10956  * Return value: A #GtkAdjustment object, or %NULL if none is currently being
10957  * used.
10958  **/
10959 GtkAdjustment *
10960 gtk_tree_view_get_vadjustment (GtkTreeView *tree_view)
10961 {
10962   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
10963
10964   if (tree_view->priv->vadjustment == NULL)
10965     gtk_tree_view_set_vadjustment (tree_view, NULL);
10966
10967   return tree_view->priv->vadjustment;
10968 }
10969
10970 /**
10971  * gtk_tree_view_set_vadjustment:
10972  * @tree_view: A #GtkTreeView
10973  * @adjustment: (allow-none): The #GtkAdjustment to set, or %NULL
10974  *
10975  * Sets the #GtkAdjustment for the current vertical aspect.
10976  **/
10977 void
10978 gtk_tree_view_set_vadjustment (GtkTreeView   *tree_view,
10979                                GtkAdjustment *adjustment)
10980 {
10981   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
10982
10983   gtk_tree_view_set_adjustments (tree_view,
10984                                  tree_view->priv->hadjustment,
10985                                  adjustment);
10986
10987   g_object_notify (G_OBJECT (tree_view), "vadjustment");
10988 }
10989
10990 /* Column and header operations */
10991
10992 /**
10993  * gtk_tree_view_get_headers_visible:
10994  * @tree_view: A #GtkTreeView.
10995  *
10996  * Returns %TRUE if the headers on the @tree_view are visible.
10997  *
10998  * Return value: Whether the headers are visible or not.
10999  **/
11000 gboolean
11001 gtk_tree_view_get_headers_visible (GtkTreeView *tree_view)
11002 {
11003   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
11004
11005   return GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE);
11006 }
11007
11008 /**
11009  * gtk_tree_view_set_headers_visible:
11010  * @tree_view: A #GtkTreeView.
11011  * @headers_visible: %TRUE if the headers are visible
11012  *
11013  * Sets the visibility state of the headers.
11014  **/
11015 void
11016 gtk_tree_view_set_headers_visible (GtkTreeView *tree_view,
11017                                    gboolean     headers_visible)
11018 {
11019   gint x, y;
11020   GList *list;
11021   GtkTreeViewColumn *column;
11022
11023   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11024
11025   headers_visible = !! headers_visible;
11026
11027   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE) == headers_visible)
11028     return;
11029
11030   if (headers_visible)
11031     GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE);
11032   else
11033     GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE);
11034
11035   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11036     {
11037       gdk_window_get_position (tree_view->priv->bin_window, &x, &y);
11038       if (headers_visible)
11039         {
11040           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));
11041
11042           if (gtk_widget_get_mapped (GTK_WIDGET (tree_view)))
11043             gtk_tree_view_map_buttons (tree_view);
11044         }
11045       else
11046         {
11047           gdk_window_move_resize (tree_view->priv->bin_window, x, y, tree_view->priv->width, tree_view->priv->height);
11048
11049           for (list = tree_view->priv->columns; list; list = list->next)
11050             {
11051               column = list->data;
11052               gtk_widget_unmap (column->button);
11053             }
11054           gdk_window_hide (tree_view->priv->header_window);
11055         }
11056     }
11057
11058   tree_view->priv->vadjustment->page_size = GTK_WIDGET (tree_view)->allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view);
11059   tree_view->priv->vadjustment->page_increment = (GTK_WIDGET (tree_view)->allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view)) / 2;
11060   tree_view->priv->vadjustment->lower = 0;
11061   tree_view->priv->vadjustment->upper = tree_view->priv->height;
11062   gtk_adjustment_changed (tree_view->priv->vadjustment);
11063
11064   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11065
11066   g_object_notify (G_OBJECT (tree_view), "headers-visible");
11067 }
11068
11069 /**
11070  * gtk_tree_view_columns_autosize:
11071  * @tree_view: A #GtkTreeView.
11072  *
11073  * Resizes all columns to their optimal width. Only works after the
11074  * treeview has been realized.
11075  **/
11076 void
11077 gtk_tree_view_columns_autosize (GtkTreeView *tree_view)
11078 {
11079   gboolean dirty = FALSE;
11080   GList *list;
11081   GtkTreeViewColumn *column;
11082
11083   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11084
11085   for (list = tree_view->priv->columns; list; list = list->next)
11086     {
11087       column = list->data;
11088       if (column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
11089         continue;
11090       _gtk_tree_view_column_cell_set_dirty (column, TRUE);
11091       dirty = TRUE;
11092     }
11093
11094   if (dirty)
11095     gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11096 }
11097
11098 /**
11099  * gtk_tree_view_set_headers_clickable:
11100  * @tree_view: A #GtkTreeView.
11101  * @setting: %TRUE if the columns are clickable.
11102  *
11103  * Allow the column title buttons to be clicked.
11104  **/
11105 void
11106 gtk_tree_view_set_headers_clickable (GtkTreeView *tree_view,
11107                                      gboolean   setting)
11108 {
11109   GList *list;
11110
11111   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11112
11113   for (list = tree_view->priv->columns; list; list = list->next)
11114     gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (list->data), setting);
11115
11116   g_object_notify (G_OBJECT (tree_view), "headers-clickable");
11117 }
11118
11119
11120 /**
11121  * gtk_tree_view_get_headers_clickable:
11122  * @tree_view: A #GtkTreeView.
11123  *
11124  * Returns whether all header columns are clickable.
11125  *
11126  * Return value: %TRUE if all header columns are clickable, otherwise %FALSE
11127  *
11128  * Since: 2.10
11129  **/
11130 gboolean 
11131 gtk_tree_view_get_headers_clickable (GtkTreeView *tree_view)
11132 {
11133   GList *list;
11134   
11135   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
11136
11137   for (list = tree_view->priv->columns; list; list = list->next)
11138     if (!GTK_TREE_VIEW_COLUMN (list->data)->clickable)
11139       return FALSE;
11140
11141   return TRUE;
11142 }
11143
11144 /**
11145  * gtk_tree_view_set_rules_hint
11146  * @tree_view: a #GtkTreeView
11147  * @setting: %TRUE if the tree requires reading across rows
11148  *
11149  * This function tells GTK+ that the user interface for your
11150  * application requires users to read across tree rows and associate
11151  * cells with one another. By default, GTK+ will then render the tree
11152  * with alternating row colors. Do <emphasis>not</emphasis> use it
11153  * just because you prefer the appearance of the ruled tree; that's a
11154  * question for the theme. Some themes will draw tree rows in
11155  * alternating colors even when rules are turned off, and users who
11156  * prefer that appearance all the time can choose those themes. You
11157  * should call this function only as a <emphasis>semantic</emphasis>
11158  * hint to the theme engine that your tree makes alternating colors
11159  * useful from a functional standpoint (since it has lots of columns,
11160  * generally).
11161  *
11162  **/
11163 void
11164 gtk_tree_view_set_rules_hint (GtkTreeView  *tree_view,
11165                               gboolean      setting)
11166 {
11167   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11168
11169   setting = setting != FALSE;
11170
11171   if (tree_view->priv->has_rules != setting)
11172     {
11173       tree_view->priv->has_rules = setting;
11174       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
11175     }
11176
11177   g_object_notify (G_OBJECT (tree_view), "rules-hint");
11178 }
11179
11180 /**
11181  * gtk_tree_view_get_rules_hint
11182  * @tree_view: a #GtkTreeView
11183  *
11184  * Gets the setting set by gtk_tree_view_set_rules_hint().
11185  *
11186  * Return value: %TRUE if rules are useful for the user of this tree
11187  **/
11188 gboolean
11189 gtk_tree_view_get_rules_hint (GtkTreeView  *tree_view)
11190 {
11191   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
11192
11193   return tree_view->priv->has_rules;
11194 }
11195
11196 /* Public Column functions
11197  */
11198
11199 /**
11200  * gtk_tree_view_append_column:
11201  * @tree_view: A #GtkTreeView.
11202  * @column: The #GtkTreeViewColumn to add.
11203  *
11204  * Appends @column to the list of columns. If @tree_view has "fixed_height"
11205  * mode enabled, then @column must have its "sizing" property set to be
11206  * GTK_TREE_VIEW_COLUMN_FIXED.
11207  *
11208  * Return value: The number of columns in @tree_view after appending.
11209  **/
11210 gint
11211 gtk_tree_view_append_column (GtkTreeView       *tree_view,
11212                              GtkTreeViewColumn *column)
11213 {
11214   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11215   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
11216   g_return_val_if_fail (column->tree_view == NULL, -1);
11217
11218   return gtk_tree_view_insert_column (tree_view, column, -1);
11219 }
11220
11221
11222 /**
11223  * gtk_tree_view_remove_column:
11224  * @tree_view: A #GtkTreeView.
11225  * @column: The #GtkTreeViewColumn to remove.
11226  *
11227  * Removes @column from @tree_view.
11228  *
11229  * Return value: The number of columns in @tree_view after removing.
11230  **/
11231 gint
11232 gtk_tree_view_remove_column (GtkTreeView       *tree_view,
11233                              GtkTreeViewColumn *column)
11234 {
11235   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11236   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
11237   g_return_val_if_fail (column->tree_view == GTK_WIDGET (tree_view), -1);
11238
11239   if (tree_view->priv->focus_column == column)
11240     tree_view->priv->focus_column = NULL;
11241
11242   if (tree_view->priv->edited_column == column)
11243     {
11244       gtk_tree_view_stop_editing (tree_view, TRUE);
11245
11246       /* no need to, but just to be sure ... */
11247       tree_view->priv->edited_column = NULL;
11248     }
11249
11250   if (tree_view->priv->expander_column == column)
11251     tree_view->priv->expander_column = NULL;
11252
11253   g_signal_handlers_disconnect_by_func (column,
11254                                         G_CALLBACK (column_sizing_notify),
11255                                         tree_view);
11256
11257   _gtk_tree_view_column_unset_tree_view (column);
11258
11259   tree_view->priv->columns = g_list_remove (tree_view->priv->columns, column);
11260   tree_view->priv->n_columns--;
11261
11262   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11263     {
11264       GList *list;
11265
11266       _gtk_tree_view_column_unrealize_button (column);
11267       for (list = tree_view->priv->columns; list; list = list->next)
11268         {
11269           GtkTreeViewColumn *tmp_column;
11270
11271           tmp_column = GTK_TREE_VIEW_COLUMN (list->data);
11272           if (tmp_column->visible)
11273             _gtk_tree_view_column_cell_set_dirty (tmp_column, TRUE);
11274         }
11275
11276       if (tree_view->priv->n_columns == 0 &&
11277           gtk_tree_view_get_headers_visible (tree_view))
11278         gdk_window_hide (tree_view->priv->header_window);
11279
11280       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11281     }
11282
11283   g_object_unref (column);
11284   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
11285
11286   return tree_view->priv->n_columns;
11287 }
11288
11289 /**
11290  * gtk_tree_view_insert_column:
11291  * @tree_view: A #GtkTreeView.
11292  * @column: The #GtkTreeViewColumn to be inserted.
11293  * @position: The position to insert @column in.
11294  *
11295  * This inserts the @column into the @tree_view at @position.  If @position is
11296  * -1, then the column is inserted at the end. If @tree_view has
11297  * "fixed_height" mode enabled, then @column must have its "sizing" property
11298  * set to be GTK_TREE_VIEW_COLUMN_FIXED.
11299  *
11300  * Return value: The number of columns in @tree_view after insertion.
11301  **/
11302 gint
11303 gtk_tree_view_insert_column (GtkTreeView       *tree_view,
11304                              GtkTreeViewColumn *column,
11305                              gint               position)
11306 {
11307   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11308   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
11309   g_return_val_if_fail (column->tree_view == NULL, -1);
11310
11311   if (tree_view->priv->fixed_height_mode)
11312     g_return_val_if_fail (gtk_tree_view_column_get_sizing (column)
11313                           == GTK_TREE_VIEW_COLUMN_FIXED, -1);
11314
11315   g_object_ref_sink (column);
11316
11317   if (tree_view->priv->n_columns == 0 &&
11318       gtk_widget_get_realized (GTK_WIDGET (tree_view)) &&
11319       gtk_tree_view_get_headers_visible (tree_view))
11320     {
11321       gdk_window_show (tree_view->priv->header_window);
11322     }
11323
11324   g_signal_connect (column, "notify::sizing",
11325                     G_CALLBACK (column_sizing_notify), tree_view);
11326
11327   tree_view->priv->columns = g_list_insert (tree_view->priv->columns,
11328                                             column, position);
11329   tree_view->priv->n_columns++;
11330
11331   _gtk_tree_view_column_set_tree_view (column, tree_view);
11332
11333   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11334     {
11335       GList *list;
11336
11337       _gtk_tree_view_column_realize_button (column);
11338
11339       for (list = tree_view->priv->columns; list; list = list->next)
11340         {
11341           column = GTK_TREE_VIEW_COLUMN (list->data);
11342           if (column->visible)
11343             _gtk_tree_view_column_cell_set_dirty (column, TRUE);
11344         }
11345       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11346     }
11347
11348   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
11349
11350   return tree_view->priv->n_columns;
11351 }
11352
11353 /**
11354  * gtk_tree_view_insert_column_with_attributes:
11355  * @tree_view: A #GtkTreeView
11356  * @position: The position to insert the new column in.
11357  * @title: The title to set the header to.
11358  * @cell: The #GtkCellRenderer.
11359  * @Varargs: A %NULL-terminated list of attributes.
11360  *
11361  * Creates a new #GtkTreeViewColumn and inserts it into the @tree_view at
11362  * @position.  If @position is -1, then the newly created column is inserted at
11363  * the end.  The column is initialized with the attributes given. If @tree_view
11364  * has "fixed_height" mode enabled, then the new column will have its sizing
11365  * property set to be GTK_TREE_VIEW_COLUMN_FIXED.
11366  *
11367  * Return value: The number of columns in @tree_view after insertion.
11368  **/
11369 gint
11370 gtk_tree_view_insert_column_with_attributes (GtkTreeView     *tree_view,
11371                                              gint             position,
11372                                              const gchar     *title,
11373                                              GtkCellRenderer *cell,
11374                                              ...)
11375 {
11376   GtkTreeViewColumn *column;
11377   gchar *attribute;
11378   va_list args;
11379   gint column_id;
11380
11381   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11382
11383   column = gtk_tree_view_column_new ();
11384   if (tree_view->priv->fixed_height_mode)
11385     gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
11386
11387   gtk_tree_view_column_set_title (column, title);
11388   gtk_tree_view_column_pack_start (column, cell, TRUE);
11389
11390   va_start (args, cell);
11391
11392   attribute = va_arg (args, gchar *);
11393
11394   while (attribute != NULL)
11395     {
11396       column_id = va_arg (args, gint);
11397       gtk_tree_view_column_add_attribute (column, cell, attribute, column_id);
11398       attribute = va_arg (args, gchar *);
11399     }
11400
11401   va_end (args);
11402
11403   gtk_tree_view_insert_column (tree_view, column, position);
11404
11405   return tree_view->priv->n_columns;
11406 }
11407
11408 /**
11409  * gtk_tree_view_insert_column_with_data_func:
11410  * @tree_view: a #GtkTreeView
11411  * @position: Position to insert, -1 for append
11412  * @title: column title
11413  * @cell: cell renderer for column
11414  * @func: function to set attributes of cell renderer
11415  * @data: data for @func
11416  * @dnotify: destroy notifier for @data
11417  *
11418  * Convenience function that inserts a new column into the #GtkTreeView
11419  * with the given cell renderer and a #GtkCellDataFunc to set cell renderer
11420  * attributes (normally using data from the model). See also
11421  * gtk_tree_view_column_set_cell_data_func(), gtk_tree_view_column_pack_start().
11422  * If @tree_view has "fixed_height" mode enabled, then the new column will have its
11423  * "sizing" property set to be GTK_TREE_VIEW_COLUMN_FIXED.
11424  *
11425  * Return value: number of columns in the tree view post-insert
11426  **/
11427 gint
11428 gtk_tree_view_insert_column_with_data_func  (GtkTreeView               *tree_view,
11429                                              gint                       position,
11430                                              const gchar               *title,
11431                                              GtkCellRenderer           *cell,
11432                                              GtkTreeCellDataFunc        func,
11433                                              gpointer                   data,
11434                                              GDestroyNotify             dnotify)
11435 {
11436   GtkTreeViewColumn *column;
11437
11438   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11439
11440   column = gtk_tree_view_column_new ();
11441   if (tree_view->priv->fixed_height_mode)
11442     gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
11443
11444   gtk_tree_view_column_set_title (column, title);
11445   gtk_tree_view_column_pack_start (column, cell, TRUE);
11446   gtk_tree_view_column_set_cell_data_func (column, cell, func, data, dnotify);
11447
11448   gtk_tree_view_insert_column (tree_view, column, position);
11449
11450   return tree_view->priv->n_columns;
11451 }
11452
11453 /**
11454  * gtk_tree_view_get_column:
11455  * @tree_view: A #GtkTreeView.
11456  * @n: The position of the column, counting from 0.
11457  *
11458  * Gets the #GtkTreeViewColumn at the given position in the #tree_view.
11459  *
11460  * Return value: The #GtkTreeViewColumn, or %NULL if the position is outside the
11461  * range of columns.
11462  **/
11463 GtkTreeViewColumn *
11464 gtk_tree_view_get_column (GtkTreeView *tree_view,
11465                           gint         n)
11466 {
11467   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11468
11469   if (n < 0 || n >= tree_view->priv->n_columns)
11470     return NULL;
11471
11472   if (tree_view->priv->columns == NULL)
11473     return NULL;
11474
11475   return GTK_TREE_VIEW_COLUMN (g_list_nth (tree_view->priv->columns, n)->data);
11476 }
11477
11478 /**
11479  * gtk_tree_view_get_columns:
11480  * @tree_view: A #GtkTreeView
11481  *
11482  * Returns a #GList of all the #GtkTreeViewColumn s currently in @tree_view.
11483  * The returned list must be freed with g_list_free ().
11484  *
11485  * Return value: (element-type GtkTreeViewColumn) (transfer container): A list of #GtkTreeViewColumn s
11486  **/
11487 GList *
11488 gtk_tree_view_get_columns (GtkTreeView *tree_view)
11489 {
11490   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11491
11492   return g_list_copy (tree_view->priv->columns);
11493 }
11494
11495 /**
11496  * gtk_tree_view_move_column_after:
11497  * @tree_view: A #GtkTreeView
11498  * @column: The #GtkTreeViewColumn to be moved.
11499  * @base_column: (allow-none): The #GtkTreeViewColumn to be moved relative to, or %NULL.
11500  *
11501  * Moves @column to be after to @base_column.  If @base_column is %NULL, then
11502  * @column is placed in the first position.
11503  **/
11504 void
11505 gtk_tree_view_move_column_after (GtkTreeView       *tree_view,
11506                                  GtkTreeViewColumn *column,
11507                                  GtkTreeViewColumn *base_column)
11508 {
11509   GList *column_list_el, *base_el = NULL;
11510
11511   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11512
11513   column_list_el = g_list_find (tree_view->priv->columns, column);
11514   g_return_if_fail (column_list_el != NULL);
11515
11516   if (base_column)
11517     {
11518       base_el = g_list_find (tree_view->priv->columns, base_column);
11519       g_return_if_fail (base_el != NULL);
11520     }
11521
11522   if (column_list_el->prev == base_el)
11523     return;
11524
11525   tree_view->priv->columns = g_list_remove_link (tree_view->priv->columns, column_list_el);
11526   if (base_el == NULL)
11527     {
11528       column_list_el->prev = NULL;
11529       column_list_el->next = tree_view->priv->columns;
11530       if (column_list_el->next)
11531         column_list_el->next->prev = column_list_el;
11532       tree_view->priv->columns = column_list_el;
11533     }
11534   else
11535     {
11536       column_list_el->prev = base_el;
11537       column_list_el->next = base_el->next;
11538       if (column_list_el->next)
11539         column_list_el->next->prev = column_list_el;
11540       base_el->next = column_list_el;
11541     }
11542
11543   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11544     {
11545       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11546       gtk_tree_view_size_allocate_columns (GTK_WIDGET (tree_view), NULL);
11547     }
11548
11549   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
11550 }
11551
11552 /**
11553  * gtk_tree_view_set_expander_column:
11554  * @tree_view: A #GtkTreeView
11555  * @column: %NULL, or the column to draw the expander arrow at.
11556  *
11557  * Sets the column to draw the expander arrow at. It must be in @tree_view.  
11558  * If @column is %NULL, then the expander arrow is always at the first 
11559  * visible column.
11560  *
11561  * If you do not want expander arrow to appear in your tree, set the 
11562  * expander column to a hidden column.
11563  **/
11564 void
11565 gtk_tree_view_set_expander_column (GtkTreeView       *tree_view,
11566                                    GtkTreeViewColumn *column)
11567 {
11568   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11569   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
11570
11571   if (tree_view->priv->expander_column != column)
11572     {
11573       GList *list;
11574
11575       if (column)
11576         {
11577           /* Confirm that column is in tree_view */
11578           for (list = tree_view->priv->columns; list; list = list->next)
11579             if (list->data == column)
11580               break;
11581           g_return_if_fail (list != NULL);
11582         }
11583
11584       tree_view->priv->expander_column = column;
11585       g_object_notify (G_OBJECT (tree_view), "expander-column");
11586     }
11587 }
11588
11589 /**
11590  * gtk_tree_view_get_expander_column:
11591  * @tree_view: A #GtkTreeView
11592  *
11593  * Returns the column that is the current expander column.  This
11594  * column has the expander arrow drawn next to it.
11595  *
11596  * Return value: The expander column.
11597  **/
11598 GtkTreeViewColumn *
11599 gtk_tree_view_get_expander_column (GtkTreeView *tree_view)
11600 {
11601   GList *list;
11602
11603   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11604
11605   for (list = tree_view->priv->columns; list; list = list->next)
11606     if (gtk_tree_view_is_expander_column (tree_view, GTK_TREE_VIEW_COLUMN (list->data)))
11607       return (GtkTreeViewColumn *) list->data;
11608   return NULL;
11609 }
11610
11611
11612 /**
11613  * gtk_tree_view_set_column_drag_function:
11614  * @tree_view: A #GtkTreeView.
11615  * @func: (allow-none): A function to determine which columns are reorderable, or %NULL.
11616  * @user_data: (allow-none): User data to be passed to @func, or %NULL
11617  * @destroy: (allow-none): Destroy notifier for @user_data, or %NULL
11618  *
11619  * Sets a user function for determining where a column may be dropped when
11620  * dragged.  This function is called on every column pair in turn at the
11621  * beginning of a column drag to determine where a drop can take place.  The
11622  * arguments passed to @func are: the @tree_view, the #GtkTreeViewColumn being
11623  * dragged, the two #GtkTreeViewColumn s determining the drop spot, and
11624  * @user_data.  If either of the #GtkTreeViewColumn arguments for the drop spot
11625  * are %NULL, then they indicate an edge.  If @func is set to be %NULL, then
11626  * @tree_view reverts to the default behavior of allowing all columns to be
11627  * dropped everywhere.
11628  **/
11629 void
11630 gtk_tree_view_set_column_drag_function (GtkTreeView               *tree_view,
11631                                         GtkTreeViewColumnDropFunc  func,
11632                                         gpointer                   user_data,
11633                                         GDestroyNotify             destroy)
11634 {
11635   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11636
11637   if (tree_view->priv->column_drop_func_data_destroy)
11638     tree_view->priv->column_drop_func_data_destroy (tree_view->priv->column_drop_func_data);
11639
11640   tree_view->priv->column_drop_func = func;
11641   tree_view->priv->column_drop_func_data = user_data;
11642   tree_view->priv->column_drop_func_data_destroy = destroy;
11643 }
11644
11645 /**
11646  * gtk_tree_view_scroll_to_point:
11647  * @tree_view: a #GtkTreeView
11648  * @tree_x: X coordinate of new top-left pixel of visible area, or -1
11649  * @tree_y: Y coordinate of new top-left pixel of visible area, or -1
11650  *
11651  * Scrolls the tree view such that the top-left corner of the visible
11652  * area is @tree_x, @tree_y, where @tree_x and @tree_y are specified
11653  * in tree coordinates.  The @tree_view must be realized before
11654  * this function is called.  If it isn't, you probably want to be
11655  * using gtk_tree_view_scroll_to_cell().
11656  *
11657  * If either @tree_x or @tree_y are -1, then that direction isn't scrolled.
11658  **/
11659 void
11660 gtk_tree_view_scroll_to_point (GtkTreeView *tree_view,
11661                                gint         tree_x,
11662                                gint         tree_y)
11663 {
11664   GtkAdjustment *hadj;
11665   GtkAdjustment *vadj;
11666
11667   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11668   g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (tree_view)));
11669
11670   hadj = tree_view->priv->hadjustment;
11671   vadj = tree_view->priv->vadjustment;
11672
11673   if (tree_x != -1)
11674     gtk_adjustment_set_value (hadj, tree_x);
11675   if (tree_y != -1)
11676     gtk_adjustment_set_value (vadj, tree_y);
11677 }
11678
11679 /**
11680  * gtk_tree_view_scroll_to_cell:
11681  * @tree_view: A #GtkTreeView.
11682  * @path: (allow-none): The path of the row to move to, or %NULL.
11683  * @column: (allow-none): The #GtkTreeViewColumn to move horizontally to, or %NULL.
11684  * @use_align: whether to use alignment arguments, or %FALSE.
11685  * @row_align: The vertical alignment of the row specified by @path.
11686  * @col_align: The horizontal alignment of the column specified by @column.
11687  *
11688  * Moves the alignments of @tree_view to the position specified by @column and
11689  * @path.  If @column is %NULL, then no horizontal scrolling occurs.  Likewise,
11690  * if @path is %NULL no vertical scrolling occurs.  At a minimum, one of @column
11691  * or @path need to be non-%NULL.  @row_align determines where the row is
11692  * placed, and @col_align determines where @column is placed.  Both are expected
11693  * to be between 0.0 and 1.0. 0.0 means left/top alignment, 1.0 means
11694  * right/bottom alignment, 0.5 means center.
11695  *
11696  * If @use_align is %FALSE, then the alignment arguments are ignored, and the
11697  * tree does the minimum amount of work to scroll the cell onto the screen.
11698  * This means that the cell will be scrolled to the edge closest to its current
11699  * position.  If the cell is currently visible on the screen, nothing is done.
11700  *
11701  * This function only works if the model is set, and @path is a valid row on the
11702  * model.  If the model changes before the @tree_view is realized, the centered
11703  * path will be modified to reflect this change.
11704  **/
11705 void
11706 gtk_tree_view_scroll_to_cell (GtkTreeView       *tree_view,
11707                               GtkTreePath       *path,
11708                               GtkTreeViewColumn *column,
11709                               gboolean           use_align,
11710                               gfloat             row_align,
11711                               gfloat             col_align)
11712 {
11713   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11714   g_return_if_fail (tree_view->priv->model != NULL);
11715   g_return_if_fail (tree_view->priv->tree != NULL);
11716   g_return_if_fail (row_align >= 0.0 && row_align <= 1.0);
11717   g_return_if_fail (col_align >= 0.0 && col_align <= 1.0);
11718   g_return_if_fail (path != NULL || column != NULL);
11719
11720 #if 0
11721   g_print ("gtk_tree_view_scroll_to_cell:\npath: %s\ncolumn: %s\nuse_align: %d\nrow_align: %f\ncol_align: %f\n",
11722            gtk_tree_path_to_string (path), column?"non-null":"null", use_align, row_align, col_align);
11723 #endif
11724   row_align = CLAMP (row_align, 0.0, 1.0);
11725   col_align = CLAMP (col_align, 0.0, 1.0);
11726
11727
11728   /* Note: Despite the benefits that come from having one code path for the
11729    * scrolling code, we short-circuit validate_visible_area's immplementation as
11730    * it is much slower than just going to the point.
11731    */
11732   if (!gtk_widget_get_visible (GTK_WIDGET (tree_view)) ||
11733       !gtk_widget_get_realized (GTK_WIDGET (tree_view)) ||
11734       GTK_WIDGET_ALLOC_NEEDED (tree_view) || 
11735       GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID))
11736     {
11737       if (tree_view->priv->scroll_to_path)
11738         gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
11739
11740       tree_view->priv->scroll_to_path = NULL;
11741       tree_view->priv->scroll_to_column = NULL;
11742
11743       if (path)
11744         tree_view->priv->scroll_to_path = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
11745       if (column)
11746         tree_view->priv->scroll_to_column = column;
11747       tree_view->priv->scroll_to_use_align = use_align;
11748       tree_view->priv->scroll_to_row_align = row_align;
11749       tree_view->priv->scroll_to_col_align = col_align;
11750
11751       install_presize_handler (tree_view);
11752     }
11753   else
11754     {
11755       GdkRectangle cell_rect;
11756       GdkRectangle vis_rect;
11757       gint dest_x, dest_y;
11758
11759       gtk_tree_view_get_background_area (tree_view, path, column, &cell_rect);
11760       gtk_tree_view_get_visible_rect (tree_view, &vis_rect);
11761
11762       cell_rect.y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, cell_rect.y);
11763
11764       dest_x = vis_rect.x;
11765       dest_y = vis_rect.y;
11766
11767       if (column)
11768         {
11769           if (use_align)
11770             {
11771               dest_x = cell_rect.x - ((vis_rect.width - cell_rect.width) * col_align);
11772             }
11773           else
11774             {
11775               if (cell_rect.x < vis_rect.x)
11776                 dest_x = cell_rect.x;
11777               if (cell_rect.x + cell_rect.width > vis_rect.x + vis_rect.width)
11778                 dest_x = cell_rect.x + cell_rect.width - vis_rect.width;
11779             }
11780         }
11781
11782       if (path)
11783         {
11784           if (use_align)
11785             {
11786               dest_y = cell_rect.y - ((vis_rect.height - cell_rect.height) * row_align);
11787               dest_y = MAX (dest_y, 0);
11788             }
11789           else
11790             {
11791               if (cell_rect.y < vis_rect.y)
11792                 dest_y = cell_rect.y;
11793               if (cell_rect.y + cell_rect.height > vis_rect.y + vis_rect.height)
11794                 dest_y = cell_rect.y + cell_rect.height - vis_rect.height;
11795             }
11796         }
11797
11798       gtk_tree_view_scroll_to_point (tree_view, dest_x, dest_y);
11799     }
11800 }
11801
11802 /**
11803  * gtk_tree_view_row_activated:
11804  * @tree_view: A #GtkTreeView
11805  * @path: The #GtkTreePath to be activated.
11806  * @column: The #GtkTreeViewColumn to be activated.
11807  *
11808  * Activates the cell determined by @path and @column.
11809  **/
11810 void
11811 gtk_tree_view_row_activated (GtkTreeView       *tree_view,
11812                              GtkTreePath       *path,
11813                              GtkTreeViewColumn *column)
11814 {
11815   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11816
11817   g_signal_emit (tree_view, tree_view_signals[ROW_ACTIVATED], 0, path, column);
11818 }
11819
11820
11821 static void
11822 gtk_tree_view_expand_all_emission_helper (GtkRBTree *tree,
11823                                           GtkRBNode *node,
11824                                           gpointer   data)
11825 {
11826   GtkTreeView *tree_view = data;
11827
11828   if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT &&
11829       node->children)
11830     {
11831       GtkTreePath *path;
11832       GtkTreeIter iter;
11833
11834       path = _gtk_tree_view_find_path (tree_view, tree, node);
11835       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
11836
11837       g_signal_emit (tree_view, tree_view_signals[ROW_EXPANDED], 0, &iter, path);
11838
11839       gtk_tree_path_free (path);
11840     }
11841
11842   if (node->children)
11843     _gtk_rbtree_traverse (node->children,
11844                           node->children->root,
11845                           G_PRE_ORDER,
11846                           gtk_tree_view_expand_all_emission_helper,
11847                           tree_view);
11848 }
11849
11850 /**
11851  * gtk_tree_view_expand_all:
11852  * @tree_view: A #GtkTreeView.
11853  *
11854  * Recursively expands all nodes in the @tree_view.
11855  **/
11856 void
11857 gtk_tree_view_expand_all (GtkTreeView *tree_view)
11858 {
11859   GtkTreePath *path;
11860   GtkRBTree *tree;
11861   GtkRBNode *node;
11862
11863   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11864
11865   if (tree_view->priv->tree == NULL)
11866     return;
11867
11868   path = gtk_tree_path_new_first ();
11869   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
11870
11871   while (node)
11872     {
11873       gtk_tree_view_real_expand_row (tree_view, path, tree, node, TRUE, FALSE);
11874       node = _gtk_rbtree_next (tree, node);
11875       gtk_tree_path_next (path);
11876   }
11877
11878   gtk_tree_path_free (path);
11879 }
11880
11881 /* Timeout to animate the expander during expands and collapses */
11882 static gboolean
11883 expand_collapse_timeout (gpointer data)
11884 {
11885   return do_expand_collapse (data);
11886 }
11887
11888 static void
11889 add_expand_collapse_timeout (GtkTreeView *tree_view,
11890                              GtkRBTree   *tree,
11891                              GtkRBNode   *node,
11892                              gboolean     expand)
11893 {
11894   if (tree_view->priv->expand_collapse_timeout != 0)
11895     return;
11896
11897   tree_view->priv->expand_collapse_timeout =
11898       gdk_threads_add_timeout (50, expand_collapse_timeout, tree_view);
11899   tree_view->priv->expanded_collapsed_tree = tree;
11900   tree_view->priv->expanded_collapsed_node = node;
11901
11902   if (expand)
11903     GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
11904   else
11905     GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
11906 }
11907
11908 static void
11909 remove_expand_collapse_timeout (GtkTreeView *tree_view)
11910 {
11911   if (tree_view->priv->expand_collapse_timeout)
11912     {
11913       g_source_remove (tree_view->priv->expand_collapse_timeout);
11914       tree_view->priv->expand_collapse_timeout = 0;
11915     }
11916
11917   if (tree_view->priv->expanded_collapsed_node != NULL)
11918     {
11919       GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_EXPANDED);
11920       GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_COLLAPSED);
11921
11922       tree_view->priv->expanded_collapsed_node = NULL;
11923     }
11924 }
11925
11926 static void
11927 cancel_arrow_animation (GtkTreeView *tree_view)
11928 {
11929   if (tree_view->priv->expand_collapse_timeout)
11930     {
11931       while (do_expand_collapse (tree_view));
11932
11933       remove_expand_collapse_timeout (tree_view);
11934     }
11935 }
11936
11937 static gboolean
11938 do_expand_collapse (GtkTreeView *tree_view)
11939 {
11940   GtkRBNode *node;
11941   GtkRBTree *tree;
11942   gboolean expanding;
11943   gboolean redraw;
11944
11945   redraw = FALSE;
11946   expanding = TRUE;
11947
11948   node = tree_view->priv->expanded_collapsed_node;
11949   tree = tree_view->priv->expanded_collapsed_tree;
11950
11951   if (node->children == NULL)
11952     expanding = FALSE;
11953
11954   if (expanding)
11955     {
11956       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_COLLAPSED))
11957         {
11958           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
11959           GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
11960
11961           redraw = TRUE;
11962
11963         }
11964       else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_EXPANDED))
11965         {
11966           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
11967
11968           redraw = TRUE;
11969         }
11970     }
11971   else
11972     {
11973       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_EXPANDED))
11974         {
11975           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
11976           GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
11977
11978           redraw = TRUE;
11979         }
11980       else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_COLLAPSED))
11981         {
11982           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
11983
11984           redraw = TRUE;
11985
11986         }
11987     }
11988
11989   if (redraw)
11990     {
11991       gtk_tree_view_queue_draw_arrow (tree_view, tree, node, NULL);
11992
11993       return TRUE;
11994     }
11995
11996   return FALSE;
11997 }
11998
11999 /**
12000  * gtk_tree_view_collapse_all:
12001  * @tree_view: A #GtkTreeView.
12002  *
12003  * Recursively collapses all visible, expanded nodes in @tree_view.
12004  **/
12005 void
12006 gtk_tree_view_collapse_all (GtkTreeView *tree_view)
12007 {
12008   GtkRBTree *tree;
12009   GtkRBNode *node;
12010   GtkTreePath *path;
12011   gint *indices;
12012
12013   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12014
12015   if (tree_view->priv->tree == NULL)
12016     return;
12017
12018   path = gtk_tree_path_new ();
12019   gtk_tree_path_down (path);
12020   indices = gtk_tree_path_get_indices (path);
12021
12022   tree = tree_view->priv->tree;
12023   node = tree->root;
12024   while (node && node->left != tree->nil)
12025     node = node->left;
12026
12027   while (node)
12028     {
12029       if (node->children)
12030         gtk_tree_view_real_collapse_row (tree_view, path, tree, node, FALSE);
12031       indices[0]++;
12032       node = _gtk_rbtree_next (tree, node);
12033     }
12034
12035   gtk_tree_path_free (path);
12036 }
12037
12038 /**
12039  * gtk_tree_view_expand_to_path:
12040  * @tree_view: A #GtkTreeView.
12041  * @path: path to a row.
12042  *
12043  * Expands the row at @path. This will also expand all parent rows of
12044  * @path as necessary.
12045  *
12046  * Since: 2.2
12047  **/
12048 void
12049 gtk_tree_view_expand_to_path (GtkTreeView *tree_view,
12050                               GtkTreePath *path)
12051 {
12052   gint i, depth;
12053   gint *indices;
12054   GtkTreePath *tmp;
12055
12056   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12057   g_return_if_fail (path != NULL);
12058
12059   depth = gtk_tree_path_get_depth (path);
12060   indices = gtk_tree_path_get_indices (path);
12061
12062   tmp = gtk_tree_path_new ();
12063   g_return_if_fail (tmp != NULL);
12064
12065   for (i = 0; i < depth; i++)
12066     {
12067       gtk_tree_path_append_index (tmp, indices[i]);
12068       gtk_tree_view_expand_row (tree_view, tmp, FALSE);
12069     }
12070
12071   gtk_tree_path_free (tmp);
12072 }
12073
12074 /* FIXME the bool return values for expand_row and collapse_row are
12075  * not analagous; they should be TRUE if the row had children and
12076  * was not already in the requested state.
12077  */
12078
12079
12080 static gboolean
12081 gtk_tree_view_real_expand_row (GtkTreeView *tree_view,
12082                                GtkTreePath *path,
12083                                GtkRBTree   *tree,
12084                                GtkRBNode   *node,
12085                                gboolean     open_all,
12086                                gboolean     animate)
12087 {
12088   GtkTreeIter iter;
12089   GtkTreeIter temp;
12090   gboolean expand;
12091
12092   if (animate)
12093     g_object_get (gtk_widget_get_settings (GTK_WIDGET (tree_view)),
12094                   "gtk-enable-animations", &animate,
12095                   NULL);
12096
12097   remove_auto_expand_timeout (tree_view);
12098
12099   if (node->children && !open_all)
12100     return FALSE;
12101
12102   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
12103     return FALSE;
12104
12105   gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
12106   if (! gtk_tree_model_iter_has_child (tree_view->priv->model, &iter))
12107     return FALSE;
12108
12109
12110    if (node->children && open_all)
12111     {
12112       gboolean retval = FALSE;
12113       GtkTreePath *tmp_path = gtk_tree_path_copy (path);
12114
12115       gtk_tree_path_append_index (tmp_path, 0);
12116       tree = node->children;
12117       node = tree->root;
12118       while (node->left != tree->nil)
12119         node = node->left;
12120       /* try to expand the children */
12121       do
12122         {
12123          gboolean t;
12124          t = gtk_tree_view_real_expand_row (tree_view, tmp_path, tree, node,
12125                                             TRUE, animate);
12126          if (t)
12127            retval = TRUE;
12128
12129          gtk_tree_path_next (tmp_path);
12130          node = _gtk_rbtree_next (tree, node);
12131        }
12132       while (node != NULL);
12133
12134       gtk_tree_path_free (tmp_path);
12135
12136       return retval;
12137     }
12138
12139   g_signal_emit (tree_view, tree_view_signals[TEST_EXPAND_ROW], 0, &iter, path, &expand);
12140
12141   if (!gtk_tree_model_iter_has_child (tree_view->priv->model, &iter))
12142     return FALSE;
12143
12144   if (expand)
12145     return FALSE;
12146
12147   node->children = _gtk_rbtree_new ();
12148   node->children->parent_tree = tree;
12149   node->children->parent_node = node;
12150
12151   gtk_tree_model_iter_children (tree_view->priv->model, &temp, &iter);
12152
12153   gtk_tree_view_build_tree (tree_view,
12154                             node->children,
12155                             &temp,
12156                             gtk_tree_path_get_depth (path) + 1,
12157                             open_all);
12158
12159   remove_expand_collapse_timeout (tree_view);
12160
12161   if (animate)
12162     add_expand_collapse_timeout (tree_view, tree, node, TRUE);
12163
12164   install_presize_handler (tree_view);
12165
12166   g_signal_emit (tree_view, tree_view_signals[ROW_EXPANDED], 0, &iter, path);
12167   if (open_all && node->children)
12168     {
12169       _gtk_rbtree_traverse (node->children,
12170                             node->children->root,
12171                             G_PRE_ORDER,
12172                             gtk_tree_view_expand_all_emission_helper,
12173                             tree_view);
12174     }
12175   return TRUE;
12176 }
12177
12178
12179 /**
12180  * gtk_tree_view_expand_row:
12181  * @tree_view: a #GtkTreeView
12182  * @path: path to a row
12183  * @open_all: whether to recursively expand, or just expand immediate children
12184  *
12185  * Opens the row so its children are visible.
12186  *
12187  * Return value: %TRUE if the row existed and had children
12188  **/
12189 gboolean
12190 gtk_tree_view_expand_row (GtkTreeView *tree_view,
12191                           GtkTreePath *path,
12192                           gboolean     open_all)
12193 {
12194   GtkRBTree *tree;
12195   GtkRBNode *node;
12196
12197   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12198   g_return_val_if_fail (tree_view->priv->model != NULL, FALSE);
12199   g_return_val_if_fail (path != NULL, FALSE);
12200
12201   if (_gtk_tree_view_find_node (tree_view,
12202                                 path,
12203                                 &tree,
12204                                 &node))
12205     return FALSE;
12206
12207   if (tree != NULL)
12208     return gtk_tree_view_real_expand_row (tree_view, path, tree, node, open_all, FALSE);
12209   else
12210     return FALSE;
12211 }
12212
12213 static gboolean
12214 gtk_tree_view_real_collapse_row (GtkTreeView *tree_view,
12215                                  GtkTreePath *path,
12216                                  GtkRBTree   *tree,
12217                                  GtkRBNode   *node,
12218                                  gboolean     animate)
12219 {
12220   GtkTreeIter iter;
12221   GtkTreeIter children;
12222   gboolean collapse;
12223   gint x, y;
12224   GList *list;
12225   GdkWindow *child, *parent;
12226
12227   if (animate)
12228     g_object_get (gtk_widget_get_settings (GTK_WIDGET (tree_view)),
12229                   "gtk-enable-animations", &animate,
12230                   NULL);
12231
12232   remove_auto_expand_timeout (tree_view);
12233
12234   if (node->children == NULL)
12235     return FALSE;
12236
12237   gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
12238
12239   g_signal_emit (tree_view, tree_view_signals[TEST_COLLAPSE_ROW], 0, &iter, path, &collapse);
12240
12241   if (collapse)
12242     return FALSE;
12243
12244   /* if the prelighted node is a child of us, we want to unprelight it.  We have
12245    * a chance to prelight the correct node below */
12246
12247   if (tree_view->priv->prelight_tree)
12248     {
12249       GtkRBTree *parent_tree;
12250       GtkRBNode *parent_node;
12251
12252       parent_tree = tree_view->priv->prelight_tree->parent_tree;
12253       parent_node = tree_view->priv->prelight_tree->parent_node;
12254       while (parent_tree)
12255         {
12256           if (parent_tree == tree && parent_node == node)
12257             {
12258               ensure_unprelighted (tree_view);
12259               break;
12260             }
12261           parent_node = parent_tree->parent_node;
12262           parent_tree = parent_tree->parent_tree;
12263         }
12264     }
12265
12266   TREE_VIEW_INTERNAL_ASSERT (gtk_tree_model_iter_children (tree_view->priv->model, &children, &iter), FALSE);
12267
12268   for (list = tree_view->priv->columns; list; list = list->next)
12269     {
12270       GtkTreeViewColumn *column = list->data;
12271
12272       if (column->visible == FALSE)
12273         continue;
12274       if (gtk_tree_view_column_get_sizing (column) == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
12275         _gtk_tree_view_column_cell_set_dirty (column, TRUE);
12276     }
12277
12278   if (tree_view->priv->destroy_count_func)
12279     {
12280       GtkTreePath *child_path;
12281       gint child_count = 0;
12282       child_path = gtk_tree_path_copy (path);
12283       gtk_tree_path_down (child_path);
12284       if (node->children)
12285         _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, &child_count);
12286       tree_view->priv->destroy_count_func (tree_view, child_path, child_count, tree_view->priv->destroy_count_data);
12287       gtk_tree_path_free (child_path);
12288     }
12289
12290   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
12291     {
12292       GtkTreePath *cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
12293
12294       if (gtk_tree_path_is_ancestor (path, cursor_path))
12295         {
12296           gtk_tree_row_reference_free (tree_view->priv->cursor);
12297           tree_view->priv->cursor = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
12298                                                                       tree_view->priv->model,
12299                                                                       path);
12300         }
12301       gtk_tree_path_free (cursor_path);
12302     }
12303
12304   if (gtk_tree_row_reference_valid (tree_view->priv->anchor))
12305     {
12306       GtkTreePath *anchor_path = gtk_tree_row_reference_get_path (tree_view->priv->anchor);
12307       if (gtk_tree_path_is_ancestor (path, anchor_path))
12308         {
12309           gtk_tree_row_reference_free (tree_view->priv->anchor);
12310           tree_view->priv->anchor = NULL;
12311         }
12312       gtk_tree_path_free (anchor_path);
12313     }
12314
12315   /* Stop a pending double click */
12316   tree_view->priv->last_button_x = -1;
12317   tree_view->priv->last_button_y = -1;
12318
12319   remove_expand_collapse_timeout (tree_view);
12320
12321   if (gtk_tree_view_unref_and_check_selection_tree (tree_view, node->children))
12322     {
12323       _gtk_rbtree_remove (node->children);
12324       g_signal_emit_by_name (tree_view->priv->selection, "changed");
12325     }
12326   else
12327     _gtk_rbtree_remove (node->children);
12328   
12329   if (animate)
12330     add_expand_collapse_timeout (tree_view, tree, node, FALSE);
12331   
12332   if (gtk_widget_get_mapped (GTK_WIDGET (tree_view)))
12333     {
12334       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
12335     }
12336
12337   g_signal_emit (tree_view, tree_view_signals[ROW_COLLAPSED], 0, &iter, path);
12338
12339   if (gtk_widget_get_mapped (GTK_WIDGET (tree_view)))
12340     {
12341       /* now that we've collapsed all rows, we want to try to set the prelight
12342        * again. To do this, we fake a motion event and send it to ourselves. */
12343
12344       child = tree_view->priv->bin_window;
12345       parent = gdk_window_get_parent (child);
12346
12347       if (gdk_window_get_pointer (parent, &x, &y, NULL) == child)
12348         {
12349           GdkEventMotion event;
12350           gint child_x, child_y;
12351
12352           gdk_window_get_position (child, &child_x, &child_y);
12353
12354           event.window = tree_view->priv->bin_window;
12355           event.x = x - child_x;
12356           event.y = y - child_y;
12357
12358           /* despite the fact this isn't a real event, I'm almost positive it will
12359            * never trigger a drag event.  maybe_drag is the only function that uses
12360            * more than just event.x and event.y. */
12361           gtk_tree_view_motion_bin_window (GTK_WIDGET (tree_view), &event);
12362         }
12363     }
12364
12365   return TRUE;
12366 }
12367
12368 /**
12369  * gtk_tree_view_collapse_row:
12370  * @tree_view: a #GtkTreeView
12371  * @path: path to a row in the @tree_view
12372  *
12373  * Collapses a row (hides its child rows, if they exist).
12374  *
12375  * Return value: %TRUE if the row was collapsed.
12376  **/
12377 gboolean
12378 gtk_tree_view_collapse_row (GtkTreeView *tree_view,
12379                             GtkTreePath *path)
12380 {
12381   GtkRBTree *tree;
12382   GtkRBNode *node;
12383
12384   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12385   g_return_val_if_fail (tree_view->priv->tree != NULL, FALSE);
12386   g_return_val_if_fail (path != NULL, FALSE);
12387
12388   if (_gtk_tree_view_find_node (tree_view,
12389                                 path,
12390                                 &tree,
12391                                 &node))
12392     return FALSE;
12393
12394   if (tree == NULL || node->children == NULL)
12395     return FALSE;
12396
12397   return gtk_tree_view_real_collapse_row (tree_view, path, tree, node, FALSE);
12398 }
12399
12400 static void
12401 gtk_tree_view_map_expanded_rows_helper (GtkTreeView            *tree_view,
12402                                         GtkRBTree              *tree,
12403                                         GtkTreePath            *path,
12404                                         GtkTreeViewMappingFunc  func,
12405                                         gpointer                user_data)
12406 {
12407   GtkRBNode *node;
12408
12409   if (tree == NULL || tree->root == NULL)
12410     return;
12411
12412   node = tree->root;
12413
12414   while (node && node->left != tree->nil)
12415     node = node->left;
12416
12417   while (node)
12418     {
12419       if (node->children)
12420         {
12421           (* func) (tree_view, path, user_data);
12422           gtk_tree_path_down (path);
12423           gtk_tree_view_map_expanded_rows_helper (tree_view, node->children, path, func, user_data);
12424           gtk_tree_path_up (path);
12425         }
12426       gtk_tree_path_next (path);
12427       node = _gtk_rbtree_next (tree, node);
12428     }
12429 }
12430
12431 /**
12432  * gtk_tree_view_map_expanded_rows:
12433  * @tree_view: A #GtkTreeView
12434  * @func: A function to be called
12435  * @data: User data to be passed to the function.
12436  *
12437  * Calls @func on all expanded rows.
12438  **/
12439 void
12440 gtk_tree_view_map_expanded_rows (GtkTreeView            *tree_view,
12441                                  GtkTreeViewMappingFunc  func,
12442                                  gpointer                user_data)
12443 {
12444   GtkTreePath *path;
12445
12446   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12447   g_return_if_fail (func != NULL);
12448
12449   path = gtk_tree_path_new_first ();
12450
12451   gtk_tree_view_map_expanded_rows_helper (tree_view,
12452                                           tree_view->priv->tree,
12453                                           path, func, user_data);
12454
12455   gtk_tree_path_free (path);
12456 }
12457
12458 /**
12459  * gtk_tree_view_row_expanded:
12460  * @tree_view: A #GtkTreeView.
12461  * @path: A #GtkTreePath to test expansion state.
12462  *
12463  * Returns %TRUE if the node pointed to by @path is expanded in @tree_view.
12464  *
12465  * Return value: %TRUE if #path is expanded.
12466  **/
12467 gboolean
12468 gtk_tree_view_row_expanded (GtkTreeView *tree_view,
12469                             GtkTreePath *path)
12470 {
12471   GtkRBTree *tree;
12472   GtkRBNode *node;
12473
12474   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12475   g_return_val_if_fail (path != NULL, FALSE);
12476
12477   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
12478
12479   if (node == NULL)
12480     return FALSE;
12481
12482   return (node->children != NULL);
12483 }
12484
12485 /**
12486  * gtk_tree_view_get_reorderable:
12487  * @tree_view: a #GtkTreeView
12488  *
12489  * Retrieves whether the user can reorder the tree via drag-and-drop. See
12490  * gtk_tree_view_set_reorderable().
12491  *
12492  * Return value: %TRUE if the tree can be reordered.
12493  **/
12494 gboolean
12495 gtk_tree_view_get_reorderable (GtkTreeView *tree_view)
12496 {
12497   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12498
12499   return tree_view->priv->reorderable;
12500 }
12501
12502 /**
12503  * gtk_tree_view_set_reorderable:
12504  * @tree_view: A #GtkTreeView.
12505  * @reorderable: %TRUE, if the tree can be reordered.
12506  *
12507  * This function is a convenience function to allow you to reorder
12508  * models that support the #GtkDragSourceIface and the
12509  * #GtkDragDestIface.  Both #GtkTreeStore and #GtkListStore support
12510  * these.  If @reorderable is %TRUE, then the user can reorder the
12511  * model by dragging and dropping rows. The developer can listen to
12512  * these changes by connecting to the model's row_inserted and
12513  * row_deleted signals. The reordering is implemented by setting up
12514  * the tree view as a drag source and destination. Therefore, drag and
12515  * drop can not be used in a reorderable view for any other purpose.
12516  *
12517  * This function does not give you any degree of control over the order -- any
12518  * reordering is allowed.  If more control is needed, you should probably
12519  * handle drag and drop manually.
12520  **/
12521 void
12522 gtk_tree_view_set_reorderable (GtkTreeView *tree_view,
12523                                gboolean     reorderable)
12524 {
12525   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12526
12527   reorderable = reorderable != FALSE;
12528
12529   if (tree_view->priv->reorderable == reorderable)
12530     return;
12531
12532   if (reorderable)
12533     {
12534       const GtkTargetEntry row_targets[] = {
12535         { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, 0 }
12536       };
12537
12538       gtk_tree_view_enable_model_drag_source (tree_view,
12539                                               GDK_BUTTON1_MASK,
12540                                               row_targets,
12541                                               G_N_ELEMENTS (row_targets),
12542                                               GDK_ACTION_MOVE);
12543       gtk_tree_view_enable_model_drag_dest (tree_view,
12544                                             row_targets,
12545                                             G_N_ELEMENTS (row_targets),
12546                                             GDK_ACTION_MOVE);
12547     }
12548   else
12549     {
12550       gtk_tree_view_unset_rows_drag_source (tree_view);
12551       gtk_tree_view_unset_rows_drag_dest (tree_view);
12552     }
12553
12554   tree_view->priv->reorderable = reorderable;
12555
12556   g_object_notify (G_OBJECT (tree_view), "reorderable");
12557 }
12558
12559 static void
12560 gtk_tree_view_real_set_cursor (GtkTreeView     *tree_view,
12561                                GtkTreePath     *path,
12562                                gboolean         clear_and_select,
12563                                gboolean         clamp_node)
12564 {
12565   GtkRBTree *tree = NULL;
12566   GtkRBNode *node = NULL;
12567
12568   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
12569     {
12570       GtkTreePath *cursor_path;
12571       cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
12572       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
12573       gtk_tree_path_free (cursor_path);
12574     }
12575
12576   gtk_tree_row_reference_free (tree_view->priv->cursor);
12577   tree_view->priv->cursor = NULL;
12578
12579   /* One cannot set the cursor on a separator.   Also, if
12580    * _gtk_tree_view_find_node returns TRUE, it ran out of tree
12581    * before finding the tree and node belonging to path.  The
12582    * path maps to a non-existing path and we will silently bail out.
12583    * We unset tree and node to avoid further processing.
12584    */
12585   if (!row_is_separator (tree_view, NULL, path)
12586       && _gtk_tree_view_find_node (tree_view, path, &tree, &node) == FALSE)
12587     {
12588       tree_view->priv->cursor =
12589           gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
12590                                             tree_view->priv->model,
12591                                             path);
12592     }
12593   else
12594     {
12595       tree = NULL;
12596       node = NULL;
12597     }
12598
12599   if (tree != NULL)
12600     {
12601       GtkRBTree *new_tree = NULL;
12602       GtkRBNode *new_node = NULL;
12603
12604       if (clear_and_select && !tree_view->priv->ctrl_pressed)
12605         {
12606           GtkTreeSelectMode mode = 0;
12607
12608           if (tree_view->priv->ctrl_pressed)
12609             mode |= GTK_TREE_SELECT_MODE_TOGGLE;
12610           if (tree_view->priv->shift_pressed)
12611             mode |= GTK_TREE_SELECT_MODE_EXTEND;
12612
12613           _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
12614                                                     node, tree, path, mode,
12615                                                     FALSE);
12616         }
12617
12618       /* We have to re-find tree and node here again, somebody might have
12619        * cleared the node or the whole tree in the GtkTreeSelection::changed
12620        * callback. If the nodes differ we bail out here.
12621        */
12622       _gtk_tree_view_find_node (tree_view, path, &new_tree, &new_node);
12623
12624       if (tree != new_tree || node != new_node)
12625         return;
12626
12627       if (clamp_node)
12628         {
12629           gtk_tree_view_clamp_node_visible (tree_view, tree, node);
12630           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
12631         }
12632     }
12633
12634   g_signal_emit (tree_view, tree_view_signals[CURSOR_CHANGED], 0);
12635 }
12636
12637 /**
12638  * gtk_tree_view_get_cursor:
12639  * @tree_view: A #GtkTreeView
12640  * @path: (out) (allow-none): A pointer to be filled with the current cursor path, or %NULL
12641  * @focus_column: (out) (allow-none): A pointer to be filled with the current focus column, or %NULL
12642  *
12643  * Fills in @path and @focus_column with the current path and focus column.  If
12644  * the cursor isn't currently set, then *@path will be %NULL.  If no column
12645  * currently has focus, then *@focus_column will be %NULL.
12646  *
12647  * The returned #GtkTreePath must be freed with gtk_tree_path_free() when
12648  * you are done with it.
12649  **/
12650 void
12651 gtk_tree_view_get_cursor (GtkTreeView        *tree_view,
12652                           GtkTreePath       **path,
12653                           GtkTreeViewColumn **focus_column)
12654 {
12655   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12656
12657   if (path)
12658     {
12659       if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
12660         *path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
12661       else
12662         *path = NULL;
12663     }
12664
12665   if (focus_column)
12666     {
12667       *focus_column = tree_view->priv->focus_column;
12668     }
12669 }
12670
12671 /**
12672  * gtk_tree_view_set_cursor:
12673  * @tree_view: A #GtkTreeView
12674  * @path: A #GtkTreePath
12675  * @focus_column: (allow-none): A #GtkTreeViewColumn, or %NULL
12676  * @start_editing: %TRUE if the specified cell should start being edited.
12677  *
12678  * Sets the current keyboard focus to be at @path, and selects it.  This is
12679  * useful when you want to focus the user's attention on a particular row.  If
12680  * @focus_column is not %NULL, then focus is given to the column specified by 
12681  * it. Additionally, if @focus_column is specified, and @start_editing is 
12682  * %TRUE, then editing should be started in the specified cell.  
12683  * This function is often followed by @gtk_widget_grab_focus (@tree_view) 
12684  * in order to give keyboard focus to the widget.  Please note that editing 
12685  * can only happen when the widget is realized.
12686  *
12687  * If @path is invalid for @model, the current cursor (if any) will be unset
12688  * and the function will return without failing.
12689  **/
12690 void
12691 gtk_tree_view_set_cursor (GtkTreeView       *tree_view,
12692                           GtkTreePath       *path,
12693                           GtkTreeViewColumn *focus_column,
12694                           gboolean           start_editing)
12695 {
12696   gtk_tree_view_set_cursor_on_cell (tree_view, path, focus_column,
12697                                     NULL, start_editing);
12698 }
12699
12700 /**
12701  * gtk_tree_view_set_cursor_on_cell:
12702  * @tree_view: A #GtkTreeView
12703  * @path: A #GtkTreePath
12704  * @focus_column: (allow-none): A #GtkTreeViewColumn, or %NULL
12705  * @focus_cell: (allow-none): A #GtkCellRenderer, or %NULL
12706  * @start_editing: %TRUE if the specified cell should start being edited.
12707  *
12708  * Sets the current keyboard focus to be at @path, and selects it.  This is
12709  * useful when you want to focus the user's attention on a particular row.  If
12710  * @focus_column is not %NULL, then focus is given to the column specified by
12711  * it. If @focus_column and @focus_cell are not %NULL, and @focus_column
12712  * contains 2 or more editable or activatable cells, then focus is given to
12713  * the cell specified by @focus_cell. Additionally, if @focus_column is
12714  * specified, and @start_editing is %TRUE, then editing should be started in
12715  * the specified cell.  This function is often followed by
12716  * @gtk_widget_grab_focus (@tree_view) in order to give keyboard focus to the
12717  * widget.  Please note that editing can only happen when the widget is
12718  * realized.
12719  *
12720  * If @path is invalid for @model, the current cursor (if any) will be unset
12721  * and the function will return without failing.
12722  *
12723  * Since: 2.2
12724  **/
12725 void
12726 gtk_tree_view_set_cursor_on_cell (GtkTreeView       *tree_view,
12727                                   GtkTreePath       *path,
12728                                   GtkTreeViewColumn *focus_column,
12729                                   GtkCellRenderer   *focus_cell,
12730                                   gboolean           start_editing)
12731 {
12732   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12733   g_return_if_fail (path != NULL);
12734   g_return_if_fail (focus_column == NULL || GTK_IS_TREE_VIEW_COLUMN (focus_column));
12735
12736   if (!tree_view->priv->model)
12737     return;
12738
12739   if (focus_cell)
12740     {
12741       g_return_if_fail (focus_column);
12742       g_return_if_fail (GTK_IS_CELL_RENDERER (focus_cell));
12743     }
12744
12745   /* cancel the current editing, if it exists */
12746   if (tree_view->priv->edited_column &&
12747       tree_view->priv->edited_column->editable_widget)
12748     gtk_tree_view_stop_editing (tree_view, TRUE);
12749
12750   gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
12751
12752   if (focus_column && focus_column->visible)
12753     {
12754       GList *list;
12755       gboolean column_in_tree = FALSE;
12756
12757       for (list = tree_view->priv->columns; list; list = list->next)
12758         if (list->data == focus_column)
12759           {
12760             column_in_tree = TRUE;
12761             break;
12762           }
12763       g_return_if_fail (column_in_tree);
12764       tree_view->priv->focus_column = focus_column;
12765       if (focus_cell)
12766         gtk_tree_view_column_focus_cell (focus_column, focus_cell);
12767       if (start_editing)
12768         gtk_tree_view_start_editing (tree_view, path);
12769     }
12770 }
12771
12772 /**
12773  * gtk_tree_view_get_bin_window:
12774  * @tree_view: A #GtkTreeView
12775  * 
12776  * Returns the window that @tree_view renders to.  This is used primarily to
12777  * compare to <literal>event->window</literal> to confirm that the event on
12778  * @tree_view is on the right window.
12779  * 
12780  * Return value: A #GdkWindow, or %NULL when @tree_view hasn't been realized yet
12781  **/
12782 GdkWindow *
12783 gtk_tree_view_get_bin_window (GtkTreeView *tree_view)
12784 {
12785   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
12786
12787   return tree_view->priv->bin_window;
12788 }
12789
12790 /**
12791  * gtk_tree_view_get_path_at_pos:
12792  * @tree_view: A #GtkTreeView.
12793  * @x: The x position to be identified (relative to bin_window).
12794  * @y: The y position to be identified (relative to bin_window).
12795  * @path: (out) (allow-none): A pointer to a #GtkTreePath pointer to be filled in, or %NULL
12796  * @column: (out) (allow-none): A pointer to a #GtkTreeViewColumn pointer to be filled in, or %NULL
12797  * @cell_x: (out) (allow-none): A pointer where the X coordinate relative to the cell can be placed, or %NULL
12798  * @cell_y: (out) (allow-none): A pointer where the Y coordinate relative to the cell can be placed, or %NULL
12799  *
12800  * Finds the path at the point (@x, @y), relative to bin_window coordinates
12801  * (please see gtk_tree_view_get_bin_window()).
12802  * That is, @x and @y are relative to an events coordinates. @x and @y must
12803  * come from an event on the @tree_view only where <literal>event->window ==
12804  * gtk_tree_view_get_bin_window (<!-- -->)</literal>. It is primarily for
12805  * things like popup menus. If @path is non-%NULL, then it will be filled
12806  * with the #GtkTreePath at that point.  This path should be freed with
12807  * gtk_tree_path_free().  If @column is non-%NULL, then it will be filled
12808  * with the column at that point.  @cell_x and @cell_y return the coordinates
12809  * relative to the cell background (i.e. the @background_area passed to
12810  * gtk_cell_renderer_render()).  This function is only meaningful if
12811  * @tree_view is realized.  Therefore this function will always return %FALSE
12812  * if @tree_view is not realized or does not have a model.
12813  *
12814  * For converting widget coordinates (eg. the ones you get from
12815  * GtkWidget::query-tooltip), please see
12816  * gtk_tree_view_convert_widget_to_bin_window_coords().
12817  *
12818  * Return value: %TRUE if a row exists at that coordinate.
12819  **/
12820 gboolean
12821 gtk_tree_view_get_path_at_pos (GtkTreeView        *tree_view,
12822                                gint                x,
12823                                gint                y,
12824                                GtkTreePath       **path,
12825                                GtkTreeViewColumn **column,
12826                                gint               *cell_x,
12827                                gint               *cell_y)
12828 {
12829   GtkRBTree *tree;
12830   GtkRBNode *node;
12831   gint y_offset;
12832
12833   g_return_val_if_fail (tree_view != NULL, FALSE);
12834
12835   if (path)
12836     *path = NULL;
12837   if (column)
12838     *column = NULL;
12839
12840   if (tree_view->priv->bin_window == NULL)
12841     return FALSE;
12842
12843   if (tree_view->priv->tree == NULL)
12844     return FALSE;
12845
12846   if (x > tree_view->priv->hadjustment->upper)
12847     return FALSE;
12848
12849   if (x < 0 || y < 0)
12850     return FALSE;
12851
12852   if (column || cell_x)
12853     {
12854       GtkTreeViewColumn *tmp_column;
12855       GtkTreeViewColumn *last_column = NULL;
12856       GList *list;
12857       gint remaining_x = x;
12858       gboolean found = FALSE;
12859       gboolean rtl;
12860
12861       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
12862       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
12863            list;
12864            list = (rtl ? list->prev : list->next))
12865         {
12866           tmp_column = list->data;
12867
12868           if (tmp_column->visible == FALSE)
12869             continue;
12870
12871           last_column = tmp_column;
12872           if (remaining_x <= tmp_column->width)
12873             {
12874               found = TRUE;
12875
12876               if (column)
12877                 *column = tmp_column;
12878
12879               if (cell_x)
12880                 *cell_x = remaining_x;
12881
12882               break;
12883             }
12884           remaining_x -= tmp_column->width;
12885         }
12886
12887       /* If found is FALSE and there is a last_column, then it the remainder
12888        * space is in that area
12889        */
12890       if (!found)
12891         {
12892           if (last_column)
12893             {
12894               if (column)
12895                 *column = last_column;
12896               
12897               if (cell_x)
12898                 *cell_x = last_column->width + remaining_x;
12899             }
12900           else
12901             {
12902               return FALSE;
12903             }
12904         }
12905     }
12906
12907   y_offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
12908                                       TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, y),
12909                                       &tree, &node);
12910
12911   if (tree == NULL)
12912     return FALSE;
12913
12914   if (cell_y)
12915     *cell_y = y_offset;
12916
12917   if (path)
12918     *path = _gtk_tree_view_find_path (tree_view, tree, node);
12919
12920   return TRUE;
12921 }
12922
12923
12924 /**
12925  * gtk_tree_view_get_cell_area:
12926  * @tree_view: a #GtkTreeView
12927  * @path: (allow-none): a #GtkTreePath for the row, or %NULL to get only horizontal coordinates
12928  * @column: (allow-none): a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordinates
12929  * @rect: rectangle to fill with cell rect
12930  *
12931  * Fills the bounding rectangle in bin_window coordinates for the cell at the
12932  * row specified by @path and the column specified by @column.  If @path is
12933  * %NULL, or points to a path not currently displayed, the @y and @height fields
12934  * of the rectangle will be filled with 0. If @column is %NULL, the @x and @width
12935  * fields will be filled with 0.  The sum of all cell rects does not cover the
12936  * entire tree; there are extra pixels in between rows, for example. The
12937  * returned rectangle is equivalent to the @cell_area passed to
12938  * gtk_cell_renderer_render().  This function is only valid if @tree_view is
12939  * realized.
12940  **/
12941 void
12942 gtk_tree_view_get_cell_area (GtkTreeView        *tree_view,
12943                              GtkTreePath        *path,
12944                              GtkTreeViewColumn  *column,
12945                              GdkRectangle       *rect)
12946 {
12947   GtkRBTree *tree = NULL;
12948   GtkRBNode *node = NULL;
12949   gint vertical_separator;
12950   gint horizontal_separator;
12951
12952   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12953   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
12954   g_return_if_fail (rect != NULL);
12955   g_return_if_fail (!column || column->tree_view == (GtkWidget *) tree_view);
12956   g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (tree_view)));
12957
12958   gtk_widget_style_get (GTK_WIDGET (tree_view),
12959                         "vertical-separator", &vertical_separator,
12960                         "horizontal-separator", &horizontal_separator,
12961                         NULL);
12962
12963   rect->x = 0;
12964   rect->y = 0;
12965   rect->width = 0;
12966   rect->height = 0;
12967
12968   if (column)
12969     {
12970       rect->x = column->button->allocation.x + horizontal_separator/2;
12971       rect->width = column->button->allocation.width - horizontal_separator;
12972     }
12973
12974   if (path)
12975     {
12976       gboolean ret = _gtk_tree_view_find_node (tree_view, path, &tree, &node);
12977
12978       /* Get vertical coords */
12979       if ((!ret && tree == NULL) || ret)
12980         return;
12981
12982       rect->y = CELL_FIRST_PIXEL (tree_view, tree, node, vertical_separator);
12983       rect->height = MAX (CELL_HEIGHT (node, vertical_separator), tree_view->priv->expander_size - vertical_separator);
12984
12985       if (column &&
12986           gtk_tree_view_is_expander_column (tree_view, column))
12987         {
12988           gint depth = gtk_tree_path_get_depth (path);
12989           gboolean rtl;
12990
12991           rtl = gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL;
12992
12993           if (!rtl)
12994             rect->x += (depth - 1) * tree_view->priv->level_indentation;
12995           rect->width -= (depth - 1) * tree_view->priv->level_indentation;
12996
12997           if (TREE_VIEW_DRAW_EXPANDERS (tree_view))
12998             {
12999               if (!rtl)
13000                 rect->x += depth * tree_view->priv->expander_size;
13001               rect->width -= depth * tree_view->priv->expander_size;
13002             }
13003
13004           rect->width = MAX (rect->width, 0);
13005         }
13006     }
13007 }
13008
13009 /**
13010  * gtk_tree_view_get_background_area:
13011  * @tree_view: a #GtkTreeView
13012  * @path: (allow-none): a #GtkTreePath for the row, or %NULL to get only horizontal coordinates
13013  * @column: (allow-none): a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordiantes
13014  * @rect: rectangle to fill with cell background rect
13015  *
13016  * Fills the bounding rectangle in bin_window coordinates for the cell at the
13017  * row specified by @path and the column specified by @column.  If @path is
13018  * %NULL, or points to a node not found in the tree, the @y and @height fields of
13019  * the rectangle will be filled with 0. If @column is %NULL, the @x and @width
13020  * fields will be filled with 0.  The returned rectangle is equivalent to the
13021  * @background_area passed to gtk_cell_renderer_render().  These background
13022  * areas tile to cover the entire bin window.  Contrast with the @cell_area,
13023  * returned by gtk_tree_view_get_cell_area(), which returns only the cell
13024  * itself, excluding surrounding borders and the tree expander area.
13025  *
13026  **/
13027 void
13028 gtk_tree_view_get_background_area (GtkTreeView        *tree_view,
13029                                    GtkTreePath        *path,
13030                                    GtkTreeViewColumn  *column,
13031                                    GdkRectangle       *rect)
13032 {
13033   GtkRBTree *tree = NULL;
13034   GtkRBNode *node = NULL;
13035
13036   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13037   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
13038   g_return_if_fail (rect != NULL);
13039
13040   rect->x = 0;
13041   rect->y = 0;
13042   rect->width = 0;
13043   rect->height = 0;
13044
13045   if (path)
13046     {
13047       /* Get vertical coords */
13048
13049       if (!_gtk_tree_view_find_node (tree_view, path, &tree, &node) &&
13050           tree == NULL)
13051         return;
13052
13053       rect->y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
13054
13055       rect->height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
13056     }
13057
13058   if (column)
13059     {
13060       gint x2 = 0;
13061
13062       gtk_tree_view_get_background_xrange (tree_view, tree, column, &rect->x, &x2);
13063       rect->width = x2 - rect->x;
13064     }
13065 }
13066
13067 /**
13068  * gtk_tree_view_get_visible_rect:
13069  * @tree_view: a #GtkTreeView
13070  * @visible_rect: rectangle to fill
13071  *
13072  * Fills @visible_rect with the currently-visible region of the
13073  * buffer, in tree coordinates. Convert to bin_window coordinates with
13074  * gtk_tree_view_convert_tree_to_bin_window_coords().
13075  * Tree coordinates start at 0,0 for row 0 of the tree, and cover the entire
13076  * scrollable area of the tree.
13077  **/
13078 void
13079 gtk_tree_view_get_visible_rect (GtkTreeView  *tree_view,
13080                                 GdkRectangle *visible_rect)
13081 {
13082   GtkWidget *widget;
13083
13084   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13085
13086   widget = GTK_WIDGET (tree_view);
13087
13088   if (visible_rect)
13089     {
13090       visible_rect->x = tree_view->priv->hadjustment->value;
13091       visible_rect->y = tree_view->priv->vadjustment->value;
13092       visible_rect->width = widget->allocation.width;
13093       visible_rect->height = widget->allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view);
13094     }
13095 }
13096
13097 /**
13098  * gtk_tree_view_convert_widget_to_tree_coords:
13099  * @tree_view: a #GtkTreeView
13100  * @wx: X coordinate relative to the widget
13101  * @wy: Y coordinate relative to the widget
13102  * @tx: return location for tree X coordinate
13103  * @ty: return location for tree Y coordinate
13104  *
13105  * Converts widget coordinates to coordinates for the
13106  * tree (the full scrollable area of the tree).
13107  *
13108  * Since: 2.12
13109  **/
13110 void
13111 gtk_tree_view_convert_widget_to_tree_coords (GtkTreeView *tree_view,
13112                                              gint         wx,
13113                                              gint         wy,
13114                                              gint        *tx,
13115                                              gint        *ty)
13116 {
13117   gint x, y;
13118
13119   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13120
13121   gtk_tree_view_convert_widget_to_bin_window_coords (tree_view,
13122                                                      wx, wy,
13123                                                      &x, &y);
13124   gtk_tree_view_convert_bin_window_to_tree_coords (tree_view,
13125                                                    x, y,
13126                                                    tx, ty);
13127 }
13128
13129 /**
13130  * gtk_tree_view_convert_tree_to_widget_coords:
13131  * @tree_view: a #GtkTreeView
13132  * @tx: X coordinate relative to the tree
13133  * @ty: Y coordinate relative to the tree
13134  * @wx: return location for widget X coordinate
13135  * @wy: return location for widget Y coordinate
13136  *
13137  * Converts tree coordinates (coordinates in full scrollable area of the tree)
13138  * to widget coordinates.
13139  *
13140  * Since: 2.12
13141  **/
13142 void
13143 gtk_tree_view_convert_tree_to_widget_coords (GtkTreeView *tree_view,
13144                                              gint         tx,
13145                                              gint         ty,
13146                                              gint        *wx,
13147                                              gint        *wy)
13148 {
13149   gint x, y;
13150
13151   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13152
13153   gtk_tree_view_convert_tree_to_bin_window_coords (tree_view,
13154                                                    tx, ty,
13155                                                    &x, &y);
13156   gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
13157                                                      x, y,
13158                                                      wx, wy);
13159 }
13160
13161 /**
13162  * gtk_tree_view_convert_widget_to_bin_window_coords:
13163  * @tree_view: a #GtkTreeView
13164  * @wx: X coordinate relative to the widget
13165  * @wy: Y coordinate relative to the widget
13166  * @bx: return location for bin_window X coordinate
13167  * @by: return location for bin_window Y coordinate
13168  *
13169  * Converts widget coordinates to coordinates for the bin_window
13170  * (see gtk_tree_view_get_bin_window()).
13171  *
13172  * Since: 2.12
13173  **/
13174 void
13175 gtk_tree_view_convert_widget_to_bin_window_coords (GtkTreeView *tree_view,
13176                                                    gint         wx,
13177                                                    gint         wy,
13178                                                    gint        *bx,
13179                                                    gint        *by)
13180 {
13181   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13182
13183   if (bx)
13184     *bx = wx + tree_view->priv->hadjustment->value;
13185   if (by)
13186     *by = wy - TREE_VIEW_HEADER_HEIGHT (tree_view);
13187 }
13188
13189 /**
13190  * gtk_tree_view_convert_bin_window_to_widget_coords:
13191  * @tree_view: a #GtkTreeView
13192  * @bx: bin_window X coordinate
13193  * @by: bin_window Y coordinate
13194  * @wx: return location for widget X coordinate
13195  * @wy: return location for widget Y coordinate
13196  *
13197  * Converts bin_window coordinates (see gtk_tree_view_get_bin_window())
13198  * to widget relative coordinates.
13199  *
13200  * Since: 2.12
13201  **/
13202 void
13203 gtk_tree_view_convert_bin_window_to_widget_coords (GtkTreeView *tree_view,
13204                                                    gint         bx,
13205                                                    gint         by,
13206                                                    gint        *wx,
13207                                                    gint        *wy)
13208 {
13209   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13210
13211   if (wx)
13212     *wx = bx - tree_view->priv->hadjustment->value;
13213   if (wy)
13214     *wy = by + TREE_VIEW_HEADER_HEIGHT (tree_view);
13215 }
13216
13217 /**
13218  * gtk_tree_view_convert_tree_to_bin_window_coords:
13219  * @tree_view: a #GtkTreeView
13220  * @tx: tree X coordinate
13221  * @ty: tree Y coordinate
13222  * @bx: return location for X coordinate relative to bin_window
13223  * @by: return location for Y coordinate relative to bin_window
13224  *
13225  * Converts tree coordinates (coordinates in full scrollable area of the tree)
13226  * to bin_window coordinates.
13227  *
13228  * Since: 2.12
13229  **/
13230 void
13231 gtk_tree_view_convert_tree_to_bin_window_coords (GtkTreeView *tree_view,
13232                                                  gint         tx,
13233                                                  gint         ty,
13234                                                  gint        *bx,
13235                                                  gint        *by)
13236 {
13237   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13238
13239   if (bx)
13240     *bx = tx;
13241   if (by)
13242     *by = ty - tree_view->priv->dy;
13243 }
13244
13245 /**
13246  * gtk_tree_view_convert_bin_window_to_tree_coords:
13247  * @tree_view: a #GtkTreeView
13248  * @bx: X coordinate relative to bin_window
13249  * @by: Y coordinate relative to bin_window
13250  * @tx: return location for tree X coordinate
13251  * @ty: return location for tree Y coordinate
13252  *
13253  * Converts bin_window coordinates to coordinates for the
13254  * tree (the full scrollable area of the tree).
13255  *
13256  * Since: 2.12
13257  **/
13258 void
13259 gtk_tree_view_convert_bin_window_to_tree_coords (GtkTreeView *tree_view,
13260                                                  gint         bx,
13261                                                  gint         by,
13262                                                  gint        *tx,
13263                                                  gint        *ty)
13264 {
13265   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13266
13267   if (tx)
13268     *tx = bx;
13269   if (ty)
13270     *ty = by + tree_view->priv->dy;
13271 }
13272
13273
13274
13275 /**
13276  * gtk_tree_view_get_visible_range:
13277  * @tree_view: A #GtkTreeView
13278  * @start_path: (allow-none): Return location for start of region, or %NULL.
13279  * @end_path: (allow-none): Return location for end of region, or %NULL.
13280  *
13281  * Sets @start_path and @end_path to be the first and last visible path.
13282  * Note that there may be invisible paths in between.
13283  *
13284  * The paths should be freed with gtk_tree_path_free() after use.
13285  *
13286  * Returns: %TRUE, if valid paths were placed in @start_path and @end_path.
13287  *
13288  * Since: 2.8
13289  **/
13290 gboolean
13291 gtk_tree_view_get_visible_range (GtkTreeView  *tree_view,
13292                                  GtkTreePath **start_path,
13293                                  GtkTreePath **end_path)
13294 {
13295   GtkRBTree *tree;
13296   GtkRBNode *node;
13297   gboolean retval;
13298   
13299   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
13300
13301   if (!tree_view->priv->tree)
13302     return FALSE;
13303
13304   retval = TRUE;
13305
13306   if (start_path)
13307     {
13308       _gtk_rbtree_find_offset (tree_view->priv->tree,
13309                                TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, 0),
13310                                &tree, &node);
13311       if (node)
13312         *start_path = _gtk_tree_view_find_path (tree_view, tree, node);
13313       else
13314         retval = FALSE;
13315     }
13316
13317   if (end_path)
13318     {
13319       gint y;
13320
13321       if (tree_view->priv->height < tree_view->priv->vadjustment->page_size)
13322         y = tree_view->priv->height - 1;
13323       else
13324         y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, tree_view->priv->vadjustment->page_size) - 1;
13325
13326       _gtk_rbtree_find_offset (tree_view->priv->tree, y, &tree, &node);
13327       if (node)
13328         *end_path = _gtk_tree_view_find_path (tree_view, tree, node);
13329       else
13330         retval = FALSE;
13331     }
13332
13333   return retval;
13334 }
13335
13336 static void
13337 unset_reorderable (GtkTreeView *tree_view)
13338 {
13339   if (tree_view->priv->reorderable)
13340     {
13341       tree_view->priv->reorderable = FALSE;
13342       g_object_notify (G_OBJECT (tree_view), "reorderable");
13343     }
13344 }
13345
13346 /**
13347  * gtk_tree_view_enable_model_drag_source:
13348  * @tree_view: a #GtkTreeView
13349  * @start_button_mask: Mask of allowed buttons to start drag
13350  * @targets: the table of targets that the drag will support
13351  * @n_targets: the number of items in @targets
13352  * @actions: the bitmask of possible actions for a drag from this
13353  *    widget
13354  *
13355  * Turns @tree_view into a drag source for automatic DND. Calling this
13356  * method sets #GtkTreeView:reorderable to %FALSE.
13357  **/
13358 void
13359 gtk_tree_view_enable_model_drag_source (GtkTreeView              *tree_view,
13360                                         GdkModifierType           start_button_mask,
13361                                         const GtkTargetEntry     *targets,
13362                                         gint                      n_targets,
13363                                         GdkDragAction             actions)
13364 {
13365   TreeViewDragInfo *di;
13366
13367   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13368
13369   gtk_drag_source_set (GTK_WIDGET (tree_view),
13370                        0,
13371                        targets,
13372                        n_targets,
13373                        actions);
13374
13375   di = ensure_info (tree_view);
13376
13377   di->start_button_mask = start_button_mask;
13378   di->source_actions = actions;
13379   di->source_set = TRUE;
13380
13381   unset_reorderable (tree_view);
13382 }
13383
13384 /**
13385  * gtk_tree_view_enable_model_drag_dest:
13386  * @tree_view: a #GtkTreeView
13387  * @targets: the table of targets that the drag will support
13388  * @n_targets: the number of items in @targets
13389  * @actions: the bitmask of possible actions for a drag from this
13390  *    widget
13391  * 
13392  * Turns @tree_view into a drop destination for automatic DND. Calling
13393  * this method sets #GtkTreeView:reorderable to %FALSE.
13394  **/
13395 void
13396 gtk_tree_view_enable_model_drag_dest (GtkTreeView              *tree_view,
13397                                       const GtkTargetEntry     *targets,
13398                                       gint                      n_targets,
13399                                       GdkDragAction             actions)
13400 {
13401   TreeViewDragInfo *di;
13402
13403   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13404
13405   gtk_drag_dest_set (GTK_WIDGET (tree_view),
13406                      0,
13407                      targets,
13408                      n_targets,
13409                      actions);
13410
13411   di = ensure_info (tree_view);
13412   di->dest_set = TRUE;
13413
13414   unset_reorderable (tree_view);
13415 }
13416
13417 /**
13418  * gtk_tree_view_unset_rows_drag_source:
13419  * @tree_view: a #GtkTreeView
13420  *
13421  * Undoes the effect of
13422  * gtk_tree_view_enable_model_drag_source(). Calling this method sets
13423  * #GtkTreeView:reorderable to %FALSE.
13424  **/
13425 void
13426 gtk_tree_view_unset_rows_drag_source (GtkTreeView *tree_view)
13427 {
13428   TreeViewDragInfo *di;
13429
13430   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13431
13432   di = get_info (tree_view);
13433
13434   if (di)
13435     {
13436       if (di->source_set)
13437         {
13438           gtk_drag_source_unset (GTK_WIDGET (tree_view));
13439           di->source_set = FALSE;
13440         }
13441
13442       if (!di->dest_set && !di->source_set)
13443         remove_info (tree_view);
13444     }
13445   
13446   unset_reorderable (tree_view);
13447 }
13448
13449 /**
13450  * gtk_tree_view_unset_rows_drag_dest:
13451  * @tree_view: a #GtkTreeView
13452  *
13453  * Undoes the effect of
13454  * gtk_tree_view_enable_model_drag_dest(). Calling this method sets
13455  * #GtkTreeView:reorderable to %FALSE.
13456  **/
13457 void
13458 gtk_tree_view_unset_rows_drag_dest (GtkTreeView *tree_view)
13459 {
13460   TreeViewDragInfo *di;
13461
13462   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13463
13464   di = get_info (tree_view);
13465
13466   if (di)
13467     {
13468       if (di->dest_set)
13469         {
13470           gtk_drag_dest_unset (GTK_WIDGET (tree_view));
13471           di->dest_set = FALSE;
13472         }
13473
13474       if (!di->dest_set && !di->source_set)
13475         remove_info (tree_view);
13476     }
13477
13478   unset_reorderable (tree_view);
13479 }
13480
13481 /**
13482  * gtk_tree_view_set_drag_dest_row:
13483  * @tree_view: a #GtkTreeView
13484  * @path: (allow-none): The path of the row to highlight, or %NULL.
13485  * @pos: Specifies whether to drop before, after or into the row
13486  * 
13487  * Sets the row that is highlighted for feedback.
13488  **/
13489 void
13490 gtk_tree_view_set_drag_dest_row (GtkTreeView            *tree_view,
13491                                  GtkTreePath            *path,
13492                                  GtkTreeViewDropPosition pos)
13493 {
13494   GtkTreePath *current_dest;
13495
13496   /* Note; this function is exported to allow a custom DND
13497    * implementation, so it can't touch TreeViewDragInfo
13498    */
13499
13500   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13501
13502   current_dest = NULL;
13503
13504   if (tree_view->priv->drag_dest_row)
13505     {
13506       current_dest = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
13507       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
13508     }
13509
13510   /* special case a drop on an empty model */
13511   tree_view->priv->empty_view_drop = 0;
13512
13513   if (pos == GTK_TREE_VIEW_DROP_BEFORE && path
13514       && gtk_tree_path_get_depth (path) == 1
13515       && gtk_tree_path_get_indices (path)[0] == 0)
13516     {
13517       gint n_children;
13518
13519       n_children = gtk_tree_model_iter_n_children (tree_view->priv->model,
13520                                                    NULL);
13521
13522       if (!n_children)
13523         tree_view->priv->empty_view_drop = 1;
13524     }
13525
13526   tree_view->priv->drag_dest_pos = pos;
13527
13528   if (path)
13529     {
13530       tree_view->priv->drag_dest_row =
13531         gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
13532       gtk_tree_view_queue_draw_path (tree_view, path, NULL);
13533     }
13534   else
13535     tree_view->priv->drag_dest_row = NULL;
13536
13537   if (current_dest)
13538     {
13539       GtkRBTree *tree, *new_tree;
13540       GtkRBNode *node, *new_node;
13541
13542       _gtk_tree_view_find_node (tree_view, current_dest, &tree, &node);
13543       _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
13544
13545       if (tree && node)
13546         {
13547           _gtk_rbtree_next_full (tree, node, &new_tree, &new_node);
13548           if (new_tree && new_node)
13549             _gtk_tree_view_queue_draw_node (tree_view, new_tree, new_node, NULL);
13550
13551           _gtk_rbtree_prev_full (tree, node, &new_tree, &new_node);
13552           if (new_tree && new_node)
13553             _gtk_tree_view_queue_draw_node (tree_view, new_tree, new_node, NULL);
13554         }
13555       gtk_tree_path_free (current_dest);
13556     }
13557 }
13558
13559 /**
13560  * gtk_tree_view_get_drag_dest_row:
13561  * @tree_view: a #GtkTreeView
13562  * @path: (out) (allow-none): Return location for the path of the highlighted row, or %NULL.
13563  * @pos: (out) (allow-none): Return location for the drop position, or %NULL
13564  * 
13565  * Gets information about the row that is highlighted for feedback.
13566  **/
13567 void
13568 gtk_tree_view_get_drag_dest_row (GtkTreeView              *tree_view,
13569                                  GtkTreePath             **path,
13570                                  GtkTreeViewDropPosition  *pos)
13571 {
13572   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13573
13574   if (path)
13575     {
13576       if (tree_view->priv->drag_dest_row)
13577         *path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
13578       else
13579         {
13580           if (tree_view->priv->empty_view_drop)
13581             *path = gtk_tree_path_new_from_indices (0, -1);
13582           else
13583             *path = NULL;
13584         }
13585     }
13586
13587   if (pos)
13588     *pos = tree_view->priv->drag_dest_pos;
13589 }
13590
13591 /**
13592  * gtk_tree_view_get_dest_row_at_pos:
13593  * @tree_view: a #GtkTreeView
13594  * @drag_x: the position to determine the destination row for
13595  * @drag_y: the position to determine the destination row for
13596  * @path: (out) (allow-none): Return location for the path of the highlighted row, or %NULL.
13597  * @pos: (out) (allow-none): Return location for the drop position, or %NULL
13598  * 
13599  * Determines the destination row for a given position.  @drag_x and
13600  * @drag_y are expected to be in widget coordinates.  This function is only
13601  * meaningful if @tree_view is realized.  Therefore this function will always
13602  * return %FALSE if @tree_view is not realized or does not have a model.
13603  * 
13604  * Return value: whether there is a row at the given position, %TRUE if this
13605  * is indeed the case.
13606  **/
13607 gboolean
13608 gtk_tree_view_get_dest_row_at_pos (GtkTreeView             *tree_view,
13609                                    gint                     drag_x,
13610                                    gint                     drag_y,
13611                                    GtkTreePath            **path,
13612                                    GtkTreeViewDropPosition *pos)
13613 {
13614   gint cell_y;
13615   gint bin_x, bin_y;
13616   gdouble offset_into_row;
13617   gdouble third;
13618   GdkRectangle cell;
13619   GtkTreeViewColumn *column = NULL;
13620   GtkTreePath *tmp_path = NULL;
13621
13622   /* Note; this function is exported to allow a custom DND
13623    * implementation, so it can't touch TreeViewDragInfo
13624    */
13625
13626   g_return_val_if_fail (tree_view != NULL, FALSE);
13627   g_return_val_if_fail (drag_x >= 0, FALSE);
13628   g_return_val_if_fail (drag_y >= 0, FALSE);
13629
13630   if (path)
13631     *path = NULL;
13632
13633   if (tree_view->priv->bin_window == NULL)
13634     return FALSE;
13635
13636   if (tree_view->priv->tree == NULL)
13637     return FALSE;
13638
13639   /* If in the top third of a row, we drop before that row; if
13640    * in the bottom third, drop after that row; if in the middle,
13641    * and the row has children, drop into the row.
13642    */
13643   gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, drag_x, drag_y,
13644                                                      &bin_x, &bin_y);
13645
13646   if (!gtk_tree_view_get_path_at_pos (tree_view,
13647                                       bin_x,
13648                                       bin_y,
13649                                       &tmp_path,
13650                                       &column,
13651                                       NULL,
13652                                       &cell_y))
13653     return FALSE;
13654
13655   gtk_tree_view_get_background_area (tree_view, tmp_path, column,
13656                                      &cell);
13657
13658   offset_into_row = cell_y;
13659
13660   if (path)
13661     *path = tmp_path;
13662   else
13663     gtk_tree_path_free (tmp_path);
13664
13665   tmp_path = NULL;
13666
13667   third = cell.height / 3.0;
13668
13669   if (pos)
13670     {
13671       if (offset_into_row < third)
13672         {
13673           *pos = GTK_TREE_VIEW_DROP_BEFORE;
13674         }
13675       else if (offset_into_row < (cell.height / 2.0))
13676         {
13677           *pos = GTK_TREE_VIEW_DROP_INTO_OR_BEFORE;
13678         }
13679       else if (offset_into_row < third * 2.0)
13680         {
13681           *pos = GTK_TREE_VIEW_DROP_INTO_OR_AFTER;
13682         }
13683       else
13684         {
13685           *pos = GTK_TREE_VIEW_DROP_AFTER;
13686         }
13687     }
13688
13689   return TRUE;
13690 }
13691
13692
13693
13694 /* KEEP IN SYNC WITH GTK_TREE_VIEW_BIN_EXPOSE */
13695 /**
13696  * gtk_tree_view_create_row_drag_icon:
13697  * @tree_view: a #GtkTreeView
13698  * @path: a #GtkTreePath in @tree_view
13699  *
13700  * Creates a #GdkPixmap representation of the row at @path.  
13701  * This image is used for a drag icon.
13702  *
13703  * Return value: a newly-allocated pixmap of the drag icon.
13704  **/
13705 GdkPixmap *
13706 gtk_tree_view_create_row_drag_icon (GtkTreeView  *tree_view,
13707                                     GtkTreePath  *path)
13708 {
13709   GtkTreeIter   iter;
13710   GtkRBTree    *tree;
13711   GtkRBNode    *node;
13712   gint cell_offset;
13713   GList *list;
13714   GdkRectangle background_area;
13715   GdkRectangle expose_area;
13716   GtkWidget *widget;
13717   gint depth;
13718   /* start drawing inside the black outline */
13719   gint x = 1, y = 1;
13720   GdkDrawable *drawable;
13721   gint bin_window_width;
13722   gboolean is_separator = FALSE;
13723   gboolean rtl;
13724
13725   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
13726   g_return_val_if_fail (path != NULL, NULL);
13727
13728   widget = GTK_WIDGET (tree_view);
13729
13730   if (!gtk_widget_get_realized (widget))
13731     return NULL;
13732
13733   depth = gtk_tree_path_get_depth (path);
13734
13735   _gtk_tree_view_find_node (tree_view,
13736                             path,
13737                             &tree,
13738                             &node);
13739
13740   if (tree == NULL)
13741     return NULL;
13742
13743   if (!gtk_tree_model_get_iter (tree_view->priv->model,
13744                                 &iter,
13745                                 path))
13746     return NULL;
13747   
13748   is_separator = row_is_separator (tree_view, &iter, NULL);
13749
13750   cell_offset = x;
13751
13752   background_area.y = y;
13753   background_area.height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
13754
13755   gdk_drawable_get_size (tree_view->priv->bin_window,
13756                          &bin_window_width, NULL);
13757
13758   drawable = gdk_pixmap_new (tree_view->priv->bin_window,
13759                              bin_window_width + 2,
13760                              background_area.height + 2,
13761                              -1);
13762
13763   expose_area.x = 0;
13764   expose_area.y = 0;
13765   expose_area.width = bin_window_width + 2;
13766   expose_area.height = background_area.height + 2;
13767
13768   gdk_draw_rectangle (drawable,
13769                       widget->style->base_gc [gtk_widget_get_state (widget)],
13770                       TRUE,
13771                       0, 0,
13772                       bin_window_width + 2,
13773                       background_area.height + 2);
13774
13775   rtl = gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL;
13776
13777   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
13778       list;
13779       list = (rtl ? list->prev : list->next))
13780     {
13781       GtkTreeViewColumn *column = list->data;
13782       GdkRectangle cell_area;
13783       gint vertical_separator;
13784
13785       if (!column->visible)
13786         continue;
13787
13788       gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, &iter,
13789                                                GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
13790                                                node->children?TRUE:FALSE);
13791
13792       background_area.x = cell_offset;
13793       background_area.width = column->width;
13794
13795       gtk_widget_style_get (widget,
13796                             "vertical-separator", &vertical_separator,
13797                             NULL);
13798
13799       cell_area = background_area;
13800
13801       cell_area.y += vertical_separator / 2;
13802       cell_area.height -= vertical_separator;
13803
13804       if (gtk_tree_view_is_expander_column (tree_view, column))
13805         {
13806           if (!rtl)
13807             cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
13808           cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
13809
13810           if (TREE_VIEW_DRAW_EXPANDERS(tree_view))
13811             {
13812               if (!rtl)
13813                 cell_area.x += depth * tree_view->priv->expander_size;
13814               cell_area.width -= depth * tree_view->priv->expander_size;
13815             }
13816         }
13817
13818       if (gtk_tree_view_column_cell_is_visible (column))
13819         {
13820           if (is_separator)
13821             gtk_paint_hline (widget->style,
13822                              drawable,
13823                              GTK_STATE_NORMAL,
13824                              &cell_area,
13825                              widget,
13826                              NULL,
13827                              cell_area.x,
13828                              cell_area.x + cell_area.width,
13829                              cell_area.y + cell_area.height / 2);
13830           else
13831             _gtk_tree_view_column_cell_render (column,
13832                                                drawable,
13833                                                &background_area,
13834                                                &cell_area,
13835                                                &expose_area,
13836                                                0);
13837         }
13838       cell_offset += column->width;
13839     }
13840
13841   gdk_draw_rectangle (drawable,
13842                       widget->style->black_gc,
13843                       FALSE,
13844                       0, 0,
13845                       bin_window_width + 1,
13846                       background_area.height + 1);
13847
13848   return drawable;
13849 }
13850
13851
13852 /**
13853  * gtk_tree_view_set_destroy_count_func:
13854  * @tree_view: A #GtkTreeView
13855  * @func: (allow-none): Function to be called when a view row is destroyed, or %NULL
13856  * @data: (allow-none): User data to be passed to @func, or %NULL
13857  * @destroy: (allow-none): Destroy notifier for @data, or %NULL
13858  *
13859  * This function should almost never be used.  It is meant for private use by
13860  * ATK for determining the number of visible children that are removed when the
13861  * user collapses a row, or a row is deleted.
13862  **/
13863 void
13864 gtk_tree_view_set_destroy_count_func (GtkTreeView             *tree_view,
13865                                       GtkTreeDestroyCountFunc  func,
13866                                       gpointer                 data,
13867                                       GDestroyNotify           destroy)
13868 {
13869   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13870
13871   if (tree_view->priv->destroy_count_destroy)
13872     tree_view->priv->destroy_count_destroy (tree_view->priv->destroy_count_data);
13873
13874   tree_view->priv->destroy_count_func = func;
13875   tree_view->priv->destroy_count_data = data;
13876   tree_view->priv->destroy_count_destroy = destroy;
13877 }
13878
13879
13880 /*
13881  * Interactive search
13882  */
13883
13884 /**
13885  * gtk_tree_view_set_enable_search:
13886  * @tree_view: A #GtkTreeView
13887  * @enable_search: %TRUE, if the user can search interactively
13888  *
13889  * If @enable_search is set, then the user can type in text to search through
13890  * the tree interactively (this is sometimes called "typeahead find").
13891  * 
13892  * Note that even if this is %FALSE, the user can still initiate a search 
13893  * using the "start-interactive-search" key binding.
13894  */
13895 void
13896 gtk_tree_view_set_enable_search (GtkTreeView *tree_view,
13897                                  gboolean     enable_search)
13898 {
13899   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13900
13901   enable_search = !!enable_search;
13902   
13903   if (tree_view->priv->enable_search != enable_search)
13904     {
13905        tree_view->priv->enable_search = enable_search;
13906        g_object_notify (G_OBJECT (tree_view), "enable-search");
13907     }
13908 }
13909
13910 /**
13911  * gtk_tree_view_get_enable_search:
13912  * @tree_view: A #GtkTreeView
13913  *
13914  * Returns whether or not the tree allows to start interactive searching 
13915  * by typing in text.
13916  *
13917  * Return value: whether or not to let the user search interactively
13918  */
13919 gboolean
13920 gtk_tree_view_get_enable_search (GtkTreeView *tree_view)
13921 {
13922   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
13923
13924   return tree_view->priv->enable_search;
13925 }
13926
13927
13928 /**
13929  * gtk_tree_view_get_search_column:
13930  * @tree_view: A #GtkTreeView
13931  *
13932  * Gets the column searched on by the interactive search code.
13933  *
13934  * Return value: the column the interactive search code searches in.
13935  */
13936 gint
13937 gtk_tree_view_get_search_column (GtkTreeView *tree_view)
13938 {
13939   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
13940
13941   return (tree_view->priv->search_column);
13942 }
13943
13944 /**
13945  * gtk_tree_view_set_search_column:
13946  * @tree_view: A #GtkTreeView
13947  * @column: the column of the model to search in, or -1 to disable searching
13948  *
13949  * Sets @column as the column where the interactive search code should
13950  * search in for the current model. 
13951  * 
13952  * If the search column is set, users can use the "start-interactive-search"
13953  * key binding to bring up search popup. The enable-search property controls
13954  * whether simply typing text will also start an interactive search.
13955  *
13956  * Note that @column refers to a column of the current model. The search 
13957  * column is reset to -1 when the model is changed.
13958  */
13959 void
13960 gtk_tree_view_set_search_column (GtkTreeView *tree_view,
13961                                  gint         column)
13962 {
13963   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13964   g_return_if_fail (column >= -1);
13965
13966   if (tree_view->priv->search_column == column)
13967     return;
13968
13969   tree_view->priv->search_column = column;
13970   g_object_notify (G_OBJECT (tree_view), "search-column");
13971 }
13972
13973 /**
13974  * gtk_tree_view_get_search_equal_func:
13975  * @tree_view: A #GtkTreeView
13976  *
13977  * Returns the compare function currently in use.
13978  *
13979  * Return value: the currently used compare function for the search code.
13980  */
13981
13982 GtkTreeViewSearchEqualFunc
13983 gtk_tree_view_get_search_equal_func (GtkTreeView *tree_view)
13984 {
13985   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
13986
13987   return tree_view->priv->search_equal_func;
13988 }
13989
13990 /**
13991  * gtk_tree_view_set_search_equal_func:
13992  * @tree_view: A #GtkTreeView
13993  * @search_equal_func: the compare function to use during the search
13994  * @search_user_data: (allow-none): user data to pass to @search_equal_func, or %NULL
13995  * @search_destroy: (allow-none): Destroy notifier for @search_user_data, or %NULL
13996  *
13997  * Sets the compare function for the interactive search capabilities; note
13998  * that somewhat like strcmp() returning 0 for equality
13999  * #GtkTreeViewSearchEqualFunc returns %FALSE on matches.
14000  **/
14001 void
14002 gtk_tree_view_set_search_equal_func (GtkTreeView                *tree_view,
14003                                      GtkTreeViewSearchEqualFunc  search_equal_func,
14004                                      gpointer                    search_user_data,
14005                                      GDestroyNotify              search_destroy)
14006 {
14007   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14008   g_return_if_fail (search_equal_func != NULL);
14009
14010   if (tree_view->priv->search_destroy)
14011     tree_view->priv->search_destroy (tree_view->priv->search_user_data);
14012
14013   tree_view->priv->search_equal_func = search_equal_func;
14014   tree_view->priv->search_user_data = search_user_data;
14015   tree_view->priv->search_destroy = search_destroy;
14016   if (tree_view->priv->search_equal_func == NULL)
14017     tree_view->priv->search_equal_func = gtk_tree_view_search_equal_func;
14018 }
14019
14020 /**
14021  * gtk_tree_view_get_search_entry:
14022  * @tree_view: A #GtkTreeView
14023  *
14024  * Returns the #GtkEntry which is currently in use as interactive search
14025  * entry for @tree_view.  In case the built-in entry is being used, %NULL
14026  * will be returned.
14027  *
14028  * Return value: the entry currently in use as search entry.
14029  *
14030  * Since: 2.10
14031  */
14032 GtkEntry *
14033 gtk_tree_view_get_search_entry (GtkTreeView *tree_view)
14034 {
14035   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14036
14037   if (tree_view->priv->search_custom_entry_set)
14038     return GTK_ENTRY (tree_view->priv->search_entry);
14039
14040   return NULL;
14041 }
14042
14043 /**
14044  * gtk_tree_view_set_search_entry:
14045  * @tree_view: A #GtkTreeView
14046  * @entry: (allow-none): the entry the interactive search code of @tree_view should use or %NULL
14047  *
14048  * Sets the entry which the interactive search code will use for this
14049  * @tree_view.  This is useful when you want to provide a search entry
14050  * in our interface at all time at a fixed position.  Passing %NULL for
14051  * @entry will make the interactive search code use the built-in popup
14052  * entry again.
14053  *
14054  * Since: 2.10
14055  */
14056 void
14057 gtk_tree_view_set_search_entry (GtkTreeView *tree_view,
14058                                 GtkEntry    *entry)
14059 {
14060   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14061   g_return_if_fail (entry == NULL || GTK_IS_ENTRY (entry));
14062
14063   if (tree_view->priv->search_custom_entry_set)
14064     {
14065       if (tree_view->priv->search_entry_changed_id)
14066         {
14067           g_signal_handler_disconnect (tree_view->priv->search_entry,
14068                                        tree_view->priv->search_entry_changed_id);
14069           tree_view->priv->search_entry_changed_id = 0;
14070         }
14071       g_signal_handlers_disconnect_by_func (tree_view->priv->search_entry,
14072                                             G_CALLBACK (gtk_tree_view_search_key_press_event),
14073                                             tree_view);
14074
14075       g_object_unref (tree_view->priv->search_entry);
14076     }
14077   else if (tree_view->priv->search_window)
14078     {
14079       gtk_widget_destroy (tree_view->priv->search_window);
14080
14081       tree_view->priv->search_window = NULL;
14082     }
14083
14084   if (entry)
14085     {
14086       tree_view->priv->search_entry = g_object_ref (entry);
14087       tree_view->priv->search_custom_entry_set = TRUE;
14088
14089       if (tree_view->priv->search_entry_changed_id == 0)
14090         {
14091           tree_view->priv->search_entry_changed_id =
14092             g_signal_connect (tree_view->priv->search_entry, "changed",
14093                               G_CALLBACK (gtk_tree_view_search_init),
14094                               tree_view);
14095         }
14096       
14097         g_signal_connect (tree_view->priv->search_entry, "key-press-event",
14098                           G_CALLBACK (gtk_tree_view_search_key_press_event),
14099                           tree_view);
14100
14101         gtk_tree_view_search_init (tree_view->priv->search_entry, tree_view);
14102     }
14103   else
14104     {
14105       tree_view->priv->search_entry = NULL;
14106       tree_view->priv->search_custom_entry_set = FALSE;
14107     }
14108 }
14109
14110 /**
14111  * gtk_tree_view_set_search_position_func:
14112  * @tree_view: A #GtkTreeView
14113  * @func: (allow-none): the function to use to position the search dialog, or %NULL
14114  *    to use the default search position function
14115  * @data: (allow-none): user data to pass to @func, or %NULL
14116  * @destroy: (allow-none): Destroy notifier for @data, or %NULL
14117  *
14118  * Sets the function to use when positioning the search dialog.
14119  *
14120  * Since: 2.10
14121  **/
14122 void
14123 gtk_tree_view_set_search_position_func (GtkTreeView                   *tree_view,
14124                                         GtkTreeViewSearchPositionFunc  func,
14125                                         gpointer                       user_data,
14126                                         GDestroyNotify                 destroy)
14127 {
14128   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14129
14130   if (tree_view->priv->search_position_destroy)
14131     tree_view->priv->search_position_destroy (tree_view->priv->search_position_user_data);
14132
14133   tree_view->priv->search_position_func = func;
14134   tree_view->priv->search_position_user_data = user_data;
14135   tree_view->priv->search_position_destroy = destroy;
14136   if (tree_view->priv->search_position_func == NULL)
14137     tree_view->priv->search_position_func = gtk_tree_view_search_position_func;
14138 }
14139
14140 /**
14141  * gtk_tree_view_get_search_position_func:
14142  * @tree_view: A #GtkTreeView
14143  *
14144  * Returns the positioning function currently in use.
14145  *
14146  * Return value: the currently used function for positioning the search dialog.
14147  *
14148  * Since: 2.10
14149  */
14150 GtkTreeViewSearchPositionFunc
14151 gtk_tree_view_get_search_position_func (GtkTreeView *tree_view)
14152 {
14153   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14154
14155   return tree_view->priv->search_position_func;
14156 }
14157
14158
14159 static void
14160 gtk_tree_view_search_dialog_hide (GtkWidget   *search_dialog,
14161                                   GtkTreeView *tree_view,
14162                                   GdkDevice   *device)
14163 {
14164   if (tree_view->priv->disable_popdown)
14165     return;
14166
14167   if (tree_view->priv->search_entry_changed_id)
14168     {
14169       g_signal_handler_disconnect (tree_view->priv->search_entry,
14170                                    tree_view->priv->search_entry_changed_id);
14171       tree_view->priv->search_entry_changed_id = 0;
14172     }
14173   if (tree_view->priv->typeselect_flush_timeout)
14174     {
14175       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14176       tree_view->priv->typeselect_flush_timeout = 0;
14177     }
14178         
14179   if (gtk_widget_get_visible (search_dialog))
14180     {
14181       /* send focus-in event */
14182       send_focus_change (GTK_WIDGET (tree_view->priv->search_entry), device, FALSE);
14183       gtk_widget_hide (search_dialog);
14184       gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
14185       send_focus_change (GTK_WIDGET (tree_view), device, TRUE);
14186     }
14187 }
14188
14189 static void
14190 gtk_tree_view_search_position_func (GtkTreeView *tree_view,
14191                                     GtkWidget   *search_dialog,
14192                                     gpointer     user_data)
14193 {
14194   gint x, y;
14195   gint tree_x, tree_y;
14196   gint tree_width, tree_height;
14197   GdkWindow *tree_window = GTK_WIDGET (tree_view)->window;
14198   GdkScreen *screen = gdk_drawable_get_screen (tree_window);
14199   GtkRequisition requisition;
14200   gint monitor_num;
14201   GdkRectangle monitor;
14202
14203   monitor_num = gdk_screen_get_monitor_at_window (screen, tree_window);
14204   gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
14205
14206   gtk_widget_realize (search_dialog);
14207
14208   gdk_window_get_origin (tree_window, &tree_x, &tree_y);
14209   gdk_drawable_get_size (tree_window,
14210                          &tree_width,
14211                          &tree_height);
14212   gtk_widget_size_request (search_dialog, &requisition);
14213
14214   if (tree_x + tree_width > gdk_screen_get_width (screen))
14215     x = gdk_screen_get_width (screen) - requisition.width;
14216   else if (tree_x + tree_width - requisition.width < 0)
14217     x = 0;
14218   else
14219     x = tree_x + tree_width - requisition.width;
14220
14221   if (tree_y + tree_height + requisition.height > gdk_screen_get_height (screen))
14222     y = gdk_screen_get_height (screen) - requisition.height;
14223   else if (tree_y + tree_height < 0) /* isn't really possible ... */
14224     y = 0;
14225   else
14226     y = tree_y + tree_height;
14227
14228   gtk_window_move (GTK_WINDOW (search_dialog), x, y);
14229 }
14230
14231 static void
14232 gtk_tree_view_search_disable_popdown (GtkEntry *entry,
14233                                       GtkMenu  *menu,
14234                                       gpointer  data)
14235 {
14236   GtkTreeView *tree_view = (GtkTreeView *)data;
14237
14238   tree_view->priv->disable_popdown = 1;
14239   g_signal_connect (menu, "hide",
14240                     G_CALLBACK (gtk_tree_view_search_enable_popdown), data);
14241 }
14242
14243 /* Because we're visible but offscreen, we just set a flag in the preedit
14244  * callback.
14245  */
14246 static void
14247 gtk_tree_view_search_preedit_changed (GtkIMContext *im_context,
14248                                       GtkTreeView  *tree_view)
14249 {
14250   tree_view->priv->imcontext_changed = 1;
14251   if (tree_view->priv->typeselect_flush_timeout)
14252     {
14253       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14254       tree_view->priv->typeselect_flush_timeout =
14255         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
14256                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
14257                        tree_view);
14258     }
14259
14260 }
14261
14262 static void
14263 gtk_tree_view_search_activate (GtkEntry    *entry,
14264                                GtkTreeView *tree_view)
14265 {
14266   GtkTreePath *path;
14267   GtkRBNode *node;
14268   GtkRBTree *tree;
14269
14270   gtk_tree_view_search_dialog_hide (tree_view->priv->search_window,
14271                                     tree_view,
14272                                     gtk_get_current_event_device ());
14273
14274   /* If we have a row selected and it's the cursor row, we activate
14275    * the row XXX */
14276   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
14277     {
14278       path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
14279       
14280       _gtk_tree_view_find_node (tree_view, path, &tree, &node);
14281       
14282       if (node && GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
14283         gtk_tree_view_row_activated (tree_view, path, tree_view->priv->focus_column);
14284       
14285       gtk_tree_path_free (path);
14286     }
14287 }
14288
14289 static gboolean
14290 gtk_tree_view_real_search_enable_popdown (gpointer data)
14291 {
14292   GtkTreeView *tree_view = (GtkTreeView *)data;
14293
14294   tree_view->priv->disable_popdown = 0;
14295
14296   return FALSE;
14297 }
14298
14299 static void
14300 gtk_tree_view_search_enable_popdown (GtkWidget *widget,
14301                                      gpointer   data)
14302 {
14303   gdk_threads_add_timeout_full (G_PRIORITY_HIGH, 200, gtk_tree_view_real_search_enable_popdown, g_object_ref (data), g_object_unref);
14304 }
14305
14306 static gboolean
14307 gtk_tree_view_search_delete_event (GtkWidget *widget,
14308                                    GdkEventAny *event,
14309                                    GtkTreeView *tree_view)
14310 {
14311   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
14312
14313   gtk_tree_view_search_dialog_hide (widget, tree_view, NULL);
14314
14315   return TRUE;
14316 }
14317
14318 static gboolean
14319 gtk_tree_view_search_button_press_event (GtkWidget *widget,
14320                                          GdkEventButton *event,
14321                                          GtkTreeView *tree_view)
14322 {
14323   GdkDevice *keyb_device;
14324
14325   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
14326
14327   keyb_device = gdk_device_get_associated_device (event->device);
14328   gtk_tree_view_search_dialog_hide (widget, tree_view, keyb_device);
14329
14330   if (event->window == tree_view->priv->bin_window)
14331     gtk_tree_view_button_press (GTK_WIDGET (tree_view), event);
14332
14333   return TRUE;
14334 }
14335
14336 static gboolean
14337 gtk_tree_view_search_scroll_event (GtkWidget *widget,
14338                                    GdkEventScroll *event,
14339                                    GtkTreeView *tree_view)
14340 {
14341   gboolean retval = FALSE;
14342
14343   if (event->direction == GDK_SCROLL_UP)
14344     {
14345       gtk_tree_view_search_move (widget, tree_view, TRUE);
14346       retval = TRUE;
14347     }
14348   else if (event->direction == GDK_SCROLL_DOWN)
14349     {
14350       gtk_tree_view_search_move (widget, tree_view, FALSE);
14351       retval = TRUE;
14352     }
14353
14354   /* renew the flush timeout */
14355   if (retval && tree_view->priv->typeselect_flush_timeout
14356       && !tree_view->priv->search_custom_entry_set)
14357     {
14358       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14359       tree_view->priv->typeselect_flush_timeout =
14360         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
14361                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
14362                        tree_view);
14363     }
14364
14365   return retval;
14366 }
14367
14368 static gboolean
14369 gtk_tree_view_search_key_press_event (GtkWidget *widget,
14370                                       GdkEventKey *event,
14371                                       GtkTreeView *tree_view)
14372 {
14373   gboolean retval = FALSE;
14374
14375   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
14376   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
14377
14378   /* close window and cancel the search */
14379   if (!tree_view->priv->search_custom_entry_set
14380       && (event->keyval == GDK_Escape ||
14381           event->keyval == GDK_Tab ||
14382             event->keyval == GDK_KP_Tab ||
14383             event->keyval == GDK_ISO_Left_Tab))
14384     {
14385       gtk_tree_view_search_dialog_hide (widget, tree_view,
14386                                         gdk_event_get_device ((GdkEvent *) event));
14387       return TRUE;
14388     }
14389
14390   /* select previous matching iter */
14391   if (event->keyval == GDK_Up || event->keyval == GDK_KP_Up)
14392     {
14393       if (!gtk_tree_view_search_move (widget, tree_view, TRUE))
14394         gtk_widget_error_bell (widget);
14395
14396       retval = TRUE;
14397     }
14398
14399   if (((event->state & (GTK_DEFAULT_ACCEL_MOD_MASK | GDK_SHIFT_MASK)) == (GTK_DEFAULT_ACCEL_MOD_MASK | GDK_SHIFT_MASK))
14400       && (event->keyval == GDK_g || event->keyval == GDK_G))
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   /* select next matching iter */
14409   if (event->keyval == GDK_Down || event->keyval == GDK_KP_Down)
14410     {
14411       if (!gtk_tree_view_search_move (widget, tree_view, FALSE))
14412         gtk_widget_error_bell (widget);
14413
14414       retval = TRUE;
14415     }
14416
14417   if (((event->state & (GTK_DEFAULT_ACCEL_MOD_MASK | GDK_SHIFT_MASK)) == GTK_DEFAULT_ACCEL_MOD_MASK)
14418       && (event->keyval == GDK_g || event->keyval == GDK_G))
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   /* renew the flush timeout */
14427   if (retval && tree_view->priv->typeselect_flush_timeout
14428       && !tree_view->priv->search_custom_entry_set)
14429     {
14430       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14431       tree_view->priv->typeselect_flush_timeout =
14432         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
14433                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
14434                        tree_view);
14435     }
14436
14437   return retval;
14438 }
14439
14440 /*  this function returns FALSE if there is a search string but
14441  *  nothing was found, and TRUE otherwise.
14442  */
14443 static gboolean
14444 gtk_tree_view_search_move (GtkWidget   *window,
14445                            GtkTreeView *tree_view,
14446                            gboolean     up)
14447 {
14448   gboolean ret;
14449   gint len;
14450   gint count = 0;
14451   const gchar *text;
14452   GtkTreeIter iter;
14453   GtkTreeModel *model;
14454   GtkTreeSelection *selection;
14455
14456   text = gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry));
14457
14458   g_return_val_if_fail (text != NULL, FALSE);
14459
14460   len = strlen (text);
14461
14462   if (up && tree_view->priv->selected_iter == 1)
14463     return strlen (text) < 1;
14464
14465   len = strlen (text);
14466
14467   if (len < 1)
14468     return TRUE;
14469
14470   model = gtk_tree_view_get_model (tree_view);
14471   selection = gtk_tree_view_get_selection (tree_view);
14472
14473   /* search */
14474   gtk_tree_selection_unselect_all (selection);
14475   if (!gtk_tree_model_get_iter_first (model, &iter))
14476     return TRUE;
14477
14478   ret = gtk_tree_view_search_iter (model, selection, &iter, text,
14479                                    &count, up?((tree_view->priv->selected_iter) - 1):((tree_view->priv->selected_iter + 1)));
14480
14481   if (ret)
14482     {
14483       /* found */
14484       tree_view->priv->selected_iter += up?(-1):(1);
14485       return TRUE;
14486     }
14487   else
14488     {
14489       /* return to old iter */
14490       count = 0;
14491       gtk_tree_model_get_iter_first (model, &iter);
14492       gtk_tree_view_search_iter (model, selection,
14493                                  &iter, text,
14494                                  &count, tree_view->priv->selected_iter);
14495       return FALSE;
14496     }
14497 }
14498
14499 static gboolean
14500 gtk_tree_view_search_equal_func (GtkTreeModel *model,
14501                                  gint          column,
14502                                  const gchar  *key,
14503                                  GtkTreeIter  *iter,
14504                                  gpointer      search_data)
14505 {
14506   gboolean retval = TRUE;
14507   const gchar *str;
14508   gchar *normalized_string;
14509   gchar *normalized_key;
14510   gchar *case_normalized_string = NULL;
14511   gchar *case_normalized_key = NULL;
14512   GValue value = {0,};
14513   GValue transformed = {0,};
14514
14515   gtk_tree_model_get_value (model, iter, column, &value);
14516
14517   g_value_init (&transformed, G_TYPE_STRING);
14518
14519   if (!g_value_transform (&value, &transformed))
14520     {
14521       g_value_unset (&value);
14522       return TRUE;
14523     }
14524
14525   g_value_unset (&value);
14526
14527   str = g_value_get_string (&transformed);
14528   if (!str)
14529     {
14530       g_value_unset (&transformed);
14531       return TRUE;
14532     }
14533
14534   normalized_string = g_utf8_normalize (str, -1, G_NORMALIZE_ALL);
14535   normalized_key = g_utf8_normalize (key, -1, G_NORMALIZE_ALL);
14536
14537   if (normalized_string && normalized_key)
14538     {
14539       case_normalized_string = g_utf8_casefold (normalized_string, -1);
14540       case_normalized_key = g_utf8_casefold (normalized_key, -1);
14541
14542       if (strncmp (case_normalized_key, case_normalized_string, strlen (case_normalized_key)) == 0)
14543         retval = FALSE;
14544     }
14545
14546   g_value_unset (&transformed);
14547   g_free (normalized_key);
14548   g_free (normalized_string);
14549   g_free (case_normalized_key);
14550   g_free (case_normalized_string);
14551
14552   return retval;
14553 }
14554
14555 static gboolean
14556 gtk_tree_view_search_iter (GtkTreeModel     *model,
14557                            GtkTreeSelection *selection,
14558                            GtkTreeIter      *iter,
14559                            const gchar      *text,
14560                            gint             *count,
14561                            gint              n)
14562 {
14563   GtkRBTree *tree = NULL;
14564   GtkRBNode *node = NULL;
14565   GtkTreePath *path;
14566
14567   GtkTreeView *tree_view = gtk_tree_selection_get_tree_view (selection);
14568
14569   path = gtk_tree_model_get_path (model, iter);
14570   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
14571
14572   do
14573     {
14574       if (! tree_view->priv->search_equal_func (model, tree_view->priv->search_column, text, iter, tree_view->priv->search_user_data))
14575         {
14576           (*count)++;
14577           if (*count == n)
14578             {
14579               gtk_tree_view_scroll_to_cell (tree_view, path, NULL,
14580                                             TRUE, 0.5, 0.0);
14581               gtk_tree_selection_select_iter (selection, iter);
14582               gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
14583
14584               if (path)
14585                 gtk_tree_path_free (path);
14586
14587               return TRUE;
14588             }
14589         }
14590
14591       if (node->children)
14592         {
14593           gboolean has_child;
14594           GtkTreeIter tmp;
14595
14596           tree = node->children;
14597           node = tree->root;
14598
14599           while (node->left != tree->nil)
14600             node = node->left;
14601
14602           tmp = *iter;
14603           has_child = gtk_tree_model_iter_children (model, iter, &tmp);
14604           gtk_tree_path_down (path);
14605
14606           /* sanity check */
14607           TREE_VIEW_INTERNAL_ASSERT (has_child, FALSE);
14608         }
14609       else
14610         {
14611           gboolean done = FALSE;
14612
14613           do
14614             {
14615               node = _gtk_rbtree_next (tree, node);
14616
14617               if (node)
14618                 {
14619                   gboolean has_next;
14620
14621                   has_next = gtk_tree_model_iter_next (model, iter);
14622
14623                   done = TRUE;
14624                   gtk_tree_path_next (path);
14625
14626                   /* sanity check */
14627                   TREE_VIEW_INTERNAL_ASSERT (has_next, FALSE);
14628                 }
14629               else
14630                 {
14631                   gboolean has_parent;
14632                   GtkTreeIter tmp_iter = *iter;
14633
14634                   node = tree->parent_node;
14635                   tree = tree->parent_tree;
14636
14637                   if (!tree)
14638                     {
14639                       if (path)
14640                         gtk_tree_path_free (path);
14641
14642                       /* we've run out of tree, done with this func */
14643                       return FALSE;
14644                     }
14645
14646                   has_parent = gtk_tree_model_iter_parent (model,
14647                                                            iter,
14648                                                            &tmp_iter);
14649                   gtk_tree_path_up (path);
14650
14651                   /* sanity check */
14652                   TREE_VIEW_INTERNAL_ASSERT (has_parent, FALSE);
14653                 }
14654             }
14655           while (!done);
14656         }
14657     }
14658   while (1);
14659
14660   return FALSE;
14661 }
14662
14663 static void
14664 gtk_tree_view_search_init (GtkWidget   *entry,
14665                            GtkTreeView *tree_view)
14666 {
14667   gint ret;
14668   gint count = 0;
14669   const gchar *text;
14670   GtkTreeIter iter;
14671   GtkTreeModel *model;
14672   GtkTreeSelection *selection;
14673
14674   g_return_if_fail (GTK_IS_ENTRY (entry));
14675   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14676
14677   text = gtk_entry_get_text (GTK_ENTRY (entry));
14678
14679   model = gtk_tree_view_get_model (tree_view);
14680   selection = gtk_tree_view_get_selection (tree_view);
14681
14682   /* search */
14683   gtk_tree_selection_unselect_all (selection);
14684   if (tree_view->priv->typeselect_flush_timeout
14685       && !tree_view->priv->search_custom_entry_set)
14686     {
14687       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14688       tree_view->priv->typeselect_flush_timeout =
14689         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
14690                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
14691                        tree_view);
14692     }
14693
14694   if (*text == '\0')
14695     return;
14696
14697   if (!gtk_tree_model_get_iter_first (model, &iter))
14698     return;
14699
14700   ret = gtk_tree_view_search_iter (model, selection,
14701                                    &iter, text,
14702                                    &count, 1);
14703
14704   if (ret)
14705     tree_view->priv->selected_iter = 1;
14706 }
14707
14708 static void
14709 gtk_tree_view_remove_widget (GtkCellEditable *cell_editable,
14710                              GtkTreeView     *tree_view)
14711 {
14712   if (tree_view->priv->edited_column == NULL)
14713     return;
14714
14715   _gtk_tree_view_column_stop_editing (tree_view->priv->edited_column);
14716   tree_view->priv->edited_column = NULL;
14717
14718   if (gtk_widget_has_focus (GTK_WIDGET (cell_editable)))
14719     gtk_widget_grab_focus (GTK_WIDGET (tree_view));
14720
14721   g_signal_handlers_disconnect_by_func (cell_editable,
14722                                         gtk_tree_view_remove_widget,
14723                                         tree_view);
14724
14725   gtk_container_remove (GTK_CONTAINER (tree_view),
14726                         GTK_WIDGET (cell_editable));  
14727
14728   /* FIXME should only redraw a single node */
14729   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
14730 }
14731
14732 static gboolean
14733 gtk_tree_view_start_editing (GtkTreeView *tree_view,
14734                              GtkTreePath *cursor_path)
14735 {
14736   GtkTreeIter iter;
14737   GdkRectangle background_area;
14738   GdkRectangle cell_area;
14739   GtkCellEditable *editable_widget = NULL;
14740   gchar *path_string;
14741   guint flags = 0; /* can be 0, as the flags are primarily for rendering */
14742   gint retval = FALSE;
14743   GtkRBTree *cursor_tree;
14744   GtkRBNode *cursor_node;
14745
14746   g_assert (tree_view->priv->focus_column);
14747
14748   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
14749     return FALSE;
14750
14751   if (_gtk_tree_view_find_node (tree_view, cursor_path, &cursor_tree, &cursor_node) ||
14752       cursor_node == NULL)
14753     return FALSE;
14754
14755   path_string = gtk_tree_path_to_string (cursor_path);
14756   gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path);
14757
14758   validate_row (tree_view, cursor_tree, cursor_node, &iter, cursor_path);
14759
14760   gtk_tree_view_column_cell_set_cell_data (tree_view->priv->focus_column,
14761                                            tree_view->priv->model,
14762                                            &iter,
14763                                            GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_PARENT),
14764                                            cursor_node->children?TRUE:FALSE);
14765   gtk_tree_view_get_background_area (tree_view,
14766                                      cursor_path,
14767                                      tree_view->priv->focus_column,
14768                                      &background_area);
14769   gtk_tree_view_get_cell_area (tree_view,
14770                                cursor_path,
14771                                tree_view->priv->focus_column,
14772                                &cell_area);
14773
14774   if (_gtk_tree_view_column_cell_event (tree_view->priv->focus_column,
14775                                         &editable_widget,
14776                                         NULL,
14777                                         path_string,
14778                                         &background_area,
14779                                         &cell_area,
14780                                         flags))
14781     {
14782       retval = TRUE;
14783       if (editable_widget != NULL)
14784         {
14785           gint left, right;
14786           GdkRectangle area;
14787           GtkCellRenderer *cell;
14788
14789           area = cell_area;
14790           cell = _gtk_tree_view_column_get_edited_cell (tree_view->priv->focus_column);
14791
14792           _gtk_tree_view_column_get_neighbor_sizes (tree_view->priv->focus_column, cell, &left, &right);
14793
14794           area.x += left;
14795           area.width -= right + left;
14796
14797           gtk_tree_view_real_start_editing (tree_view,
14798                                             tree_view->priv->focus_column,
14799                                             cursor_path,
14800                                             editable_widget,
14801                                             &area,
14802                                             NULL,
14803                                             flags);
14804         }
14805
14806     }
14807   g_free (path_string);
14808   return retval;
14809 }
14810
14811 static void
14812 gtk_tree_view_real_start_editing (GtkTreeView       *tree_view,
14813                                   GtkTreeViewColumn *column,
14814                                   GtkTreePath       *path,
14815                                   GtkCellEditable   *cell_editable,
14816                                   GdkRectangle      *cell_area,
14817                                   GdkEvent          *event,
14818                                   guint              flags)
14819 {
14820   gint pre_val = tree_view->priv->vadjustment->value;
14821   GtkRequisition requisition;
14822
14823   tree_view->priv->edited_column = column;
14824   _gtk_tree_view_column_start_editing (column, GTK_CELL_EDITABLE (cell_editable));
14825
14826   gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
14827   cell_area->y += pre_val - (int)tree_view->priv->vadjustment->value;
14828
14829   gtk_widget_size_request (GTK_WIDGET (cell_editable), &requisition);
14830
14831   GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
14832
14833   if (requisition.height < cell_area->height)
14834     {
14835       gint diff = cell_area->height - requisition.height;
14836       gtk_tree_view_put (tree_view,
14837                          GTK_WIDGET (cell_editable),
14838                          cell_area->x, cell_area->y + diff/2,
14839                          cell_area->width, requisition.height);
14840     }
14841   else
14842     {
14843       gtk_tree_view_put (tree_view,
14844                          GTK_WIDGET (cell_editable),
14845                          cell_area->x, cell_area->y,
14846                          cell_area->width, cell_area->height);
14847     }
14848
14849   gtk_cell_editable_start_editing (GTK_CELL_EDITABLE (cell_editable),
14850                                    (GdkEvent *)event);
14851
14852   gtk_widget_grab_focus (GTK_WIDGET (cell_editable));
14853   g_signal_connect (cell_editable, "remove-widget",
14854                     G_CALLBACK (gtk_tree_view_remove_widget), tree_view);
14855 }
14856
14857 static void
14858 gtk_tree_view_stop_editing (GtkTreeView *tree_view,
14859                             gboolean     cancel_editing)
14860 {
14861   GtkTreeViewColumn *column;
14862   GtkCellRenderer *cell;
14863
14864   if (tree_view->priv->edited_column == NULL)
14865     return;
14866
14867   /*
14868    * This is very evil. We need to do this, because
14869    * gtk_cell_editable_editing_done may trigger gtk_tree_view_row_changed
14870    * later on. If gtk_tree_view_row_changed notices
14871    * tree_view->priv->edited_column != NULL, it'll call
14872    * gtk_tree_view_stop_editing again. Bad things will happen then.
14873    *
14874    * Please read that again if you intend to modify anything here.
14875    */
14876
14877   column = tree_view->priv->edited_column;
14878   tree_view->priv->edited_column = NULL;
14879
14880   cell = _gtk_tree_view_column_get_edited_cell (column);
14881   gtk_cell_renderer_stop_editing (cell, cancel_editing);
14882
14883   if (!cancel_editing)
14884     gtk_cell_editable_editing_done (column->editable_widget);
14885
14886   tree_view->priv->edited_column = column;
14887
14888   gtk_cell_editable_remove_widget (column->editable_widget);
14889 }
14890
14891
14892 /**
14893  * gtk_tree_view_set_hover_selection:
14894  * @tree_view: a #GtkTreeView
14895  * @hover: %TRUE to enable hover selection mode
14896  *
14897  * Enables of disables the hover selection mode of @tree_view.
14898  * Hover selection makes the selected row follow the pointer.
14899  * Currently, this works only for the selection modes 
14900  * %GTK_SELECTION_SINGLE and %GTK_SELECTION_BROWSE.
14901  * 
14902  * Since: 2.6
14903  **/
14904 void     
14905 gtk_tree_view_set_hover_selection (GtkTreeView *tree_view,
14906                                    gboolean     hover)
14907 {
14908   hover = hover != FALSE;
14909
14910   if (hover != tree_view->priv->hover_selection)
14911     {
14912       tree_view->priv->hover_selection = hover;
14913
14914       g_object_notify (G_OBJECT (tree_view), "hover-selection");
14915     }
14916 }
14917
14918 /**
14919  * gtk_tree_view_get_hover_selection:
14920  * @tree_view: a #GtkTreeView
14921  * 
14922  * Returns whether hover selection mode is turned on for @tree_view.
14923  * 
14924  * Return value: %TRUE if @tree_view is in hover selection mode
14925  *
14926  * Since: 2.6 
14927  **/
14928 gboolean 
14929 gtk_tree_view_get_hover_selection (GtkTreeView *tree_view)
14930 {
14931   return tree_view->priv->hover_selection;
14932 }
14933
14934 /**
14935  * gtk_tree_view_set_hover_expand:
14936  * @tree_view: a #GtkTreeView
14937  * @expand: %TRUE to enable hover selection mode
14938  *
14939  * Enables of disables the hover expansion mode of @tree_view.
14940  * Hover expansion makes rows expand or collapse if the pointer 
14941  * moves over them.
14942  * 
14943  * Since: 2.6
14944  **/
14945 void     
14946 gtk_tree_view_set_hover_expand (GtkTreeView *tree_view,
14947                                 gboolean     expand)
14948 {
14949   expand = expand != FALSE;
14950
14951   if (expand != tree_view->priv->hover_expand)
14952     {
14953       tree_view->priv->hover_expand = expand;
14954
14955       g_object_notify (G_OBJECT (tree_view), "hover-expand");
14956     }
14957 }
14958
14959 /**
14960  * gtk_tree_view_get_hover_expand:
14961  * @tree_view: a #GtkTreeView
14962  * 
14963  * Returns whether hover expansion mode is turned on for @tree_view.
14964  * 
14965  * Return value: %TRUE if @tree_view is in hover expansion mode
14966  *
14967  * Since: 2.6 
14968  **/
14969 gboolean 
14970 gtk_tree_view_get_hover_expand (GtkTreeView *tree_view)
14971 {
14972   return tree_view->priv->hover_expand;
14973 }
14974
14975 /**
14976  * gtk_tree_view_set_rubber_banding:
14977  * @tree_view: a #GtkTreeView
14978  * @enable: %TRUE to enable rubber banding
14979  *
14980  * Enables or disables rubber banding in @tree_view.  If the selection mode
14981  * is #GTK_SELECTION_MULTIPLE, rubber banding will allow the user to select
14982  * multiple rows by dragging the mouse.
14983  * 
14984  * Since: 2.10
14985  **/
14986 void
14987 gtk_tree_view_set_rubber_banding (GtkTreeView *tree_view,
14988                                   gboolean     enable)
14989 {
14990   enable = enable != FALSE;
14991
14992   if (enable != tree_view->priv->rubber_banding_enable)
14993     {
14994       tree_view->priv->rubber_banding_enable = enable;
14995
14996       g_object_notify (G_OBJECT (tree_view), "rubber-banding");
14997     }
14998 }
14999
15000 /**
15001  * gtk_tree_view_get_rubber_banding:
15002  * @tree_view: a #GtkTreeView
15003  * 
15004  * Returns whether rubber banding is turned on for @tree_view.  If the
15005  * selection mode is #GTK_SELECTION_MULTIPLE, rubber banding will allow the
15006  * user to select multiple rows by dragging the mouse.
15007  * 
15008  * Return value: %TRUE if rubber banding in @tree_view is enabled.
15009  *
15010  * Since: 2.10
15011  **/
15012 gboolean
15013 gtk_tree_view_get_rubber_banding (GtkTreeView *tree_view)
15014 {
15015   return tree_view->priv->rubber_banding_enable;
15016 }
15017
15018 /**
15019  * gtk_tree_view_is_rubber_banding_active:
15020  * @tree_view: a #GtkTreeView
15021  * 
15022  * Returns whether a rubber banding operation is currently being done
15023  * in @tree_view.
15024  *
15025  * Return value: %TRUE if a rubber banding operation is currently being
15026  * done in @tree_view.
15027  *
15028  * Since: 2.12
15029  **/
15030 gboolean
15031 gtk_tree_view_is_rubber_banding_active (GtkTreeView *tree_view)
15032 {
15033   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15034
15035   if (tree_view->priv->rubber_banding_enable
15036       && tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
15037     return TRUE;
15038
15039   return FALSE;
15040 }
15041
15042 /**
15043  * gtk_tree_view_get_row_separator_func:
15044  * @tree_view: a #GtkTreeView
15045  * 
15046  * Returns the current row separator function.
15047  * 
15048  * Return value: the current row separator function.
15049  *
15050  * Since: 2.6
15051  **/
15052 GtkTreeViewRowSeparatorFunc 
15053 gtk_tree_view_get_row_separator_func (GtkTreeView *tree_view)
15054 {
15055   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
15056
15057   return tree_view->priv->row_separator_func;
15058 }
15059
15060 /**
15061  * gtk_tree_view_set_row_separator_func:
15062  * @tree_view: a #GtkTreeView
15063  * @func: a #GtkTreeViewRowSeparatorFunc
15064  * @data: (allow-none): user data to pass to @func, or %NULL
15065  * @destroy: (allow-none): destroy notifier for @data, or %NULL
15066  * 
15067  * Sets the row separator function, which is used to determine
15068  * whether a row should be drawn as a separator. If the row separator
15069  * function is %NULL, no separators are drawn. This is the default value.
15070  *
15071  * Since: 2.6
15072  **/
15073 void
15074 gtk_tree_view_set_row_separator_func (GtkTreeView                 *tree_view,
15075                                       GtkTreeViewRowSeparatorFunc  func,
15076                                       gpointer                     data,
15077                                       GDestroyNotify               destroy)
15078 {
15079   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15080
15081   if (tree_view->priv->row_separator_destroy)
15082     tree_view->priv->row_separator_destroy (tree_view->priv->row_separator_data);
15083
15084   tree_view->priv->row_separator_func = func;
15085   tree_view->priv->row_separator_data = data;
15086   tree_view->priv->row_separator_destroy = destroy;
15087
15088   /* Have the tree recalculate heights */
15089   _gtk_rbtree_mark_invalid (tree_view->priv->tree);
15090   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
15091 }
15092
15093   
15094 static void
15095 gtk_tree_view_grab_notify (GtkWidget *widget,
15096                            gboolean   was_grabbed)
15097 {
15098   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
15099
15100   tree_view->priv->in_grab = !was_grabbed;
15101
15102   if (!was_grabbed)
15103     {
15104       tree_view->priv->pressed_button = -1;
15105
15106       if (tree_view->priv->rubber_band_status)
15107         gtk_tree_view_stop_rubber_band (tree_view);
15108     }
15109 }
15110
15111 static void
15112 gtk_tree_view_state_changed (GtkWidget      *widget,
15113                              GtkStateType    previous_state)
15114 {
15115   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
15116
15117   if (gtk_widget_get_realized (widget))
15118     {
15119       gdk_window_set_back_pixmap (widget->window, NULL, FALSE);
15120       gdk_window_set_background (tree_view->priv->bin_window, &widget->style->base[widget->state]);
15121     }
15122
15123   gtk_widget_queue_draw (widget);
15124 }
15125
15126 /**
15127  * gtk_tree_view_get_grid_lines:
15128  * @tree_view: a #GtkTreeView
15129  *
15130  * Returns which grid lines are enabled in @tree_view.
15131  *
15132  * Return value: a #GtkTreeViewGridLines value indicating which grid lines
15133  * are enabled.
15134  *
15135  * Since: 2.10
15136  */
15137 GtkTreeViewGridLines
15138 gtk_tree_view_get_grid_lines (GtkTreeView *tree_view)
15139 {
15140   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
15141
15142   return tree_view->priv->grid_lines;
15143 }
15144
15145 /**
15146  * gtk_tree_view_set_grid_lines:
15147  * @tree_view: a #GtkTreeView
15148  * @grid_lines: a #GtkTreeViewGridLines value indicating which grid lines to
15149  * enable.
15150  *
15151  * Sets which grid lines to draw in @tree_view.
15152  *
15153  * Since: 2.10
15154  */
15155 void
15156 gtk_tree_view_set_grid_lines (GtkTreeView           *tree_view,
15157                               GtkTreeViewGridLines   grid_lines)
15158 {
15159   GtkTreeViewPrivate *priv;
15160   GtkWidget *widget;
15161   GtkTreeViewGridLines old_grid_lines;
15162
15163   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15164
15165   priv = tree_view->priv;
15166   widget = GTK_WIDGET (tree_view);
15167
15168   old_grid_lines = priv->grid_lines;
15169   priv->grid_lines = grid_lines;
15170   
15171   if (gtk_widget_get_realized (widget))
15172     {
15173       if (grid_lines == GTK_TREE_VIEW_GRID_LINES_NONE &&
15174           priv->grid_line_width)
15175         {
15176           priv->grid_line_width = 0;
15177         }
15178       
15179       if (grid_lines != GTK_TREE_VIEW_GRID_LINES_NONE && 
15180           !priv->grid_line_width)
15181         {
15182           gint8 *dash_list;
15183
15184           gtk_widget_style_get (widget,
15185                                 "grid-line-width", &priv->grid_line_width,
15186                                 "grid-line-pattern", (gchar *)&dash_list,
15187                                 NULL);
15188       
15189           if (dash_list)
15190             {
15191               priv->grid_line_dashes[0] = dash_list[0];
15192               if (dash_list[0])
15193                 priv->grid_line_dashes[1] = dash_list[1];
15194               
15195               g_free (dash_list);
15196             }
15197           else
15198             {
15199               priv->grid_line_dashes[0] = 1;
15200               priv->grid_line_dashes[1] = 1;
15201             }
15202         }      
15203     }
15204
15205   if (old_grid_lines != grid_lines)
15206     {
15207       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15208       
15209       g_object_notify (G_OBJECT (tree_view), "enable-grid-lines");
15210     }
15211 }
15212
15213 /**
15214  * gtk_tree_view_get_enable_tree_lines:
15215  * @tree_view: a #GtkTreeView.
15216  *
15217  * Returns whether or not tree lines are drawn in @tree_view.
15218  *
15219  * Return value: %TRUE if tree lines are drawn in @tree_view, %FALSE
15220  * otherwise.
15221  *
15222  * Since: 2.10
15223  */
15224 gboolean
15225 gtk_tree_view_get_enable_tree_lines (GtkTreeView *tree_view)
15226 {
15227   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15228
15229   return tree_view->priv->tree_lines_enabled;
15230 }
15231
15232 /**
15233  * gtk_tree_view_set_enable_tree_lines:
15234  * @tree_view: a #GtkTreeView
15235  * @enabled: %TRUE to enable tree line drawing, %FALSE otherwise.
15236  *
15237  * Sets whether to draw lines interconnecting the expanders in @tree_view.
15238  * This does not have any visible effects for lists.
15239  *
15240  * Since: 2.10
15241  */
15242 void
15243 gtk_tree_view_set_enable_tree_lines (GtkTreeView *tree_view,
15244                                      gboolean     enabled)
15245 {
15246   GtkTreeViewPrivate *priv;
15247   GtkWidget *widget;
15248   gboolean was_enabled;
15249
15250   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15251
15252   enabled = enabled != FALSE;
15253
15254   priv = tree_view->priv;
15255   widget = GTK_WIDGET (tree_view);
15256
15257   was_enabled = priv->tree_lines_enabled;
15258
15259   priv->tree_lines_enabled = enabled;
15260
15261   if (gtk_widget_get_realized (widget))
15262     {
15263       if (!enabled && priv->tree_line_width)
15264         {
15265           priv->tree_line_width = 0;
15266         }
15267       
15268       if (enabled && !priv->tree_line_width)
15269         {
15270           gint8 *dash_list;
15271           gtk_widget_style_get (widget,
15272                                 "tree-line-width", &priv->tree_line_width,
15273                                 "tree-line-pattern", (gchar *)&dash_list,
15274                                 NULL);
15275           
15276           if (dash_list)
15277             {
15278               priv->tree_line_dashes[0] = dash_list[0];
15279               if (dash_list[0])
15280                 priv->tree_line_dashes[1] = dash_list[1];
15281               
15282               g_free (dash_list);
15283             }
15284           else
15285             {
15286               priv->tree_line_dashes[0] = 1;
15287               priv->tree_line_dashes[1] = 1;
15288             }
15289         }
15290     }
15291
15292   if (was_enabled != enabled)
15293     {
15294       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15295
15296       g_object_notify (G_OBJECT (tree_view), "enable-tree-lines");
15297     }
15298 }
15299
15300
15301 /**
15302  * gtk_tree_view_set_show_expanders:
15303  * @tree_view: a #GtkTreeView
15304  * @enabled: %TRUE to enable expander drawing, %FALSE otherwise.
15305  *
15306  * Sets whether to draw and enable expanders and indent child rows in
15307  * @tree_view.  When disabled there will be no expanders visible in trees
15308  * and there will be no way to expand and collapse rows by default.  Also
15309  * note that hiding the expanders will disable the default indentation.  You
15310  * can set a custom indentation in this case using
15311  * gtk_tree_view_set_level_indentation().
15312  * This does not have any visible effects for lists.
15313  *
15314  * Since: 2.12
15315  */
15316 void
15317 gtk_tree_view_set_show_expanders (GtkTreeView *tree_view,
15318                                   gboolean     enabled)
15319 {
15320   gboolean was_enabled;
15321
15322   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15323
15324   enabled = enabled != FALSE;
15325   was_enabled = GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS);
15326
15327   if (enabled)
15328     GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS);
15329   else
15330     GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS);
15331
15332   if (enabled != was_enabled)
15333     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15334 }
15335
15336 /**
15337  * gtk_tree_view_get_show_expanders:
15338  * @tree_view: a #GtkTreeView.
15339  *
15340  * Returns whether or not expanders are drawn in @tree_view.
15341  *
15342  * Return value: %TRUE if expanders are drawn in @tree_view, %FALSE
15343  * otherwise.
15344  *
15345  * Since: 2.12
15346  */
15347 gboolean
15348 gtk_tree_view_get_show_expanders (GtkTreeView *tree_view)
15349 {
15350   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15351
15352   return GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS);
15353 }
15354
15355 /**
15356  * gtk_tree_view_set_level_indentation:
15357  * @tree_view: a #GtkTreeView
15358  * @indentation: the amount, in pixels, of extra indentation in @tree_view.
15359  *
15360  * Sets the amount of extra indentation for child levels to use in @tree_view
15361  * in addition to the default indentation.  The value should be specified in
15362  * pixels, a value of 0 disables this feature and in this case only the default
15363  * indentation will be used.
15364  * This does not have any visible effects for lists.
15365  *
15366  * Since: 2.12
15367  */
15368 void
15369 gtk_tree_view_set_level_indentation (GtkTreeView *tree_view,
15370                                      gint         indentation)
15371 {
15372   tree_view->priv->level_indentation = indentation;
15373
15374   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15375 }
15376
15377 /**
15378  * gtk_tree_view_get_level_indentation:
15379  * @tree_view: a #GtkTreeView.
15380  *
15381  * Returns the amount, in pixels, of extra indentation for child levels
15382  * in @tree_view.
15383  *
15384  * Return value: the amount of extra indentation for child levels in
15385  * @tree_view.  A return value of 0 means that this feature is disabled.
15386  *
15387  * Since: 2.12
15388  */
15389 gint
15390 gtk_tree_view_get_level_indentation (GtkTreeView *tree_view)
15391 {
15392   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
15393
15394   return tree_view->priv->level_indentation;
15395 }
15396
15397 /**
15398  * gtk_tree_view_set_tooltip_row:
15399  * @tree_view: a #GtkTreeView
15400  * @tooltip: a #GtkTooltip
15401  * @path: a #GtkTreePath
15402  *
15403  * Sets the tip area of @tooltip to be the area covered by the row at @path.
15404  * See also gtk_tree_view_set_tooltip_column() for a simpler alternative.
15405  * See also gtk_tooltip_set_tip_area().
15406  *
15407  * Since: 2.12
15408  */
15409 void
15410 gtk_tree_view_set_tooltip_row (GtkTreeView *tree_view,
15411                                GtkTooltip  *tooltip,
15412                                GtkTreePath *path)
15413 {
15414   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15415   g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
15416
15417   gtk_tree_view_set_tooltip_cell (tree_view, tooltip, path, NULL, NULL);
15418 }
15419
15420 /**
15421  * gtk_tree_view_set_tooltip_cell:
15422  * @tree_view: a #GtkTreeView
15423  * @tooltip: a #GtkTooltip
15424  * @path: (allow-none): a #GtkTreePath or %NULL
15425  * @column: (allow-none): a #GtkTreeViewColumn or %NULL
15426  * @cell: (allow-none): a #GtkCellRenderer or %NULL
15427  *
15428  * Sets the tip area of @tooltip to the area @path, @column and @cell have
15429  * in common.  For example if @path is %NULL and @column is set, the tip
15430  * area will be set to the full area covered by @column.  See also
15431  * gtk_tooltip_set_tip_area().
15432  *
15433  * Note that if @path is not specified and @cell is set and part of a column
15434  * containing the expander, the tooltip might not show and hide at the correct
15435  * position.  In such cases @path must be set to the current node under the
15436  * mouse cursor for this function to operate correctly.
15437  *
15438  * See also gtk_tree_view_set_tooltip_column() for a simpler alternative.
15439  *
15440  * Since: 2.12
15441  */
15442 void
15443 gtk_tree_view_set_tooltip_cell (GtkTreeView       *tree_view,
15444                                 GtkTooltip        *tooltip,
15445                                 GtkTreePath       *path,
15446                                 GtkTreeViewColumn *column,
15447                                 GtkCellRenderer   *cell)
15448 {
15449   GdkRectangle rect;
15450
15451   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15452   g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
15453   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
15454   g_return_if_fail (cell == NULL || GTK_IS_CELL_RENDERER (cell));
15455
15456   /* Determine x values. */
15457   if (column && cell)
15458     {
15459       GdkRectangle tmp;
15460       gint start, width;
15461
15462       /* We always pass in path here, whether it is NULL or not.
15463        * For cells in expander columns path must be specified so that
15464        * we can correctly account for the indentation.  This also means
15465        * that the tooltip is constrained vertically by the "Determine y
15466        * values" code below; this is not a real problem since cells actually
15467        * don't stretch vertically in constrast to columns.
15468        */
15469       gtk_tree_view_get_cell_area (tree_view, path, column, &tmp);
15470       gtk_tree_view_column_cell_get_position (column, cell, &start, &width);
15471
15472       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
15473                                                          tmp.x + start, 0,
15474                                                          &rect.x, NULL);
15475       rect.width = width;
15476     }
15477   else if (column)
15478     {
15479       GdkRectangle tmp;
15480
15481       gtk_tree_view_get_background_area (tree_view, NULL, column, &tmp);
15482       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
15483                                                          tmp.x, 0,
15484                                                          &rect.x, NULL);
15485       rect.width = tmp.width;
15486     }
15487   else
15488     {
15489       rect.x = 0;
15490       rect.width = GTK_WIDGET (tree_view)->allocation.width;
15491     }
15492
15493   /* Determine y values. */
15494   if (path)
15495     {
15496       GdkRectangle tmp;
15497
15498       gtk_tree_view_get_background_area (tree_view, path, NULL, &tmp);
15499       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
15500                                                          0, tmp.y,
15501                                                          NULL, &rect.y);
15502       rect.height = tmp.height;
15503     }
15504   else
15505     {
15506       rect.y = 0;
15507       rect.height = tree_view->priv->vadjustment->page_size;
15508     }
15509
15510   gtk_tooltip_set_tip_area (tooltip, &rect);
15511 }
15512
15513 /**
15514  * gtk_tree_view_get_tooltip_context:
15515  * @tree_view: a #GtkTreeView
15516  * @x: the x coordinate (relative to widget coordinates)
15517  * @y: the y coordinate (relative to widget coordinates)
15518  * @keyboard_tip: whether this is a keyboard tooltip or not
15519  * @model: (out) (allow-none): a pointer to receive a #GtkTreeModel or %NULL
15520  * @path: (out) (allow-none): a pointer to receive a #GtkTreePath or %NULL
15521  * @iter: (out) (allow-none): a pointer to receive a #GtkTreeIter or %NULL
15522  *
15523  * This function is supposed to be used in a #GtkWidget::query-tooltip
15524  * signal handler for #GtkTreeView.  The @x, @y and @keyboard_tip values
15525  * which are received in the signal handler, should be passed to this
15526  * function without modification.
15527  *
15528  * The return value indicates whether there is a tree view row at the given
15529  * coordinates (%TRUE) or not (%FALSE) for mouse tooltips.  For keyboard
15530  * tooltips the row returned will be the cursor row.  When %TRUE, then any of
15531  * @model, @path and @iter which have been provided will be set to point to
15532  * that row and the corresponding model.  @x and @y will always be converted
15533  * to be relative to @tree_view's bin_window if @keyboard_tooltip is %FALSE.
15534  *
15535  * Return value: whether or not the given tooltip context points to a row.
15536  *
15537  * Since: 2.12
15538  */
15539 gboolean
15540 gtk_tree_view_get_tooltip_context (GtkTreeView   *tree_view,
15541                                    gint          *x,
15542                                    gint          *y,
15543                                    gboolean       keyboard_tip,
15544                                    GtkTreeModel **model,
15545                                    GtkTreePath  **path,
15546                                    GtkTreeIter   *iter)
15547 {
15548   GtkTreePath *tmppath = NULL;
15549
15550   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15551   g_return_val_if_fail (x != NULL, FALSE);
15552   g_return_val_if_fail (y != NULL, FALSE);
15553
15554   if (keyboard_tip)
15555     {
15556       gtk_tree_view_get_cursor (tree_view, &tmppath, NULL);
15557
15558       if (!tmppath)
15559         return FALSE;
15560     }
15561   else
15562     {
15563       gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, *x, *y,
15564                                                          x, y);
15565
15566       if (!gtk_tree_view_get_path_at_pos (tree_view, *x, *y,
15567                                           &tmppath, NULL, NULL, NULL))
15568         return FALSE;
15569     }
15570
15571   if (model)
15572     *model = gtk_tree_view_get_model (tree_view);
15573
15574   if (iter)
15575     gtk_tree_model_get_iter (gtk_tree_view_get_model (tree_view),
15576                              iter, tmppath);
15577
15578   if (path)
15579     *path = tmppath;
15580   else
15581     gtk_tree_path_free (tmppath);
15582
15583   return TRUE;
15584 }
15585
15586 static gboolean
15587 gtk_tree_view_set_tooltip_query_cb (GtkWidget  *widget,
15588                                     gint        x,
15589                                     gint        y,
15590                                     gboolean    keyboard_tip,
15591                                     GtkTooltip *tooltip,
15592                                     gpointer    data)
15593 {
15594   GValue value = { 0, };
15595   GValue transformed = { 0, };
15596   GtkTreeIter iter;
15597   GtkTreePath *path;
15598   GtkTreeModel *model;
15599   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
15600
15601   if (!gtk_tree_view_get_tooltip_context (GTK_TREE_VIEW (widget),
15602                                           &x, &y,
15603                                           keyboard_tip,
15604                                           &model, &path, &iter))
15605     return FALSE;
15606
15607   gtk_tree_model_get_value (model, &iter,
15608                             tree_view->priv->tooltip_column, &value);
15609
15610   g_value_init (&transformed, G_TYPE_STRING);
15611
15612   if (!g_value_transform (&value, &transformed))
15613     {
15614       g_value_unset (&value);
15615       gtk_tree_path_free (path);
15616
15617       return FALSE;
15618     }
15619
15620   g_value_unset (&value);
15621
15622   if (!g_value_get_string (&transformed))
15623     {
15624       g_value_unset (&transformed);
15625       gtk_tree_path_free (path);
15626
15627       return FALSE;
15628     }
15629
15630   gtk_tooltip_set_markup (tooltip, g_value_get_string (&transformed));
15631   gtk_tree_view_set_tooltip_row (tree_view, tooltip, path);
15632
15633   gtk_tree_path_free (path);
15634   g_value_unset (&transformed);
15635
15636   return TRUE;
15637 }
15638
15639 /**
15640  * gtk_tree_view_set_tooltip_column:
15641  * @tree_view: a #GtkTreeView
15642  * @column: an integer, which is a valid column number for @tree_view's model
15643  *
15644  * If you only plan to have simple (text-only) tooltips on full rows, you
15645  * can use this function to have #GtkTreeView handle these automatically
15646  * for you. @column should be set to the column in @tree_view's model
15647  * containing the tooltip texts, or -1 to disable this feature.
15648  *
15649  * When enabled, #GtkWidget::has-tooltip will be set to %TRUE and
15650  * @tree_view will connect a #GtkWidget::query-tooltip signal handler.
15651  *
15652  * Note that the signal handler sets the text with gtk_tooltip_set_markup(),
15653  * so &amp;, &lt;, etc have to be escaped in the text.
15654  *
15655  * Since: 2.12
15656  */
15657 void
15658 gtk_tree_view_set_tooltip_column (GtkTreeView *tree_view,
15659                                   gint         column)
15660 {
15661   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15662
15663   if (column == tree_view->priv->tooltip_column)
15664     return;
15665
15666   if (column == -1)
15667     {
15668       g_signal_handlers_disconnect_by_func (tree_view,
15669                                             gtk_tree_view_set_tooltip_query_cb,
15670                                             NULL);
15671       gtk_widget_set_has_tooltip (GTK_WIDGET (tree_view), FALSE);
15672     }
15673   else
15674     {
15675       if (tree_view->priv->tooltip_column == -1)
15676         {
15677           g_signal_connect (tree_view, "query-tooltip",
15678                             G_CALLBACK (gtk_tree_view_set_tooltip_query_cb), NULL);
15679           gtk_widget_set_has_tooltip (GTK_WIDGET (tree_view), TRUE);
15680         }
15681     }
15682
15683   tree_view->priv->tooltip_column = column;
15684   g_object_notify (G_OBJECT (tree_view), "tooltip-column");
15685 }
15686
15687 /**
15688  * gtk_tree_view_get_tooltip_column:
15689  * @tree_view: a #GtkTreeView
15690  *
15691  * Returns the column of @tree_view's model which is being used for
15692  * displaying tooltips on @tree_view's rows.
15693  *
15694  * Return value: the index of the tooltip column that is currently being
15695  * used, or -1 if this is disabled.
15696  *
15697  * Since: 2.12
15698  */
15699 gint
15700 gtk_tree_view_get_tooltip_column (GtkTreeView *tree_view)
15701 {
15702   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
15703
15704   return tree_view->priv->tooltip_column;
15705 }