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