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