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