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