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