]> Pileus Git - ~andy/gtk/blob - gtk/gtktreeview.c
Deprecate flag macros for toplevel, state, no window and composite child
[~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 "gtkextendedlayout.h"
31 #include "gtkmain.h"
32 #include "gtkmarshalers.h"
33 #include "gtkbuildable.h"
34 #include "gtkbutton.h"
35 #include "gtkalignment.h"
36 #include "gtklabel.h"
37 #include "gtkhbox.h"
38 #include "gtkvbox.h"
39 #include "gtkarrow.h"
40 #include "gtkintl.h"
41 #include "gtkbindings.h"
42 #include "gtkcontainer.h"
43 #include "gtkentry.h"
44 #include "gtkframe.h"
45 #include "gtktreemodelsort.h"
46 #include "gtktooltip.h"
47 #include "gtkprivate.h"
48 #include "gtkalias.h"
49
50 #define GTK_TREE_VIEW_PRIORITY_VALIDATE (GDK_PRIORITY_REDRAW + 5)
51 #define GTK_TREE_VIEW_PRIORITY_SCROLL_SYNC (GTK_TREE_VIEW_PRIORITY_VALIDATE + 2)
52 #define GTK_TREE_VIEW_TIME_MS_PER_IDLE 30
53 #define SCROLL_EDGE_SIZE 15
54 #define EXPANDER_EXTRA_PADDING 4
55 #define GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT 5000
56 #define AUTO_EXPAND_TIMEOUT 500
57
58 /* The "background" areas of all rows/cells add up to cover the entire tree.
59  * The background includes all inter-row and inter-cell spacing.
60  * The "cell" areas are the cell_area passed in to gtk_cell_renderer_render(),
61  * i.e. just the cells, no spacing.
62  */
63
64 #define BACKGROUND_HEIGHT(node) (GTK_RBNODE_GET_HEIGHT (node))
65 #define CELL_HEIGHT(node, separator) ((BACKGROUND_HEIGHT (node)) - (separator))
66
67 /* Translate from bin_window coordinates to rbtree (tree coordinates) and
68  * vice versa.
69  */
70 #define TREE_WINDOW_Y_TO_RBTREE_Y(tree_view,y) ((y) + tree_view->priv->dy)
71 #define RBTREE_Y_TO_TREE_WINDOW_Y(tree_view,y) ((y) - tree_view->priv->dy)
72
73 /* This is in bin_window coordinates */
74 #define BACKGROUND_FIRST_PIXEL(tree_view,tree,node) (RBTREE_Y_TO_TREE_WINDOW_Y (tree_view, _gtk_rbtree_node_find_offset ((tree), (node))))
75 #define CELL_FIRST_PIXEL(tree_view,tree,node,separator) (BACKGROUND_FIRST_PIXEL (tree_view,tree,node) + separator/2)
76
77 #define ROW_HEIGHT(tree_view,height) \
78   ((height > 0) ? (height) : (tree_view)->priv->expander_size)
79
80
81 typedef struct _GtkTreeViewChild GtkTreeViewChild;
82 struct _GtkTreeViewChild
83 {
84   GtkWidget *widget;
85   gint x;
86   gint y;
87   gint width;
88   gint height;
89 };
90
91
92 typedef struct _TreeViewDragInfo TreeViewDragInfo;
93 struct _TreeViewDragInfo
94 {
95   GdkModifierType start_button_mask;
96   GtkTargetList *_unused_source_target_list;
97   GdkDragAction source_actions;
98
99   GtkTargetList *_unused_dest_target_list;
100
101   guint source_set : 1;
102   guint dest_set : 1;
103 };
104
105
106 /* Signals */
107 enum
108 {
109   ROW_ACTIVATED,
110   TEST_EXPAND_ROW,
111   TEST_COLLAPSE_ROW,
112   ROW_EXPANDED,
113   ROW_COLLAPSED,
114   COLUMNS_CHANGED,
115   CURSOR_CHANGED,
116   MOVE_CURSOR,
117   SELECT_ALL,
118   UNSELECT_ALL,
119   SELECT_CURSOR_ROW,
120   TOGGLE_CURSOR_ROW,
121   EXPAND_COLLAPSE_CURSOR_ROW,
122   SELECT_CURSOR_PARENT,
123   START_INTERACTIVE_SEARCH,
124   LAST_SIGNAL
125 };
126
127 /* Properties */
128 enum {
129   PROP_0,
130   PROP_MODEL,
131   PROP_HADJUSTMENT,
132   PROP_VADJUSTMENT,
133   PROP_HEADERS_VISIBLE,
134   PROP_HEADERS_CLICKABLE,
135   PROP_EXPANDER_COLUMN,
136   PROP_REORDERABLE,
137   PROP_RULES_HINT,
138   PROP_ENABLE_SEARCH,
139   PROP_SEARCH_COLUMN,
140   PROP_FIXED_HEIGHT_MODE,
141   PROP_HOVER_SELECTION,
142   PROP_HOVER_EXPAND,
143   PROP_SHOW_EXPANDERS,
144   PROP_LEVEL_INDENTATION,
145   PROP_RUBBER_BANDING,
146   PROP_ENABLE_GRID_LINES,
147   PROP_ENABLE_TREE_LINES,
148   PROP_TOOLTIP_COLUMN
149 };
150
151 /* object signals */
152 static void     gtk_tree_view_finalize             (GObject          *object);
153 static void     gtk_tree_view_set_property         (GObject         *object,
154                                                     guint            prop_id,
155                                                     const GValue    *value,
156                                                     GParamSpec      *pspec);
157 static void     gtk_tree_view_get_property         (GObject         *object,
158                                                     guint            prop_id,
159                                                     GValue          *value,
160                                                     GParamSpec      *pspec);
161
162 /* gtkobject signals */
163 static void     gtk_tree_view_destroy              (GtkObject        *object);
164
165 /* gtkwidget signals */
166 static void     gtk_tree_view_realize              (GtkWidget        *widget);
167 static void     gtk_tree_view_unrealize            (GtkWidget        *widget);
168 static void     gtk_tree_view_map                  (GtkWidget        *widget);
169 static void     gtk_tree_view_size_request         (GtkWidget        *widget,
170                                                     GtkRequisition   *requisition);
171 static void     gtk_tree_view_size_allocate        (GtkWidget        *widget,
172                                                     GtkAllocation    *allocation);
173 static gboolean gtk_tree_view_expose               (GtkWidget        *widget,
174                                                     GdkEventExpose   *event);
175 static gboolean gtk_tree_view_key_press            (GtkWidget        *widget,
176                                                     GdkEventKey      *event);
177 static gboolean gtk_tree_view_key_release          (GtkWidget        *widget,
178                                                     GdkEventKey      *event);
179 static gboolean gtk_tree_view_motion               (GtkWidget        *widget,
180                                                     GdkEventMotion   *event);
181 static gboolean gtk_tree_view_enter_notify         (GtkWidget        *widget,
182                                                     GdkEventCrossing *event);
183 static gboolean gtk_tree_view_leave_notify         (GtkWidget        *widget,
184                                                     GdkEventCrossing *event);
185 static gboolean gtk_tree_view_button_press         (GtkWidget        *widget,
186                                                     GdkEventButton   *event);
187 static gboolean gtk_tree_view_button_release       (GtkWidget        *widget,
188                                                     GdkEventButton   *event);
189 static gboolean gtk_tree_view_grab_broken          (GtkWidget          *widget,
190                                                     GdkEventGrabBroken *event);
191 #if 0
192 static gboolean gtk_tree_view_configure            (GtkWidget         *widget,
193                                                     GdkEventConfigure *event);
194 #endif
195
196 static void     gtk_tree_view_set_focus_child      (GtkContainer     *container,
197                                                     GtkWidget        *child);
198 static gint     gtk_tree_view_focus_out            (GtkWidget        *widget,
199                                                     GdkEventFocus    *event);
200 static gint     gtk_tree_view_focus                (GtkWidget        *widget,
201                                                     GtkDirectionType  direction);
202 static void     gtk_tree_view_grab_focus           (GtkWidget        *widget);
203 static void     gtk_tree_view_style_set            (GtkWidget        *widget,
204                                                     GtkStyle         *previous_style);
205 static void     gtk_tree_view_grab_notify          (GtkWidget        *widget,
206                                                     gboolean          was_grabbed);
207 static void     gtk_tree_view_state_changed        (GtkWidget        *widget,
208                                                     GtkStateType      previous_state);
209
210 /* container signals */
211 static void     gtk_tree_view_remove               (GtkContainer     *container,
212                                                     GtkWidget        *widget);
213 static void     gtk_tree_view_forall               (GtkContainer     *container,
214                                                     gboolean          include_internals,
215                                                     GtkCallback       callback,
216                                                     gpointer          callback_data);
217
218 /* Source side drag signals */
219 static void gtk_tree_view_drag_begin       (GtkWidget        *widget,
220                                             GdkDragContext   *context);
221 static void gtk_tree_view_drag_end         (GtkWidget        *widget,
222                                             GdkDragContext   *context);
223 static void gtk_tree_view_drag_data_get    (GtkWidget        *widget,
224                                             GdkDragContext   *context,
225                                             GtkSelectionData *selection_data,
226                                             guint             info,
227                                             guint             time);
228 static void gtk_tree_view_drag_data_delete (GtkWidget        *widget,
229                                             GdkDragContext   *context);
230
231 /* Target side drag signals */
232 static void     gtk_tree_view_drag_leave         (GtkWidget        *widget,
233                                                   GdkDragContext   *context,
234                                                   guint             time);
235 static gboolean gtk_tree_view_drag_motion        (GtkWidget        *widget,
236                                                   GdkDragContext   *context,
237                                                   gint              x,
238                                                   gint              y,
239                                                   guint             time);
240 static gboolean gtk_tree_view_drag_drop          (GtkWidget        *widget,
241                                                   GdkDragContext   *context,
242                                                   gint              x,
243                                                   gint              y,
244                                                   guint             time);
245 static void     gtk_tree_view_drag_data_received (GtkWidget        *widget,
246                                                   GdkDragContext   *context,
247                                                   gint              x,
248                                                   gint              y,
249                                                   GtkSelectionData *selection_data,
250                                                   guint             info,
251                                                   guint             time);
252
253 /* tree_model signals */
254 static void gtk_tree_view_set_adjustments                 (GtkTreeView     *tree_view,
255                                                            GtkAdjustment   *hadj,
256                                                            GtkAdjustment   *vadj);
257 static gboolean gtk_tree_view_real_move_cursor            (GtkTreeView     *tree_view,
258                                                            GtkMovementStep  step,
259                                                            gint             count);
260 static gboolean gtk_tree_view_real_select_all             (GtkTreeView     *tree_view);
261 static gboolean gtk_tree_view_real_unselect_all           (GtkTreeView     *tree_view);
262 static gboolean gtk_tree_view_real_select_cursor_row      (GtkTreeView     *tree_view,
263                                                            gboolean         start_editing);
264 static gboolean gtk_tree_view_real_toggle_cursor_row      (GtkTreeView     *tree_view);
265 static gboolean gtk_tree_view_real_expand_collapse_cursor_row (GtkTreeView     *tree_view,
266                                                                gboolean         logical,
267                                                                gboolean         expand,
268                                                                gboolean         open_all);
269 static gboolean gtk_tree_view_real_select_cursor_parent   (GtkTreeView     *tree_view);
270 static void gtk_tree_view_row_changed                     (GtkTreeModel    *model,
271                                                            GtkTreePath     *path,
272                                                            GtkTreeIter     *iter,
273                                                            gpointer         data);
274 static void gtk_tree_view_row_inserted                    (GtkTreeModel    *model,
275                                                            GtkTreePath     *path,
276                                                            GtkTreeIter     *iter,
277                                                            gpointer         data);
278 static void gtk_tree_view_row_has_child_toggled           (GtkTreeModel    *model,
279                                                            GtkTreePath     *path,
280                                                            GtkTreeIter     *iter,
281                                                            gpointer         data);
282 static void gtk_tree_view_row_deleted                     (GtkTreeModel    *model,
283                                                            GtkTreePath     *path,
284                                                            gpointer         data);
285 static void gtk_tree_view_rows_reordered                  (GtkTreeModel    *model,
286                                                            GtkTreePath     *parent,
287                                                            GtkTreeIter     *iter,
288                                                            gint            *new_order,
289                                                            gpointer         data);
290
291 /* Incremental reflow */
292 static gboolean validate_row             (GtkTreeView *tree_view,
293                                           GtkRBTree   *tree,
294                                           GtkRBNode   *node,
295                                           GtkTreeIter *iter,
296                                           GtkTreePath *path);
297 static void     validate_visible_area    (GtkTreeView *tree_view);
298 static gboolean validate_rows_handler    (GtkTreeView *tree_view);
299 static gboolean do_validate_rows         (GtkTreeView *tree_view,
300                                           gboolean     size_request);
301 static gboolean validate_rows            (GtkTreeView *tree_view);
302 static gboolean presize_handler_callback (gpointer     data);
303 static void     install_presize_handler  (GtkTreeView *tree_view);
304 static void     install_scroll_sync_handler (GtkTreeView *tree_view);
305 static void     gtk_tree_view_set_top_row   (GtkTreeView *tree_view,
306                                              GtkTreePath *path,
307                                              gint         offset);
308 static void     gtk_tree_view_dy_to_top_row (GtkTreeView *tree_view);
309 static void     gtk_tree_view_top_row_to_dy (GtkTreeView *tree_view);
310 static void     invalidate_empty_focus      (GtkTreeView *tree_view);
311
312 /* Internal functions */
313 static gboolean gtk_tree_view_is_expander_column             (GtkTreeView        *tree_view,
314                                                               GtkTreeViewColumn  *column);
315 static void     gtk_tree_view_add_move_binding               (GtkBindingSet      *binding_set,
316                                                               guint               keyval,
317                                                               guint               modmask,
318                                                               gboolean            add_shifted_binding,
319                                                               GtkMovementStep     step,
320                                                               gint                count);
321 static gint     gtk_tree_view_unref_and_check_selection_tree (GtkTreeView        *tree_view,
322                                                               GtkRBTree          *tree);
323 static void     gtk_tree_view_queue_draw_path                (GtkTreeView        *tree_view,
324                                                               GtkTreePath        *path,
325                                                               const GdkRectangle *clip_rect);
326 static void     gtk_tree_view_queue_draw_arrow               (GtkTreeView        *tree_view,
327                                                               GtkRBTree          *tree,
328                                                               GtkRBNode          *node,
329                                                               const GdkRectangle *clip_rect);
330 static void     gtk_tree_view_draw_arrow                     (GtkTreeView        *tree_view,
331                                                               GtkRBTree          *tree,
332                                                               GtkRBNode          *node,
333                                                               gint                x,
334                                                               gint                y);
335 static void     gtk_tree_view_get_arrow_xrange               (GtkTreeView        *tree_view,
336                                                               GtkRBTree          *tree,
337                                                               gint               *x1,
338                                                               gint               *x2);
339 static gint     gtk_tree_view_new_column_width               (GtkTreeView        *tree_view,
340                                                               gint                i,
341                                                               gint               *x);
342 static void     gtk_tree_view_adjustment_changed             (GtkAdjustment      *adjustment,
343                                                               GtkTreeView        *tree_view);
344 static void     gtk_tree_view_build_tree                     (GtkTreeView        *tree_view,
345                                                               GtkRBTree          *tree,
346                                                               GtkTreeIter        *iter,
347                                                               gint                depth,
348                                                               gboolean            recurse);
349 static void     gtk_tree_view_clamp_node_visible             (GtkTreeView        *tree_view,
350                                                               GtkRBTree          *tree,
351                                                               GtkRBNode          *node);
352 static void     gtk_tree_view_clamp_column_visible           (GtkTreeView        *tree_view,
353                                                               GtkTreeViewColumn  *column,
354                                                               gboolean            focus_to_cell);
355 static gboolean gtk_tree_view_maybe_begin_dragging_row       (GtkTreeView        *tree_view,
356                                                               GdkEventMotion     *event);
357 static void     gtk_tree_view_focus_to_cursor                (GtkTreeView        *tree_view);
358 static void     gtk_tree_view_move_cursor_up_down            (GtkTreeView        *tree_view,
359                                                               gint                count);
360 static void     gtk_tree_view_move_cursor_page_up_down       (GtkTreeView        *tree_view,
361                                                               gint                count);
362 static void     gtk_tree_view_move_cursor_left_right         (GtkTreeView        *tree_view,
363                                                               gint                count);
364 static void     gtk_tree_view_move_cursor_start_end          (GtkTreeView        *tree_view,
365                                                               gint                count);
366 static gboolean gtk_tree_view_real_collapse_row              (GtkTreeView        *tree_view,
367                                                               GtkTreePath        *path,
368                                                               GtkRBTree          *tree,
369                                                               GtkRBNode          *node,
370                                                               gboolean            animate);
371 static gboolean gtk_tree_view_real_expand_row                (GtkTreeView        *tree_view,
372                                                               GtkTreePath        *path,
373                                                               GtkRBTree          *tree,
374                                                               GtkRBNode          *node,
375                                                               gboolean            open_all,
376                                                               gboolean            animate);
377 static void     gtk_tree_view_real_set_cursor                (GtkTreeView        *tree_view,
378                                                               GtkTreePath        *path,
379                                                               gboolean            clear_and_select,
380                                                               gboolean            clamp_node);
381 static gboolean gtk_tree_view_has_special_cell               (GtkTreeView        *tree_view);
382 static void     column_sizing_notify                         (GObject            *object,
383                                                               GParamSpec         *pspec,
384                                                               gpointer            data);
385 static gboolean expand_collapse_timeout                      (gpointer            data);
386 static void     add_expand_collapse_timeout                  (GtkTreeView        *tree_view,
387                                                               GtkRBTree          *tree,
388                                                               GtkRBNode          *node,
389                                                               gboolean            expand);
390 static void     remove_expand_collapse_timeout               (GtkTreeView        *tree_view);
391 static void     cancel_arrow_animation                       (GtkTreeView        *tree_view);
392 static gboolean do_expand_collapse                           (GtkTreeView        *tree_view);
393 static void     gtk_tree_view_stop_rubber_band               (GtkTreeView        *tree_view);
394 static void     update_prelight                              (GtkTreeView        *tree_view,
395                                                               int                 x,
396                                                               int                 y);
397
398 /* interactive search */
399 static void     gtk_tree_view_ensure_interactive_directory (GtkTreeView *tree_view);
400 static void     gtk_tree_view_search_dialog_hide     (GtkWidget        *search_dialog,
401                                                          GtkTreeView      *tree_view);
402 static void     gtk_tree_view_search_position_func      (GtkTreeView      *tree_view,
403                                                          GtkWidget        *search_dialog,
404                                                          gpointer          user_data);
405 static void     gtk_tree_view_search_disable_popdown    (GtkEntry         *entry,
406                                                          GtkMenu          *menu,
407                                                          gpointer          data);
408 static void     gtk_tree_view_search_preedit_changed    (GtkIMContext     *im_context,
409                                                          GtkTreeView      *tree_view);
410 static void     gtk_tree_view_search_activate           (GtkEntry         *entry,
411                                                          GtkTreeView      *tree_view);
412 static gboolean gtk_tree_view_real_search_enable_popdown(gpointer          data);
413 static void     gtk_tree_view_search_enable_popdown     (GtkWidget        *widget,
414                                                          gpointer          data);
415 static gboolean gtk_tree_view_search_delete_event       (GtkWidget        *widget,
416                                                          GdkEventAny      *event,
417                                                          GtkTreeView      *tree_view);
418 static gboolean gtk_tree_view_search_button_press_event (GtkWidget        *widget,
419                                                          GdkEventButton   *event,
420                                                          GtkTreeView      *tree_view);
421 static gboolean gtk_tree_view_search_scroll_event       (GtkWidget        *entry,
422                                                          GdkEventScroll   *event,
423                                                          GtkTreeView      *tree_view);
424 static gboolean gtk_tree_view_search_key_press_event    (GtkWidget        *entry,
425                                                          GdkEventKey      *event,
426                                                          GtkTreeView      *tree_view);
427 static gboolean gtk_tree_view_search_move               (GtkWidget        *window,
428                                                          GtkTreeView      *tree_view,
429                                                          gboolean          up);
430 static gboolean gtk_tree_view_search_equal_func         (GtkTreeModel     *model,
431                                                          gint              column,
432                                                          const gchar      *key,
433                                                          GtkTreeIter      *iter,
434                                                          gpointer          search_data);
435 static gboolean gtk_tree_view_search_iter               (GtkTreeModel     *model,
436                                                          GtkTreeSelection *selection,
437                                                          GtkTreeIter      *iter,
438                                                          const gchar      *text,
439                                                          gint             *count,
440                                                          gint              n);
441 static void     gtk_tree_view_search_init               (GtkWidget        *entry,
442                                                          GtkTreeView      *tree_view);
443 static void     gtk_tree_view_put                       (GtkTreeView      *tree_view,
444                                                          GtkWidget        *child_widget,
445                                                          gint              x,
446                                                          gint              y,
447                                                          gint              width,
448                                                          gint              height);
449 static gboolean gtk_tree_view_start_editing             (GtkTreeView      *tree_view,
450                                                          GtkTreePath      *cursor_path);
451 static void gtk_tree_view_real_start_editing (GtkTreeView       *tree_view,
452                                               GtkTreeViewColumn *column,
453                                               GtkTreePath       *path,
454                                               GtkCellEditable   *cell_editable,
455                                               GdkRectangle      *cell_area,
456                                               GdkEvent          *event,
457                                               guint              flags);
458 static void gtk_tree_view_stop_editing                  (GtkTreeView *tree_view,
459                                                          gboolean     cancel_editing);
460 static gboolean gtk_tree_view_real_start_interactive_search (GtkTreeView *tree_view,
461                                                              gboolean     keybinding);
462 static gboolean gtk_tree_view_start_interactive_search      (GtkTreeView *tree_view);
463 static GtkTreeViewColumn *gtk_tree_view_get_drop_column (GtkTreeView       *tree_view,
464                                                          GtkTreeViewColumn *column,
465                                                          gint               drop_position);
466
467 /* GtkBuildable */
468 static void gtk_tree_view_buildable_add_child (GtkBuildable *tree_view,
469                                                GtkBuilder  *builder,
470                                                GObject     *child,
471                                                const gchar *type);
472 static void gtk_tree_view_buildable_init      (GtkBuildableIface *iface);
473 static void gtk_tree_view_extended_layout_init (GtkExtendedLayoutIface *iface);
474
475 static gboolean scroll_row_timeout                   (gpointer     data);
476 static void     add_scroll_timeout                   (GtkTreeView *tree_view);
477 static void     remove_scroll_timeout                (GtkTreeView *tree_view);
478
479 static guint tree_view_signals [LAST_SIGNAL] = { 0 };
480
481 \f
482
483 /* GType Methods
484  */
485
486 G_DEFINE_TYPE_WITH_CODE (GtkTreeView, gtk_tree_view, GTK_TYPE_CONTAINER,
487                          G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
488                                                 gtk_tree_view_buildable_init)
489                          G_IMPLEMENT_INTERFACE (GTK_TYPE_EXTENDED_LAYOUT,
490                                                 gtk_tree_view_extended_layout_init))
491
492
493 static void
494 gtk_tree_view_class_init (GtkTreeViewClass *class)
495 {
496   GObjectClass *o_class;
497   GtkObjectClass *object_class;
498   GtkWidgetClass *widget_class;
499   GtkContainerClass *container_class;
500   GtkBindingSet *binding_set;
501
502   binding_set = gtk_binding_set_by_class (class);
503
504   o_class = (GObjectClass *) class;
505   object_class = (GtkObjectClass *) class;
506   widget_class = (GtkWidgetClass *) class;
507   container_class = (GtkContainerClass *) class;
508
509   /* GObject signals */
510   o_class->set_property = gtk_tree_view_set_property;
511   o_class->get_property = gtk_tree_view_get_property;
512   o_class->finalize = gtk_tree_view_finalize;
513
514   /* GtkObject signals */
515   object_class->destroy = gtk_tree_view_destroy;
516
517   /* GtkWidget signals */
518   widget_class->map = gtk_tree_view_map;
519   widget_class->realize = gtk_tree_view_realize;
520   widget_class->unrealize = gtk_tree_view_unrealize;
521   widget_class->size_request = gtk_tree_view_size_request;
522   widget_class->size_allocate = gtk_tree_view_size_allocate;
523   widget_class->button_press_event = gtk_tree_view_button_press;
524   widget_class->button_release_event = gtk_tree_view_button_release;
525   widget_class->grab_broken_event = gtk_tree_view_grab_broken;
526   /*widget_class->configure_event = gtk_tree_view_configure;*/
527   widget_class->motion_notify_event = gtk_tree_view_motion;
528   widget_class->expose_event = gtk_tree_view_expose;
529   widget_class->key_press_event = gtk_tree_view_key_press;
530   widget_class->key_release_event = gtk_tree_view_key_release;
531   widget_class->enter_notify_event = gtk_tree_view_enter_notify;
532   widget_class->leave_notify_event = gtk_tree_view_leave_notify;
533   widget_class->focus_out_event = gtk_tree_view_focus_out;
534   widget_class->drag_begin = gtk_tree_view_drag_begin;
535   widget_class->drag_end = gtk_tree_view_drag_end;
536   widget_class->drag_data_get = gtk_tree_view_drag_data_get;
537   widget_class->drag_data_delete = gtk_tree_view_drag_data_delete;
538   widget_class->drag_leave = gtk_tree_view_drag_leave;
539   widget_class->drag_motion = gtk_tree_view_drag_motion;
540   widget_class->drag_drop = gtk_tree_view_drag_drop;
541   widget_class->drag_data_received = gtk_tree_view_drag_data_received;
542   widget_class->focus = gtk_tree_view_focus;
543   widget_class->grab_focus = gtk_tree_view_grab_focus;
544   widget_class->style_set = gtk_tree_view_style_set;
545   widget_class->grab_notify = gtk_tree_view_grab_notify;
546   widget_class->state_changed = gtk_tree_view_state_changed;
547
548   /* GtkContainer signals */
549   container_class->remove = gtk_tree_view_remove;
550   container_class->forall = gtk_tree_view_forall;
551   container_class->set_focus_child = gtk_tree_view_set_focus_child;
552
553   class->set_scroll_adjustments = gtk_tree_view_set_adjustments;
554   class->move_cursor = gtk_tree_view_real_move_cursor;
555   class->select_all = gtk_tree_view_real_select_all;
556   class->unselect_all = gtk_tree_view_real_unselect_all;
557   class->select_cursor_row = gtk_tree_view_real_select_cursor_row;
558   class->toggle_cursor_row = gtk_tree_view_real_toggle_cursor_row;
559   class->expand_collapse_cursor_row = gtk_tree_view_real_expand_collapse_cursor_row;
560   class->select_cursor_parent = gtk_tree_view_real_select_cursor_parent;
561   class->start_interactive_search = gtk_tree_view_start_interactive_search;
562
563   /* Properties */
564
565   g_object_class_install_property (o_class,
566                                    PROP_MODEL,
567                                    g_param_spec_object ("model",
568                                                         P_("TreeView Model"),
569                                                         P_("The model for the tree view"),
570                                                         GTK_TYPE_TREE_MODEL,
571                                                         GTK_PARAM_READWRITE));
572
573   g_object_class_install_property (o_class,
574                                    PROP_HADJUSTMENT,
575                                    g_param_spec_object ("hadjustment",
576                                                         P_("Horizontal Adjustment"),
577                                                         P_("Horizontal Adjustment for the widget"),
578                                                         GTK_TYPE_ADJUSTMENT,
579                                                         GTK_PARAM_READWRITE));
580
581   g_object_class_install_property (o_class,
582                                    PROP_VADJUSTMENT,
583                                    g_param_spec_object ("vadjustment",
584                                                         P_("Vertical Adjustment"),
585                                                         P_("Vertical Adjustment for the widget"),
586                                                         GTK_TYPE_ADJUSTMENT,
587                                                         GTK_PARAM_READWRITE));
588
589   g_object_class_install_property (o_class,
590                                    PROP_HEADERS_VISIBLE,
591                                    g_param_spec_boolean ("headers-visible",
592                                                          P_("Headers Visible"),
593                                                          P_("Show the column header buttons"),
594                                                          TRUE,
595                                                          GTK_PARAM_READWRITE));
596
597   g_object_class_install_property (o_class,
598                                    PROP_HEADERS_CLICKABLE,
599                                    g_param_spec_boolean ("headers-clickable",
600                                                          P_("Headers Clickable"),
601                                                          P_("Column headers respond to click events"),
602                                                          TRUE,
603                                                          GTK_PARAM_READWRITE));
604
605   g_object_class_install_property (o_class,
606                                    PROP_EXPANDER_COLUMN,
607                                    g_param_spec_object ("expander-column",
608                                                         P_("Expander Column"),
609                                                         P_("Set the column for the expander column"),
610                                                         GTK_TYPE_TREE_VIEW_COLUMN,
611                                                         GTK_PARAM_READWRITE));
612
613   g_object_class_install_property (o_class,
614                                    PROP_REORDERABLE,
615                                    g_param_spec_boolean ("reorderable",
616                                                          P_("Reorderable"),
617                                                          P_("View is reorderable"),
618                                                          FALSE,
619                                                          GTK_PARAM_READWRITE));
620
621   g_object_class_install_property (o_class,
622                                    PROP_RULES_HINT,
623                                    g_param_spec_boolean ("rules-hint",
624                                                          P_("Rules Hint"),
625                                                          P_("Set a hint to the theme engine to draw rows in alternating colors"),
626                                                          FALSE,
627                                                          GTK_PARAM_READWRITE));
628
629     g_object_class_install_property (o_class,
630                                      PROP_ENABLE_SEARCH,
631                                      g_param_spec_boolean ("enable-search",
632                                                            P_("Enable Search"),
633                                                            P_("View allows user to search through columns interactively"),
634                                                            TRUE,
635                                                            GTK_PARAM_READWRITE));
636
637     g_object_class_install_property (o_class,
638                                      PROP_SEARCH_COLUMN,
639                                      g_param_spec_int ("search-column",
640                                                        P_("Search Column"),
641                                                        P_("Model column to search through during interactive search"),
642                                                        -1,
643                                                        G_MAXINT,
644                                                        -1,
645                                                        GTK_PARAM_READWRITE));
646
647     /**
648      * GtkTreeView:fixed-height-mode:
649      *
650      * Setting the ::fixed-height-mode property to %TRUE speeds up 
651      * #GtkTreeView by assuming that all rows have the same height. 
652      * Only enable this option if all rows are the same height.  
653      * Please see gtk_tree_view_set_fixed_height_mode() for more 
654      * information on this option.
655      *
656      * Since: 2.4
657      **/
658     g_object_class_install_property (o_class,
659                                      PROP_FIXED_HEIGHT_MODE,
660                                      g_param_spec_boolean ("fixed-height-mode",
661                                                            P_("Fixed Height Mode"),
662                                                            P_("Speeds up GtkTreeView by assuming that all rows have the same height"),
663                                                            FALSE,
664                                                            GTK_PARAM_READWRITE));
665     
666     /**
667      * GtkTreeView:hover-selection:
668      * 
669      * Enables of disables the hover selection mode of @tree_view.
670      * Hover selection makes the selected row follow the pointer.
671      * Currently, this works only for the selection modes 
672      * %GTK_SELECTION_SINGLE and %GTK_SELECTION_BROWSE.
673      *
674      * This mode is primarily intended for treeviews in popups, e.g.
675      * in #GtkComboBox or #GtkEntryCompletion.
676      *
677      * Since: 2.6
678      */
679     g_object_class_install_property (o_class,
680                                      PROP_HOVER_SELECTION,
681                                      g_param_spec_boolean ("hover-selection",
682                                                            P_("Hover Selection"),
683                                                            P_("Whether the selection should follow the pointer"),
684                                                            FALSE,
685                                                            GTK_PARAM_READWRITE));
686
687     /**
688      * GtkTreeView:hover-expand:
689      * 
690      * Enables of disables the hover expansion mode of @tree_view.
691      * Hover expansion makes rows expand or collapse if the pointer moves 
692      * over them.
693      *
694      * This mode is primarily intended for treeviews in popups, e.g.
695      * in #GtkComboBox or #GtkEntryCompletion.
696      *
697      * Since: 2.6
698      */
699     g_object_class_install_property (o_class,
700                                      PROP_HOVER_EXPAND,
701                                      g_param_spec_boolean ("hover-expand",
702                                                            P_("Hover Expand"),
703                                                            P_("Whether rows should be expanded/collapsed when the pointer moves over them"),
704                                                            FALSE,
705                                                            GTK_PARAM_READWRITE));
706
707     /**
708      * GtkTreeView:show-expanders:
709      *
710      * %TRUE if the view has expanders.
711      *
712      * Since: 2.12
713      */
714     g_object_class_install_property (o_class,
715                                      PROP_SHOW_EXPANDERS,
716                                      g_param_spec_boolean ("show-expanders",
717                                                            P_("Show Expanders"),
718                                                            P_("View has expanders"),
719                                                            TRUE,
720                                                            GTK_PARAM_READWRITE));
721
722     /**
723      * GtkTreeView:level-indentation:
724      *
725      * Extra indentation for each level.
726      *
727      * Since: 2.12
728      */
729     g_object_class_install_property (o_class,
730                                      PROP_LEVEL_INDENTATION,
731                                      g_param_spec_int ("level-indentation",
732                                                        P_("Level Indentation"),
733                                                        P_("Extra indentation for each level"),
734                                                        0,
735                                                        G_MAXINT,
736                                                        0,
737                                                        GTK_PARAM_READWRITE));
738
739     g_object_class_install_property (o_class,
740                                      PROP_RUBBER_BANDING,
741                                      g_param_spec_boolean ("rubber-banding",
742                                                            P_("Rubber Banding"),
743                                                            P_("Whether to enable selection of multiple items by dragging the mouse pointer"),
744                                                            FALSE,
745                                                            GTK_PARAM_READWRITE));
746
747     g_object_class_install_property (o_class,
748                                      PROP_ENABLE_GRID_LINES,
749                                      g_param_spec_enum ("enable-grid-lines",
750                                                         P_("Enable Grid Lines"),
751                                                         P_("Whether grid lines should be drawn in the tree view"),
752                                                         GTK_TYPE_TREE_VIEW_GRID_LINES,
753                                                         GTK_TREE_VIEW_GRID_LINES_NONE,
754                                                         GTK_PARAM_READWRITE));
755
756     g_object_class_install_property (o_class,
757                                      PROP_ENABLE_TREE_LINES,
758                                      g_param_spec_boolean ("enable-tree-lines",
759                                                            P_("Enable Tree Lines"),
760                                                            P_("Whether tree lines should be drawn in the tree view"),
761                                                            FALSE,
762                                                            GTK_PARAM_READWRITE));
763
764     g_object_class_install_property (o_class,
765                                      PROP_TOOLTIP_COLUMN,
766                                      g_param_spec_int ("tooltip-column",
767                                                        P_("Tooltip Column"),
768                                                        P_("The column in the model containing the tooltip texts for the rows"),
769                                                        -1,
770                                                        G_MAXINT,
771                                                        -1,
772                                                        GTK_PARAM_READWRITE));
773
774   /* Style properties */
775 #define _TREE_VIEW_EXPANDER_SIZE 12
776 #define _TREE_VIEW_VERTICAL_SEPARATOR 2
777 #define _TREE_VIEW_HORIZONTAL_SEPARATOR 2
778
779   gtk_widget_class_install_style_property (widget_class,
780                                            g_param_spec_int ("expander-size",
781                                                              P_("Expander Size"),
782                                                              P_("Size of the expander arrow"),
783                                                              0,
784                                                              G_MAXINT,
785                                                              _TREE_VIEW_EXPANDER_SIZE,
786                                                              GTK_PARAM_READABLE));
787
788   gtk_widget_class_install_style_property (widget_class,
789                                            g_param_spec_int ("vertical-separator",
790                                                              P_("Vertical Separator Width"),
791                                                              P_("Vertical space between cells.  Must be an even number"),
792                                                              0,
793                                                              G_MAXINT,
794                                                              _TREE_VIEW_VERTICAL_SEPARATOR,
795                                                              GTK_PARAM_READABLE));
796
797   gtk_widget_class_install_style_property (widget_class,
798                                            g_param_spec_int ("horizontal-separator",
799                                                              P_("Horizontal Separator Width"),
800                                                              P_("Horizontal space between cells.  Must be an even number"),
801                                                              0,
802                                                              G_MAXINT,
803                                                              _TREE_VIEW_HORIZONTAL_SEPARATOR,
804                                                              GTK_PARAM_READABLE));
805
806   gtk_widget_class_install_style_property (widget_class,
807                                            g_param_spec_boolean ("allow-rules",
808                                                                  P_("Allow Rules"),
809                                                                  P_("Allow drawing of alternating color rows"),
810                                                                  TRUE,
811                                                                  GTK_PARAM_READABLE));
812
813   gtk_widget_class_install_style_property (widget_class,
814                                            g_param_spec_boolean ("indent-expanders",
815                                                                  P_("Indent Expanders"),
816                                                                  P_("Make the expanders indented"),
817                                                                  TRUE,
818                                                                  GTK_PARAM_READABLE));
819
820   gtk_widget_class_install_style_property (widget_class,
821                                            g_param_spec_boxed ("even-row-color",
822                                                                P_("Even Row Color"),
823                                                                P_("Color to use for even rows"),
824                                                                GDK_TYPE_COLOR,
825                                                                GTK_PARAM_READABLE));
826
827   gtk_widget_class_install_style_property (widget_class,
828                                            g_param_spec_boxed ("odd-row-color",
829                                                                P_("Odd Row Color"),
830                                                                P_("Color to use for odd rows"),
831                                                                GDK_TYPE_COLOR,
832                                                                GTK_PARAM_READABLE));
833
834   gtk_widget_class_install_style_property (widget_class,
835                                            g_param_spec_boolean ("row-ending-details",
836                                                                  P_("Row Ending details"),
837                                                                  P_("Enable extended row background theming"),
838                                                                  FALSE,
839                                                                  GTK_PARAM_READABLE));
840
841   gtk_widget_class_install_style_property (widget_class,
842                                            g_param_spec_int ("grid-line-width",
843                                                              P_("Grid line width"),
844                                                              P_("Width, in pixels, of the tree view grid lines"),
845                                                              0, G_MAXINT, 1,
846                                                              GTK_PARAM_READABLE));
847
848   gtk_widget_class_install_style_property (widget_class,
849                                            g_param_spec_int ("tree-line-width",
850                                                              P_("Tree line width"),
851                                                              P_("Width, in pixels, of the tree view lines"),
852                                                              0, G_MAXINT, 1,
853                                                              GTK_PARAM_READABLE));
854
855   gtk_widget_class_install_style_property (widget_class,
856                                            g_param_spec_string ("grid-line-pattern",
857                                                                 P_("Grid line pattern"),
858                                                                 P_("Dash pattern used to draw the tree view grid lines"),
859                                                                 "\1\1",
860                                                                 GTK_PARAM_READABLE));
861
862   gtk_widget_class_install_style_property (widget_class,
863                                            g_param_spec_string ("tree-line-pattern",
864                                                                 P_("Tree line pattern"),
865                                                                 P_("Dash pattern used to draw the tree view lines"),
866                                                                 "\1\1",
867                                                                 GTK_PARAM_READABLE));
868
869   /* Signals */
870   /**
871    * GtkTreeView::set-scroll-adjustments
872    * @horizontal: the horizontal #GtkAdjustment
873    * @vertical: the vertical #GtkAdjustment
874    *
875    * Set the scroll adjustments for the tree view. Usually scrolled containers
876    * like #GtkScrolledWindow will emit this signal to connect two instances
877    * of #GtkScrollbar to the scroll directions of the #GtkTreeView.
878    */
879   widget_class->set_scroll_adjustments_signal =
880     g_signal_new (I_("set-scroll-adjustments"),
881                   G_TYPE_FROM_CLASS (o_class),
882                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
883                   G_STRUCT_OFFSET (GtkTreeViewClass, set_scroll_adjustments),
884                   NULL, NULL,
885                   _gtk_marshal_VOID__OBJECT_OBJECT,
886                   G_TYPE_NONE, 2,
887                   GTK_TYPE_ADJUSTMENT,
888                   GTK_TYPE_ADJUSTMENT);
889
890   /**
891    * GtkTreeView::row-activated:
892    * @tree_view: the object on which the signal is emitted
893    * @path: the #GtkTreePath for the activated row
894    * @column: the #GtkTreeViewColumn in which the activation occurred
895    *
896    * The "row-activated" signal is emitted when the method
897    * gtk_tree_view_row_activated() is called or the user double clicks 
898    * a treeview row. It is also emitted when a non-editable row is 
899    * selected and one of the keys: Space, Shift+Space, Return or 
900    * Enter is pressed.
901    * 
902    * For selection handling refer to the <link linkend="TreeWidget">tree 
903    * widget conceptual overview</link> as well as #GtkTreeSelection.
904    */
905   tree_view_signals[ROW_ACTIVATED] =
906     g_signal_new (I_("row-activated"),
907                   G_TYPE_FROM_CLASS (o_class),
908                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
909                   G_STRUCT_OFFSET (GtkTreeViewClass, row_activated),
910                   NULL, NULL,
911                   _gtk_marshal_VOID__BOXED_OBJECT,
912                   G_TYPE_NONE, 2,
913                   GTK_TYPE_TREE_PATH,
914                   GTK_TYPE_TREE_VIEW_COLUMN);
915
916   /**
917    * GtkTreeView::test-expand-row:
918    * @tree_view: the object on which the signal is emitted
919    * @iter: the tree iter of the row to expand
920    * @path: a tree path that points to the row 
921    * 
922    * The given row is about to be expanded (show its children nodes). Use this
923    * signal if you need to control the expandability of individual rows.
924    *
925    * Returns: %FALSE to allow expansion, %TRUE to reject
926    */
927   tree_view_signals[TEST_EXPAND_ROW] =
928     g_signal_new (I_("test-expand-row"),
929                   G_TYPE_FROM_CLASS (o_class),
930                   G_SIGNAL_RUN_LAST,
931                   G_STRUCT_OFFSET (GtkTreeViewClass, test_expand_row),
932                   _gtk_boolean_handled_accumulator, NULL,
933                   _gtk_marshal_BOOLEAN__BOXED_BOXED,
934                   G_TYPE_BOOLEAN, 2,
935                   GTK_TYPE_TREE_ITER,
936                   GTK_TYPE_TREE_PATH);
937
938   /**
939    * GtkTreeView::test-collapse-row:
940    * @tree_view: the object on which the signal is emitted
941    * @iter: the tree iter of the row to collapse
942    * @path: a tree path that points to the row 
943    * 
944    * The given row is about to be collapsed (hide its children nodes). Use this
945    * signal if you need to control the collapsibility of individual rows.
946    *
947    * Returns: %FALSE to allow collapsing, %TRUE to reject
948    */
949   tree_view_signals[TEST_COLLAPSE_ROW] =
950     g_signal_new (I_("test-collapse-row"),
951                   G_TYPE_FROM_CLASS (o_class),
952                   G_SIGNAL_RUN_LAST,
953                   G_STRUCT_OFFSET (GtkTreeViewClass, test_collapse_row),
954                   _gtk_boolean_handled_accumulator, NULL,
955                   _gtk_marshal_BOOLEAN__BOXED_BOXED,
956                   G_TYPE_BOOLEAN, 2,
957                   GTK_TYPE_TREE_ITER,
958                   GTK_TYPE_TREE_PATH);
959
960   /**
961    * GtkTreeView::row-expanded:
962    * @tree_view: the object on which the signal is emitted
963    * @iter: the tree iter of the expanded row
964    * @path: a tree path that points to the row 
965    * 
966    * The given row has been expanded (child nodes are shown).
967    */
968   tree_view_signals[ROW_EXPANDED] =
969     g_signal_new (I_("row-expanded"),
970                   G_TYPE_FROM_CLASS (o_class),
971                   G_SIGNAL_RUN_LAST,
972                   G_STRUCT_OFFSET (GtkTreeViewClass, row_expanded),
973                   NULL, NULL,
974                   _gtk_marshal_VOID__BOXED_BOXED,
975                   G_TYPE_NONE, 2,
976                   GTK_TYPE_TREE_ITER,
977                   GTK_TYPE_TREE_PATH);
978
979   /**
980    * GtkTreeView::row-collapsed:
981    * @tree_view: the object on which the signal is emitted
982    * @iter: the tree iter of the collapsed row
983    * @path: a tree path that points to the row 
984    * 
985    * The given row has been collapsed (child nodes are hidden).
986    */
987   tree_view_signals[ROW_COLLAPSED] =
988     g_signal_new (I_("row-collapsed"),
989                   G_TYPE_FROM_CLASS (o_class),
990                   G_SIGNAL_RUN_LAST,
991                   G_STRUCT_OFFSET (GtkTreeViewClass, row_collapsed),
992                   NULL, NULL,
993                   _gtk_marshal_VOID__BOXED_BOXED,
994                   G_TYPE_NONE, 2,
995                   GTK_TYPE_TREE_ITER,
996                   GTK_TYPE_TREE_PATH);
997
998   /**
999    * GtkTreeView::columns-changed:
1000    * @tree_view: the object on which the signal is emitted 
1001    * 
1002    * The number of columns of the treeview has changed.
1003    */
1004   tree_view_signals[COLUMNS_CHANGED] =
1005     g_signal_new (I_("columns-changed"),
1006                   G_TYPE_FROM_CLASS (o_class),
1007                   G_SIGNAL_RUN_LAST,
1008                   G_STRUCT_OFFSET (GtkTreeViewClass, columns_changed),
1009                   NULL, NULL,
1010                   _gtk_marshal_VOID__VOID,
1011                   G_TYPE_NONE, 0);
1012
1013   /**
1014    * GtkTreeView::cursor-changed:
1015    * @tree_view: the object on which the signal is emitted
1016    * 
1017    * The position of the cursor (focused cell) has changed.
1018    */
1019   tree_view_signals[CURSOR_CHANGED] =
1020     g_signal_new (I_("cursor-changed"),
1021                   G_TYPE_FROM_CLASS (o_class),
1022                   G_SIGNAL_RUN_LAST,
1023                   G_STRUCT_OFFSET (GtkTreeViewClass, cursor_changed),
1024                   NULL, NULL,
1025                   _gtk_marshal_VOID__VOID,
1026                   G_TYPE_NONE, 0);
1027
1028   tree_view_signals[MOVE_CURSOR] =
1029     g_signal_new (I_("move-cursor"),
1030                   G_TYPE_FROM_CLASS (object_class),
1031                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1032                   G_STRUCT_OFFSET (GtkTreeViewClass, move_cursor),
1033                   NULL, NULL,
1034                   _gtk_marshal_BOOLEAN__ENUM_INT,
1035                   G_TYPE_BOOLEAN, 2,
1036                   GTK_TYPE_MOVEMENT_STEP,
1037                   G_TYPE_INT);
1038
1039   tree_view_signals[SELECT_ALL] =
1040     g_signal_new (I_("select-all"),
1041                   G_TYPE_FROM_CLASS (object_class),
1042                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1043                   G_STRUCT_OFFSET (GtkTreeViewClass, select_all),
1044                   NULL, NULL,
1045                   _gtk_marshal_BOOLEAN__VOID,
1046                   G_TYPE_BOOLEAN, 0);
1047
1048   tree_view_signals[UNSELECT_ALL] =
1049     g_signal_new (I_("unselect-all"),
1050                   G_TYPE_FROM_CLASS (object_class),
1051                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1052                   G_STRUCT_OFFSET (GtkTreeViewClass, unselect_all),
1053                   NULL, NULL,
1054                   _gtk_marshal_BOOLEAN__VOID,
1055                   G_TYPE_BOOLEAN, 0);
1056
1057   tree_view_signals[SELECT_CURSOR_ROW] =
1058     g_signal_new (I_("select-cursor-row"),
1059                   G_TYPE_FROM_CLASS (object_class),
1060                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1061                   G_STRUCT_OFFSET (GtkTreeViewClass, select_cursor_row),
1062                   NULL, NULL,
1063                   _gtk_marshal_BOOLEAN__BOOLEAN,
1064                   G_TYPE_BOOLEAN, 1,
1065                   G_TYPE_BOOLEAN);
1066
1067   tree_view_signals[TOGGLE_CURSOR_ROW] =
1068     g_signal_new (I_("toggle-cursor-row"),
1069                   G_TYPE_FROM_CLASS (object_class),
1070                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1071                   G_STRUCT_OFFSET (GtkTreeViewClass, toggle_cursor_row),
1072                   NULL, NULL,
1073                   _gtk_marshal_BOOLEAN__VOID,
1074                   G_TYPE_BOOLEAN, 0);
1075
1076   tree_view_signals[EXPAND_COLLAPSE_CURSOR_ROW] =
1077     g_signal_new (I_("expand-collapse-cursor-row"),
1078                   G_TYPE_FROM_CLASS (object_class),
1079                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1080                   G_STRUCT_OFFSET (GtkTreeViewClass, expand_collapse_cursor_row),
1081                   NULL, NULL,
1082                   _gtk_marshal_BOOLEAN__BOOLEAN_BOOLEAN_BOOLEAN,
1083                   G_TYPE_BOOLEAN, 3,
1084                   G_TYPE_BOOLEAN,
1085                   G_TYPE_BOOLEAN,
1086                   G_TYPE_BOOLEAN);
1087
1088   tree_view_signals[SELECT_CURSOR_PARENT] =
1089     g_signal_new (I_("select-cursor-parent"),
1090                   G_TYPE_FROM_CLASS (object_class),
1091                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1092                   G_STRUCT_OFFSET (GtkTreeViewClass, select_cursor_parent),
1093                   NULL, NULL,
1094                   _gtk_marshal_BOOLEAN__VOID,
1095                   G_TYPE_BOOLEAN, 0);
1096
1097   tree_view_signals[START_INTERACTIVE_SEARCH] =
1098     g_signal_new (I_("start-interactive-search"),
1099                   G_TYPE_FROM_CLASS (object_class),
1100                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1101                   G_STRUCT_OFFSET (GtkTreeViewClass, start_interactive_search),
1102                   NULL, NULL,
1103                   _gtk_marshal_BOOLEAN__VOID,
1104                   G_TYPE_BOOLEAN, 0);
1105
1106   /* Key bindings */
1107   gtk_tree_view_add_move_binding (binding_set, GDK_Up, 0, TRUE,
1108                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
1109   gtk_tree_view_add_move_binding (binding_set, GDK_KP_Up, 0, TRUE,
1110                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
1111
1112   gtk_tree_view_add_move_binding (binding_set, GDK_Down, 0, TRUE,
1113                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
1114   gtk_tree_view_add_move_binding (binding_set, GDK_KP_Down, 0, TRUE,
1115                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
1116
1117   gtk_tree_view_add_move_binding (binding_set, GDK_p, GDK_CONTROL_MASK, FALSE,
1118                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
1119
1120   gtk_tree_view_add_move_binding (binding_set, GDK_n, GDK_CONTROL_MASK, FALSE,
1121                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
1122
1123   gtk_tree_view_add_move_binding (binding_set, GDK_Home, 0, TRUE,
1124                                   GTK_MOVEMENT_BUFFER_ENDS, -1);
1125   gtk_tree_view_add_move_binding (binding_set, GDK_KP_Home, 0, TRUE,
1126                                   GTK_MOVEMENT_BUFFER_ENDS, -1);
1127
1128   gtk_tree_view_add_move_binding (binding_set, GDK_End, 0, TRUE,
1129                                   GTK_MOVEMENT_BUFFER_ENDS, 1);
1130   gtk_tree_view_add_move_binding (binding_set, GDK_KP_End, 0, TRUE,
1131                                   GTK_MOVEMENT_BUFFER_ENDS, 1);
1132
1133   gtk_tree_view_add_move_binding (binding_set, GDK_Page_Up, 0, TRUE,
1134                                   GTK_MOVEMENT_PAGES, -1);
1135   gtk_tree_view_add_move_binding (binding_set, GDK_KP_Page_Up, 0, TRUE,
1136                                   GTK_MOVEMENT_PAGES, -1);
1137
1138   gtk_tree_view_add_move_binding (binding_set, GDK_Page_Down, 0, TRUE,
1139                                   GTK_MOVEMENT_PAGES, 1);
1140   gtk_tree_view_add_move_binding (binding_set, GDK_KP_Page_Down, 0, TRUE,
1141                                   GTK_MOVEMENT_PAGES, 1);
1142
1143
1144   gtk_binding_entry_add_signal (binding_set, GDK_Right, 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_Left, 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_Right, 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_KP_Left, 0, "move-cursor", 2,
1157                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1158                                 G_TYPE_INT, -1);
1159
1160   gtk_binding_entry_add_signal (binding_set, GDK_Right, GDK_CONTROL_MASK,
1161                                 "move-cursor", 2,
1162                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1163                                 G_TYPE_INT, 1);
1164
1165   gtk_binding_entry_add_signal (binding_set, GDK_Left, GDK_CONTROL_MASK,
1166                                 "move-cursor", 2,
1167                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1168                                 G_TYPE_INT, -1);
1169
1170   gtk_binding_entry_add_signal (binding_set, GDK_KP_Right, GDK_CONTROL_MASK,
1171                                 "move-cursor", 2,
1172                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1173                                 G_TYPE_INT, 1);
1174
1175   gtk_binding_entry_add_signal (binding_set, GDK_KP_Left, GDK_CONTROL_MASK,
1176                                 "move-cursor", 2,
1177                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1178                                 G_TYPE_INT, -1);
1179
1180   gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_CONTROL_MASK, "toggle-cursor-row", 0);
1181   gtk_binding_entry_add_signal (binding_set, GDK_KP_Space, GDK_CONTROL_MASK, "toggle-cursor-row", 0);
1182
1183   gtk_binding_entry_add_signal (binding_set, GDK_a, GDK_CONTROL_MASK, "select-all", 0);
1184   gtk_binding_entry_add_signal (binding_set, GDK_slash, GDK_CONTROL_MASK, "select-all", 0);
1185
1186   gtk_binding_entry_add_signal (binding_set, GDK_A, GDK_CONTROL_MASK | GDK_SHIFT_MASK, "unselect-all", 0);
1187   gtk_binding_entry_add_signal (binding_set, GDK_backslash, GDK_CONTROL_MASK, "unselect-all", 0);
1188
1189   gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_SHIFT_MASK, "select-cursor-row", 1,
1190                                 G_TYPE_BOOLEAN, TRUE);
1191   gtk_binding_entry_add_signal (binding_set, GDK_KP_Space, GDK_SHIFT_MASK, "select-cursor-row", 1,
1192                                 G_TYPE_BOOLEAN, TRUE);
1193
1194   gtk_binding_entry_add_signal (binding_set, GDK_space, 0, "select-cursor-row", 1,
1195                                 G_TYPE_BOOLEAN, TRUE);
1196   gtk_binding_entry_add_signal (binding_set, GDK_KP_Space, 0, "select-cursor-row", 1,
1197                                 G_TYPE_BOOLEAN, TRUE);
1198   gtk_binding_entry_add_signal (binding_set, GDK_Return, 0, "select-cursor-row", 1,
1199                                 G_TYPE_BOOLEAN, TRUE);
1200   gtk_binding_entry_add_signal (binding_set, GDK_ISO_Enter, 0, "select-cursor-row", 1,
1201                                 G_TYPE_BOOLEAN, TRUE);
1202   gtk_binding_entry_add_signal (binding_set, GDK_KP_Enter, 0, "select-cursor-row", 1,
1203                                 G_TYPE_BOOLEAN, TRUE);
1204
1205   /* expand and collapse rows */
1206   gtk_binding_entry_add_signal (binding_set, GDK_plus, 0, "expand-collapse-cursor-row", 3,
1207                                 G_TYPE_BOOLEAN, TRUE,
1208                                 G_TYPE_BOOLEAN, TRUE,
1209                                 G_TYPE_BOOLEAN, FALSE);
1210
1211   gtk_binding_entry_add_signal (binding_set, GDK_asterisk, 0,
1212                                 "expand-collapse-cursor-row", 3,
1213                                 G_TYPE_BOOLEAN, TRUE,
1214                                 G_TYPE_BOOLEAN, TRUE,
1215                                 G_TYPE_BOOLEAN, TRUE);
1216   gtk_binding_entry_add_signal (binding_set, GDK_KP_Multiply, 0,
1217                                 "expand-collapse-cursor-row", 3,
1218                                 G_TYPE_BOOLEAN, TRUE,
1219                                 G_TYPE_BOOLEAN, TRUE,
1220                                 G_TYPE_BOOLEAN, TRUE);
1221
1222   gtk_binding_entry_add_signal (binding_set, GDK_slash, 0,
1223                                 "expand-collapse-cursor-row", 3,
1224                                 G_TYPE_BOOLEAN, TRUE,
1225                                 G_TYPE_BOOLEAN, FALSE,
1226                                 G_TYPE_BOOLEAN, FALSE);
1227   gtk_binding_entry_add_signal (binding_set, GDK_KP_Divide, 0,
1228                                 "expand-collapse-cursor-row", 3,
1229                                 G_TYPE_BOOLEAN, TRUE,
1230                                 G_TYPE_BOOLEAN, FALSE,
1231                                 G_TYPE_BOOLEAN, FALSE);
1232
1233   /* Not doable on US keyboards */
1234   gtk_binding_entry_add_signal (binding_set, GDK_plus, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1235                                 G_TYPE_BOOLEAN, TRUE,
1236                                 G_TYPE_BOOLEAN, TRUE,
1237                                 G_TYPE_BOOLEAN, TRUE);
1238   gtk_binding_entry_add_signal (binding_set, GDK_KP_Add, 0, "expand-collapse-cursor-row", 3,
1239                                 G_TYPE_BOOLEAN, TRUE,
1240                                 G_TYPE_BOOLEAN, TRUE,
1241                                 G_TYPE_BOOLEAN, FALSE);
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_KP_Add, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1247                                 G_TYPE_BOOLEAN, TRUE,
1248                                 G_TYPE_BOOLEAN, TRUE,
1249                                 G_TYPE_BOOLEAN, TRUE);
1250   gtk_binding_entry_add_signal (binding_set, GDK_Right, GDK_SHIFT_MASK,
1251                                 "expand-collapse-cursor-row", 3,
1252                                 G_TYPE_BOOLEAN, FALSE,
1253                                 G_TYPE_BOOLEAN, TRUE,
1254                                 G_TYPE_BOOLEAN, TRUE);
1255   gtk_binding_entry_add_signal (binding_set, GDK_KP_Right, GDK_SHIFT_MASK,
1256                                 "expand-collapse-cursor-row", 3,
1257                                 G_TYPE_BOOLEAN, FALSE,
1258                                 G_TYPE_BOOLEAN, TRUE,
1259                                 G_TYPE_BOOLEAN, TRUE);
1260   gtk_binding_entry_add_signal (binding_set, GDK_Right,
1261                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1262                                 "expand-collapse-cursor-row", 3,
1263                                 G_TYPE_BOOLEAN, FALSE,
1264                                 G_TYPE_BOOLEAN, TRUE,
1265                                 G_TYPE_BOOLEAN, TRUE);
1266   gtk_binding_entry_add_signal (binding_set, GDK_KP_Right,
1267                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1268                                 "expand-collapse-cursor-row", 3,
1269                                 G_TYPE_BOOLEAN, FALSE,
1270                                 G_TYPE_BOOLEAN, TRUE,
1271                                 G_TYPE_BOOLEAN, TRUE);
1272
1273   gtk_binding_entry_add_signal (binding_set, GDK_minus, 0, "expand-collapse-cursor-row", 3,
1274                                 G_TYPE_BOOLEAN, TRUE,
1275                                 G_TYPE_BOOLEAN, FALSE,
1276                                 G_TYPE_BOOLEAN, FALSE);
1277   gtk_binding_entry_add_signal (binding_set, GDK_minus, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1278                                 G_TYPE_BOOLEAN, TRUE,
1279                                 G_TYPE_BOOLEAN, FALSE,
1280                                 G_TYPE_BOOLEAN, TRUE);
1281   gtk_binding_entry_add_signal (binding_set, GDK_KP_Subtract, 0, "expand-collapse-cursor-row", 3,
1282                                 G_TYPE_BOOLEAN, TRUE,
1283                                 G_TYPE_BOOLEAN, FALSE,
1284                                 G_TYPE_BOOLEAN, FALSE);
1285   gtk_binding_entry_add_signal (binding_set, GDK_KP_Subtract, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1286                                 G_TYPE_BOOLEAN, TRUE,
1287                                 G_TYPE_BOOLEAN, FALSE,
1288                                 G_TYPE_BOOLEAN, TRUE);
1289   gtk_binding_entry_add_signal (binding_set, GDK_Left, GDK_SHIFT_MASK,
1290                                 "expand-collapse-cursor-row", 3,
1291                                 G_TYPE_BOOLEAN, FALSE,
1292                                 G_TYPE_BOOLEAN, FALSE,
1293                                 G_TYPE_BOOLEAN, TRUE);
1294   gtk_binding_entry_add_signal (binding_set, GDK_KP_Left, GDK_SHIFT_MASK,
1295                                 "expand-collapse-cursor-row", 3,
1296                                 G_TYPE_BOOLEAN, FALSE,
1297                                 G_TYPE_BOOLEAN, FALSE,
1298                                 G_TYPE_BOOLEAN, TRUE);
1299   gtk_binding_entry_add_signal (binding_set, GDK_Left,
1300                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1301                                 "expand-collapse-cursor-row", 3,
1302                                 G_TYPE_BOOLEAN, FALSE,
1303                                 G_TYPE_BOOLEAN, FALSE,
1304                                 G_TYPE_BOOLEAN, TRUE);
1305   gtk_binding_entry_add_signal (binding_set, GDK_KP_Left,
1306                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1307                                 "expand-collapse-cursor-row", 3,
1308                                 G_TYPE_BOOLEAN, FALSE,
1309                                 G_TYPE_BOOLEAN, FALSE,
1310                                 G_TYPE_BOOLEAN, TRUE);
1311
1312   gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, 0, "select-cursor-parent", 0);
1313   gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, GDK_CONTROL_MASK, "select-cursor-parent", 0);
1314
1315   gtk_binding_entry_add_signal (binding_set, GDK_f, GDK_CONTROL_MASK, "start-interactive-search", 0);
1316
1317   gtk_binding_entry_add_signal (binding_set, GDK_F, GDK_CONTROL_MASK, "start-interactive-search", 0);
1318
1319   g_type_class_add_private (o_class, sizeof (GtkTreeViewPrivate));
1320 }
1321
1322 static void
1323 gtk_tree_view_buildable_init (GtkBuildableIface *iface)
1324 {
1325   iface->add_child = gtk_tree_view_buildable_add_child;
1326 }
1327
1328 static void
1329 gtk_tree_view_init (GtkTreeView *tree_view)
1330 {
1331   tree_view->priv = G_TYPE_INSTANCE_GET_PRIVATE (tree_view, GTK_TYPE_TREE_VIEW, GtkTreeViewPrivate);
1332
1333   GTK_WIDGET_SET_FLAGS (tree_view, GTK_CAN_FOCUS);
1334
1335   gtk_widget_set_redraw_on_allocate (GTK_WIDGET (tree_view), FALSE);
1336
1337   tree_view->priv->flags =  GTK_TREE_VIEW_SHOW_EXPANDERS
1338                             | GTK_TREE_VIEW_DRAW_KEYFOCUS
1339                             | GTK_TREE_VIEW_HEADERS_VISIBLE;
1340
1341   /* We need some padding */
1342   tree_view->priv->dy = 0;
1343   tree_view->priv->cursor_offset = 0;
1344   tree_view->priv->n_columns = 0;
1345   tree_view->priv->header_height = 1;
1346   tree_view->priv->x_drag = 0;
1347   tree_view->priv->drag_pos = -1;
1348   tree_view->priv->header_has_focus = FALSE;
1349   tree_view->priv->pressed_button = -1;
1350   tree_view->priv->press_start_x = -1;
1351   tree_view->priv->press_start_y = -1;
1352   tree_view->priv->reorderable = FALSE;
1353   tree_view->priv->presize_handler_timer = 0;
1354   tree_view->priv->scroll_sync_timer = 0;
1355   tree_view->priv->fixed_height = -1;
1356   tree_view->priv->fixed_height_mode = FALSE;
1357   tree_view->priv->fixed_height_check = 0;
1358   gtk_tree_view_set_adjustments (tree_view, NULL, NULL);
1359   tree_view->priv->selection = _gtk_tree_selection_new_with_tree_view (tree_view);
1360   tree_view->priv->enable_search = TRUE;
1361   tree_view->priv->search_column = -1;
1362   tree_view->priv->search_position_func = gtk_tree_view_search_position_func;
1363   tree_view->priv->search_equal_func = gtk_tree_view_search_equal_func;
1364   tree_view->priv->search_custom_entry_set = FALSE;
1365   tree_view->priv->typeselect_flush_timeout = 0;
1366   tree_view->priv->init_hadjust_value = TRUE;    
1367   tree_view->priv->width = 0;
1368           
1369   tree_view->priv->hover_selection = FALSE;
1370   tree_view->priv->hover_expand = FALSE;
1371
1372   tree_view->priv->level_indentation = 0;
1373
1374   tree_view->priv->rubber_banding_enable = FALSE;
1375
1376   tree_view->priv->grid_lines = GTK_TREE_VIEW_GRID_LINES_NONE;
1377   tree_view->priv->tree_lines_enabled = FALSE;
1378
1379   tree_view->priv->tooltip_column = -1;
1380
1381   tree_view->priv->post_validation_flag = FALSE;
1382
1383   tree_view->priv->last_button_x = -1;
1384   tree_view->priv->last_button_y = -1;
1385
1386   tree_view->priv->event_last_x = -10000;
1387   tree_view->priv->event_last_y = -10000;
1388 }
1389
1390 \f
1391
1392 /* GObject Methods
1393  */
1394
1395 static void
1396 gtk_tree_view_set_property (GObject         *object,
1397                             guint            prop_id,
1398                             const GValue    *value,
1399                             GParamSpec      *pspec)
1400 {
1401   GtkTreeView *tree_view;
1402
1403   tree_view = GTK_TREE_VIEW (object);
1404
1405   switch (prop_id)
1406     {
1407     case PROP_MODEL:
1408       gtk_tree_view_set_model (tree_view, g_value_get_object (value));
1409       break;
1410     case PROP_HADJUSTMENT:
1411       gtk_tree_view_set_hadjustment (tree_view, g_value_get_object (value));
1412       break;
1413     case PROP_VADJUSTMENT:
1414       gtk_tree_view_set_vadjustment (tree_view, g_value_get_object (value));
1415       break;
1416     case PROP_HEADERS_VISIBLE:
1417       gtk_tree_view_set_headers_visible (tree_view, g_value_get_boolean (value));
1418       break;
1419     case PROP_HEADERS_CLICKABLE:
1420       gtk_tree_view_set_headers_clickable (tree_view, g_value_get_boolean (value));
1421       break;
1422     case PROP_EXPANDER_COLUMN:
1423       gtk_tree_view_set_expander_column (tree_view, g_value_get_object (value));
1424       break;
1425     case PROP_REORDERABLE:
1426       gtk_tree_view_set_reorderable (tree_view, g_value_get_boolean (value));
1427       break;
1428     case PROP_RULES_HINT:
1429       gtk_tree_view_set_rules_hint (tree_view, g_value_get_boolean (value));
1430       break;
1431     case PROP_ENABLE_SEARCH:
1432       gtk_tree_view_set_enable_search (tree_view, g_value_get_boolean (value));
1433       break;
1434     case PROP_SEARCH_COLUMN:
1435       gtk_tree_view_set_search_column (tree_view, g_value_get_int (value));
1436       break;
1437     case PROP_FIXED_HEIGHT_MODE:
1438       gtk_tree_view_set_fixed_height_mode (tree_view, g_value_get_boolean (value));
1439       break;
1440     case PROP_HOVER_SELECTION:
1441       tree_view->priv->hover_selection = g_value_get_boolean (value);
1442       break;
1443     case PROP_HOVER_EXPAND:
1444       tree_view->priv->hover_expand = g_value_get_boolean (value);
1445       break;
1446     case PROP_SHOW_EXPANDERS:
1447       gtk_tree_view_set_show_expanders (tree_view, g_value_get_boolean (value));
1448       break;
1449     case PROP_LEVEL_INDENTATION:
1450       tree_view->priv->level_indentation = g_value_get_int (value);
1451       break;
1452     case PROP_RUBBER_BANDING:
1453       tree_view->priv->rubber_banding_enable = g_value_get_boolean (value);
1454       break;
1455     case PROP_ENABLE_GRID_LINES:
1456       gtk_tree_view_set_grid_lines (tree_view, g_value_get_enum (value));
1457       break;
1458     case PROP_ENABLE_TREE_LINES:
1459       gtk_tree_view_set_enable_tree_lines (tree_view, g_value_get_boolean (value));
1460       break;
1461     case PROP_TOOLTIP_COLUMN:
1462       gtk_tree_view_set_tooltip_column (tree_view, g_value_get_int (value));
1463       break;
1464     default:
1465       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1466       break;
1467     }
1468 }
1469
1470 static void
1471 gtk_tree_view_get_property (GObject    *object,
1472                             guint       prop_id,
1473                             GValue     *value,
1474                             GParamSpec *pspec)
1475 {
1476   GtkTreeView *tree_view;
1477
1478   tree_view = GTK_TREE_VIEW (object);
1479
1480   switch (prop_id)
1481     {
1482     case PROP_MODEL:
1483       g_value_set_object (value, tree_view->priv->model);
1484       break;
1485     case PROP_HADJUSTMENT:
1486       g_value_set_object (value, tree_view->priv->hadjustment);
1487       break;
1488     case PROP_VADJUSTMENT:
1489       g_value_set_object (value, tree_view->priv->vadjustment);
1490       break;
1491     case PROP_HEADERS_VISIBLE:
1492       g_value_set_boolean (value, gtk_tree_view_get_headers_visible (tree_view));
1493       break;
1494     case PROP_HEADERS_CLICKABLE:
1495       g_value_set_boolean (value, gtk_tree_view_get_headers_clickable (tree_view));
1496       break;
1497     case PROP_EXPANDER_COLUMN:
1498       g_value_set_object (value, tree_view->priv->expander_column);
1499       break;
1500     case PROP_REORDERABLE:
1501       g_value_set_boolean (value, tree_view->priv->reorderable);
1502       break;
1503     case PROP_RULES_HINT:
1504       g_value_set_boolean (value, tree_view->priv->has_rules);
1505       break;
1506     case PROP_ENABLE_SEARCH:
1507       g_value_set_boolean (value, tree_view->priv->enable_search);
1508       break;
1509     case PROP_SEARCH_COLUMN:
1510       g_value_set_int (value, tree_view->priv->search_column);
1511       break;
1512     case PROP_FIXED_HEIGHT_MODE:
1513       g_value_set_boolean (value, tree_view->priv->fixed_height_mode);
1514       break;
1515     case PROP_HOVER_SELECTION:
1516       g_value_set_boolean (value, tree_view->priv->hover_selection);
1517       break;
1518     case PROP_HOVER_EXPAND:
1519       g_value_set_boolean (value, tree_view->priv->hover_expand);
1520       break;
1521     case PROP_SHOW_EXPANDERS:
1522       g_value_set_boolean (value, GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS));
1523       break;
1524     case PROP_LEVEL_INDENTATION:
1525       g_value_set_int (value, tree_view->priv->level_indentation);
1526       break;
1527     case PROP_RUBBER_BANDING:
1528       g_value_set_boolean (value, tree_view->priv->rubber_banding_enable);
1529       break;
1530     case PROP_ENABLE_GRID_LINES:
1531       g_value_set_enum (value, tree_view->priv->grid_lines);
1532       break;
1533     case PROP_ENABLE_TREE_LINES:
1534       g_value_set_boolean (value, tree_view->priv->tree_lines_enabled);
1535       break;
1536     case PROP_TOOLTIP_COLUMN:
1537       g_value_set_int (value, tree_view->priv->tooltip_column);
1538       break;
1539     default:
1540       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1541       break;
1542     }
1543 }
1544
1545 static void
1546 gtk_tree_view_finalize (GObject *object)
1547 {
1548   G_OBJECT_CLASS (gtk_tree_view_parent_class)->finalize (object);
1549 }
1550
1551 \f
1552
1553 static void
1554 gtk_tree_view_buildable_add_child (GtkBuildable *tree_view,
1555                                    GtkBuilder  *builder,
1556                                    GObject     *child,
1557                                    const gchar *type)
1558 {
1559   gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), GTK_TREE_VIEW_COLUMN (child));
1560 }
1561
1562 /* GtkObject Methods
1563  */
1564
1565 static void
1566 gtk_tree_view_free_rbtree (GtkTreeView *tree_view)
1567 {
1568   _gtk_rbtree_free (tree_view->priv->tree);
1569   
1570   tree_view->priv->tree = NULL;
1571   tree_view->priv->button_pressed_node = NULL;
1572   tree_view->priv->button_pressed_tree = NULL;
1573   tree_view->priv->prelight_tree = NULL;
1574   tree_view->priv->prelight_node = NULL;
1575   tree_view->priv->expanded_collapsed_node = NULL;
1576   tree_view->priv->expanded_collapsed_tree = NULL;
1577 }
1578
1579 static void
1580 gtk_tree_view_destroy (GtkObject *object)
1581 {
1582   GtkTreeView *tree_view = GTK_TREE_VIEW (object);
1583   GList *list;
1584
1585   gtk_tree_view_stop_editing (tree_view, TRUE);
1586
1587   if (tree_view->priv->columns != NULL)
1588     {
1589       list = tree_view->priv->columns;
1590       while (list)
1591         {
1592           GtkTreeViewColumn *column;
1593           column = GTK_TREE_VIEW_COLUMN (list->data);
1594           list = list->next;
1595           gtk_tree_view_remove_column (tree_view, column);
1596         }
1597       tree_view->priv->columns = NULL;
1598     }
1599
1600   if (tree_view->priv->tree != NULL)
1601     {
1602       gtk_tree_view_unref_and_check_selection_tree (tree_view, tree_view->priv->tree);
1603
1604       gtk_tree_view_free_rbtree (tree_view);
1605     }
1606
1607   if (tree_view->priv->selection != NULL)
1608     {
1609       _gtk_tree_selection_set_tree_view (tree_view->priv->selection, NULL);
1610       g_object_unref (tree_view->priv->selection);
1611       tree_view->priv->selection = NULL;
1612     }
1613
1614   if (tree_view->priv->scroll_to_path != NULL)
1615     {
1616       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
1617       tree_view->priv->scroll_to_path = NULL;
1618     }
1619
1620   if (tree_view->priv->drag_dest_row != NULL)
1621     {
1622       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
1623       tree_view->priv->drag_dest_row = NULL;
1624     }
1625
1626   if (tree_view->priv->top_row != NULL)
1627     {
1628       gtk_tree_row_reference_free (tree_view->priv->top_row);
1629       tree_view->priv->top_row = NULL;
1630     }
1631
1632   if (tree_view->priv->column_drop_func_data &&
1633       tree_view->priv->column_drop_func_data_destroy)
1634     {
1635       tree_view->priv->column_drop_func_data_destroy (tree_view->priv->column_drop_func_data);
1636       tree_view->priv->column_drop_func_data = NULL;
1637     }
1638
1639   if (tree_view->priv->destroy_count_destroy &&
1640       tree_view->priv->destroy_count_data)
1641     {
1642       tree_view->priv->destroy_count_destroy (tree_view->priv->destroy_count_data);
1643       tree_view->priv->destroy_count_data = NULL;
1644     }
1645
1646   gtk_tree_row_reference_free (tree_view->priv->cursor);
1647   tree_view->priv->cursor = NULL;
1648
1649   gtk_tree_row_reference_free (tree_view->priv->anchor);
1650   tree_view->priv->anchor = NULL;
1651
1652   /* destroy interactive search dialog */
1653   if (tree_view->priv->search_window)
1654     {
1655       gtk_widget_destroy (tree_view->priv->search_window);
1656       tree_view->priv->search_window = NULL;
1657       tree_view->priv->search_entry = NULL;
1658       if (tree_view->priv->typeselect_flush_timeout)
1659         {
1660           g_source_remove (tree_view->priv->typeselect_flush_timeout);
1661           tree_view->priv->typeselect_flush_timeout = 0;
1662         }
1663     }
1664
1665   if (tree_view->priv->search_destroy && tree_view->priv->search_user_data)
1666     {
1667       tree_view->priv->search_destroy (tree_view->priv->search_user_data);
1668       tree_view->priv->search_user_data = NULL;
1669     }
1670
1671   if (tree_view->priv->search_position_destroy && tree_view->priv->search_position_user_data)
1672     {
1673       tree_view->priv->search_position_destroy (tree_view->priv->search_position_user_data);
1674       tree_view->priv->search_position_user_data = NULL;
1675     }
1676
1677   if (tree_view->priv->row_separator_destroy && tree_view->priv->row_separator_data)
1678     {
1679       tree_view->priv->row_separator_destroy (tree_view->priv->row_separator_data);
1680       tree_view->priv->row_separator_data = NULL;
1681     }
1682   
1683   gtk_tree_view_set_model (tree_view, NULL);
1684
1685   if (tree_view->priv->hadjustment)
1686     {
1687       g_object_unref (tree_view->priv->hadjustment);
1688       tree_view->priv->hadjustment = NULL;
1689     }
1690   if (tree_view->priv->vadjustment)
1691     {
1692       g_object_unref (tree_view->priv->vadjustment);
1693       tree_view->priv->vadjustment = NULL;
1694     }
1695
1696   GTK_OBJECT_CLASS (gtk_tree_view_parent_class)->destroy (object);
1697 }
1698
1699 \f
1700
1701 /* GtkWidget Methods
1702  */
1703
1704 /* GtkWidget::map helper */
1705 static void
1706 gtk_tree_view_map_buttons (GtkTreeView *tree_view)
1707 {
1708   GList *list;
1709
1710   g_return_if_fail (GTK_WIDGET_MAPPED (tree_view));
1711
1712   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
1713     {
1714       GtkTreeViewColumn *column;
1715
1716       for (list = tree_view->priv->columns; list; list = list->next)
1717         {
1718           column = list->data;
1719           if (GTK_WIDGET_VISIBLE (column->button) &&
1720               !GTK_WIDGET_MAPPED (column->button))
1721             gtk_widget_map (column->button);
1722         }
1723       for (list = tree_view->priv->columns; list; list = list->next)
1724         {
1725           column = list->data;
1726           if (column->visible == FALSE)
1727             continue;
1728           if (column->resizable)
1729             {
1730               gdk_window_raise (column->window);
1731               gdk_window_show (column->window);
1732             }
1733           else
1734             gdk_window_hide (column->window);
1735         }
1736       gdk_window_show (tree_view->priv->header_window);
1737     }
1738 }
1739
1740 static void
1741 gtk_tree_view_map (GtkWidget *widget)
1742 {
1743   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
1744   GList *tmp_list;
1745
1746   GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
1747
1748   tmp_list = tree_view->priv->children;
1749   while (tmp_list)
1750     {
1751       GtkTreeViewChild *child = tmp_list->data;
1752       tmp_list = tmp_list->next;
1753
1754       if (GTK_WIDGET_VISIBLE (child->widget))
1755         {
1756           if (!GTK_WIDGET_MAPPED (child->widget))
1757             gtk_widget_map (child->widget);
1758         }
1759     }
1760   gdk_window_show (tree_view->priv->bin_window);
1761
1762   gtk_tree_view_map_buttons (tree_view);
1763
1764   gdk_window_show (widget->window);
1765 }
1766
1767 static void
1768 gtk_tree_view_realize (GtkWidget *widget)
1769 {
1770   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
1771   GList *tmp_list;
1772   GdkWindowAttr attributes;
1773   gint attributes_mask;
1774
1775   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
1776
1777   /* Make the main, clipping window */
1778   attributes.window_type = GDK_WINDOW_CHILD;
1779   attributes.x = widget->allocation.x;
1780   attributes.y = widget->allocation.y;
1781   attributes.width = widget->allocation.width;
1782   attributes.height = widget->allocation.height;
1783   attributes.wclass = GDK_INPUT_OUTPUT;
1784   attributes.visual = gtk_widget_get_visual (widget);
1785   attributes.colormap = gtk_widget_get_colormap (widget);
1786   attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK;
1787
1788   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
1789
1790   widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
1791                                    &attributes, attributes_mask);
1792   gdk_window_set_user_data (widget->window, widget);
1793
1794   /* Make the window for the tree */
1795   attributes.x = 0;
1796   attributes.y = TREE_VIEW_HEADER_HEIGHT (tree_view);
1797   attributes.width = MAX (tree_view->priv->width, widget->allocation.width);
1798   attributes.height = widget->allocation.height;
1799   attributes.event_mask = (GDK_EXPOSURE_MASK |
1800                            GDK_SCROLL_MASK |
1801                            GDK_POINTER_MOTION_MASK |
1802                            GDK_ENTER_NOTIFY_MASK |
1803                            GDK_LEAVE_NOTIFY_MASK |
1804                            GDK_BUTTON_PRESS_MASK |
1805                            GDK_BUTTON_RELEASE_MASK |
1806                            gtk_widget_get_events (widget));
1807
1808   tree_view->priv->bin_window = gdk_window_new (widget->window,
1809                                                 &attributes, attributes_mask);
1810   gdk_window_set_user_data (tree_view->priv->bin_window, widget);
1811
1812   /* Make the column header window */
1813   attributes.x = 0;
1814   attributes.y = 0;
1815   attributes.width = MAX (tree_view->priv->width, widget->allocation.width);
1816   attributes.height = tree_view->priv->header_height;
1817   attributes.event_mask = (GDK_EXPOSURE_MASK |
1818                            GDK_SCROLL_MASK |
1819                            GDK_BUTTON_PRESS_MASK |
1820                            GDK_BUTTON_RELEASE_MASK |
1821                            GDK_KEY_PRESS_MASK |
1822                            GDK_KEY_RELEASE_MASK |
1823                            gtk_widget_get_events (widget));
1824
1825   tree_view->priv->header_window = gdk_window_new (widget->window,
1826                                                    &attributes, attributes_mask);
1827   gdk_window_set_user_data (tree_view->priv->header_window, widget);
1828
1829   /* Add them all up. */
1830   widget->style = gtk_style_attach (widget->style, widget->window);
1831   gdk_window_set_back_pixmap (widget->window, NULL, FALSE);
1832   gdk_window_set_background (tree_view->priv->bin_window, &widget->style->base[widget->state]);
1833   gtk_style_set_background (widget->style, tree_view->priv->header_window, GTK_STATE_NORMAL);
1834
1835   tmp_list = tree_view->priv->children;
1836   while (tmp_list)
1837     {
1838       GtkTreeViewChild *child = tmp_list->data;
1839       tmp_list = tmp_list->next;
1840
1841       gtk_widget_set_parent_window (child->widget, tree_view->priv->bin_window);
1842     }
1843
1844   for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
1845     _gtk_tree_view_column_realize_button (GTK_TREE_VIEW_COLUMN (tmp_list->data));
1846
1847   /* Need to call those here, since they create GCs */
1848   gtk_tree_view_set_grid_lines (tree_view, tree_view->priv->grid_lines);
1849   gtk_tree_view_set_enable_tree_lines (tree_view, tree_view->priv->tree_lines_enabled);
1850
1851   install_presize_handler (tree_view); 
1852 }
1853
1854 static void
1855 gtk_tree_view_unrealize (GtkWidget *widget)
1856 {
1857   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
1858   GtkTreeViewPrivate *priv = tree_view->priv;
1859   GList *list;
1860
1861   if (priv->scroll_timeout != 0)
1862     {
1863       g_source_remove (priv->scroll_timeout);
1864       priv->scroll_timeout = 0;
1865     }
1866
1867   if (priv->auto_expand_timeout != 0)
1868     {
1869       g_source_remove (priv->auto_expand_timeout);
1870       priv->auto_expand_timeout = 0;
1871     }
1872
1873   if (priv->open_dest_timeout != 0)
1874     {
1875       g_source_remove (priv->open_dest_timeout);
1876       priv->open_dest_timeout = 0;
1877     }
1878
1879   remove_expand_collapse_timeout (tree_view);
1880   
1881   if (priv->presize_handler_timer != 0)
1882     {
1883       g_source_remove (priv->presize_handler_timer);
1884       priv->presize_handler_timer = 0;
1885     }
1886
1887   if (priv->validate_rows_timer != 0)
1888     {
1889       g_source_remove (priv->validate_rows_timer);
1890       priv->validate_rows_timer = 0;
1891     }
1892
1893   if (priv->scroll_sync_timer != 0)
1894     {
1895       g_source_remove (priv->scroll_sync_timer);
1896       priv->scroll_sync_timer = 0;
1897     }
1898
1899   if (priv->typeselect_flush_timeout)
1900     {
1901       g_source_remove (priv->typeselect_flush_timeout);
1902       priv->typeselect_flush_timeout = 0;
1903     }
1904   
1905   for (list = priv->columns; list; list = list->next)
1906     _gtk_tree_view_column_unrealize_button (GTK_TREE_VIEW_COLUMN (list->data));
1907
1908   gdk_window_set_user_data (priv->bin_window, NULL);
1909   gdk_window_destroy (priv->bin_window);
1910   priv->bin_window = NULL;
1911
1912   gdk_window_set_user_data (priv->header_window, NULL);
1913   gdk_window_destroy (priv->header_window);
1914   priv->header_window = NULL;
1915
1916   if (priv->drag_window)
1917     {
1918       gdk_window_set_user_data (priv->drag_window, NULL);
1919       gdk_window_destroy (priv->drag_window);
1920       priv->drag_window = NULL;
1921     }
1922
1923   if (priv->drag_highlight_window)
1924     {
1925       gdk_window_set_user_data (priv->drag_highlight_window, NULL);
1926       gdk_window_destroy (priv->drag_highlight_window);
1927       priv->drag_highlight_window = NULL;
1928     }
1929
1930   if (priv->tree_line_gc)
1931     {
1932       g_object_unref (priv->tree_line_gc);
1933       priv->tree_line_gc = NULL;
1934     }
1935
1936   if (priv->grid_line_gc)
1937     {
1938       g_object_unref (priv->grid_line_gc);
1939       priv->grid_line_gc = NULL;
1940     }
1941
1942   GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->unrealize (widget);
1943 }
1944
1945 /* GtkWidget::size_request helper */
1946 static void
1947 gtk_tree_view_size_request_columns (GtkTreeView *tree_view)
1948 {
1949   GList *list;
1950
1951   tree_view->priv->header_height = 0;
1952
1953   if (tree_view->priv->model)
1954     {
1955       for (list = tree_view->priv->columns; list; list = list->next)
1956         {
1957           GtkRequisition requisition;
1958           GtkTreeViewColumn *column = list->data;
1959
1960           if (column->button == NULL)
1961             continue;
1962
1963           column = list->data;
1964           
1965           gtk_widget_size_request (column->button, &requisition);
1966           column->button_request = requisition.width;
1967           tree_view->priv->header_height = MAX (tree_view->priv->header_height, requisition.height);
1968         }
1969     }
1970 }
1971
1972
1973 /* Called only by ::size_request */
1974 static void
1975 gtk_tree_view_update_size (GtkTreeView *tree_view)
1976 {
1977   GList *list;
1978   GtkTreeViewColumn *column;
1979   gint i;
1980
1981   if (tree_view->priv->model == NULL)
1982     {
1983       tree_view->priv->width = 0;
1984       tree_view->priv->prev_width = 0;                   
1985       tree_view->priv->height = 0;
1986       return;
1987     }
1988
1989   tree_view->priv->prev_width = tree_view->priv->width;  
1990   tree_view->priv->width = 0;
1991
1992   /* keep this in sync with size_allocate below */
1993   for (list = tree_view->priv->columns, i = 0; list; list = list->next, i++)
1994     {
1995       gint real_requested_width = 0;
1996       column = list->data;
1997       if (!column->visible)
1998         continue;
1999
2000       if (column->use_resized_width)
2001         {
2002           real_requested_width = column->resized_width;
2003         }
2004       else if (column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
2005         {
2006           real_requested_width = column->fixed_width;
2007         }
2008       else if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
2009         {
2010           real_requested_width = MAX (column->requested_width, column->button_request);
2011         }
2012       else
2013         {
2014           real_requested_width = column->requested_width;
2015         }
2016
2017       if (column->min_width != -1)
2018         real_requested_width = MAX (real_requested_width, column->min_width);
2019       if (column->max_width != -1)
2020         real_requested_width = MIN (real_requested_width, column->max_width);
2021
2022       tree_view->priv->width += real_requested_width;
2023     }
2024
2025   if (tree_view->priv->tree == NULL)
2026     tree_view->priv->height = 0;
2027   else
2028     tree_view->priv->height = tree_view->priv->tree->root->offset;
2029 }
2030
2031 static void
2032 gtk_tree_view_size_request (GtkWidget      *widget,
2033                             GtkRequisition *requisition)
2034 {
2035   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2036   GList *tmp_list;
2037
2038   /* we validate some rows initially just to make sure we have some size. 
2039    * In practice, with a lot of static lists, this should get a good width.
2040    */
2041   do_validate_rows (tree_view, FALSE);
2042   gtk_tree_view_size_request_columns (tree_view);
2043   gtk_tree_view_update_size (GTK_TREE_VIEW (widget));
2044
2045   requisition->width = tree_view->priv->width;
2046   requisition->height = tree_view->priv->height + TREE_VIEW_HEADER_HEIGHT (tree_view);
2047
2048   tmp_list = tree_view->priv->children;
2049
2050   while (tmp_list)
2051     {
2052       GtkTreeViewChild *child = tmp_list->data;
2053       GtkRequisition child_requisition;
2054
2055       tmp_list = tmp_list->next;
2056
2057       if (GTK_WIDGET_VISIBLE (child->widget))
2058         gtk_widget_size_request (child->widget, &child_requisition);
2059     }
2060 }
2061
2062 static int
2063 gtk_tree_view_calculate_width_before_expander (GtkTreeView *tree_view)
2064 {
2065   int width = 0;
2066   GList *list;
2067   gboolean rtl;
2068
2069   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2070   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
2071        list->data != tree_view->priv->expander_column;
2072        list = (rtl ? list->prev : list->next))
2073     {
2074       GtkTreeViewColumn *column = list->data;
2075
2076       width += column->width;
2077     }
2078
2079   return width;
2080 }
2081
2082 static void
2083 invalidate_column (GtkTreeView       *tree_view,
2084                    GtkTreeViewColumn *column)
2085 {
2086   gint column_offset = 0;
2087   GList *list;
2088   GtkWidget *widget = GTK_WIDGET (tree_view);
2089   gboolean rtl;
2090
2091   if (!GTK_WIDGET_REALIZED (widget))
2092     return;
2093
2094   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2095   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
2096        list;
2097        list = (rtl ? list->prev : list->next))
2098     {
2099       GtkTreeViewColumn *tmpcolumn = list->data;
2100       if (tmpcolumn == column)
2101         {
2102           GdkRectangle invalid_rect;
2103           
2104           invalid_rect.x = column_offset;
2105           invalid_rect.y = 0;
2106           invalid_rect.width = column->width;
2107           invalid_rect.height = widget->allocation.height;
2108           
2109           gdk_window_invalidate_rect (widget->window, &invalid_rect, TRUE);
2110           break;
2111         }
2112       
2113       column_offset += tmpcolumn->width;
2114     }
2115 }
2116
2117 static void
2118 invalidate_last_column (GtkTreeView *tree_view)
2119 {
2120   GList *last_column;
2121   gboolean rtl;
2122
2123   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2124
2125   for (last_column = (rtl ? g_list_first (tree_view->priv->columns) : g_list_last (tree_view->priv->columns));
2126        last_column;
2127        last_column = (rtl ? last_column->next : last_column->prev))
2128     {
2129       if (GTK_TREE_VIEW_COLUMN (last_column->data)->visible)
2130         {
2131           invalidate_column (tree_view, last_column->data);
2132           return;
2133         }
2134     }
2135 }
2136
2137 static gint
2138 gtk_tree_view_get_real_requested_width_from_column (GtkTreeView       *tree_view,
2139                                                     GtkTreeViewColumn *column)
2140 {
2141   gint real_requested_width;
2142
2143   if (column->use_resized_width)
2144     {
2145       real_requested_width = column->resized_width;
2146     }
2147   else if (column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
2148     {
2149       real_requested_width = column->fixed_width;
2150     }
2151   else if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
2152     {
2153       real_requested_width = MAX (column->requested_width, column->button_request);
2154     }
2155   else
2156     {
2157       real_requested_width = column->requested_width;
2158       if (real_requested_width < 0)
2159         real_requested_width = 0;
2160     }
2161
2162   if (column->min_width != -1)
2163     real_requested_width = MAX (real_requested_width, column->min_width);
2164   if (column->max_width != -1)
2165     real_requested_width = MIN (real_requested_width, column->max_width);
2166
2167   return real_requested_width;
2168 }
2169
2170 static gint
2171 gtk_tree_view_get_real_natural_width_from_column (GtkTreeView       *tree_view,
2172                                                   GtkTreeViewColumn *column)
2173 {
2174   GtkTreeViewColumnPrivate *column_priv;
2175   GtkRequisition button_natural_size;
2176   gint column_natural_width;
2177
2178   column_priv = GTK_TREE_VIEW_COLUMN_GET_PRIVATE (column);
2179   column_natural_width = column_priv->natural_width;
2180
2181   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
2182     {
2183       gtk_extended_layout_get_desired_size (GTK_EXTENDED_LAYOUT (column->button),
2184                                             NULL, &button_natural_size);
2185
2186       column_natural_width = MAX (column_natural_width, button_natural_size.width);
2187     }
2188
2189   return column_natural_width;
2190 }
2191
2192 /* GtkWidget::size_allocate helper */
2193 static void
2194 gtk_tree_view_size_allocate_columns (GtkWidget *widget,
2195                                      gboolean  *width_changed)
2196 {
2197   GtkTreeView *tree_view;
2198   GList *list, *first_column, *last_column;
2199   GtkTreeViewColumn *column;
2200   GtkAllocation allocation;
2201   gint width = 0, natural_width;
2202   gint extra, extra_per_column, extra_for_last;
2203   gint full_requested_width = 0;
2204   gint full_natural_width = 0;
2205   gint number_of_expand_columns = 0;
2206   gboolean column_changed = FALSE;
2207   gboolean rtl;
2208   gboolean update_expand;
2209   
2210   tree_view = GTK_TREE_VIEW (widget);
2211
2212   for (last_column = g_list_last (tree_view->priv->columns);
2213        last_column && !(GTK_TREE_VIEW_COLUMN (last_column->data)->visible);
2214        last_column = last_column->prev)
2215     ;
2216   if (last_column == NULL)
2217     return;
2218
2219   for (first_column = g_list_first (tree_view->priv->columns);
2220        first_column && !(GTK_TREE_VIEW_COLUMN (first_column->data)->visible);
2221        first_column = first_column->next)
2222     ;
2223
2224   allocation.y = 0;
2225   allocation.height = tree_view->priv->header_height;
2226
2227   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
2228
2229   /* find out how many extra space and expandable columns we have */
2230   for (list = tree_view->priv->columns; list != last_column->next; list = list->next)
2231     {
2232       column = (GtkTreeViewColumn *)list->data;
2233
2234       if (!column->visible)
2235         continue;
2236
2237       full_requested_width += gtk_tree_view_get_real_requested_width_from_column (tree_view, column);
2238       full_natural_width += gtk_tree_view_get_real_natural_width_from_column (tree_view, column);
2239
2240       if (column->expand)
2241         number_of_expand_columns++;
2242     }
2243
2244   /* Only update the expand value if the width of the widget has changed,
2245    * or the number of expand columns has changed, or if there are no expand
2246    * columns, or if we didn't have an size-allocation yet after the
2247    * last validated node.
2248    */
2249   update_expand = (width_changed && *width_changed == TRUE)
2250       || number_of_expand_columns != tree_view->priv->last_number_of_expand_columns
2251       || number_of_expand_columns == 0
2252       || tree_view->priv->post_validation_flag == TRUE;
2253
2254   tree_view->priv->post_validation_flag = FALSE;
2255
2256   if (!update_expand)
2257     {
2258       extra = tree_view->priv->last_extra_space;
2259       extra_for_last = MAX (widget->allocation.width - full_requested_width - extra, 0);
2260     }
2261   else
2262     {
2263       full_natural_width -= full_requested_width;
2264       extra = MAX (widget->allocation.width - full_requested_width, 0);
2265       natural_width = MIN (extra, full_natural_width);
2266       extra_for_last = 0;
2267
2268       tree_view->priv->last_extra_space = extra;
2269     }
2270
2271   if (number_of_expand_columns > 0)
2272     extra_per_column = extra/number_of_expand_columns;
2273   else
2274     extra_per_column = 0;
2275
2276   if (update_expand)
2277     {
2278       tree_view->priv->last_extra_space_per_column = extra_per_column;
2279       tree_view->priv->last_number_of_expand_columns = number_of_expand_columns;
2280     }
2281
2282   for (list = (rtl ? last_column : first_column); 
2283        list != (rtl ? first_column->prev : last_column->next);
2284        list = (rtl ? list->prev : list->next)) 
2285     {
2286       gint real_requested_width = 0;
2287       gint real_natural_width = 0;
2288       gint old_width;
2289
2290       column = list->data;
2291       old_width = column->width;
2292
2293       if (!column->visible)
2294         continue;
2295
2296       /* We need to handle the dragged button specially.
2297        */
2298       if (column == tree_view->priv->drag_column)
2299         {
2300           GtkAllocation drag_allocation;
2301           gdk_drawable_get_size (tree_view->priv->drag_window,
2302                                  &(drag_allocation.width),
2303                                  &(drag_allocation.height));
2304           drag_allocation.x = 0;
2305           drag_allocation.y = 0;
2306           gtk_widget_size_allocate (tree_view->priv->drag_column->button,
2307                                     &drag_allocation);
2308           width += drag_allocation.width;
2309           continue;
2310         }
2311
2312       real_requested_width = gtk_tree_view_get_real_requested_width_from_column (tree_view, column);
2313       real_natural_width = gtk_tree_view_get_real_natural_width_from_column (tree_view, column);
2314       real_natural_width -= real_requested_width;
2315
2316       allocation.x = width;
2317       column->width = real_requested_width;
2318
2319       if (full_natural_width > 0)
2320         column->width += natural_width * real_natural_width / full_natural_width;
2321       if (column->expand)
2322         {
2323           if (number_of_expand_columns == 1)
2324             {
2325               /* We add the remander to the last column as
2326                * */
2327               column->width += extra;
2328             }
2329           else
2330             {
2331               column->width += extra_per_column;
2332               extra -= extra_per_column;
2333               number_of_expand_columns --;
2334             }
2335         }
2336       else if (number_of_expand_columns == 0 &&
2337                list == last_column)
2338         {
2339           column->width += extra;
2340         }
2341
2342       /* In addition to expand, the last column can get even more
2343        * extra space so all available space is filled up.
2344        */
2345       if (extra_for_last > 0 && list == last_column)
2346         column->width += extra_for_last;
2347
2348       g_object_notify (G_OBJECT (column), "width");
2349
2350       allocation.width = column->width;
2351       width += column->width;
2352
2353       if (column->width > old_width)
2354         column_changed = TRUE;
2355
2356       gtk_widget_size_allocate (column->button, &allocation);
2357
2358       if (column->window)
2359         gdk_window_move_resize (column->window,
2360                                 allocation.x + (rtl ? 0 : allocation.width) - TREE_VIEW_DRAG_WIDTH/2,
2361                                 allocation.y,
2362                                 TREE_VIEW_DRAG_WIDTH, allocation.height);
2363     }
2364
2365   /* We change the width here.  The user might have been resizing columns,
2366    * so the total width of the tree view changes.
2367    */
2368   tree_view->priv->width = width;
2369   if (width_changed)
2370     *width_changed = TRUE;
2371
2372   if (column_changed)
2373     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
2374 }
2375
2376
2377 static void
2378 gtk_tree_view_size_allocate (GtkWidget     *widget,
2379                              GtkAllocation *allocation)
2380 {
2381   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2382   GList *tmp_list;
2383   gboolean width_changed = FALSE;
2384   gint old_width = widget->allocation.width;
2385
2386   if (allocation->width != widget->allocation.width)
2387     width_changed = TRUE;
2388
2389   widget->allocation = *allocation;
2390
2391   tmp_list = tree_view->priv->children;
2392
2393   while (tmp_list)
2394     {
2395       GtkAllocation allocation;
2396
2397       GtkTreeViewChild *child = tmp_list->data;
2398       tmp_list = tmp_list->next;
2399
2400       /* totally ignore our child's requisition */
2401       allocation.x = child->x;
2402       allocation.y = child->y;
2403       allocation.width = child->width;
2404       allocation.height = child->height;
2405       gtk_widget_size_allocate (child->widget, &allocation);
2406     }
2407
2408   /* We size-allocate the columns first because the width of the
2409    * tree view (used in updating the adjustments below) might change.
2410    */
2411   gtk_tree_view_size_allocate_columns (widget, &width_changed);
2412
2413   tree_view->priv->hadjustment->page_size = allocation->width;
2414   tree_view->priv->hadjustment->page_increment = allocation->width * 0.9;
2415   tree_view->priv->hadjustment->step_increment = allocation->width * 0.1;
2416   tree_view->priv->hadjustment->lower = 0;
2417   tree_view->priv->hadjustment->upper = MAX (tree_view->priv->hadjustment->page_size, tree_view->priv->width);
2418
2419   if (gtk_widget_get_direction(widget) == GTK_TEXT_DIR_RTL)   
2420     {
2421       if (allocation->width < tree_view->priv->width)
2422         {
2423           if (tree_view->priv->init_hadjust_value)
2424             {
2425               tree_view->priv->hadjustment->value = MAX (tree_view->priv->width - allocation->width, 0);
2426               tree_view->priv->init_hadjust_value = FALSE;
2427             }
2428           else if (allocation->width != old_width)
2429             {
2430               tree_view->priv->hadjustment->value = CLAMP (tree_view->priv->hadjustment->value - allocation->width + old_width, 0, tree_view->priv->width - allocation->width);
2431             }
2432           else
2433             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);
2434         }
2435       else
2436         {
2437           tree_view->priv->hadjustment->value = 0;
2438           tree_view->priv->init_hadjust_value = TRUE;
2439         }
2440     }
2441   else
2442     if (tree_view->priv->hadjustment->value + allocation->width > tree_view->priv->width)
2443       tree_view->priv->hadjustment->value = MAX (tree_view->priv->width - allocation->width, 0);
2444
2445   gtk_adjustment_changed (tree_view->priv->hadjustment);
2446
2447   tree_view->priv->vadjustment->page_size = allocation->height - TREE_VIEW_HEADER_HEIGHT (tree_view);
2448   tree_view->priv->vadjustment->step_increment = tree_view->priv->vadjustment->page_size * 0.1;
2449   tree_view->priv->vadjustment->page_increment = tree_view->priv->vadjustment->page_size * 0.9;
2450   tree_view->priv->vadjustment->lower = 0;
2451   tree_view->priv->vadjustment->upper = MAX (tree_view->priv->vadjustment->page_size, tree_view->priv->height);
2452
2453   gtk_adjustment_changed (tree_view->priv->vadjustment);
2454
2455   /* now the adjustments and window sizes are in sync, we can sync toprow/dy again */
2456   if (tree_view->priv->height <= tree_view->priv->vadjustment->page_size)
2457     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
2458   else if (tree_view->priv->vadjustment->value + tree_view->priv->vadjustment->page_size > tree_view->priv->height)
2459     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment),
2460                               tree_view->priv->height - tree_view->priv->vadjustment->page_size);
2461   else if (gtk_tree_row_reference_valid (tree_view->priv->top_row))
2462     gtk_tree_view_top_row_to_dy (tree_view);
2463   else
2464     gtk_tree_view_dy_to_top_row (tree_view);
2465   
2466   if (GTK_WIDGET_REALIZED (widget))
2467     {
2468       gdk_window_move_resize (widget->window,
2469                               allocation->x, allocation->y,
2470                               allocation->width, allocation->height);
2471       gdk_window_move_resize (tree_view->priv->header_window,
2472                               - (gint) tree_view->priv->hadjustment->value,
2473                               0,
2474                               MAX (tree_view->priv->width, allocation->width),
2475                               tree_view->priv->header_height);
2476       gdk_window_move_resize (tree_view->priv->bin_window,
2477                               - (gint) tree_view->priv->hadjustment->value,
2478                               TREE_VIEW_HEADER_HEIGHT (tree_view),
2479                               MAX (tree_view->priv->width, allocation->width),
2480                               allocation->height - TREE_VIEW_HEADER_HEIGHT (tree_view));
2481     }
2482
2483   if (tree_view->priv->tree == NULL)
2484     invalidate_empty_focus (tree_view);
2485
2486   if (GTK_WIDGET_REALIZED (widget))
2487     {
2488       gboolean has_expand_column = FALSE;
2489       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
2490         {
2491           if (gtk_tree_view_column_get_expand (GTK_TREE_VIEW_COLUMN (tmp_list->data)))
2492             {
2493               has_expand_column = TRUE;
2494               break;
2495             }
2496         }
2497
2498       if (width_changed && tree_view->priv->expander_column)
2499         {
2500           /* Might seem awkward, but is the best heuristic I could come up
2501            * with.  Only if the width of the columns before the expander
2502            * changes, we will update the prelight status.  It is this
2503            * width that makes the expander move vertically.  Always updating
2504            * prelight status causes trouble with hover selections.
2505            */
2506           gint width_before_expander;
2507
2508           width_before_expander = gtk_tree_view_calculate_width_before_expander (tree_view);
2509
2510           if (tree_view->priv->prev_width_before_expander
2511               != width_before_expander)
2512               update_prelight (tree_view,
2513                                tree_view->priv->event_last_x,
2514                                tree_view->priv->event_last_y);
2515
2516           tree_view->priv->prev_width_before_expander = width_before_expander;
2517         }
2518
2519       /* This little hack only works if we have an LTR locale, and no column has the  */
2520       if (width_changed)
2521         {
2522           if (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_LTR &&
2523               ! has_expand_column)
2524             invalidate_last_column (tree_view);
2525           else
2526             gtk_widget_queue_draw (widget);
2527         }
2528     }
2529 }
2530
2531 /* Grabs the focus and unsets the GTK_TREE_VIEW_DRAW_KEYFOCUS flag */
2532 static void
2533 grab_focus_and_unset_draw_keyfocus (GtkTreeView *tree_view)
2534 {
2535   if (GTK_WIDGET_CAN_FOCUS (tree_view) && !GTK_WIDGET_HAS_FOCUS (tree_view))
2536     gtk_widget_grab_focus (GTK_WIDGET (tree_view));
2537   GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
2538 }
2539
2540 static inline gboolean
2541 row_is_separator (GtkTreeView *tree_view,
2542                   GtkTreeIter *iter,
2543                   GtkTreePath *path)
2544 {
2545   gboolean is_separator = FALSE;
2546
2547   if (tree_view->priv->row_separator_func)
2548     {
2549       GtkTreeIter tmpiter;
2550
2551       if (iter)
2552         tmpiter = *iter;
2553       else
2554         gtk_tree_model_get_iter (tree_view->priv->model, &tmpiter, path);
2555
2556       is_separator = tree_view->priv->row_separator_func (tree_view->priv->model,
2557                                                           &tmpiter,
2558                                                           tree_view->priv->row_separator_data);
2559     }
2560
2561   return is_separator;
2562 }
2563
2564 static gboolean
2565 gtk_tree_view_button_press (GtkWidget      *widget,
2566                             GdkEventButton *event)
2567 {
2568   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2569   GList *list;
2570   GtkTreeViewColumn *column = NULL;
2571   gint i;
2572   GdkRectangle background_area;
2573   GdkRectangle cell_area;
2574   gint vertical_separator;
2575   gint horizontal_separator;
2576   gboolean path_is_selectable;
2577   gboolean rtl;
2578
2579   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
2580   gtk_tree_view_stop_editing (tree_view, FALSE);
2581   gtk_widget_style_get (widget,
2582                         "vertical-separator", &vertical_separator,
2583                         "horizontal-separator", &horizontal_separator,
2584                         NULL);
2585
2586
2587   /* Because grab_focus can cause reentrancy, we delay grab_focus until after
2588    * we're done handling the button press.
2589    */
2590
2591   if (event->window == tree_view->priv->bin_window)
2592     {
2593       GtkRBNode *node;
2594       GtkRBTree *tree;
2595       GtkTreePath *path;
2596       gchar *path_string;
2597       gint depth;
2598       gint new_y;
2599       gint y_offset;
2600       gint dval;
2601       gint pre_val, aft_val;
2602       GtkTreeViewColumn *column = NULL;
2603       GtkCellRenderer *focus_cell = NULL;
2604       gint column_handled_click = FALSE;
2605       gboolean row_double_click = FALSE;
2606       gboolean rtl;
2607       gboolean node_selected;
2608
2609       /* Empty tree? */
2610       if (tree_view->priv->tree == NULL)
2611         {
2612           grab_focus_and_unset_draw_keyfocus (tree_view);
2613           return TRUE;
2614         }
2615
2616       /* are we in an arrow? */
2617       if (tree_view->priv->prelight_node &&
2618           GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT) &&
2619           TREE_VIEW_DRAW_EXPANDERS (tree_view))
2620         {
2621           if (event->button == 1)
2622             {
2623               gtk_grab_add (widget);
2624               tree_view->priv->button_pressed_node = tree_view->priv->prelight_node;
2625               tree_view->priv->button_pressed_tree = tree_view->priv->prelight_tree;
2626               gtk_tree_view_draw_arrow (GTK_TREE_VIEW (widget),
2627                                         tree_view->priv->prelight_tree,
2628                                         tree_view->priv->prelight_node,
2629                                         event->x,
2630                                         event->y);
2631             }
2632
2633           grab_focus_and_unset_draw_keyfocus (tree_view);
2634           return TRUE;
2635         }
2636
2637       /* find the node that was clicked */
2638       new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
2639       if (new_y < 0)
2640         new_y = 0;
2641       y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
2642
2643       if (node == NULL)
2644         {
2645           /* We clicked in dead space */
2646           grab_focus_and_unset_draw_keyfocus (tree_view);
2647           return TRUE;
2648         }
2649
2650       /* Get the path and the node */
2651       path = _gtk_tree_view_find_path (tree_view, tree, node);
2652       path_is_selectable = !row_is_separator (tree_view, NULL, path);
2653
2654       if (!path_is_selectable)
2655         {
2656           gtk_tree_path_free (path);
2657           grab_focus_and_unset_draw_keyfocus (tree_view);
2658           return TRUE;
2659         }
2660
2661       depth = gtk_tree_path_get_depth (path);
2662       background_area.y = y_offset + event->y;
2663       background_area.height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
2664       background_area.x = 0;
2665
2666
2667       /* Let the column have a chance at selecting it. */
2668       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2669       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
2670            list; list = (rtl ? list->prev : list->next))
2671         {
2672           GtkTreeViewColumn *candidate = list->data;
2673
2674           if (!candidate->visible)
2675             continue;
2676
2677           background_area.width = candidate->width;
2678           if ((background_area.x > (gint) event->x) ||
2679               (background_area.x + background_area.width <= (gint) event->x))
2680             {
2681               background_area.x += background_area.width;
2682               continue;
2683             }
2684
2685           /* we found the focus column */
2686           column = candidate;
2687           cell_area = background_area;
2688           cell_area.width -= horizontal_separator;
2689           cell_area.height -= vertical_separator;
2690           cell_area.x += horizontal_separator/2;
2691           cell_area.y += vertical_separator/2;
2692           if (gtk_tree_view_is_expander_column (tree_view, column))
2693             {
2694               if (!rtl)
2695                 cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
2696               cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
2697
2698               if (TREE_VIEW_DRAW_EXPANDERS (tree_view))
2699                 {
2700                   if (!rtl)
2701                     cell_area.x += depth * tree_view->priv->expander_size;
2702                   cell_area.width -= depth * tree_view->priv->expander_size;
2703                 }
2704             }
2705           break;
2706         }
2707
2708       if (column == NULL)
2709         {
2710           gtk_tree_path_free (path);
2711           grab_focus_and_unset_draw_keyfocus (tree_view);
2712           return FALSE;
2713         }
2714
2715       tree_view->priv->focus_column = column;
2716
2717       /* decide if we edit */
2718       if (event->type == GDK_BUTTON_PRESS && event->button == 1 &&
2719           !(event->state & gtk_accelerator_get_default_mod_mask ()))
2720         {
2721           GtkTreePath *anchor;
2722           GtkTreeIter iter;
2723
2724           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
2725           gtk_tree_view_column_cell_set_cell_data (column,
2726                                                    tree_view->priv->model,
2727                                                    &iter,
2728                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
2729                                                    node->children?TRUE:FALSE);
2730
2731           if (tree_view->priv->anchor)
2732             anchor = gtk_tree_row_reference_get_path (tree_view->priv->anchor);
2733           else
2734             anchor = NULL;
2735
2736           if ((anchor && !gtk_tree_path_compare (anchor, path))
2737               || !_gtk_tree_view_column_has_editable_cell (column))
2738             {
2739               GtkCellEditable *cell_editable = NULL;
2740
2741               /* FIXME: get the right flags */
2742               guint flags = 0;
2743
2744               path_string = gtk_tree_path_to_string (path);
2745
2746               if (_gtk_tree_view_column_cell_event (column,
2747                                                     &cell_editable,
2748                                                     (GdkEvent *)event,
2749                                                     path_string,
2750                                                     &background_area,
2751                                                     &cell_area, flags))
2752                 {
2753                   if (cell_editable != NULL)
2754                     {
2755                       gint left, right;
2756                       GdkRectangle area;
2757
2758                       area = cell_area;
2759                       _gtk_tree_view_column_get_neighbor_sizes (column, _gtk_tree_view_column_get_edited_cell (column), &left, &right);
2760
2761                       area.x += left;
2762                       area.width -= right + left;
2763
2764                       gtk_tree_view_real_start_editing (tree_view,
2765                                                         column,
2766                                                         path,
2767                                                         cell_editable,
2768                                                         &area,
2769                                                         (GdkEvent *)event,
2770                                                         flags);
2771                       g_free (path_string);
2772                       gtk_tree_path_free (path);
2773                       gtk_tree_path_free (anchor);
2774                       return TRUE;
2775                     }
2776                   column_handled_click = TRUE;
2777                 }
2778               g_free (path_string);
2779             }
2780           if (anchor)
2781             gtk_tree_path_free (anchor);
2782         }
2783
2784       /* select */
2785       node_selected = GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED);
2786       pre_val = tree_view->priv->vadjustment->value;
2787
2788       /* we only handle selection modifications on the first button press
2789        */
2790       if (event->type == GDK_BUTTON_PRESS)
2791         {
2792           if ((event->state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
2793             tree_view->priv->ctrl_pressed = TRUE;
2794           if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
2795             tree_view->priv->shift_pressed = TRUE;
2796
2797           focus_cell = _gtk_tree_view_column_get_cell_at_pos (column, event->x - background_area.x);
2798           if (focus_cell)
2799             gtk_tree_view_column_focus_cell (column, focus_cell);
2800
2801           if (event->state & GDK_CONTROL_MASK)
2802             {
2803               gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
2804               gtk_tree_view_real_toggle_cursor_row (tree_view);
2805             }
2806           else if (event->state & GDK_SHIFT_MASK)
2807             {
2808               gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
2809               gtk_tree_view_real_select_cursor_row (tree_view, FALSE);
2810             }
2811           else
2812             {
2813               gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
2814             }
2815
2816           tree_view->priv->ctrl_pressed = FALSE;
2817           tree_view->priv->shift_pressed = FALSE;
2818         }
2819
2820       /* the treeview may have been scrolled because of _set_cursor,
2821        * correct here
2822        */
2823
2824       aft_val = tree_view->priv->vadjustment->value;
2825       dval = pre_val - aft_val;
2826
2827       cell_area.y += dval;
2828       background_area.y += dval;
2829
2830       /* Save press to possibly begin a drag
2831        */
2832       if (!column_handled_click &&
2833           !tree_view->priv->in_grab &&
2834           tree_view->priv->pressed_button < 0)
2835         {
2836           tree_view->priv->pressed_button = event->button;
2837           tree_view->priv->press_start_x = event->x;
2838           tree_view->priv->press_start_y = event->y;
2839
2840           if (tree_view->priv->rubber_banding_enable
2841               && !node_selected
2842               && tree_view->priv->selection->type == GTK_SELECTION_MULTIPLE)
2843             {
2844               tree_view->priv->press_start_y += tree_view->priv->dy;
2845               tree_view->priv->rubber_band_x = event->x;
2846               tree_view->priv->rubber_band_y = event->y + tree_view->priv->dy;
2847               tree_view->priv->rubber_band_status = RUBBER_BAND_MAYBE_START;
2848
2849               if ((event->state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
2850                 tree_view->priv->rubber_band_ctrl = TRUE;
2851               if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
2852                 tree_view->priv->rubber_band_shift = TRUE;
2853             }
2854         }
2855
2856       /* Test if a double click happened on the same row. */
2857       if (event->button == 1 && event->type == GDK_BUTTON_PRESS)
2858         {
2859           if (tree_view->priv->last_button_x != -1)
2860             {
2861               int double_click_time, double_click_distance;
2862
2863               g_object_get (gtk_settings_get_default (),
2864                             "gtk-double-click-time", &double_click_time,
2865                             "gtk-double-click-distance", &double_click_distance,
2866                             NULL);
2867
2868               /* Same conditions as _gdk_event_button_generate */
2869               if ((event->time < tree_view->priv->last_button_time + double_click_time) &&
2870                   (ABS (event->x - tree_view->priv->last_button_x) <= double_click_distance) &&
2871                   (ABS (event->y - tree_view->priv->last_button_y) <= double_click_distance))
2872                 {
2873                   /* We do no longer compare paths of this row and the
2874                    * row clicked previously.  We use the double click
2875                    * distance to decide whether this is a valid click,
2876                    * allowing the mouse to slightly move over another row.
2877                    */
2878                   row_double_click = TRUE;
2879                 }
2880
2881               tree_view->priv->last_button_time = 0;
2882               tree_view->priv->last_button_x = -1;
2883               tree_view->priv->last_button_y = -1;
2884             }
2885           else
2886             {
2887               tree_view->priv->last_button_time = event->time;
2888               tree_view->priv->last_button_x = event->x;
2889               tree_view->priv->last_button_y = event->y;
2890             }
2891         }
2892
2893       if (row_double_click)
2894         {
2895           gtk_grab_remove (widget);
2896           gtk_tree_view_row_activated (tree_view, path, column);
2897
2898           if (tree_view->priv->pressed_button == event->button)
2899             tree_view->priv->pressed_button = -1;
2900         }
2901
2902       gtk_tree_path_free (path);
2903
2904       /* If we activated the row through a double click we don't want to grab
2905        * focus back, as moving focus to another widget is pretty common.
2906        */
2907       if (!row_double_click)
2908         grab_focus_and_unset_draw_keyfocus (tree_view);
2909
2910       return TRUE;
2911     }
2912
2913   /* We didn't click in the window.  Let's check to see if we clicked on a column resize window.
2914    */
2915   for (i = 0, list = tree_view->priv->columns; list; list = list->next, i++)
2916     {
2917       column = list->data;
2918       if (event->window == column->window &&
2919           column->resizable &&
2920           column->window)
2921         {
2922           gpointer drag_data;
2923
2924           if (event->type == GDK_2BUTTON_PRESS &&
2925               gtk_tree_view_column_get_sizing (column) != GTK_TREE_VIEW_COLUMN_AUTOSIZE)
2926             {
2927               column->use_resized_width = FALSE;
2928               _gtk_tree_view_column_autosize (tree_view, column);
2929               return TRUE;
2930             }
2931
2932           if (gdk_pointer_grab (column->window, FALSE,
2933                                 GDK_POINTER_MOTION_HINT_MASK |
2934                                 GDK_BUTTON1_MOTION_MASK |
2935                                 GDK_BUTTON_RELEASE_MASK,
2936                                 NULL, NULL, event->time))
2937             return FALSE;
2938
2939           gtk_grab_add (widget);
2940           GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE);
2941           column->resized_width = column->width - tree_view->priv->last_extra_space_per_column;
2942
2943           /* block attached dnd signal handler */
2944           drag_data = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
2945           if (drag_data)
2946             g_signal_handlers_block_matched (widget,
2947                                              G_SIGNAL_MATCH_DATA,
2948                                              0, 0, NULL, NULL,
2949                                              drag_data);
2950
2951           tree_view->priv->drag_pos = i;
2952           tree_view->priv->x_drag = column->button->allocation.x + (rtl ? 0 : column->button->allocation.width);
2953
2954           if (!GTK_WIDGET_HAS_FOCUS (widget))
2955             gtk_widget_grab_focus (widget);
2956
2957           return TRUE;
2958         }
2959     }
2960   return FALSE;
2961 }
2962
2963 /* GtkWidget::button_release_event helper */
2964 static gboolean
2965 gtk_tree_view_button_release_drag_column (GtkWidget      *widget,
2966                                           GdkEventButton *event)
2967 {
2968   GtkTreeView *tree_view;
2969   GList *l;
2970   gboolean rtl;
2971
2972   tree_view = GTK_TREE_VIEW (widget);
2973
2974   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
2975   gdk_display_pointer_ungrab (gtk_widget_get_display (widget), GDK_CURRENT_TIME);
2976   gdk_display_keyboard_ungrab (gtk_widget_get_display (widget), GDK_CURRENT_TIME);
2977
2978   /* Move the button back */
2979   g_object_ref (tree_view->priv->drag_column->button);
2980   gtk_container_remove (GTK_CONTAINER (tree_view), tree_view->priv->drag_column->button);
2981   gtk_widget_set_parent_window (tree_view->priv->drag_column->button, tree_view->priv->header_window);
2982   gtk_widget_set_parent (tree_view->priv->drag_column->button, GTK_WIDGET (tree_view));
2983   g_object_unref (tree_view->priv->drag_column->button);
2984   gtk_widget_queue_resize (widget);
2985   if (tree_view->priv->drag_column->resizable)
2986     {
2987       gdk_window_raise (tree_view->priv->drag_column->window);
2988       gdk_window_show (tree_view->priv->drag_column->window);
2989     }
2990   else
2991     gdk_window_hide (tree_view->priv->drag_column->window);
2992
2993   gtk_widget_grab_focus (tree_view->priv->drag_column->button);
2994
2995   if (rtl)
2996     {
2997       if (tree_view->priv->cur_reorder &&
2998           tree_view->priv->cur_reorder->right_column != tree_view->priv->drag_column)
2999         gtk_tree_view_move_column_after (tree_view, tree_view->priv->drag_column,
3000                                          tree_view->priv->cur_reorder->right_column);
3001     }
3002   else
3003     {
3004       if (tree_view->priv->cur_reorder &&
3005           tree_view->priv->cur_reorder->left_column != tree_view->priv->drag_column)
3006         gtk_tree_view_move_column_after (tree_view, tree_view->priv->drag_column,
3007                                          tree_view->priv->cur_reorder->left_column);
3008     }
3009   tree_view->priv->drag_column = NULL;
3010   gdk_window_hide (tree_view->priv->drag_window);
3011
3012   for (l = tree_view->priv->column_drag_info; l != NULL; l = l->next)
3013     g_slice_free (GtkTreeViewColumnReorder, l->data);
3014   g_list_free (tree_view->priv->column_drag_info);
3015   tree_view->priv->column_drag_info = NULL;
3016   tree_view->priv->cur_reorder = NULL;
3017
3018   if (tree_view->priv->drag_highlight_window)
3019     gdk_window_hide (tree_view->priv->drag_highlight_window);
3020
3021   /* Reset our flags */
3022   tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_UNSET;
3023   GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG);
3024
3025   return TRUE;
3026 }
3027
3028 /* GtkWidget::button_release_event helper */
3029 static gboolean
3030 gtk_tree_view_button_release_column_resize (GtkWidget      *widget,
3031                                             GdkEventButton *event)
3032 {
3033   GtkTreeView *tree_view;
3034   gpointer drag_data;
3035
3036   tree_view = GTK_TREE_VIEW (widget);
3037
3038   tree_view->priv->drag_pos = -1;
3039
3040   /* unblock attached dnd signal handler */
3041   drag_data = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
3042   if (drag_data)
3043     g_signal_handlers_unblock_matched (widget,
3044                                        G_SIGNAL_MATCH_DATA,
3045                                        0, 0, NULL, NULL,
3046                                        drag_data);
3047
3048   GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE);
3049   gtk_grab_remove (widget);
3050   gdk_display_pointer_ungrab (gdk_drawable_get_display (event->window),
3051                               event->time);
3052   return TRUE;
3053 }
3054
3055 static gboolean
3056 gtk_tree_view_button_release (GtkWidget      *widget,
3057                               GdkEventButton *event)
3058 {
3059   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
3060
3061   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
3062     return gtk_tree_view_button_release_drag_column (widget, event);
3063
3064   if (tree_view->priv->rubber_band_status)
3065     gtk_tree_view_stop_rubber_band (tree_view);
3066
3067   if (tree_view->priv->pressed_button == event->button)
3068     tree_view->priv->pressed_button = -1;
3069
3070   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE))
3071     return gtk_tree_view_button_release_column_resize (widget, event);
3072
3073   if (tree_view->priv->button_pressed_node == NULL)
3074     return FALSE;
3075
3076   if (event->button == 1)
3077     {
3078       gtk_grab_remove (widget);
3079       if (tree_view->priv->button_pressed_node == tree_view->priv->prelight_node &&
3080           GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT))
3081         {
3082           GtkTreePath *path = NULL;
3083
3084           path = _gtk_tree_view_find_path (tree_view,
3085                                            tree_view->priv->button_pressed_tree,
3086                                            tree_view->priv->button_pressed_node);
3087           /* Actually activate the node */
3088           if (tree_view->priv->button_pressed_node->children == NULL)
3089             gtk_tree_view_real_expand_row (tree_view, path,
3090                                            tree_view->priv->button_pressed_tree,
3091                                            tree_view->priv->button_pressed_node,
3092                                            FALSE, TRUE);
3093           else
3094             gtk_tree_view_real_collapse_row (GTK_TREE_VIEW (widget), path,
3095                                              tree_view->priv->button_pressed_tree,
3096                                              tree_view->priv->button_pressed_node, TRUE);
3097           gtk_tree_path_free (path);
3098         }
3099
3100       tree_view->priv->button_pressed_tree = NULL;
3101       tree_view->priv->button_pressed_node = NULL;
3102     }
3103
3104   return TRUE;
3105 }
3106
3107 static gboolean
3108 gtk_tree_view_grab_broken (GtkWidget          *widget,
3109                            GdkEventGrabBroken *event)
3110 {
3111   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
3112
3113   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
3114     gtk_tree_view_button_release_drag_column (widget, (GdkEventButton *)event);
3115
3116   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE))
3117     gtk_tree_view_button_release_column_resize (widget, (GdkEventButton *)event);
3118
3119   return TRUE;
3120 }
3121
3122 #if 0
3123 static gboolean
3124 gtk_tree_view_configure (GtkWidget *widget,
3125                          GdkEventConfigure *event)
3126 {
3127   GtkTreeView *tree_view;
3128
3129   tree_view = GTK_TREE_VIEW (widget);
3130   tree_view->priv->search_position_func (tree_view, tree_view->priv->search_window);
3131
3132   return FALSE;
3133 }
3134 #endif
3135
3136 /* GtkWidget::motion_event function set.
3137  */
3138
3139 static gboolean
3140 coords_are_over_arrow (GtkTreeView *tree_view,
3141                        GtkRBTree   *tree,
3142                        GtkRBNode   *node,
3143                        /* these are in bin window coords */
3144                        gint         x,
3145                        gint         y)
3146 {
3147   GdkRectangle arrow;
3148   gint x2;
3149
3150   if (!GTK_WIDGET_REALIZED (tree_view))
3151     return FALSE;
3152
3153   if ((node->flags & GTK_RBNODE_IS_PARENT) == 0)
3154     return FALSE;
3155
3156   arrow.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
3157
3158   arrow.height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
3159
3160   gtk_tree_view_get_arrow_xrange (tree_view, tree, &arrow.x, &x2);
3161
3162   arrow.width = x2 - arrow.x;
3163
3164   return (x >= arrow.x &&
3165           x < (arrow.x + arrow.width) &&
3166           y >= arrow.y &&
3167           y < (arrow.y + arrow.height));
3168 }
3169
3170 static gboolean
3171 auto_expand_timeout (gpointer data)
3172 {
3173   GtkTreeView *tree_view = GTK_TREE_VIEW (data);
3174   GtkTreePath *path;
3175
3176   if (tree_view->priv->prelight_node)
3177     {
3178       path = _gtk_tree_view_find_path (tree_view,
3179                                        tree_view->priv->prelight_tree,
3180                                        tree_view->priv->prelight_node);   
3181
3182       if (tree_view->priv->prelight_node->children)
3183         gtk_tree_view_collapse_row (tree_view, path);
3184       else
3185         gtk_tree_view_expand_row (tree_view, path, FALSE);
3186
3187       gtk_tree_path_free (path);
3188     }
3189
3190   tree_view->priv->auto_expand_timeout = 0;
3191
3192   return FALSE;
3193 }
3194
3195 static void
3196 remove_auto_expand_timeout (GtkTreeView *tree_view)
3197 {
3198   if (tree_view->priv->auto_expand_timeout != 0)
3199     {
3200       g_source_remove (tree_view->priv->auto_expand_timeout);
3201       tree_view->priv->auto_expand_timeout = 0;
3202     }
3203 }
3204
3205 static void
3206 do_prelight (GtkTreeView *tree_view,
3207              GtkRBTree   *tree,
3208              GtkRBNode   *node,
3209              /* these are in bin_window coords */
3210              gint         x,
3211              gint         y)
3212 {
3213   if (tree_view->priv->prelight_tree == tree &&
3214       tree_view->priv->prelight_node == node)
3215     {
3216       /*  We are still on the same node,
3217           but we might need to take care of the arrow  */
3218
3219       if (tree && node && TREE_VIEW_DRAW_EXPANDERS (tree_view))
3220         {
3221           gboolean over_arrow;
3222           gboolean flag_set;
3223
3224           over_arrow = coords_are_over_arrow (tree_view, tree, node, x, y);
3225           flag_set = GTK_TREE_VIEW_FLAG_SET (tree_view,
3226                                              GTK_TREE_VIEW_ARROW_PRELIT);
3227
3228           if (over_arrow != flag_set)
3229             {
3230               if (over_arrow)
3231                 GTK_TREE_VIEW_SET_FLAG (tree_view,
3232                                         GTK_TREE_VIEW_ARROW_PRELIT);
3233               else
3234                 GTK_TREE_VIEW_UNSET_FLAG (tree_view,
3235                                           GTK_TREE_VIEW_ARROW_PRELIT);
3236
3237               gtk_tree_view_draw_arrow (tree_view, tree, node, x, y);
3238             }
3239         }
3240
3241       return;
3242     }
3243
3244   if (tree_view->priv->prelight_tree && tree_view->priv->prelight_node)
3245     {
3246       /*  Unprelight the old node and arrow  */
3247
3248       GTK_RBNODE_UNSET_FLAG (tree_view->priv->prelight_node,
3249                              GTK_RBNODE_IS_PRELIT);
3250
3251       if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT)
3252           && TREE_VIEW_DRAW_EXPANDERS (tree_view))
3253         {
3254           GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_ARROW_PRELIT);
3255           
3256           gtk_tree_view_draw_arrow (tree_view,
3257                                     tree_view->priv->prelight_tree,
3258                                     tree_view->priv->prelight_node,
3259                                     x,
3260                                     y);
3261         }
3262
3263       _gtk_tree_view_queue_draw_node (tree_view,
3264                                       tree_view->priv->prelight_tree,
3265                                       tree_view->priv->prelight_node,
3266                                       NULL);
3267     }
3268
3269
3270   if (tree_view->priv->hover_expand)
3271     remove_auto_expand_timeout (tree_view);
3272
3273   /*  Set the new prelight values  */
3274   tree_view->priv->prelight_node = node;
3275   tree_view->priv->prelight_tree = tree;
3276
3277   if (!node || !tree)
3278     return;
3279
3280   /*  Prelight the new node and arrow  */
3281
3282   if (TREE_VIEW_DRAW_EXPANDERS (tree_view)
3283       && coords_are_over_arrow (tree_view, tree, node, x, y))
3284     {
3285       GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_ARROW_PRELIT);
3286
3287       gtk_tree_view_draw_arrow (tree_view, tree, node, x, y);
3288     }
3289
3290   GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_PRELIT);
3291
3292   _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
3293
3294   if (tree_view->priv->hover_expand)
3295     {
3296       tree_view->priv->auto_expand_timeout = 
3297         gdk_threads_add_timeout (AUTO_EXPAND_TIMEOUT, auto_expand_timeout, tree_view);
3298     }
3299 }
3300
3301 static void
3302 prelight_or_select (GtkTreeView *tree_view,
3303                     GtkRBTree   *tree,
3304                     GtkRBNode   *node,
3305                     /* these are in bin_window coords */
3306                     gint         x,
3307                     gint         y)
3308 {
3309   GtkSelectionMode mode = gtk_tree_selection_get_mode (tree_view->priv->selection);
3310   
3311   if (tree_view->priv->hover_selection &&
3312       (mode == GTK_SELECTION_SINGLE || mode == GTK_SELECTION_BROWSE) &&
3313       !(tree_view->priv->edited_column &&
3314         tree_view->priv->edited_column->editable_widget))
3315     {
3316       if (node)
3317         {
3318           if (!GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
3319             {
3320               GtkTreePath *path;
3321               
3322               path = _gtk_tree_view_find_path (tree_view, tree, node);
3323               gtk_tree_selection_select_path (tree_view->priv->selection, path);
3324               if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
3325                 {
3326                   GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
3327                   gtk_tree_view_real_set_cursor (tree_view, path, FALSE, FALSE);
3328                 }
3329               gtk_tree_path_free (path);
3330             }
3331         }
3332
3333       else if (mode == GTK_SELECTION_SINGLE)
3334         gtk_tree_selection_unselect_all (tree_view->priv->selection);
3335     }
3336
3337     do_prelight (tree_view, tree, node, x, y);
3338 }
3339
3340 static void
3341 ensure_unprelighted (GtkTreeView *tree_view)
3342 {
3343   do_prelight (tree_view,
3344                NULL, NULL,
3345                -1000, -1000); /* coords not possibly over an arrow */
3346
3347   g_assert (tree_view->priv->prelight_node == NULL);
3348 }
3349
3350 static void
3351 update_prelight (GtkTreeView *tree_view,
3352                  gint         x,
3353                  gint         y)
3354 {
3355   int new_y;
3356   GtkRBTree *tree;
3357   GtkRBNode *node;
3358
3359   if (x == -10000)
3360     {
3361       ensure_unprelighted (tree_view);
3362       return;
3363     }
3364
3365   new_y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, y);
3366   if (new_y < 0)
3367     new_y = 0;
3368
3369   _gtk_rbtree_find_offset (tree_view->priv->tree,
3370                            new_y, &tree, &node);
3371
3372   if (node)
3373     prelight_or_select (tree_view, tree, node, x, y);
3374 }
3375
3376
3377
3378
3379 /* Our motion arrow is either a box (in the case of the original spot)
3380  * or an arrow.  It is expander_size wide.
3381  */
3382 /*
3383  * 11111111111111
3384  * 01111111111110
3385  * 00111111111100
3386  * 00011111111000
3387  * 00001111110000
3388  * 00000111100000
3389  * 00000111100000
3390  * 00000111100000
3391  * ~ ~ ~ ~ ~ ~ ~
3392  * 00000111100000
3393  * 00000111100000
3394  * 00000111100000
3395  * 00001111110000
3396  * 00011111111000
3397  * 00111111111100
3398  * 01111111111110
3399  * 11111111111111
3400  */
3401
3402 static void
3403 gtk_tree_view_motion_draw_column_motion_arrow (GtkTreeView *tree_view)
3404 {
3405   GtkTreeViewColumnReorder *reorder = tree_view->priv->cur_reorder;
3406   GtkWidget *widget = GTK_WIDGET (tree_view);
3407   GdkBitmap *mask = NULL;
3408   gint x;
3409   gint y;
3410   gint width;
3411   gint height;
3412   gint arrow_type = DRAG_COLUMN_WINDOW_STATE_UNSET;
3413   GdkWindowAttr attributes;
3414   guint attributes_mask;
3415
3416   if (!reorder ||
3417       reorder->left_column == tree_view->priv->drag_column ||
3418       reorder->right_column == tree_view->priv->drag_column)
3419     arrow_type = DRAG_COLUMN_WINDOW_STATE_ORIGINAL;
3420   else if (reorder->left_column || reorder->right_column)
3421     {
3422       GdkRectangle visible_rect;
3423       gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
3424       if (reorder->left_column)
3425         x = reorder->left_column->button->allocation.x + reorder->left_column->button->allocation.width;
3426       else
3427         x = reorder->right_column->button->allocation.x;
3428
3429       if (x < visible_rect.x)
3430         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT;
3431       else if (x > visible_rect.x + visible_rect.width)
3432         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT;
3433       else
3434         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW;
3435     }
3436
3437   /* We want to draw the rectangle over the initial location. */
3438   if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ORIGINAL)
3439     {
3440       GdkGC *gc;
3441       GdkColor col;
3442
3443       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ORIGINAL)
3444         {
3445           if (tree_view->priv->drag_highlight_window)
3446             {
3447               gdk_window_set_user_data (tree_view->priv->drag_highlight_window,
3448                                         NULL);
3449               gdk_window_destroy (tree_view->priv->drag_highlight_window);
3450             }
3451
3452           attributes.window_type = GDK_WINDOW_CHILD;
3453           attributes.wclass = GDK_INPUT_OUTPUT;
3454           attributes.x = tree_view->priv->drag_column_x;
3455           attributes.y = 0;
3456           width = attributes.width = tree_view->priv->drag_column->button->allocation.width;
3457           height = attributes.height = tree_view->priv->drag_column->button->allocation.height;
3458           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
3459           attributes.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
3460           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3461           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
3462           tree_view->priv->drag_highlight_window = gdk_window_new (tree_view->priv->header_window, &attributes, attributes_mask);
3463           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
3464
3465           mask = gdk_pixmap_new (tree_view->priv->drag_highlight_window, width, height, 1);
3466           gc = gdk_gc_new (mask);
3467           col.pixel = 1;
3468           gdk_gc_set_foreground (gc, &col);
3469           gdk_draw_rectangle (mask, gc, TRUE, 0, 0, width, height);
3470           col.pixel = 0;
3471           gdk_gc_set_foreground(gc, &col);
3472           gdk_draw_rectangle (mask, gc, TRUE, 2, 2, width - 4, height - 4);
3473           g_object_unref (gc);
3474
3475           gdk_window_shape_combine_mask (tree_view->priv->drag_highlight_window,
3476                                          mask, 0, 0);
3477           if (mask) g_object_unref (mask);
3478           tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_ORIGINAL;
3479         }
3480     }
3481   else if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW)
3482     {
3483       gint i, j = 1;
3484       GdkGC *gc;
3485       GdkColor col;
3486
3487       width = tree_view->priv->expander_size;
3488
3489       /* Get x, y, width, height of arrow */
3490       gdk_window_get_origin (tree_view->priv->header_window, &x, &y);
3491       if (reorder->left_column)
3492         {
3493           x += reorder->left_column->button->allocation.x + reorder->left_column->button->allocation.width - width/2;
3494           height = reorder->left_column->button->allocation.height;
3495         }
3496       else
3497         {
3498           x += reorder->right_column->button->allocation.x - width/2;
3499           height = reorder->right_column->button->allocation.height;
3500         }
3501       y -= tree_view->priv->expander_size/2; /* The arrow takes up only half the space */
3502       height += tree_view->priv->expander_size;
3503
3504       /* Create the new window */
3505       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW)
3506         {
3507           if (tree_view->priv->drag_highlight_window)
3508             {
3509               gdk_window_set_user_data (tree_view->priv->drag_highlight_window,
3510                                         NULL);
3511               gdk_window_destroy (tree_view->priv->drag_highlight_window);
3512             }
3513
3514           attributes.window_type = GDK_WINDOW_TEMP;
3515           attributes.wclass = GDK_INPUT_OUTPUT;
3516           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
3517           attributes.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
3518           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3519           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
3520           attributes.x = x;
3521           attributes.y = y;
3522           attributes.width = width;
3523           attributes.height = height;
3524           tree_view->priv->drag_highlight_window = gdk_window_new (gtk_widget_get_root_window (widget),
3525                                                                    &attributes, attributes_mask);
3526           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
3527
3528           mask = gdk_pixmap_new (tree_view->priv->drag_highlight_window, width, height, 1);
3529           gc = gdk_gc_new (mask);
3530           col.pixel = 1;
3531           gdk_gc_set_foreground (gc, &col);
3532           gdk_draw_rectangle (mask, gc, TRUE, 0, 0, width, height);
3533
3534           /* Draw the 2 arrows as per above */
3535           col.pixel = 0;
3536           gdk_gc_set_foreground (gc, &col);
3537           for (i = 0; i < width; i ++)
3538             {
3539               if (i == (width/2 - 1))
3540                 continue;
3541               gdk_draw_line (mask, gc, i, j, i, height - j);
3542               if (i < (width/2 - 1))
3543                 j++;
3544               else
3545                 j--;
3546             }
3547           g_object_unref (gc);
3548           gdk_window_shape_combine_mask (tree_view->priv->drag_highlight_window,
3549                                          mask, 0, 0);
3550           if (mask) g_object_unref (mask);
3551         }
3552
3553       tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_ARROW;
3554       gdk_window_move (tree_view->priv->drag_highlight_window, x, y);
3555     }
3556   else if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT ||
3557            arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
3558     {
3559       gint i, j = 1;
3560       GdkGC *gc;
3561       GdkColor col;
3562
3563       width = tree_view->priv->expander_size;
3564
3565       /* Get x, y, width, height of arrow */
3566       width = width/2; /* remember, the arrow only takes half the available width */
3567       gdk_window_get_origin (widget->window, &x, &y);
3568       if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
3569         x += widget->allocation.width - width;
3570
3571       if (reorder->left_column)
3572         height = reorder->left_column->button->allocation.height;
3573       else
3574         height = reorder->right_column->button->allocation.height;
3575
3576       y -= tree_view->priv->expander_size;
3577       height += 2*tree_view->priv->expander_size;
3578
3579       /* Create the new window */
3580       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT &&
3581           tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
3582         {
3583           if (tree_view->priv->drag_highlight_window)
3584             {
3585               gdk_window_set_user_data (tree_view->priv->drag_highlight_window,
3586                                         NULL);
3587               gdk_window_destroy (tree_view->priv->drag_highlight_window);
3588             }
3589
3590           attributes.window_type = GDK_WINDOW_TEMP;
3591           attributes.wclass = GDK_INPUT_OUTPUT;
3592           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
3593           attributes.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
3594           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3595           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
3596           attributes.x = x;
3597           attributes.y = y;
3598           attributes.width = width;
3599           attributes.height = height;
3600           tree_view->priv->drag_highlight_window = gdk_window_new (NULL, &attributes, attributes_mask);
3601           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
3602
3603           mask = gdk_pixmap_new (tree_view->priv->drag_highlight_window, width, height, 1);
3604           gc = gdk_gc_new (mask);
3605           col.pixel = 1;
3606           gdk_gc_set_foreground (gc, &col);
3607           gdk_draw_rectangle (mask, gc, TRUE, 0, 0, width, height);
3608
3609           /* Draw the 2 arrows as per above */
3610           col.pixel = 0;
3611           gdk_gc_set_foreground (gc, &col);
3612           j = tree_view->priv->expander_size;
3613           for (i = 0; i < width; i ++)
3614             {
3615               gint k;
3616               if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT)
3617                 k = width - i - 1;
3618               else
3619                 k = i;
3620               gdk_draw_line (mask, gc, k, j, k, height - j);
3621               gdk_draw_line (mask, gc, k, 0, k, tree_view->priv->expander_size - j);
3622               gdk_draw_line (mask, gc, k, height, k, height - tree_view->priv->expander_size + j);
3623               j--;
3624             }
3625           g_object_unref (gc);
3626           gdk_window_shape_combine_mask (tree_view->priv->drag_highlight_window,
3627                                          mask, 0, 0);
3628           if (mask) g_object_unref (mask);
3629         }
3630
3631       tree_view->priv->drag_column_window_state = arrow_type;
3632       gdk_window_move (tree_view->priv->drag_highlight_window, x, y);
3633    }
3634   else
3635     {
3636       g_warning (G_STRLOC"Invalid GtkTreeViewColumnReorder struct");
3637       gdk_window_hide (tree_view->priv->drag_highlight_window);
3638       return;
3639     }
3640
3641   gdk_window_show (tree_view->priv->drag_highlight_window);
3642   gdk_window_raise (tree_view->priv->drag_highlight_window);
3643 }
3644
3645 static gboolean
3646 gtk_tree_view_motion_resize_column (GtkWidget      *widget,
3647                                     GdkEventMotion *event)
3648 {
3649   gint x;
3650   gint new_width;
3651   GtkTreeViewColumn *column;
3652   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
3653
3654   column = gtk_tree_view_get_column (tree_view, tree_view->priv->drag_pos);
3655
3656   if (event->is_hint || event->window != widget->window)
3657     gtk_widget_get_pointer (widget, &x, NULL);
3658   else
3659     x = event->x;
3660
3661   if (tree_view->priv->hadjustment)
3662     x += tree_view->priv->hadjustment->value;
3663
3664   new_width = gtk_tree_view_new_column_width (tree_view,
3665                                               tree_view->priv->drag_pos, &x);
3666   if (x != tree_view->priv->x_drag &&
3667       (new_width != column->fixed_width))
3668     {
3669       column->use_resized_width = TRUE;
3670       column->resized_width = new_width;
3671       if (column->expand)
3672         column->resized_width -= tree_view->priv->last_extra_space_per_column;
3673       gtk_widget_queue_resize (widget);
3674     }
3675
3676   return FALSE;
3677 }
3678
3679
3680 static void
3681 gtk_tree_view_update_current_reorder (GtkTreeView *tree_view)
3682 {
3683   GtkTreeViewColumnReorder *reorder = NULL;
3684   GList *list;
3685   gint mouse_x;
3686
3687   gdk_window_get_pointer (tree_view->priv->header_window, &mouse_x, NULL, NULL);
3688   for (list = tree_view->priv->column_drag_info; list; list = list->next)
3689     {
3690       reorder = (GtkTreeViewColumnReorder *) list->data;
3691       if (mouse_x >= reorder->left_align && mouse_x < reorder->right_align)
3692         break;
3693       reorder = NULL;
3694     }
3695
3696   /*  if (reorder && reorder == tree_view->priv->cur_reorder)
3697       return;*/
3698
3699   tree_view->priv->cur_reorder = reorder;
3700   gtk_tree_view_motion_draw_column_motion_arrow (tree_view);
3701 }
3702
3703 static void
3704 gtk_tree_view_vertical_autoscroll (GtkTreeView *tree_view)
3705 {
3706   GdkRectangle visible_rect;
3707   gint y;
3708   gint offset;
3709   gfloat value;
3710
3711   gdk_window_get_pointer (tree_view->priv->bin_window, NULL, &y, NULL);
3712   y += tree_view->priv->dy;
3713
3714   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
3715
3716   /* see if we are near the edge. */
3717   offset = y - (visible_rect.y + 2 * SCROLL_EDGE_SIZE);
3718   if (offset > 0)
3719     {
3720       offset = y - (visible_rect.y + visible_rect.height - 2 * SCROLL_EDGE_SIZE);
3721       if (offset < 0)
3722         return;
3723     }
3724
3725   value = CLAMP (tree_view->priv->vadjustment->value + offset, 0.0,
3726                  tree_view->priv->vadjustment->upper - tree_view->priv->vadjustment->page_size);
3727   gtk_adjustment_set_value (tree_view->priv->vadjustment, value);
3728 }
3729
3730 static gboolean
3731 gtk_tree_view_horizontal_autoscroll (GtkTreeView *tree_view)
3732 {
3733   GdkRectangle visible_rect;
3734   gint x;
3735   gint offset;
3736   gfloat value;
3737
3738   gdk_window_get_pointer (tree_view->priv->bin_window, &x, NULL, NULL);
3739
3740   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
3741
3742   /* See if we are near the edge. */
3743   offset = x - (visible_rect.x + SCROLL_EDGE_SIZE);
3744   if (offset > 0)
3745     {
3746       offset = x - (visible_rect.x + visible_rect.width - SCROLL_EDGE_SIZE);
3747       if (offset < 0)
3748         return TRUE;
3749     }
3750   offset = offset/3;
3751
3752   value = CLAMP (tree_view->priv->hadjustment->value + offset,
3753                  0.0, tree_view->priv->hadjustment->upper - tree_view->priv->hadjustment->page_size);
3754   gtk_adjustment_set_value (tree_view->priv->hadjustment, value);
3755
3756   return TRUE;
3757
3758 }
3759
3760 static gboolean
3761 gtk_tree_view_motion_drag_column (GtkWidget      *widget,
3762                                   GdkEventMotion *event)
3763 {
3764   GtkTreeView *tree_view = (GtkTreeView *) widget;
3765   GtkTreeViewColumn *column = tree_view->priv->drag_column;
3766   gint x, y;
3767
3768   /* Sanity Check */
3769   if ((column == NULL) ||
3770       (event->window != tree_view->priv->drag_window))
3771     return FALSE;
3772
3773   /* Handle moving the header */
3774   gdk_window_get_position (tree_view->priv->drag_window, &x, &y);
3775   x = CLAMP (x + (gint)event->x - column->drag_x, 0,
3776              MAX (tree_view->priv->width, GTK_WIDGET (tree_view)->allocation.width) - column->button->allocation.width);
3777   gdk_window_move (tree_view->priv->drag_window, x, y);
3778   
3779   /* autoscroll, if needed */
3780   gtk_tree_view_horizontal_autoscroll (tree_view);
3781   /* Update the current reorder position and arrow; */
3782   gtk_tree_view_update_current_reorder (tree_view);
3783
3784   return TRUE;
3785 }
3786
3787 static void
3788 gtk_tree_view_stop_rubber_band (GtkTreeView *tree_view)
3789 {
3790   remove_scroll_timeout (tree_view);
3791   gtk_grab_remove (GTK_WIDGET (tree_view));
3792
3793   if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
3794     {
3795       GtkTreePath *tmp_path;
3796
3797       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
3798
3799       /* The anchor path should be set to the start path */
3800       tmp_path = _gtk_tree_view_find_path (tree_view,
3801                                            tree_view->priv->rubber_band_start_tree,
3802                                            tree_view->priv->rubber_band_start_node);
3803
3804       if (tree_view->priv->anchor)
3805         gtk_tree_row_reference_free (tree_view->priv->anchor);
3806
3807       tree_view->priv->anchor =
3808         gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
3809                                           tree_view->priv->model,
3810                                           tmp_path);
3811
3812       gtk_tree_path_free (tmp_path);
3813
3814       /* ... and the cursor to the end path */
3815       tmp_path = _gtk_tree_view_find_path (tree_view,
3816                                            tree_view->priv->rubber_band_end_tree,
3817                                            tree_view->priv->rubber_band_end_node);
3818       gtk_tree_view_real_set_cursor (GTK_TREE_VIEW (tree_view), tmp_path, FALSE, FALSE);
3819       gtk_tree_path_free (tmp_path);
3820
3821       _gtk_tree_selection_emit_changed (tree_view->priv->selection);
3822     }
3823
3824   /* Clear status variables */
3825   tree_view->priv->rubber_band_status = RUBBER_BAND_OFF;
3826   tree_view->priv->rubber_band_shift = 0;
3827   tree_view->priv->rubber_band_ctrl = 0;
3828
3829   tree_view->priv->rubber_band_start_node = NULL;
3830   tree_view->priv->rubber_band_start_tree = NULL;
3831   tree_view->priv->rubber_band_end_node = NULL;
3832   tree_view->priv->rubber_band_end_tree = NULL;
3833 }
3834
3835 static void
3836 gtk_tree_view_update_rubber_band_selection_range (GtkTreeView *tree_view,
3837                                                  GtkRBTree   *start_tree,
3838                                                  GtkRBNode   *start_node,
3839                                                  GtkRBTree   *end_tree,
3840                                                  GtkRBNode   *end_node,
3841                                                  gboolean     select,
3842                                                  gboolean     skip_start,
3843                                                  gboolean     skip_end)
3844 {
3845   if (start_node == end_node)
3846     return;
3847
3848   /* We skip the first node and jump inside the loop */
3849   if (skip_start)
3850     goto skip_first;
3851
3852   do
3853     {
3854       /* Small optimization by assuming insensitive nodes are never
3855        * selected.
3856        */
3857       if (!GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
3858         {
3859           GtkTreePath *path;
3860           gboolean selectable;
3861
3862           path = _gtk_tree_view_find_path (tree_view, start_tree, start_node);
3863           selectable = _gtk_tree_selection_row_is_selectable (tree_view->priv->selection, start_node, path);
3864           gtk_tree_path_free (path);
3865
3866           if (!selectable)
3867             goto node_not_selectable;
3868         }
3869
3870       if (select)
3871         {
3872           if (tree_view->priv->rubber_band_shift)
3873             GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3874           else if (tree_view->priv->rubber_band_ctrl)
3875             {
3876               /* Toggle the selection state */
3877               if (GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
3878                 GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3879               else
3880                 GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3881             }
3882           else
3883             GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3884         }
3885       else
3886         {
3887           /* Mirror the above */
3888           if (tree_view->priv->rubber_band_shift)
3889             GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3890           else if (tree_view->priv->rubber_band_ctrl)
3891             {
3892               /* Toggle the selection state */
3893               if (GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
3894                 GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3895               else
3896                 GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3897             }
3898           else
3899             GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3900         }
3901
3902       _gtk_tree_view_queue_draw_node (tree_view, start_tree, start_node, NULL);
3903
3904 node_not_selectable:
3905       if (start_node == end_node)
3906         break;
3907
3908 skip_first:
3909
3910       if (start_node->children)
3911         {
3912           start_tree = start_node->children;
3913           start_node = start_tree->root;
3914           while (start_node->left != start_tree->nil)
3915             start_node = start_node->left;
3916         }
3917       else
3918         {
3919           _gtk_rbtree_next_full (start_tree, start_node, &start_tree, &start_node);
3920
3921           if (!start_tree)
3922             /* Ran out of tree */
3923             break;
3924         }
3925
3926       if (skip_end && start_node == end_node)
3927         break;
3928     }
3929   while (TRUE);
3930 }
3931
3932 static void
3933 gtk_tree_view_update_rubber_band_selection (GtkTreeView *tree_view)
3934 {
3935   GtkRBTree *start_tree, *end_tree;
3936   GtkRBNode *start_node, *end_node;
3937
3938   _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);
3939   _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);
3940
3941   /* Handle the start area first */
3942   if (!tree_view->priv->rubber_band_start_node)
3943     {
3944       gtk_tree_view_update_rubber_band_selection_range (tree_view,
3945                                                        start_tree,
3946                                                        start_node,
3947                                                        end_tree,
3948                                                        end_node,
3949                                                        TRUE,
3950                                                        FALSE,
3951                                                        FALSE);
3952     }
3953   else if (_gtk_rbtree_node_find_offset (start_tree, start_node) <
3954            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_start_tree, tree_view->priv->rubber_band_start_node))
3955     {
3956       /* New node is above the old one; selection became bigger */
3957       gtk_tree_view_update_rubber_band_selection_range (tree_view,
3958                                                        start_tree,
3959                                                        start_node,
3960                                                        tree_view->priv->rubber_band_start_tree,
3961                                                        tree_view->priv->rubber_band_start_node,
3962                                                        TRUE,
3963                                                        FALSE,
3964                                                        TRUE);
3965     }
3966   else if (_gtk_rbtree_node_find_offset (start_tree, start_node) >
3967            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_start_tree, tree_view->priv->rubber_band_start_node))
3968     {
3969       /* New node is below the old one; selection became smaller */
3970       gtk_tree_view_update_rubber_band_selection_range (tree_view,
3971                                                        tree_view->priv->rubber_band_start_tree,
3972                                                        tree_view->priv->rubber_band_start_node,
3973                                                        start_tree,
3974                                                        start_node,
3975                                                        FALSE,
3976                                                        FALSE,
3977                                                        TRUE);
3978     }
3979
3980   tree_view->priv->rubber_band_start_tree = start_tree;
3981   tree_view->priv->rubber_band_start_node = start_node;
3982
3983   /* Next, handle the end area */
3984   if (!tree_view->priv->rubber_band_end_node)
3985     {
3986       /* In the event this happens, start_node was also NULL; this case is
3987        * handled above.
3988        */
3989     }
3990   else if (!end_node)
3991     {
3992       /* Find the last node in the tree */
3993       _gtk_rbtree_find_offset (tree_view->priv->tree, tree_view->priv->height - 1,
3994                                &end_tree, &end_node);
3995
3996       /* Selection reached end of the tree */
3997       gtk_tree_view_update_rubber_band_selection_range (tree_view,
3998                                                        tree_view->priv->rubber_band_end_tree,
3999                                                        tree_view->priv->rubber_band_end_node,
4000                                                        end_tree,
4001                                                        end_node,
4002                                                        TRUE,
4003                                                        TRUE,
4004                                                        FALSE);
4005     }
4006   else if (_gtk_rbtree_node_find_offset (end_tree, end_node) >
4007            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_end_tree, tree_view->priv->rubber_band_end_node))
4008     {
4009       /* New node is below the old one; selection became bigger */
4010       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4011                                                        tree_view->priv->rubber_band_end_tree,
4012                                                        tree_view->priv->rubber_band_end_node,
4013                                                        end_tree,
4014                                                        end_node,
4015                                                        TRUE,
4016                                                        TRUE,
4017                                                        FALSE);
4018     }
4019   else if (_gtk_rbtree_node_find_offset (end_tree, end_node) <
4020            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_end_tree, tree_view->priv->rubber_band_end_node))
4021     {
4022       /* New node is above the old one; selection became smaller */
4023       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4024                                                        end_tree,
4025                                                        end_node,
4026                                                        tree_view->priv->rubber_band_end_tree,
4027                                                        tree_view->priv->rubber_band_end_node,
4028                                                        FALSE,
4029                                                        TRUE,
4030                                                        FALSE);
4031     }
4032
4033   tree_view->priv->rubber_band_end_tree = end_tree;
4034   tree_view->priv->rubber_band_end_node = end_node;
4035 }
4036
4037 static void
4038 gtk_tree_view_update_rubber_band (GtkTreeView *tree_view)
4039 {
4040   gint x, y;
4041   GdkRectangle old_area;
4042   GdkRectangle new_area;
4043   GdkRectangle common;
4044   GdkRegion *invalid_region;
4045
4046   old_area.x = MIN (tree_view->priv->press_start_x, tree_view->priv->rubber_band_x);
4047   old_area.y = MIN (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y) - tree_view->priv->dy;
4048   old_area.width = ABS (tree_view->priv->rubber_band_x - tree_view->priv->press_start_x) + 1;
4049   old_area.height = ABS (tree_view->priv->rubber_band_y - tree_view->priv->press_start_y) + 1;
4050
4051   gdk_window_get_pointer (tree_view->priv->bin_window, &x, &y, NULL);
4052
4053   x = MAX (x, 0);
4054   y = MAX (y, 0) + tree_view->priv->dy;
4055
4056   new_area.x = MIN (tree_view->priv->press_start_x, x);
4057   new_area.y = MIN (tree_view->priv->press_start_y, y) - tree_view->priv->dy;
4058   new_area.width = ABS (x - tree_view->priv->press_start_x) + 1;
4059   new_area.height = ABS (y - tree_view->priv->press_start_y) + 1;
4060
4061   invalid_region = gdk_region_rectangle (&old_area);
4062   gdk_region_union_with_rect (invalid_region, &new_area);
4063
4064   gdk_rectangle_intersect (&old_area, &new_area, &common);
4065   if (common.width > 2 && common.height > 2)
4066     {
4067       GdkRegion *common_region;
4068
4069       /* make sure the border is invalidated */
4070       common.x += 1;
4071       common.y += 1;
4072       common.width -= 2;
4073       common.height -= 2;
4074
4075       common_region = gdk_region_rectangle (&common);
4076
4077       gdk_region_subtract (invalid_region, common_region);
4078       gdk_region_destroy (common_region);
4079     }
4080
4081   gdk_window_invalidate_region (tree_view->priv->bin_window, invalid_region, TRUE);
4082
4083   gdk_region_destroy (invalid_region);
4084
4085   tree_view->priv->rubber_band_x = x;
4086   tree_view->priv->rubber_band_y = y;
4087
4088   gtk_tree_view_update_rubber_band_selection (tree_view);
4089 }
4090
4091 static void
4092 gtk_tree_view_paint_rubber_band (GtkTreeView  *tree_view,
4093                                 GdkRectangle *area)
4094 {
4095   cairo_t *cr;
4096   GdkRectangle rect;
4097   GdkRectangle rubber_rect;
4098
4099   rubber_rect.x = MIN (tree_view->priv->press_start_x, tree_view->priv->rubber_band_x);
4100   rubber_rect.y = MIN (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y) - tree_view->priv->dy;
4101   rubber_rect.width = ABS (tree_view->priv->press_start_x - tree_view->priv->rubber_band_x) + 1;
4102   rubber_rect.height = ABS (tree_view->priv->press_start_y - tree_view->priv->rubber_band_y) + 1;
4103
4104   if (!gdk_rectangle_intersect (&rubber_rect, area, &rect))
4105     return;
4106
4107   cr = gdk_cairo_create (tree_view->priv->bin_window);
4108   cairo_set_line_width (cr, 1.0);
4109
4110   cairo_set_source_rgba (cr,
4111                          GTK_WIDGET (tree_view)->style->fg[GTK_STATE_NORMAL].red / 65535.,
4112                          GTK_WIDGET (tree_view)->style->fg[GTK_STATE_NORMAL].green / 65535.,
4113                          GTK_WIDGET (tree_view)->style->fg[GTK_STATE_NORMAL].blue / 65535.,
4114                          .25);
4115
4116   gdk_cairo_rectangle (cr, &rect);
4117   cairo_clip (cr);
4118   cairo_paint (cr);
4119
4120   cairo_set_source_rgb (cr,
4121                         GTK_WIDGET (tree_view)->style->fg[GTK_STATE_NORMAL].red / 65535.,
4122                         GTK_WIDGET (tree_view)->style->fg[GTK_STATE_NORMAL].green / 65535.,
4123                         GTK_WIDGET (tree_view)->style->fg[GTK_STATE_NORMAL].blue / 65535.);
4124
4125   cairo_rectangle (cr,
4126                    rubber_rect.x + 0.5, rubber_rect.y + 0.5,
4127                    rubber_rect.width - 1, rubber_rect.height - 1);
4128   cairo_stroke (cr);
4129
4130   cairo_destroy (cr);
4131 }
4132
4133 static gboolean
4134 gtk_tree_view_motion_bin_window (GtkWidget      *widget,
4135                                  GdkEventMotion *event)
4136 {
4137   GtkTreeView *tree_view;
4138   GtkRBTree *tree;
4139   GtkRBNode *node;
4140   gint new_y;
4141
4142   tree_view = (GtkTreeView *) widget;
4143
4144   if (tree_view->priv->tree == NULL)
4145     return FALSE;
4146
4147   if (tree_view->priv->rubber_band_status == RUBBER_BAND_MAYBE_START)
4148     {
4149       gtk_grab_add (GTK_WIDGET (tree_view));
4150       gtk_tree_view_update_rubber_band (tree_view);
4151
4152       tree_view->priv->rubber_band_status = RUBBER_BAND_ACTIVE;
4153     }
4154   else if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
4155     {
4156       gtk_tree_view_update_rubber_band (tree_view);
4157
4158       add_scroll_timeout (tree_view);
4159     }
4160
4161   /* only check for an initiated drag when a button is pressed */
4162   if (tree_view->priv->pressed_button >= 0
4163       && !tree_view->priv->rubber_band_status)
4164     gtk_tree_view_maybe_begin_dragging_row (tree_view, event);
4165
4166   new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
4167   if (new_y < 0)
4168     new_y = 0;
4169
4170   _gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
4171
4172   /* If we are currently pressing down a button, we don't want to prelight anything else. */
4173   if ((tree_view->priv->button_pressed_node != NULL) &&
4174       (tree_view->priv->button_pressed_node != node))
4175     node = NULL;
4176
4177   tree_view->priv->event_last_x = event->x;
4178   tree_view->priv->event_last_y = event->y;
4179
4180   prelight_or_select (tree_view, tree, node, event->x, event->y);
4181
4182   return TRUE;
4183 }
4184
4185 static gboolean
4186 gtk_tree_view_motion (GtkWidget      *widget,
4187                       GdkEventMotion *event)
4188 {
4189   GtkTreeView *tree_view;
4190
4191   tree_view = (GtkTreeView *) widget;
4192
4193   /* Resizing a column */
4194   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE))
4195     return gtk_tree_view_motion_resize_column (widget, event);
4196
4197   /* Drag column */
4198   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
4199     return gtk_tree_view_motion_drag_column (widget, event);
4200
4201   /* Sanity check it */
4202   if (event->window == tree_view->priv->bin_window)
4203     return gtk_tree_view_motion_bin_window (widget, event);
4204
4205   return FALSE;
4206 }
4207
4208 /* Invalidate the focus rectangle near the edge of the bin_window; used when
4209  * the tree is empty.
4210  */
4211 static void
4212 invalidate_empty_focus (GtkTreeView *tree_view)
4213 {
4214   GdkRectangle area;
4215
4216   if (!GTK_WIDGET_HAS_FOCUS (tree_view))
4217     return;
4218
4219   area.x = 0;
4220   area.y = 0;
4221   gdk_drawable_get_size (tree_view->priv->bin_window, &area.width, &area.height);
4222   gdk_window_invalidate_rect (tree_view->priv->bin_window, &area, FALSE);
4223 }
4224
4225 /* Draws a focus rectangle near the edge of the bin_window; used when the tree
4226  * is empty.
4227  */
4228 static void
4229 draw_empty_focus (GtkTreeView *tree_view, GdkRectangle *clip_area)
4230 {
4231   gint w, h;
4232
4233   if (!GTK_WIDGET_HAS_FOCUS (tree_view))
4234     return;
4235
4236   gdk_drawable_get_size (tree_view->priv->bin_window, &w, &h);
4237
4238   w -= 2;
4239   h -= 2;
4240
4241   if (w > 0 && h > 0)
4242     gtk_paint_focus (GTK_WIDGET (tree_view)->style,
4243                      tree_view->priv->bin_window,
4244                      GTK_WIDGET_STATE (tree_view),
4245                      clip_area,
4246                      GTK_WIDGET (tree_view),
4247                      NULL,
4248                      1, 1, w, h);
4249 }
4250
4251 static void
4252 gtk_tree_view_draw_grid_lines (GtkTreeView    *tree_view,
4253                                GdkEventExpose *event,
4254                                gint            n_visible_columns)
4255 {
4256   GList *list = tree_view->priv->columns;
4257   gint i = 0;
4258   gint current_x = 0;
4259
4260   if (tree_view->priv->grid_lines != GTK_TREE_VIEW_GRID_LINES_VERTICAL
4261       && tree_view->priv->grid_lines != GTK_TREE_VIEW_GRID_LINES_BOTH)
4262     return;
4263
4264   /* Only draw the lines for visible rows and columns */
4265   for (list = tree_view->priv->columns; list; list = list->next, i++)
4266     {
4267       GtkTreeViewColumn *column = list->data;
4268
4269       /* We don't want a line for the last column */
4270       if (i == n_visible_columns - 1)
4271         break;
4272
4273       if (! column->visible)
4274         continue;
4275
4276       current_x += column->width;
4277
4278       gdk_draw_line (event->window,
4279                      tree_view->priv->grid_line_gc,
4280                      current_x - 1, 0,
4281                      current_x - 1, tree_view->priv->height);
4282     }
4283 }
4284
4285 /* Warning: Very scary function.
4286  * Modify at your own risk
4287  *
4288  * KEEP IN SYNC WITH gtk_tree_view_create_row_drag_icon()!
4289  * FIXME: It's not...
4290  */
4291 static gboolean
4292 gtk_tree_view_bin_expose (GtkWidget      *widget,
4293                           GdkEventExpose *event)
4294 {
4295   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
4296   GtkTreePath *path;
4297   GtkRBTree *tree;
4298   GList *list;
4299   GtkRBNode *node;
4300   GtkRBNode *cursor = NULL;
4301   GtkRBTree *cursor_tree = NULL;
4302   GtkRBNode *drag_highlight = NULL;
4303   GtkRBTree *drag_highlight_tree = NULL;
4304   GtkTreeIter iter;
4305   gint new_y;
4306   gint y_offset, cell_offset;
4307   gint max_height;
4308   gint depth;
4309   GdkRectangle background_area;
4310   GdkRectangle cell_area;
4311   guint flags;
4312   gint highlight_x;
4313   gint expander_cell_width;
4314   gint bin_window_width;
4315   gint bin_window_height;
4316   GtkTreePath *cursor_path;
4317   GtkTreePath *drag_dest_path;
4318   GList *first_column, *last_column;
4319   gint vertical_separator;
4320   gint horizontal_separator;
4321   gint focus_line_width;
4322   gboolean allow_rules;
4323   gboolean has_special_cell;
4324   gboolean rtl;
4325   gint n_visible_columns;
4326   gint pointer_x, pointer_y;
4327   gint grid_line_width;
4328   gboolean got_pointer = FALSE;
4329   gboolean row_ending_details;
4330   gboolean draw_vgrid_lines, draw_hgrid_lines;
4331
4332   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
4333
4334   gtk_widget_style_get (widget,
4335                         "horizontal-separator", &horizontal_separator,
4336                         "vertical-separator", &vertical_separator,
4337                         "allow-rules", &allow_rules,
4338                         "focus-line-width", &focus_line_width,
4339                         "row-ending-details", &row_ending_details,
4340                         NULL);
4341
4342   if (tree_view->priv->tree == NULL)
4343     {
4344       draw_empty_focus (tree_view, &event->area);
4345       return TRUE;
4346     }
4347
4348   /* clip event->area to the visible area */
4349   if (event->area.height < 0)
4350     return TRUE;
4351
4352   validate_visible_area (tree_view);
4353
4354   new_y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, event->area.y);
4355
4356   if (new_y < 0)
4357     new_y = 0;
4358   y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
4359   gdk_drawable_get_size (tree_view->priv->bin_window,
4360                          &bin_window_width, &bin_window_height);
4361
4362   if (tree_view->priv->height < bin_window_height)
4363     {
4364       gtk_paint_flat_box (widget->style,
4365                           event->window,
4366                           widget->state,
4367                           GTK_SHADOW_NONE,
4368                           &event->area,
4369                           widget,
4370                           "cell_even",
4371                           0, tree_view->priv->height,
4372                           bin_window_width,
4373                           bin_window_height - tree_view->priv->height);
4374     }
4375
4376   if (node == NULL)
4377     return TRUE;
4378
4379   /* find the path for the node */
4380   path = _gtk_tree_view_find_path ((GtkTreeView *)widget,
4381                                    tree,
4382                                    node);
4383   gtk_tree_model_get_iter (tree_view->priv->model,
4384                            &iter,
4385                            path);
4386   depth = gtk_tree_path_get_depth (path);
4387   gtk_tree_path_free (path);
4388   
4389   cursor_path = NULL;
4390   drag_dest_path = NULL;
4391
4392   if (tree_view->priv->cursor)
4393     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
4394
4395   if (cursor_path)
4396     _gtk_tree_view_find_node (tree_view, cursor_path,
4397                               &cursor_tree, &cursor);
4398
4399   if (tree_view->priv->drag_dest_row)
4400     drag_dest_path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
4401
4402   if (drag_dest_path)
4403     _gtk_tree_view_find_node (tree_view, drag_dest_path,
4404                               &drag_highlight_tree, &drag_highlight);
4405
4406   draw_vgrid_lines =
4407     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_VERTICAL
4408     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
4409   draw_hgrid_lines =
4410     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_HORIZONTAL
4411     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
4412
4413   if (draw_vgrid_lines || draw_hgrid_lines)
4414     gtk_widget_style_get (widget, "grid-line-width", &grid_line_width, NULL);
4415   
4416   n_visible_columns = 0;
4417   for (list = tree_view->priv->columns; list; list = list->next)
4418     {
4419       if (! GTK_TREE_VIEW_COLUMN (list->data)->visible)
4420         continue;
4421       n_visible_columns ++;
4422     }
4423
4424   /* Find the last column */
4425   for (last_column = g_list_last (tree_view->priv->columns);
4426        last_column && !(GTK_TREE_VIEW_COLUMN (last_column->data)->visible);
4427        last_column = last_column->prev)
4428     ;
4429
4430   /* and the first */
4431   for (first_column = g_list_first (tree_view->priv->columns);
4432        first_column && !(GTK_TREE_VIEW_COLUMN (first_column->data)->visible);
4433        first_column = first_column->next)
4434     ;
4435
4436   /* Actually process the expose event.  To do this, we want to
4437    * start at the first node of the event, and walk the tree in
4438    * order, drawing each successive node.
4439    */
4440
4441   do
4442     {
4443       gboolean parity;
4444       gboolean is_separator = FALSE;
4445       gboolean is_first = FALSE;
4446       gboolean is_last = FALSE;
4447       
4448       is_separator = row_is_separator (tree_view, &iter, NULL);
4449
4450       max_height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
4451
4452       cell_offset = 0;
4453       highlight_x = 0; /* should match x coord of first cell */
4454       expander_cell_width = 0;
4455
4456       background_area.y = y_offset + event->area.y;
4457       background_area.height = max_height;
4458
4459       flags = 0;
4460
4461       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PRELIT))
4462         flags |= GTK_CELL_RENDERER_PRELIT;
4463
4464       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
4465         flags |= GTK_CELL_RENDERER_SELECTED;
4466
4467       parity = _gtk_rbtree_node_find_parity (tree, node);
4468
4469       /* we *need* to set cell data on all cells before the call
4470        * to _has_special_cell, else _has_special_cell() does not
4471        * return a correct value.
4472        */
4473       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
4474            list;
4475            list = (rtl ? list->prev : list->next))
4476         {
4477           GtkTreeViewColumn *column = list->data;
4478           gtk_tree_view_column_cell_set_cell_data (column,
4479                                                    tree_view->priv->model,
4480                                                    &iter,
4481                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
4482                                                    node->children?TRUE:FALSE);
4483         }
4484
4485       has_special_cell = gtk_tree_view_has_special_cell (tree_view);
4486
4487       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
4488            list;
4489            list = (rtl ? list->prev : list->next))
4490         {
4491           GtkTreeViewColumn *column = list->data;
4492           const gchar *detail = NULL;
4493           GtkStateType state;
4494
4495           if (!column->visible)
4496             continue;
4497
4498           if (cell_offset > event->area.x + event->area.width ||
4499               cell_offset + column->width < event->area.x)
4500             {
4501               cell_offset += column->width;
4502               continue;
4503             }
4504
4505           if (column->show_sort_indicator)
4506             flags |= GTK_CELL_RENDERER_SORTED;
4507           else
4508             flags &= ~GTK_CELL_RENDERER_SORTED;
4509
4510           if (cursor == node)
4511             flags |= GTK_CELL_RENDERER_FOCUSED;
4512           else
4513             flags &= ~GTK_CELL_RENDERER_FOCUSED;
4514
4515           background_area.x = cell_offset;
4516           background_area.width = column->width;
4517
4518           cell_area = background_area;
4519           cell_area.y += vertical_separator / 2;
4520           cell_area.x += horizontal_separator / 2;
4521           cell_area.height -= vertical_separator;
4522           cell_area.width -= horizontal_separator;
4523
4524           if (draw_vgrid_lines)
4525             {
4526               if (list == first_column)
4527                 {
4528                   cell_area.width -= grid_line_width / 2;
4529                 }
4530               else if (list == last_column)
4531                 {
4532                   cell_area.x += grid_line_width / 2;
4533                   cell_area.width -= grid_line_width / 2;
4534                 }
4535               else
4536                 {
4537                   cell_area.x += grid_line_width / 2;
4538                   cell_area.width -= grid_line_width;
4539                 }
4540             }
4541
4542           if (draw_hgrid_lines)
4543             {
4544               cell_area.y += grid_line_width / 2;
4545               cell_area.height -= grid_line_width;
4546             }
4547
4548           if (gdk_region_rect_in (event->region, &background_area) == GDK_OVERLAP_RECTANGLE_OUT)
4549             {
4550               cell_offset += column->width;
4551               continue;
4552             }
4553
4554           gtk_tree_view_column_cell_set_cell_data (column,
4555                                                    tree_view->priv->model,
4556                                                    &iter,
4557                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
4558                                                    node->children?TRUE:FALSE);
4559
4560           /* Select the detail for drawing the cell.  relevant
4561            * factors are parity, sortedness, and whether to
4562            * display rules.
4563            */
4564           if (allow_rules && tree_view->priv->has_rules)
4565             {
4566               if ((flags & GTK_CELL_RENDERER_SORTED) &&
4567                   n_visible_columns >= 3)
4568                 {
4569                   if (parity)
4570                     detail = "cell_odd_ruled_sorted";
4571                   else
4572                     detail = "cell_even_ruled_sorted";
4573                 }
4574               else
4575                 {
4576                   if (parity)
4577                     detail = "cell_odd_ruled";
4578                   else
4579                     detail = "cell_even_ruled";
4580                 }
4581             }
4582           else
4583             {
4584               if ((flags & GTK_CELL_RENDERER_SORTED) &&
4585                   n_visible_columns >= 3)
4586                 {
4587                   if (parity)
4588                     detail = "cell_odd_sorted";
4589                   else
4590                     detail = "cell_even_sorted";
4591                 }
4592               else
4593                 {
4594                   if (parity)
4595                     detail = "cell_odd";
4596                   else
4597                     detail = "cell_even";
4598                 }
4599             }
4600
4601           g_assert (detail);
4602
4603           if (widget->state == GTK_STATE_INSENSITIVE)
4604             state = GTK_STATE_INSENSITIVE;          
4605           else if (flags & GTK_CELL_RENDERER_SELECTED)
4606             state = GTK_STATE_SELECTED;
4607           else
4608             state = GTK_STATE_NORMAL;
4609
4610           /* Draw background */
4611           if (row_ending_details)
4612             {
4613               char new_detail[128];
4614
4615               is_first = (rtl ? !list->next : !list->prev);
4616               is_last = (rtl ? !list->prev : !list->next);
4617
4618               /* (I don't like the snprintfs either, but couldn't find a
4619                * less messy way).
4620                */
4621               if (is_first && is_last)
4622                 g_snprintf (new_detail, 127, "%s", detail);
4623               else if (is_first)
4624                 g_snprintf (new_detail, 127, "%s_start", detail);
4625               else if (is_last)
4626                 g_snprintf (new_detail, 127, "%s_end", detail);
4627               else
4628                 g_snprintf (new_detail, 128, "%s_middle", detail);
4629
4630               gtk_paint_flat_box (widget->style,
4631                                   event->window,
4632                                   state,
4633                                   GTK_SHADOW_NONE,
4634                                   &event->area,
4635                                   widget,
4636                                   new_detail,
4637                                   background_area.x,
4638                                   background_area.y,
4639                                   background_area.width,
4640                                   background_area.height);
4641             }
4642           else
4643             {
4644               gtk_paint_flat_box (widget->style,
4645                                   event->window,
4646                                   state,
4647                                   GTK_SHADOW_NONE,
4648                                   &event->area,
4649                                   widget,
4650                                   detail,
4651                                   background_area.x,
4652                                   background_area.y,
4653                                   background_area.width,
4654                                   background_area.height);
4655             }
4656
4657           if (draw_hgrid_lines)
4658             {
4659               if (background_area.y > 0)
4660                 gdk_draw_line (event->window,
4661                                tree_view->priv->grid_line_gc,
4662                                background_area.x, background_area.y,
4663                                background_area.x + background_area.width,
4664                                background_area.y);
4665
4666               if (y_offset + max_height >= event->area.height)
4667                 gdk_draw_line (event->window,
4668                                tree_view->priv->grid_line_gc,
4669                                background_area.x, background_area.y + max_height,
4670                                background_area.x + background_area.width,
4671                                background_area.y + max_height);
4672             }
4673
4674           if (gtk_tree_view_is_expander_column (tree_view, column))
4675             {
4676               if (!rtl)
4677                 cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
4678               cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
4679
4680               if (TREE_VIEW_DRAW_EXPANDERS(tree_view))
4681                 {
4682                   if (!rtl)
4683                     cell_area.x += depth * tree_view->priv->expander_size;
4684                   cell_area.width -= depth * tree_view->priv->expander_size;
4685                 }
4686
4687               /* If we have an expander column, the highlight underline
4688                * starts with that column, so that it indicates which
4689                * level of the tree we're dropping at.
4690                */
4691               highlight_x = cell_area.x;
4692               expander_cell_width = cell_area.width;
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               if (TREE_VIEW_DRAW_EXPANDERS(tree_view)
4712                   && (node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT)
4713                 {
4714                   if (!got_pointer)
4715                     {
4716                       gdk_window_get_pointer (tree_view->priv->bin_window, 
4717                                               &pointer_x, &pointer_y, NULL);
4718                       got_pointer = TRUE;
4719                     }
4720
4721                   gtk_tree_view_draw_arrow (GTK_TREE_VIEW (widget),
4722                                             tree,
4723                                             node,
4724                                             pointer_x, pointer_y);
4725                 }
4726             }
4727           else
4728             {
4729               if (is_separator)
4730                 gtk_paint_hline (widget->style,
4731                                  event->window,
4732                                  state,
4733                                  &cell_area,
4734                                  widget,
4735                                  NULL,
4736                                  cell_area.x,
4737                                  cell_area.x + cell_area.width,
4738                                  cell_area.y + cell_area.height / 2);
4739               else
4740                 _gtk_tree_view_column_cell_render (column,
4741                                                    event->window,
4742                                                    &background_area,
4743                                                    &cell_area,
4744                                                    &event->area,
4745                                                    flags);
4746             }
4747
4748           if (gtk_tree_view_is_expander_column (tree_view, column) &&
4749               tree_view->priv->tree_lines_enabled)
4750             {
4751               gint x = background_area.x;
4752               gint mult = rtl ? -1 : 1;
4753               gint y0 = background_area.y;
4754               gint y1 = background_area.y + background_area.height/2;
4755               gint y2 = background_area.y + background_area.height;
4756
4757               if (rtl)
4758                 x += background_area.width - 1;
4759
4760               if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT
4761                   && depth > 1)
4762                 {
4763                   gdk_draw_line (event->window,
4764                                  tree_view->priv->tree_line_gc,
4765                                  x + tree_view->priv->expander_size * (depth - 1.5) * mult,
4766                                  y1,
4767                                  x + tree_view->priv->expander_size * (depth - 1.1) * mult,
4768                                  y1);
4769                 }
4770               else if (depth > 1)
4771                 {
4772                   gdk_draw_line (event->window,
4773                                  tree_view->priv->tree_line_gc,
4774                                  x + tree_view->priv->expander_size * (depth - 1.5) * mult,
4775                                  y1,
4776                                  x + tree_view->priv->expander_size * (depth - 0.5) * mult,
4777                                  y1);
4778                 }
4779
4780               if (depth > 1)
4781                 {
4782                   gint i;
4783                   GtkRBNode *tmp_node;
4784                   GtkRBTree *tmp_tree;
4785
4786                   if (!_gtk_rbtree_next (tree, node))
4787                     gdk_draw_line (event->window,
4788                                    tree_view->priv->tree_line_gc,
4789                                    x + tree_view->priv->expander_size * (depth - 1.5) * mult,
4790                                    y0,
4791                                    x + tree_view->priv->expander_size * (depth - 1.5) * mult,
4792                                    y1);
4793                   else
4794                     gdk_draw_line (event->window,
4795                                    tree_view->priv->tree_line_gc,
4796                                    x + tree_view->priv->expander_size * (depth - 1.5) * mult,
4797                                    y0,
4798                                    x + tree_view->priv->expander_size * (depth - 1.5) * mult,
4799                                    y2);
4800
4801                   tmp_node = tree->parent_node;
4802                   tmp_tree = tree->parent_tree;
4803
4804                   for (i = depth - 2; i > 0; i--)
4805                     {
4806                       if (_gtk_rbtree_next (tmp_tree, tmp_node))
4807                         gdk_draw_line (event->window,
4808                                        tree_view->priv->tree_line_gc,
4809                                        x + tree_view->priv->expander_size * (i - 0.5) * mult,
4810                                        y0,
4811                                        x + tree_view->priv->expander_size * (i - 0.5) * mult,
4812                                        y2);
4813
4814                       tmp_node = tmp_tree->parent_node;
4815                       tmp_tree = tmp_tree->parent_tree;
4816                     }
4817                 }
4818             }
4819
4820           if (node == cursor && has_special_cell &&
4821               ((column == tree_view->priv->focus_column &&
4822                 GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS) &&
4823                 GTK_WIDGET_HAS_FOCUS (widget)) ||
4824                (column == tree_view->priv->edited_column)))
4825             {
4826               _gtk_tree_view_column_cell_draw_focus (column,
4827                                                      event->window,
4828                                                      &background_area,
4829                                                      &cell_area,
4830                                                      &event->area,
4831                                                      flags);
4832             }
4833
4834           cell_offset += column->width;
4835         }
4836
4837       if (node == drag_highlight)
4838         {
4839           /* Draw indicator for the drop
4840            */
4841           gint highlight_y = -1;
4842           GtkRBTree *tree = NULL;
4843           GtkRBNode *node = NULL;
4844           gint width;
4845
4846           switch (tree_view->priv->drag_dest_pos)
4847             {
4848             case GTK_TREE_VIEW_DROP_BEFORE:
4849               highlight_y = background_area.y - 1;
4850               if (highlight_y < 0)
4851                       highlight_y = 0;
4852               break;
4853
4854             case GTK_TREE_VIEW_DROP_AFTER:
4855               highlight_y = background_area.y + background_area.height - 1;
4856               break;
4857
4858             case GTK_TREE_VIEW_DROP_INTO_OR_BEFORE:
4859             case GTK_TREE_VIEW_DROP_INTO_OR_AFTER:
4860               _gtk_tree_view_find_node (tree_view, drag_dest_path, &tree, &node);
4861
4862               if (tree == NULL)
4863                 break;
4864               gdk_drawable_get_size (tree_view->priv->bin_window,
4865                                      &width, NULL);
4866
4867               if (row_ending_details)
4868                 gtk_paint_focus (widget->style,
4869                                  tree_view->priv->bin_window,
4870                                  GTK_WIDGET_STATE (widget),
4871                                  &event->area,
4872                                  widget,
4873                                  (is_first
4874                                   ? (is_last ? "treeview-drop-indicator" : "treeview-drop-indicator-left" )
4875                                   : (is_last ? "treeview-drop-indicator-right" : "tree-view-drop-indicator-middle" )),
4876                                  0, BACKGROUND_FIRST_PIXEL (tree_view, tree, node)
4877                                  - focus_line_width / 2,
4878                                  width, ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node))
4879                                - focus_line_width + 1);
4880               else
4881                 gtk_paint_focus (widget->style,
4882                                  tree_view->priv->bin_window,
4883                                  GTK_WIDGET_STATE (widget),
4884                                  &event->area,
4885                                  widget,
4886                                  "treeview-drop-indicator",
4887                                  0, BACKGROUND_FIRST_PIXEL (tree_view, tree, node)
4888                                  - focus_line_width / 2,
4889                                  width, ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node))
4890                                  - focus_line_width + 1);
4891               break;
4892             }
4893
4894           if (highlight_y >= 0)
4895             {
4896               gdk_draw_line (event->window,
4897                              widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
4898                              rtl ? highlight_x + expander_cell_width : highlight_x,
4899                              highlight_y,
4900                              rtl ? 0 : bin_window_width,
4901                              highlight_y);
4902             }
4903         }
4904
4905       /* draw the big row-spanning focus rectangle, if needed */
4906       if (!has_special_cell && node == cursor &&
4907           GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS) &&
4908           GTK_WIDGET_HAS_FOCUS (widget))
4909         {
4910           gint tmp_y, tmp_height;
4911           gint width;
4912           GtkStateType focus_rect_state;
4913
4914           focus_rect_state =
4915             flags & GTK_CELL_RENDERER_SELECTED ? GTK_STATE_SELECTED :
4916             (flags & GTK_CELL_RENDERER_PRELIT ? GTK_STATE_PRELIGHT :
4917              (flags & GTK_CELL_RENDERER_INSENSITIVE ? GTK_STATE_INSENSITIVE :
4918               GTK_STATE_NORMAL));
4919
4920           gdk_drawable_get_size (tree_view->priv->bin_window,
4921                                  &width, NULL);
4922           
4923           if (draw_hgrid_lines)
4924             {
4925               tmp_y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node) + grid_line_width / 2;
4926               tmp_height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node)) - grid_line_width;
4927             }
4928           else
4929             {
4930               tmp_y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
4931               tmp_height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
4932             }
4933
4934           if (row_ending_details)
4935             gtk_paint_focus (widget->style,
4936                              tree_view->priv->bin_window,
4937                              focus_rect_state,
4938                              &event->area,
4939                              widget,
4940                              (is_first
4941                               ? (is_last ? "treeview" : "treeview-left" )
4942                               : (is_last ? "treeview-right" : "treeview-middle" )),
4943                              0, tmp_y,
4944                              width, tmp_height);
4945           else
4946             gtk_paint_focus (widget->style,
4947                              tree_view->priv->bin_window,
4948                              focus_rect_state,
4949                              &event->area,
4950                              widget,
4951                              "treeview",
4952                              0, tmp_y,
4953                              width, tmp_height);
4954         }
4955
4956       y_offset += max_height;
4957       if (node->children)
4958         {
4959           GtkTreeIter parent = iter;
4960           gboolean has_child;
4961
4962           tree = node->children;
4963           node = tree->root;
4964
4965           g_assert (node != tree->nil);
4966
4967           while (node->left != tree->nil)
4968             node = node->left;
4969           has_child = gtk_tree_model_iter_children (tree_view->priv->model,
4970                                                     &iter,
4971                                                     &parent);
4972           depth++;
4973
4974           /* Sanity Check! */
4975           TREE_VIEW_INTERNAL_ASSERT (has_child, FALSE);
4976         }
4977       else
4978         {
4979           gboolean done = FALSE;
4980
4981           do
4982             {
4983               node = _gtk_rbtree_next (tree, node);
4984               if (node != NULL)
4985                 {
4986                   gboolean has_next = gtk_tree_model_iter_next (tree_view->priv->model, &iter);
4987                   done = TRUE;
4988
4989                   /* Sanity Check! */
4990                   TREE_VIEW_INTERNAL_ASSERT (has_next, FALSE);
4991                 }
4992               else
4993                 {
4994                   GtkTreeIter parent_iter = iter;
4995                   gboolean has_parent;
4996
4997                   node = tree->parent_node;
4998                   tree = tree->parent_tree;
4999                   if (tree == NULL)
5000                     /* we should go to done to free some memory */
5001                     goto done;
5002                   has_parent = gtk_tree_model_iter_parent (tree_view->priv->model,
5003                                                            &iter,
5004                                                            &parent_iter);
5005                   depth--;
5006
5007                   /* Sanity check */
5008                   TREE_VIEW_INTERNAL_ASSERT (has_parent, FALSE);
5009                 }
5010             }
5011           while (!done);
5012         }
5013     }
5014   while (y_offset < event->area.height);
5015
5016 done:
5017   gtk_tree_view_draw_grid_lines (tree_view, event, n_visible_columns);
5018
5019  if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
5020    {
5021      GdkRectangle *rectangles;
5022      gint n_rectangles;
5023
5024      gdk_region_get_rectangles (event->region,
5025                                 &rectangles,
5026                                 &n_rectangles);
5027
5028      while (n_rectangles--)
5029        gtk_tree_view_paint_rubber_band (tree_view, &rectangles[n_rectangles]);
5030
5031      g_free (rectangles);
5032    }
5033
5034   if (cursor_path)
5035     gtk_tree_path_free (cursor_path);
5036
5037   if (drag_dest_path)
5038     gtk_tree_path_free (drag_dest_path);
5039
5040   return FALSE;
5041 }
5042
5043 static gboolean
5044 gtk_tree_view_expose (GtkWidget      *widget,
5045                       GdkEventExpose *event)
5046 {
5047   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
5048
5049   if (event->window == tree_view->priv->bin_window)
5050     {
5051       gboolean retval;
5052       GList *tmp_list;
5053
5054       retval = gtk_tree_view_bin_expose (widget, event);
5055
5056       /* We can't just chain up to Container::expose as it will try to send the
5057        * event to the headers, so we handle propagating it to our children
5058        * (eg. widgets being edited) ourselves.
5059        */
5060       tmp_list = tree_view->priv->children;
5061       while (tmp_list)
5062         {
5063           GtkTreeViewChild *child = tmp_list->data;
5064           tmp_list = tmp_list->next;
5065
5066           gtk_container_propagate_expose (GTK_CONTAINER (tree_view), child->widget, event);
5067         }
5068
5069       return retval;
5070     }
5071
5072   else if (event->window == tree_view->priv->header_window)
5073     {
5074       GList *list;
5075       
5076       for (list = tree_view->priv->columns; list != NULL; list = list->next)
5077         {
5078           GtkTreeViewColumn *column = list->data;
5079
5080           if (column == tree_view->priv->drag_column)
5081             continue;
5082
5083           if (column->visible)
5084             gtk_container_propagate_expose (GTK_CONTAINER (tree_view),
5085                                             column->button,
5086                                             event);
5087         }
5088     }
5089   else if (event->window == tree_view->priv->drag_window)
5090     {
5091       gtk_container_propagate_expose (GTK_CONTAINER (tree_view),
5092                                       tree_view->priv->drag_column->button,
5093                                       event);
5094     }
5095   return TRUE;
5096 }
5097
5098 enum
5099 {
5100   DROP_HOME,
5101   DROP_RIGHT,
5102   DROP_LEFT,
5103   DROP_END
5104 };
5105
5106 /* returns 0x1 when no column has been found -- yes it's hackish */
5107 static GtkTreeViewColumn *
5108 gtk_tree_view_get_drop_column (GtkTreeView       *tree_view,
5109                                GtkTreeViewColumn *column,
5110                                gint               drop_position)
5111 {
5112   GtkTreeViewColumn *left_column = NULL;
5113   GtkTreeViewColumn *cur_column = NULL;
5114   GList *tmp_list;
5115
5116   if (!column->reorderable)
5117     return (GtkTreeViewColumn *)0x1;
5118
5119   switch (drop_position)
5120     {
5121       case DROP_HOME:
5122         /* find first column where we can drop */
5123         tmp_list = tree_view->priv->columns;
5124         if (column == GTK_TREE_VIEW_COLUMN (tmp_list->data))
5125           return (GtkTreeViewColumn *)0x1;
5126
5127         while (tmp_list)
5128           {
5129             g_assert (tmp_list);
5130
5131             cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5132             tmp_list = tmp_list->next;
5133
5134             if (left_column && left_column->visible == FALSE)
5135               continue;
5136
5137             if (!tree_view->priv->column_drop_func)
5138               return left_column;
5139
5140             if (!tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5141               {
5142                 left_column = cur_column;
5143                 continue;
5144               }
5145
5146             return left_column;
5147           }
5148
5149         if (!tree_view->priv->column_drop_func)
5150           return left_column;
5151
5152         if (tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data))
5153           return left_column;
5154         else
5155           return (GtkTreeViewColumn *)0x1;
5156         break;
5157
5158       case DROP_RIGHT:
5159         /* find first column after column where we can drop */
5160         tmp_list = tree_view->priv->columns;
5161
5162         for (; tmp_list; tmp_list = tmp_list->next)
5163           if (GTK_TREE_VIEW_COLUMN (tmp_list->data) == column)
5164             break;
5165
5166         if (!tmp_list || !tmp_list->next)
5167           return (GtkTreeViewColumn *)0x1;
5168
5169         tmp_list = tmp_list->next;
5170         left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5171         tmp_list = tmp_list->next;
5172
5173         while (tmp_list)
5174           {
5175             g_assert (tmp_list);
5176
5177             cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5178             tmp_list = tmp_list->next;
5179
5180             if (left_column && left_column->visible == FALSE)
5181               {
5182                 left_column = cur_column;
5183                 if (tmp_list)
5184                   tmp_list = tmp_list->next;
5185                 continue;
5186               }
5187
5188             if (!tree_view->priv->column_drop_func)
5189               return left_column;
5190
5191             if (!tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5192               {
5193                 left_column = cur_column;
5194                 continue;
5195               }
5196
5197             return left_column;
5198           }
5199
5200         if (!tree_view->priv->column_drop_func)
5201           return left_column;
5202
5203         if (tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data))
5204           return left_column;
5205         else
5206           return (GtkTreeViewColumn *)0x1;
5207         break;
5208
5209       case DROP_LEFT:
5210         /* find first column before column where we can drop */
5211         tmp_list = tree_view->priv->columns;
5212
5213         for (; tmp_list; tmp_list = tmp_list->next)
5214           if (GTK_TREE_VIEW_COLUMN (tmp_list->data) == column)
5215             break;
5216
5217         if (!tmp_list || !tmp_list->prev)
5218           return (GtkTreeViewColumn *)0x1;
5219
5220         tmp_list = tmp_list->prev;
5221         cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5222         tmp_list = tmp_list->prev;
5223
5224         while (tmp_list)
5225           {
5226             g_assert (tmp_list);
5227
5228             left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5229
5230             if (left_column && !left_column->visible)
5231               {
5232                 /*if (!tmp_list->prev)
5233                   return (GtkTreeViewColumn *)0x1;
5234                   */
5235 /*
5236                 cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->prev->data);
5237                 tmp_list = tmp_list->prev->prev;
5238                 continue;*/
5239
5240                 cur_column = left_column;
5241                 if (tmp_list)
5242                   tmp_list = tmp_list->prev;
5243                 continue;
5244               }
5245
5246             if (!tree_view->priv->column_drop_func)
5247               return left_column;
5248
5249             if (tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5250               return left_column;
5251
5252             cur_column = left_column;
5253             tmp_list = tmp_list->prev;
5254           }
5255
5256         if (!tree_view->priv->column_drop_func)
5257           return NULL;
5258
5259         if (tree_view->priv->column_drop_func (tree_view, column, NULL, cur_column, tree_view->priv->column_drop_func_data))
5260           return NULL;
5261         else
5262           return (GtkTreeViewColumn *)0x1;
5263         break;
5264
5265       case DROP_END:
5266         /* same as DROP_HOME case, but doing it backwards */
5267         tmp_list = g_list_last (tree_view->priv->columns);
5268         cur_column = NULL;
5269
5270         if (column == GTK_TREE_VIEW_COLUMN (tmp_list->data))
5271           return (GtkTreeViewColumn *)0x1;
5272
5273         while (tmp_list)
5274           {
5275             g_assert (tmp_list);
5276
5277             left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5278
5279             if (left_column && !left_column->visible)
5280               {
5281                 cur_column = left_column;
5282                 tmp_list = tmp_list->prev;
5283               }
5284
5285             if (!tree_view->priv->column_drop_func)
5286               return left_column;
5287
5288             if (tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5289               return left_column;
5290
5291             cur_column = left_column;
5292             tmp_list = tmp_list->prev;
5293           }
5294
5295         if (!tree_view->priv->column_drop_func)
5296           return NULL;
5297
5298         if (tree_view->priv->column_drop_func (tree_view, column, NULL, cur_column, tree_view->priv->column_drop_func_data))
5299           return NULL;
5300         else
5301           return (GtkTreeViewColumn *)0x1;
5302         break;
5303     }
5304
5305   return (GtkTreeViewColumn *)0x1;
5306 }
5307
5308 static gboolean
5309 gtk_tree_view_key_press (GtkWidget   *widget,
5310                          GdkEventKey *event)
5311 {
5312   GtkTreeView *tree_view = (GtkTreeView *) widget;
5313
5314   if (tree_view->priv->rubber_band_status)
5315     {
5316       if (event->keyval == GDK_Escape)
5317         gtk_tree_view_stop_rubber_band (tree_view);
5318
5319       return TRUE;
5320     }
5321
5322   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
5323     {
5324       if (event->keyval == GDK_Escape)
5325         {
5326           tree_view->priv->cur_reorder = NULL;
5327           gtk_tree_view_button_release_drag_column (widget, NULL);
5328         }
5329       return TRUE;
5330     }
5331
5332   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
5333     {
5334       GList *focus_column;
5335       gboolean rtl;
5336
5337       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
5338
5339       for (focus_column = tree_view->priv->columns;
5340            focus_column;
5341            focus_column = focus_column->next)
5342         {
5343           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
5344
5345           if (GTK_WIDGET_HAS_FOCUS (column->button))
5346             break;
5347         }
5348
5349       if (focus_column &&
5350           (event->state & GDK_SHIFT_MASK) && (event->state & GDK_MOD1_MASK) &&
5351           (event->keyval == GDK_Left || event->keyval == GDK_KP_Left
5352            || event->keyval == GDK_Right || event->keyval == GDK_KP_Right))
5353         {
5354           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
5355
5356           if (!column->resizable)
5357             {
5358               gtk_widget_error_bell (widget);
5359               return TRUE;
5360             }
5361
5362           if (event->keyval == (rtl ? GDK_Right : GDK_Left)
5363               || event->keyval == (rtl ? GDK_KP_Right : GDK_KP_Left))
5364             {
5365               gint old_width = column->resized_width;
5366
5367               column->resized_width = MAX (column->resized_width,
5368                                            column->width);
5369               column->resized_width -= 2;
5370               if (column->resized_width < 0)
5371                 column->resized_width = 0;
5372
5373               if (column->min_width == -1)
5374                 column->resized_width = MAX (column->button->requisition.width,
5375                                              column->resized_width);
5376               else
5377                 column->resized_width = MAX (column->min_width,
5378                                              column->resized_width);
5379
5380               if (column->max_width != -1)
5381                 column->resized_width = MIN (column->resized_width,
5382                                              column->max_width);
5383
5384               column->use_resized_width = TRUE;
5385
5386               if (column->resized_width != old_width)
5387                 gtk_widget_queue_resize (widget);
5388               else
5389                 gtk_widget_error_bell (widget);
5390             }
5391           else if (event->keyval == (rtl ? GDK_Left : GDK_Right)
5392                    || event->keyval == (rtl ? GDK_KP_Left : GDK_KP_Right))
5393             {
5394               gint old_width = column->resized_width;
5395
5396               column->resized_width = MAX (column->resized_width,
5397                                            column->width);
5398               column->resized_width += 2;
5399
5400               if (column->max_width != -1)
5401                 column->resized_width = MIN (column->resized_width,
5402                                              column->max_width);
5403
5404               column->use_resized_width = TRUE;
5405
5406               if (column->resized_width != old_width)
5407                 gtk_widget_queue_resize (widget);
5408               else
5409                 gtk_widget_error_bell (widget);
5410             }
5411
5412           return TRUE;
5413         }
5414
5415       if (focus_column &&
5416           (event->state & GDK_MOD1_MASK) &&
5417           (event->keyval == GDK_Left || event->keyval == GDK_KP_Left
5418            || event->keyval == GDK_Right || event->keyval == GDK_KP_Right
5419            || event->keyval == GDK_Home || event->keyval == GDK_KP_Home
5420            || event->keyval == GDK_End || event->keyval == GDK_KP_End))
5421         {
5422           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
5423
5424           if (event->keyval == (rtl ? GDK_Right : GDK_Left)
5425               || event->keyval == (rtl ? GDK_KP_Right : GDK_KP_Left))
5426             {
5427               GtkTreeViewColumn *col;
5428               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_LEFT);
5429               if (col != (GtkTreeViewColumn *)0x1)
5430                 gtk_tree_view_move_column_after (tree_view, column, col);
5431               else
5432                 gtk_widget_error_bell (widget);
5433             }
5434           else if (event->keyval == (rtl ? GDK_Left : GDK_Right)
5435                    || event->keyval == (rtl ? GDK_KP_Left : GDK_KP_Right))
5436             {
5437               GtkTreeViewColumn *col;
5438               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_RIGHT);
5439               if (col != (GtkTreeViewColumn *)0x1)
5440                 gtk_tree_view_move_column_after (tree_view, column, col);
5441               else
5442                 gtk_widget_error_bell (widget);
5443             }
5444           else if (event->keyval == GDK_Home || event->keyval == GDK_KP_Home)
5445             {
5446               GtkTreeViewColumn *col;
5447               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_HOME);
5448               if (col != (GtkTreeViewColumn *)0x1)
5449                 gtk_tree_view_move_column_after (tree_view, column, col);
5450               else
5451                 gtk_widget_error_bell (widget);
5452             }
5453           else if (event->keyval == GDK_End || event->keyval == GDK_KP_End)
5454             {
5455               GtkTreeViewColumn *col;
5456               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_END);
5457               if (col != (GtkTreeViewColumn *)0x1)
5458                 gtk_tree_view_move_column_after (tree_view, column, col);
5459               else
5460                 gtk_widget_error_bell (widget);
5461             }
5462
5463           return TRUE;
5464         }
5465     }
5466
5467   /* Chain up to the parent class.  It handles the keybindings. */
5468   if (GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->key_press_event (widget, event))
5469     return TRUE;
5470
5471   if (tree_view->priv->search_entry_avoid_unhandled_binding)
5472     {
5473       tree_view->priv->search_entry_avoid_unhandled_binding = FALSE;
5474       return FALSE;
5475     }
5476
5477   /* We pass the event to the search_entry.  If its text changes, then we start
5478    * the typeahead find capabilities. */
5479   if (GTK_WIDGET_HAS_FOCUS (tree_view)
5480       && tree_view->priv->enable_search
5481       && !tree_view->priv->search_custom_entry_set)
5482     {
5483       GdkEvent *new_event;
5484       char *old_text;
5485       const char *new_text;
5486       gboolean retval;
5487       GdkScreen *screen;
5488       gboolean text_modified;
5489       gulong popup_menu_id;
5490
5491       gtk_tree_view_ensure_interactive_directory (tree_view);
5492
5493       /* Make a copy of the current text */
5494       old_text = g_strdup (gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry)));
5495       new_event = gdk_event_copy ((GdkEvent *) event);
5496       g_object_unref (((GdkEventKey *) new_event)->window);
5497       ((GdkEventKey *) new_event)->window = g_object_ref (tree_view->priv->search_window->window);
5498       gtk_widget_realize (tree_view->priv->search_window);
5499
5500       popup_menu_id = g_signal_connect (tree_view->priv->search_entry, 
5501                                         "popup-menu", G_CALLBACK (gtk_true),
5502                                         NULL);
5503
5504       /* Move the entry off screen */
5505       screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
5506       gtk_window_move (GTK_WINDOW (tree_view->priv->search_window),
5507                        gdk_screen_get_width (screen) + 1,
5508                        gdk_screen_get_height (screen) + 1);
5509       gtk_widget_show (tree_view->priv->search_window);
5510
5511       /* Send the event to the window.  If the preedit_changed signal is emitted
5512        * during this event, we will set priv->imcontext_changed  */
5513       tree_view->priv->imcontext_changed = FALSE;
5514       retval = gtk_widget_event (tree_view->priv->search_window, new_event);
5515       gdk_event_free (new_event);
5516       gtk_widget_hide (tree_view->priv->search_window);
5517
5518       g_signal_handler_disconnect (tree_view->priv->search_entry, 
5519                                    popup_menu_id);
5520
5521       /* We check to make sure that the entry tried to handle the text, and that
5522        * the text has changed.
5523        */
5524       new_text = gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry));
5525       text_modified = strcmp (old_text, new_text) != 0;
5526       g_free (old_text);
5527       if (tree_view->priv->imcontext_changed ||    /* we're in a preedit */
5528           (retval && text_modified))               /* ...or the text was modified */
5529         {
5530           if (gtk_tree_view_real_start_interactive_search (tree_view, FALSE))
5531             {
5532               gtk_widget_grab_focus (GTK_WIDGET (tree_view));
5533               return TRUE;
5534             }
5535           else
5536             {
5537               gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
5538               return FALSE;
5539             }
5540         }
5541     }
5542
5543   return FALSE;
5544 }
5545
5546 static gboolean
5547 gtk_tree_view_key_release (GtkWidget   *widget,
5548                            GdkEventKey *event)
5549 {
5550   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
5551
5552   if (tree_view->priv->rubber_band_status)
5553     return TRUE;
5554
5555   return GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->key_release_event (widget, event);
5556 }
5557
5558 /* FIXME Is this function necessary? Can I get an enter_notify event
5559  * w/o either an expose event or a mouse motion event?
5560  */
5561 static gboolean
5562 gtk_tree_view_enter_notify (GtkWidget        *widget,
5563                             GdkEventCrossing *event)
5564 {
5565   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
5566   GtkRBTree *tree;
5567   GtkRBNode *node;
5568   gint new_y;
5569
5570   /* Sanity check it */
5571   if (event->window != tree_view->priv->bin_window)
5572     return FALSE;
5573
5574   if (tree_view->priv->tree == NULL)
5575     return FALSE;
5576
5577   if (event->mode == GDK_CROSSING_GRAB ||
5578       event->mode == GDK_CROSSING_GTK_GRAB ||
5579       event->mode == GDK_CROSSING_GTK_UNGRAB ||
5580       event->mode == GDK_CROSSING_STATE_CHANGED)
5581     return TRUE;
5582
5583   /* find the node internally */
5584   new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
5585   if (new_y < 0)
5586     new_y = 0;
5587   _gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
5588
5589   tree_view->priv->event_last_x = event->x;
5590   tree_view->priv->event_last_y = event->y;
5591
5592   if ((tree_view->priv->button_pressed_node == NULL) ||
5593       (tree_view->priv->button_pressed_node == node))
5594     prelight_or_select (tree_view, tree, node, event->x, event->y);
5595
5596   return TRUE;
5597 }
5598
5599 static gboolean
5600 gtk_tree_view_leave_notify (GtkWidget        *widget,
5601                             GdkEventCrossing *event)
5602 {
5603   GtkTreeView *tree_view;
5604
5605   if (event->mode == GDK_CROSSING_GRAB)
5606     return TRUE;
5607
5608   tree_view = GTK_TREE_VIEW (widget);
5609
5610   if (tree_view->priv->prelight_node)
5611     _gtk_tree_view_queue_draw_node (tree_view,
5612                                    tree_view->priv->prelight_tree,
5613                                    tree_view->priv->prelight_node,
5614                                    NULL);
5615
5616   tree_view->priv->event_last_x = -10000;
5617   tree_view->priv->event_last_y = -10000;
5618
5619   prelight_or_select (tree_view,
5620                       NULL, NULL,
5621                       -1000, -1000); /* coords not possibly over an arrow */
5622
5623   return TRUE;
5624 }
5625
5626
5627 static gint
5628 gtk_tree_view_focus_out (GtkWidget     *widget,
5629                          GdkEventFocus *event)
5630 {
5631   GtkTreeView *tree_view;
5632
5633   tree_view = GTK_TREE_VIEW (widget);
5634
5635   gtk_widget_queue_draw (widget);
5636
5637   /* destroy interactive search dialog */
5638   if (tree_view->priv->search_window)
5639     gtk_tree_view_search_dialog_hide (tree_view->priv->search_window, tree_view);
5640
5641   return FALSE;
5642 }
5643
5644
5645 /* Incremental Reflow
5646  */
5647
5648 static void
5649 gtk_tree_view_node_queue_redraw (GtkTreeView *tree_view,
5650                                  GtkRBTree   *tree,
5651                                  GtkRBNode   *node)
5652 {
5653   gint y;
5654
5655   y = _gtk_rbtree_node_find_offset (tree, node)
5656     - tree_view->priv->vadjustment->value
5657     + TREE_VIEW_HEADER_HEIGHT (tree_view);
5658
5659   gtk_widget_queue_draw_area (GTK_WIDGET (tree_view),
5660                               0, y,
5661                               GTK_WIDGET (tree_view)->allocation.width,
5662                               GTK_RBNODE_GET_HEIGHT (node));
5663 }
5664
5665 static gboolean
5666 node_is_visible (GtkTreeView *tree_view,
5667                  GtkRBTree   *tree,
5668                  GtkRBNode   *node)
5669 {
5670   int y;
5671   int height;
5672
5673   y = _gtk_rbtree_node_find_offset (tree, node);
5674   height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
5675
5676   if (y >= tree_view->priv->vadjustment->value &&
5677       y + height <= (tree_view->priv->vadjustment->value
5678                      + tree_view->priv->vadjustment->page_size))
5679     return TRUE;
5680
5681   return FALSE;
5682 }
5683
5684 /* Returns TRUE if it updated the size
5685  */
5686 static gboolean
5687 validate_row (GtkTreeView *tree_view,
5688               GtkRBTree   *tree,
5689               GtkRBNode   *node,
5690               GtkTreeIter *iter,
5691               GtkTreePath *path)
5692 {
5693   GtkTreeViewColumn *column;
5694   GList *list, *first_column, *last_column;
5695   gint height = 0;
5696   gint horizontal_separator;
5697   gint vertical_separator;
5698   gint focus_line_width;
5699   gint depth = gtk_tree_path_get_depth (path);
5700   gboolean retval = FALSE;
5701   gboolean is_separator = FALSE;
5702   gboolean draw_vgrid_lines, draw_hgrid_lines;
5703   gint focus_pad;
5704   gint grid_line_width;
5705   gboolean wide_separators;
5706   gint separator_height;
5707
5708   /* double check the row needs validating */
5709   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) &&
5710       ! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
5711     return FALSE;
5712
5713   is_separator = row_is_separator (tree_view, iter, NULL);
5714
5715   gtk_widget_style_get (GTK_WIDGET (tree_view),
5716                         "focus-padding", &focus_pad,
5717                         "focus-line-width", &focus_line_width,
5718                         "horizontal-separator", &horizontal_separator,
5719                         "vertical-separator", &vertical_separator,
5720                         "grid-line-width", &grid_line_width,
5721                         "wide-separators",  &wide_separators,
5722                         "separator-height", &separator_height,
5723                         NULL);
5724   
5725   draw_vgrid_lines =
5726     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_VERTICAL
5727     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
5728   draw_hgrid_lines =
5729     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_HORIZONTAL
5730     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
5731
5732   for (last_column = g_list_last (tree_view->priv->columns);
5733        last_column && !(GTK_TREE_VIEW_COLUMN (last_column->data)->visible);
5734        last_column = last_column->prev)
5735     ;
5736
5737   for (first_column = g_list_first (tree_view->priv->columns);
5738        first_column && !(GTK_TREE_VIEW_COLUMN (first_column->data)->visible);
5739        first_column = first_column->next)
5740     ;
5741
5742   for (list = tree_view->priv->columns; list; list = list->next)
5743     {
5744       GtkTreeViewColumnPrivate *column_priv;
5745       GtkRequisition requested_size;
5746       GtkRequisition natural_size;
5747       gint padding;
5748
5749       column = list->data;
5750       column_priv = GTK_TREE_VIEW_COLUMN_GET_PRIVATE (column);
5751
5752       if (! column->visible)
5753         continue;
5754
5755       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID) && !column->dirty)
5756         continue;
5757
5758       gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, iter,
5759                                                GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
5760                                                node->children?TRUE:FALSE);
5761       gtk_tree_view_column_cell_get_size (column,
5762                                           NULL, NULL, NULL,
5763                                           &requested_size.width,
5764                                           &requested_size.height);
5765       gtk_extended_layout_get_desired_size (GTK_EXTENDED_LAYOUT (column),
5766                                             NULL, &natural_size);
5767
5768       if (!is_separator)
5769         {
5770           requested_size.height += vertical_separator;
5771           height = MAX (height, requested_size.height);
5772           height = MAX (height, tree_view->priv->expander_size);
5773         }
5774       else
5775         {
5776           if (wide_separators)
5777             height = separator_height + 2 * focus_pad;
5778           else
5779             height = 2 + 2 * focus_pad;
5780         }
5781
5782       if (gtk_tree_view_is_expander_column (tree_view, column))
5783         {
5784           padding = horizontal_separator + (depth - 1) * tree_view->priv->level_indentation;
5785
5786           if (TREE_VIEW_DRAW_EXPANDERS (tree_view))
5787             padding += depth * tree_view->priv->expander_size;
5788         }
5789       else
5790         padding = horizontal_separator;
5791
5792       if (draw_vgrid_lines)
5793         {
5794           if (list->data == first_column || list->data == last_column)
5795             padding += grid_line_width / 2.0;
5796           else
5797             padding += grid_line_width;
5798         }
5799
5800       requested_size.width += padding;
5801       natural_size.width += padding;
5802
5803       if (requested_size.width > column->requested_width ||
5804           natural_size.width > column_priv->natural_width)
5805         {
5806           retval = TRUE;
5807           column->requested_width = requested_size.width;
5808           column_priv->natural_width = natural_size.width;
5809         }
5810     }
5811
5812   if (draw_hgrid_lines)
5813     height += grid_line_width;
5814
5815   if (height != GTK_RBNODE_GET_HEIGHT (node))
5816     {
5817       retval = TRUE;
5818       _gtk_rbtree_node_set_height (tree, node, height);
5819     }
5820   _gtk_rbtree_node_mark_valid (tree, node);
5821   tree_view->priv->post_validation_flag = TRUE;
5822
5823   return retval;
5824 }
5825
5826
5827 static void
5828 validate_visible_area (GtkTreeView *tree_view)
5829 {
5830   GtkTreePath *path = NULL;
5831   GtkTreePath *above_path = NULL;
5832   GtkTreeIter iter;
5833   GtkRBTree *tree = NULL;
5834   GtkRBNode *node = NULL;
5835   gboolean need_redraw = FALSE;
5836   gboolean size_changed = FALSE;
5837   gint total_height;
5838   gint area_above = 0;
5839   gint area_below = 0;
5840
5841   if (tree_view->priv->tree == NULL)
5842     return;
5843
5844   if (! GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID) &&
5845       tree_view->priv->scroll_to_path == NULL)
5846     return;
5847
5848   total_height = GTK_WIDGET (tree_view)->allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view);
5849
5850   if (total_height == 0)
5851     return;
5852
5853   /* First, we check to see if we need to scroll anywhere
5854    */
5855   if (tree_view->priv->scroll_to_path)
5856     {
5857       path = gtk_tree_row_reference_get_path (tree_view->priv->scroll_to_path);
5858       if (path && !_gtk_tree_view_find_node (tree_view, path, &tree, &node))
5859         {
5860           /* we are going to scroll, and will update dy */
5861           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
5862           if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
5863               GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
5864             {
5865               _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
5866               if (validate_row (tree_view, tree, node, &iter, path))
5867                 size_changed = TRUE;
5868             }
5869
5870           if (tree_view->priv->scroll_to_use_align)
5871             {
5872               gint height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
5873               area_above = (total_height - height) *
5874                 tree_view->priv->scroll_to_row_align;
5875               area_below = total_height - area_above - height;
5876               area_above = MAX (area_above, 0);
5877               area_below = MAX (area_below, 0);
5878             }
5879           else
5880             {
5881               /* two cases:
5882                * 1) row not visible
5883                * 2) row visible
5884                */
5885               gint dy;
5886               gint height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
5887
5888               dy = _gtk_rbtree_node_find_offset (tree, node);
5889
5890               if (dy >= tree_view->priv->vadjustment->value &&
5891                   dy + height <= (tree_view->priv->vadjustment->value
5892                                   + tree_view->priv->vadjustment->page_size))
5893                 {
5894                   /* row visible: keep the row at the same position */
5895                   area_above = dy - tree_view->priv->vadjustment->value;
5896                   area_below = (tree_view->priv->vadjustment->value +
5897                                 tree_view->priv->vadjustment->page_size)
5898                                - dy - height;
5899                 }
5900               else
5901                 {
5902                   /* row not visible */
5903                   if (dy >= 0
5904                       && dy + height <= tree_view->priv->vadjustment->page_size)
5905                     {
5906                       /* row at the beginning -- fixed */
5907                       area_above = dy;
5908                       area_below = tree_view->priv->vadjustment->page_size
5909                                    - area_above - height;
5910                     }
5911                   else if (dy >= (tree_view->priv->vadjustment->upper -
5912                                   tree_view->priv->vadjustment->page_size))
5913                     {
5914                       /* row at the end -- fixed */
5915                       area_above = dy - (tree_view->priv->vadjustment->upper -
5916                                    tree_view->priv->vadjustment->page_size);
5917                       area_below = tree_view->priv->vadjustment->page_size -
5918                                    area_above - height;
5919
5920                       if (area_below < 0)
5921                         {
5922                           area_above = tree_view->priv->vadjustment->page_size - height;
5923                           area_below = 0;
5924                         }
5925                     }
5926                   else
5927                     {
5928                       /* row somewhere in the middle, bring it to the top
5929                        * of the view
5930                        */
5931                       area_above = 0;
5932                       area_below = total_height - height;
5933                     }
5934                 }
5935             }
5936         }
5937       else
5938         /* the scroll to isn't valid; ignore it.
5939          */
5940         {
5941           if (tree_view->priv->scroll_to_path && !path)
5942             {
5943               gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
5944               tree_view->priv->scroll_to_path = NULL;
5945             }
5946           if (path)
5947             gtk_tree_path_free (path);
5948           path = NULL;
5949         }      
5950     }
5951
5952   /* We didn't have a scroll_to set, so we just handle things normally
5953    */
5954   if (path == NULL)
5955     {
5956       gint offset;
5957
5958       offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
5959                                         TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, 0),
5960                                         &tree, &node);
5961       if (node == NULL)
5962         {
5963           /* In this case, nothing has been validated */
5964           path = gtk_tree_path_new_first ();
5965           _gtk_tree_view_find_node (tree_view, path, &tree, &node);
5966         }
5967       else
5968         {
5969           path = _gtk_tree_view_find_path (tree_view, tree, node);
5970           total_height += offset;
5971         }
5972
5973       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
5974
5975       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
5976           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
5977         {
5978           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
5979           if (validate_row (tree_view, tree, node, &iter, path))
5980             size_changed = TRUE;
5981         }
5982       area_above = 0;
5983       area_below = total_height - ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
5984     }
5985
5986   above_path = gtk_tree_path_copy (path);
5987
5988   /* if we do not validate any row above the new top_row, we will make sure
5989    * that the row immediately above top_row has been validated. (if we do not
5990    * do this, _gtk_rbtree_find_offset will find the row above top_row, because
5991    * when invalidated that row's height will be zero. and this will mess up
5992    * scrolling).
5993    */
5994   if (area_above == 0)
5995     {
5996       GtkRBTree *tmptree;
5997       GtkRBNode *tmpnode;
5998
5999       _gtk_tree_view_find_node (tree_view, above_path, &tmptree, &tmpnode);
6000       _gtk_rbtree_prev_full (tmptree, tmpnode, &tmptree, &tmpnode);
6001
6002       if (tmpnode)
6003         {
6004           GtkTreePath *tmppath;
6005           GtkTreeIter tmpiter;
6006
6007           tmppath = _gtk_tree_view_find_path (tree_view, tmptree, tmpnode);
6008           gtk_tree_model_get_iter (tree_view->priv->model, &tmpiter, tmppath);
6009
6010           if (GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_INVALID) ||
6011               GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_COLUMN_INVALID))
6012             {
6013               _gtk_tree_view_queue_draw_node (tree_view, tmptree, tmpnode, NULL);
6014               if (validate_row (tree_view, tmptree, tmpnode, &tmpiter, tmppath))
6015                 size_changed = TRUE;
6016             }
6017
6018           gtk_tree_path_free (tmppath);
6019         }
6020     }
6021
6022   /* Now, we walk forwards and backwards, measuring rows. Unfortunately,
6023    * backwards is much slower then forward, as there is no iter_prev function.
6024    * We go forwards first in case we run out of tree.  Then we go backwards to
6025    * fill out the top.
6026    */
6027   while (node && area_below > 0)
6028     {
6029       if (node->children)
6030         {
6031           GtkTreeIter parent = iter;
6032           gboolean has_child;
6033
6034           tree = node->children;
6035           node = tree->root;
6036
6037           g_assert (node != tree->nil);
6038
6039           while (node->left != tree->nil)
6040             node = node->left;
6041           has_child = gtk_tree_model_iter_children (tree_view->priv->model,
6042                                                     &iter,
6043                                                     &parent);
6044           TREE_VIEW_INTERNAL_ASSERT_VOID (has_child);
6045           gtk_tree_path_down (path);
6046         }
6047       else
6048         {
6049           gboolean done = FALSE;
6050           do
6051             {
6052               node = _gtk_rbtree_next (tree, node);
6053               if (node != NULL)
6054                 {
6055                   gboolean has_next = gtk_tree_model_iter_next (tree_view->priv->model, &iter);
6056                   done = TRUE;
6057                   gtk_tree_path_next (path);
6058
6059                   /* Sanity Check! */
6060                   TREE_VIEW_INTERNAL_ASSERT_VOID (has_next);
6061                 }
6062               else
6063                 {
6064                   GtkTreeIter parent_iter = iter;
6065                   gboolean has_parent;
6066
6067                   node = tree->parent_node;
6068                   tree = tree->parent_tree;
6069                   if (tree == NULL)
6070                     break;
6071                   has_parent = gtk_tree_model_iter_parent (tree_view->priv->model,
6072                                                            &iter,
6073                                                            &parent_iter);
6074                   gtk_tree_path_up (path);
6075
6076                   /* Sanity check */
6077                   TREE_VIEW_INTERNAL_ASSERT_VOID (has_parent);
6078                 }
6079             }
6080           while (!done);
6081         }
6082
6083       if (!node)
6084         break;
6085
6086       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6087           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6088         {
6089           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
6090           if (validate_row (tree_view, tree, node, &iter, path))
6091               size_changed = TRUE;
6092         }
6093
6094       area_below -= ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
6095     }
6096   gtk_tree_path_free (path);
6097
6098   /* If we ran out of tree, and have extra area_below left, we need to add it
6099    * to area_above */
6100   if (area_below > 0)
6101     area_above += area_below;
6102
6103   _gtk_tree_view_find_node (tree_view, above_path, &tree, &node);
6104
6105   /* We walk backwards */
6106   while (area_above > 0)
6107     {
6108       _gtk_rbtree_prev_full (tree, node, &tree, &node);
6109
6110       /* Always find the new path in the tree.  We cannot just assume
6111        * a gtk_tree_path_prev() is enough here, as there might be children
6112        * in between this node and the previous sibling node.  If this
6113        * appears to be a performance hotspot in profiles, we can look into
6114        * intrigate logic for keeping path, node and iter in sync like
6115        * we do for forward walks.  (Which will be hard because of the lacking
6116        * iter_prev).
6117        */
6118
6119       if (node == NULL)
6120         break;
6121
6122       gtk_tree_path_free (above_path);
6123       above_path = _gtk_tree_view_find_path (tree_view, tree, node);
6124
6125       gtk_tree_model_get_iter (tree_view->priv->model, &iter, above_path);
6126
6127       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6128           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6129         {
6130           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
6131           if (validate_row (tree_view, tree, node, &iter, above_path))
6132             size_changed = TRUE;
6133         }
6134       area_above -= ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
6135     }
6136
6137   /* if we scrolled to a path, we need to set the dy here,
6138    * and sync the top row accordingly
6139    */
6140   if (tree_view->priv->scroll_to_path)
6141     {
6142       gtk_tree_view_set_top_row (tree_view, above_path, -area_above);
6143       gtk_tree_view_top_row_to_dy (tree_view);
6144
6145       need_redraw = TRUE;
6146     }
6147   else if (tree_view->priv->height <= tree_view->priv->vadjustment->page_size)
6148     {
6149       /* when we are not scrolling, we should never set dy to something
6150        * else than zero. we update top_row to be in sync with dy = 0.
6151        */
6152       gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
6153       gtk_tree_view_dy_to_top_row (tree_view);
6154     }
6155   else if (tree_view->priv->vadjustment->value + tree_view->priv->vadjustment->page_size > tree_view->priv->height)
6156     {
6157       gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), tree_view->priv->height - tree_view->priv->vadjustment->page_size);
6158       gtk_tree_view_dy_to_top_row (tree_view);
6159     }
6160   else
6161     gtk_tree_view_top_row_to_dy (tree_view);
6162
6163   /* update width/height and queue a resize */
6164   if (size_changed)
6165     {
6166       GtkRequisition requisition;
6167
6168       /* We temporarily guess a size, under the assumption that it will be the
6169        * same when we get our next size_allocate.  If we don't do this, we'll be
6170        * in an inconsistent state if we call top_row_to_dy. */
6171
6172       gtk_widget_size_request (GTK_WIDGET (tree_view), &requisition);
6173       tree_view->priv->hadjustment->upper = MAX (tree_view->priv->hadjustment->upper, (gfloat)requisition.width);
6174       tree_view->priv->vadjustment->upper = MAX (tree_view->priv->vadjustment->upper, (gfloat)requisition.height);
6175       gtk_adjustment_changed (tree_view->priv->hadjustment);
6176       gtk_adjustment_changed (tree_view->priv->vadjustment);
6177       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6178     }
6179
6180   if (tree_view->priv->scroll_to_path)
6181     {
6182       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
6183       tree_view->priv->scroll_to_path = NULL;
6184     }
6185
6186   if (above_path)
6187     gtk_tree_path_free (above_path);
6188
6189   if (tree_view->priv->scroll_to_column)
6190     {
6191       tree_view->priv->scroll_to_column = NULL;
6192     }
6193   if (need_redraw)
6194     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
6195 }
6196
6197 static void
6198 initialize_fixed_height_mode (GtkTreeView *tree_view)
6199 {
6200   if (!tree_view->priv->tree)
6201     return;
6202
6203   if (tree_view->priv->fixed_height < 0)
6204     {
6205       GtkTreeIter iter;
6206       GtkTreePath *path;
6207
6208       GtkRBTree *tree = NULL;
6209       GtkRBNode *node = NULL;
6210
6211       tree = tree_view->priv->tree;
6212       node = tree->root;
6213
6214       path = _gtk_tree_view_find_path (tree_view, tree, node);
6215       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6216
6217       validate_row (tree_view, tree, node, &iter, path);
6218
6219       gtk_tree_path_free (path);
6220
6221       tree_view->priv->fixed_height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
6222     }
6223
6224    _gtk_rbtree_set_fixed_height (tree_view->priv->tree,
6225                                  tree_view->priv->fixed_height, TRUE);
6226 }
6227
6228 /* Our strategy for finding nodes to validate is a little convoluted.  We find
6229  * the left-most uninvalidated node.  We then try walking right, validating
6230  * nodes.  Once we find a valid node, we repeat the previous process of finding
6231  * the first invalid node.
6232  */
6233
6234 static gboolean
6235 do_validate_rows (GtkTreeView *tree_view, gboolean queue_resize)
6236 {
6237   GtkRBTree *tree = NULL;
6238   GtkRBNode *node = NULL;
6239   gboolean validated_area = FALSE;
6240   gint retval = TRUE;
6241   GtkTreePath *path = NULL;
6242   GtkTreeIter iter;
6243   GTimer *timer;
6244   gint i = 0;
6245
6246   gint prev_height = -1;
6247   gboolean fixed_height = TRUE;
6248
6249   g_assert (tree_view);
6250
6251   if (tree_view->priv->tree == NULL)
6252       return FALSE;
6253
6254   if (tree_view->priv->fixed_height_mode)
6255     {
6256       if (tree_view->priv->fixed_height < 0)
6257         initialize_fixed_height_mode (tree_view);
6258
6259       return FALSE;
6260     }
6261
6262   timer = g_timer_new ();
6263   g_timer_start (timer);
6264
6265   do
6266     {
6267       if (! GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID))
6268         {
6269           retval = FALSE;
6270           goto done;
6271         }
6272
6273       if (path != NULL)
6274         {
6275           node = _gtk_rbtree_next (tree, node);
6276           if (node != NULL)
6277             {
6278               TREE_VIEW_INTERNAL_ASSERT (gtk_tree_model_iter_next (tree_view->priv->model, &iter), FALSE);
6279               gtk_tree_path_next (path);
6280             }
6281           else
6282             {
6283               gtk_tree_path_free (path);
6284               path = NULL;
6285             }
6286         }
6287
6288       if (path == NULL)
6289         {
6290           tree = tree_view->priv->tree;
6291           node = tree_view->priv->tree->root;
6292
6293           g_assert (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_DESCENDANTS_INVALID));
6294
6295           do
6296             {
6297               if (node->left != tree->nil &&
6298                   GTK_RBNODE_FLAG_SET (node->left, GTK_RBNODE_DESCENDANTS_INVALID))
6299                 {
6300                   node = node->left;
6301                 }
6302               else if (node->right != tree->nil &&
6303                        GTK_RBNODE_FLAG_SET (node->right, GTK_RBNODE_DESCENDANTS_INVALID))
6304                 {
6305                   node = node->right;
6306                 }
6307               else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6308                        GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6309                 {
6310                   break;
6311                 }
6312               else if (node->children != NULL)
6313                 {
6314                   tree = node->children;
6315                   node = tree->root;
6316                 }
6317               else
6318                 /* RBTree corruption!  All bad */
6319                 g_assert_not_reached ();
6320             }
6321           while (TRUE);
6322           path = _gtk_tree_view_find_path (tree_view, tree, node);
6323           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6324         }
6325
6326       validated_area = validate_row (tree_view, tree, node, &iter, path) ||
6327                        validated_area;
6328
6329       if (!tree_view->priv->fixed_height_check)
6330         {
6331           gint height;
6332
6333           height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
6334           if (prev_height < 0)
6335             prev_height = height;
6336           else if (prev_height != height)
6337             fixed_height = FALSE;
6338         }
6339
6340       i++;
6341     }
6342   while (g_timer_elapsed (timer, NULL) < GTK_TREE_VIEW_TIME_MS_PER_IDLE / 1000.);
6343
6344   if (!tree_view->priv->fixed_height_check)
6345    {
6346      if (fixed_height)
6347        _gtk_rbtree_set_fixed_height (tree_view->priv->tree, prev_height, FALSE);
6348
6349      tree_view->priv->fixed_height_check = 1;
6350    }
6351   
6352  done:
6353   if (validated_area)
6354     {
6355       GtkRequisition requisition;
6356       /* We temporarily guess a size, under the assumption that it will be the
6357        * same when we get our next size_allocate.  If we don't do this, we'll be
6358        * in an inconsistent state when we call top_row_to_dy. */
6359
6360       gtk_widget_size_request (GTK_WIDGET (tree_view), &requisition);
6361       tree_view->priv->hadjustment->upper = MAX (tree_view->priv->hadjustment->upper, (gfloat)requisition.width);
6362       tree_view->priv->vadjustment->upper = MAX (tree_view->priv->vadjustment->upper, (gfloat)requisition.height);
6363       gtk_adjustment_changed (tree_view->priv->hadjustment);
6364       gtk_adjustment_changed (tree_view->priv->vadjustment);
6365
6366       if (queue_resize)
6367         gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6368     }
6369
6370   if (path) gtk_tree_path_free (path);
6371   g_timer_destroy (timer);
6372
6373   return retval;
6374 }
6375
6376 static gboolean
6377 validate_rows (GtkTreeView *tree_view)
6378 {
6379   gboolean retval;
6380   
6381   retval = do_validate_rows (tree_view, TRUE);
6382   
6383   if (! retval && tree_view->priv->validate_rows_timer)
6384     {
6385       g_source_remove (tree_view->priv->validate_rows_timer);
6386       tree_view->priv->validate_rows_timer = 0;
6387     }
6388
6389   return retval;
6390 }
6391
6392 static gboolean
6393 validate_rows_handler (GtkTreeView *tree_view)
6394 {
6395   gboolean retval;
6396
6397   retval = do_validate_rows (tree_view, TRUE);
6398   if (! retval && tree_view->priv->validate_rows_timer)
6399     {
6400       g_source_remove (tree_view->priv->validate_rows_timer);
6401       tree_view->priv->validate_rows_timer = 0;
6402     }
6403
6404   return retval;
6405 }
6406
6407 static gboolean
6408 do_presize_handler (GtkTreeView *tree_view)
6409 {
6410   if (tree_view->priv->mark_rows_col_dirty)
6411     {
6412       if (tree_view->priv->tree)
6413         _gtk_rbtree_column_invalid (tree_view->priv->tree);
6414       tree_view->priv->mark_rows_col_dirty = FALSE;
6415     }
6416   validate_visible_area (tree_view);
6417   tree_view->priv->presize_handler_timer = 0;
6418
6419   if (tree_view->priv->fixed_height_mode)
6420     {
6421       GtkRequisition requisition;
6422
6423       gtk_widget_size_request (GTK_WIDGET (tree_view), &requisition);
6424
6425       tree_view->priv->hadjustment->upper = MAX (tree_view->priv->hadjustment->upper, (gfloat)requisition.width);
6426       tree_view->priv->vadjustment->upper = MAX (tree_view->priv->vadjustment->upper, (gfloat)requisition.height);
6427       gtk_adjustment_changed (tree_view->priv->hadjustment);
6428       gtk_adjustment_changed (tree_view->priv->vadjustment);
6429       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6430     }
6431                    
6432   return FALSE;
6433 }
6434
6435 static gboolean
6436 presize_handler_callback (gpointer data)
6437 {
6438   do_presize_handler (GTK_TREE_VIEW (data));
6439                    
6440   return FALSE;
6441 }
6442
6443 static void
6444 install_presize_handler (GtkTreeView *tree_view)
6445 {
6446   if (! GTK_WIDGET_REALIZED (tree_view))
6447     return;
6448
6449   if (! tree_view->priv->presize_handler_timer)
6450     {
6451       tree_view->priv->presize_handler_timer =
6452         gdk_threads_add_idle_full (GTK_PRIORITY_RESIZE - 2, presize_handler_callback, tree_view, NULL);
6453     }
6454   if (! tree_view->priv->validate_rows_timer)
6455     {
6456       tree_view->priv->validate_rows_timer =
6457         gdk_threads_add_idle_full (GTK_TREE_VIEW_PRIORITY_VALIDATE, (GSourceFunc) validate_rows_handler, tree_view, NULL);
6458     }
6459 }
6460
6461 static gboolean
6462 scroll_sync_handler (GtkTreeView *tree_view)
6463 {
6464   if (tree_view->priv->height <= tree_view->priv->vadjustment->page_size)
6465     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
6466   else if (gtk_tree_row_reference_valid (tree_view->priv->top_row))
6467     gtk_tree_view_top_row_to_dy (tree_view);
6468   else
6469     gtk_tree_view_dy_to_top_row (tree_view);
6470
6471   tree_view->priv->scroll_sync_timer = 0;
6472
6473   return FALSE;
6474 }
6475
6476 static void
6477 install_scroll_sync_handler (GtkTreeView *tree_view)
6478 {
6479   if (! GTK_WIDGET_REALIZED (tree_view))
6480     return;
6481
6482   if (!tree_view->priv->scroll_sync_timer)
6483     {
6484       tree_view->priv->scroll_sync_timer =
6485         gdk_threads_add_idle_full (GTK_TREE_VIEW_PRIORITY_SCROLL_SYNC, (GSourceFunc) scroll_sync_handler, tree_view, NULL);
6486     }
6487 }
6488
6489 static void
6490 gtk_tree_view_set_top_row (GtkTreeView *tree_view,
6491                            GtkTreePath *path,
6492                            gint         offset)
6493 {
6494   gtk_tree_row_reference_free (tree_view->priv->top_row);
6495
6496   if (!path)
6497     {
6498       tree_view->priv->top_row = NULL;
6499       tree_view->priv->top_row_dy = 0;
6500     }
6501   else
6502     {
6503       tree_view->priv->top_row = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
6504       tree_view->priv->top_row_dy = offset;
6505     }
6506 }
6507
6508 /* Always call this iff dy is in the visible range.  If the tree is empty, then
6509  * it's set to be NULL, and top_row_dy is 0;
6510  */
6511 static void
6512 gtk_tree_view_dy_to_top_row (GtkTreeView *tree_view)
6513 {
6514   gint offset;
6515   GtkTreePath *path;
6516   GtkRBTree *tree;
6517   GtkRBNode *node;
6518
6519   if (tree_view->priv->tree == NULL)
6520     {
6521       gtk_tree_view_set_top_row (tree_view, NULL, 0);
6522     }
6523   else
6524     {
6525       offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
6526                                         tree_view->priv->dy,
6527                                         &tree, &node);
6528
6529       if (tree == NULL)
6530         {
6531           tree_view->priv->top_row = NULL;
6532           tree_view->priv->top_row_dy = 0;
6533         }
6534       else
6535         {
6536           path = _gtk_tree_view_find_path (tree_view, tree, node);
6537           gtk_tree_view_set_top_row (tree_view, path, offset);
6538           gtk_tree_path_free (path);
6539         }
6540     }
6541 }
6542
6543 static void
6544 gtk_tree_view_top_row_to_dy (GtkTreeView *tree_view)
6545 {
6546   GtkTreePath *path;
6547   GtkRBTree *tree;
6548   GtkRBNode *node;
6549   int new_dy;
6550
6551   /* Avoid recursive calls */
6552   if (tree_view->priv->in_top_row_to_dy)
6553     return;
6554
6555   if (tree_view->priv->top_row)
6556     path = gtk_tree_row_reference_get_path (tree_view->priv->top_row);
6557   else
6558     path = NULL;
6559
6560   if (!path)
6561     tree = NULL;
6562   else
6563     _gtk_tree_view_find_node (tree_view, path, &tree, &node);
6564
6565   if (path)
6566     gtk_tree_path_free (path);
6567
6568   if (tree == NULL)
6569     {
6570       /* keep dy and set new toprow */
6571       gtk_tree_row_reference_free (tree_view->priv->top_row);
6572       tree_view->priv->top_row = NULL;
6573       tree_view->priv->top_row_dy = 0;
6574       /* DO NOT install the idle handler */
6575       gtk_tree_view_dy_to_top_row (tree_view);
6576       return;
6577     }
6578
6579   if (ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node))
6580       < tree_view->priv->top_row_dy)
6581     {
6582       /* new top row -- do NOT install the idle handler */
6583       gtk_tree_view_dy_to_top_row (tree_view);
6584       return;
6585     }
6586
6587   new_dy = _gtk_rbtree_node_find_offset (tree, node);
6588   new_dy += tree_view->priv->top_row_dy;
6589
6590   if (new_dy + tree_view->priv->vadjustment->page_size > tree_view->priv->height)
6591     new_dy = tree_view->priv->height - tree_view->priv->vadjustment->page_size;
6592
6593   new_dy = MAX (0, new_dy);
6594
6595   tree_view->priv->in_top_row_to_dy = TRUE;
6596   gtk_adjustment_set_value (tree_view->priv->vadjustment, (gdouble)new_dy);
6597   tree_view->priv->in_top_row_to_dy = FALSE;
6598 }
6599
6600
6601 void
6602 _gtk_tree_view_install_mark_rows_col_dirty (GtkTreeView *tree_view)
6603 {
6604   tree_view->priv->mark_rows_col_dirty = TRUE;
6605
6606   install_presize_handler (tree_view);
6607 }
6608
6609 /*
6610  * This function works synchronously (due to the while (validate_rows...)
6611  * loop).
6612  *
6613  * There was a check for column_type != GTK_TREE_VIEW_COLUMN_AUTOSIZE
6614  * here. You now need to check that yourself.
6615  */
6616 void
6617 _gtk_tree_view_column_autosize (GtkTreeView *tree_view,
6618                                 GtkTreeViewColumn *column)
6619 {
6620   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
6621   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (column));
6622
6623   _gtk_tree_view_column_cell_set_dirty (column, FALSE);
6624
6625   do_presize_handler (tree_view);
6626   while (validate_rows (tree_view));
6627
6628   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6629 }
6630
6631 /* Drag-and-drop */
6632
6633 static void
6634 set_source_row (GdkDragContext *context,
6635                 GtkTreeModel   *model,
6636                 GtkTreePath    *source_row)
6637 {
6638   g_object_set_data_full (G_OBJECT (context),
6639                           I_("gtk-tree-view-source-row"),
6640                           source_row ? gtk_tree_row_reference_new (model, source_row) : NULL,
6641                           (GDestroyNotify) (source_row ? gtk_tree_row_reference_free : NULL));
6642 }
6643
6644 static GtkTreePath*
6645 get_source_row (GdkDragContext *context)
6646 {
6647   GtkTreeRowReference *ref =
6648     g_object_get_data (G_OBJECT (context), "gtk-tree-view-source-row");
6649
6650   if (ref)
6651     return gtk_tree_row_reference_get_path (ref);
6652   else
6653     return NULL;
6654 }
6655
6656 typedef struct
6657 {
6658   GtkTreeRowReference *dest_row;
6659   guint                path_down_mode   : 1;
6660   guint                empty_view_drop  : 1;
6661   guint                drop_append_mode : 1;
6662 }
6663 DestRow;
6664
6665 static void
6666 dest_row_free (gpointer data)
6667 {
6668   DestRow *dr = (DestRow *)data;
6669
6670   gtk_tree_row_reference_free (dr->dest_row);
6671   g_slice_free (DestRow, dr);
6672 }
6673
6674 static void
6675 set_dest_row (GdkDragContext *context,
6676               GtkTreeModel   *model,
6677               GtkTreePath    *dest_row,
6678               gboolean        path_down_mode,
6679               gboolean        empty_view_drop,
6680               gboolean        drop_append_mode)
6681 {
6682   DestRow *dr;
6683
6684   if (!dest_row)
6685     {
6686       g_object_set_data_full (G_OBJECT (context), I_("gtk-tree-view-dest-row"),
6687                               NULL, NULL);
6688       return;
6689     }
6690
6691   dr = g_slice_new (DestRow);
6692
6693   dr->dest_row = gtk_tree_row_reference_new (model, dest_row);
6694   dr->path_down_mode = path_down_mode != FALSE;
6695   dr->empty_view_drop = empty_view_drop != FALSE;
6696   dr->drop_append_mode = drop_append_mode != FALSE;
6697
6698   g_object_set_data_full (G_OBJECT (context), I_("gtk-tree-view-dest-row"),
6699                           dr, (GDestroyNotify) dest_row_free);
6700 }
6701
6702 static GtkTreePath*
6703 get_dest_row (GdkDragContext *context,
6704               gboolean       *path_down_mode)
6705 {
6706   DestRow *dr =
6707     g_object_get_data (G_OBJECT (context), "gtk-tree-view-dest-row");
6708
6709   if (dr)
6710     {
6711       GtkTreePath *path = NULL;
6712
6713       if (path_down_mode)
6714         *path_down_mode = dr->path_down_mode;
6715
6716       if (dr->dest_row)
6717         path = gtk_tree_row_reference_get_path (dr->dest_row);
6718       else if (dr->empty_view_drop)
6719         path = gtk_tree_path_new_from_indices (0, -1);
6720       else
6721         path = NULL;
6722
6723       if (path && dr->drop_append_mode)
6724         gtk_tree_path_next (path);
6725
6726       return path;
6727     }
6728   else
6729     return NULL;
6730 }
6731
6732 /* Get/set whether drag_motion requested the drag data and
6733  * drag_data_received should thus not actually insert the data,
6734  * since the data doesn't result from a drop.
6735  */
6736 static void
6737 set_status_pending (GdkDragContext *context,
6738                     GdkDragAction   suggested_action)
6739 {
6740   g_object_set_data (G_OBJECT (context),
6741                      I_("gtk-tree-view-status-pending"),
6742                      GINT_TO_POINTER (suggested_action));
6743 }
6744
6745 static GdkDragAction
6746 get_status_pending (GdkDragContext *context)
6747 {
6748   return GPOINTER_TO_INT (g_object_get_data (G_OBJECT (context),
6749                                              "gtk-tree-view-status-pending"));
6750 }
6751
6752 static TreeViewDragInfo*
6753 get_info (GtkTreeView *tree_view)
6754 {
6755   return g_object_get_data (G_OBJECT (tree_view), "gtk-tree-view-drag-info");
6756 }
6757
6758 static void
6759 destroy_info (TreeViewDragInfo *di)
6760 {
6761   g_slice_free (TreeViewDragInfo, di);
6762 }
6763
6764 static TreeViewDragInfo*
6765 ensure_info (GtkTreeView *tree_view)
6766 {
6767   TreeViewDragInfo *di;
6768
6769   di = get_info (tree_view);
6770
6771   if (di == NULL)
6772     {
6773       di = g_slice_new0 (TreeViewDragInfo);
6774
6775       g_object_set_data_full (G_OBJECT (tree_view),
6776                               I_("gtk-tree-view-drag-info"),
6777                               di,
6778                               (GDestroyNotify) destroy_info);
6779     }
6780
6781   return di;
6782 }
6783
6784 static void
6785 remove_info (GtkTreeView *tree_view)
6786 {
6787   g_object_set_data (G_OBJECT (tree_view), I_("gtk-tree-view-drag-info"), NULL);
6788 }
6789
6790 #if 0
6791 static gint
6792 drag_scan_timeout (gpointer data)
6793 {
6794   GtkTreeView *tree_view;
6795   gint x, y;
6796   GdkModifierType state;
6797   GtkTreePath *path = NULL;
6798   GtkTreeViewColumn *column = NULL;
6799   GdkRectangle visible_rect;
6800
6801   GDK_THREADS_ENTER ();
6802
6803   tree_view = GTK_TREE_VIEW (data);
6804
6805   gdk_window_get_pointer (tree_view->priv->bin_window,
6806                           &x, &y, &state);
6807
6808   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
6809
6810   /* See if we are near the edge. */
6811   if ((x - visible_rect.x) < SCROLL_EDGE_SIZE ||
6812       (visible_rect.x + visible_rect.width - x) < SCROLL_EDGE_SIZE ||
6813       (y - visible_rect.y) < SCROLL_EDGE_SIZE ||
6814       (visible_rect.y + visible_rect.height - y) < SCROLL_EDGE_SIZE)
6815     {
6816       gtk_tree_view_get_path_at_pos (tree_view,
6817                                      tree_view->priv->bin_window,
6818                                      x, y,
6819                                      &path,
6820                                      &column,
6821                                      NULL,
6822                                      NULL);
6823
6824       if (path != NULL)
6825         {
6826           gtk_tree_view_scroll_to_cell (tree_view,
6827                                         path,
6828                                         column,
6829                                         TRUE,
6830                                         0.5, 0.5);
6831
6832           gtk_tree_path_free (path);
6833         }
6834     }
6835
6836   GDK_THREADS_LEAVE ();
6837
6838   return TRUE;
6839 }
6840 #endif /* 0 */
6841
6842 static void
6843 add_scroll_timeout (GtkTreeView *tree_view)
6844 {
6845   if (tree_view->priv->scroll_timeout == 0)
6846     {
6847       tree_view->priv->scroll_timeout =
6848         gdk_threads_add_timeout (150, scroll_row_timeout, tree_view);
6849     }
6850 }
6851
6852 static void
6853 remove_scroll_timeout (GtkTreeView *tree_view)
6854 {
6855   if (tree_view->priv->scroll_timeout != 0)
6856     {
6857       g_source_remove (tree_view->priv->scroll_timeout);
6858       tree_view->priv->scroll_timeout = 0;
6859     }
6860 }
6861
6862 static gboolean
6863 check_model_dnd (GtkTreeModel *model,
6864                  GType         required_iface,
6865                  const gchar  *signal)
6866 {
6867   if (model == NULL || !G_TYPE_CHECK_INSTANCE_TYPE ((model), required_iface))
6868     {
6869       g_warning ("You must override the default '%s' handler "
6870                  "on GtkTreeView when using models that don't support "
6871                  "the %s interface and enabling drag-and-drop. The simplest way to do this "
6872                  "is to connect to '%s' and call "
6873                  "g_signal_stop_emission_by_name() in your signal handler to prevent "
6874                  "the default handler from running. Look at the source code "
6875                  "for the default handler in gtktreeview.c to get an idea what "
6876                  "your handler should do. (gtktreeview.c is in the GTK source "
6877                  "code.) If you're using GTK from a language other than C, "
6878                  "there may be a more natural way to override default handlers, e.g. via derivation.",
6879                  signal, g_type_name (required_iface), signal);
6880       return FALSE;
6881     }
6882   else
6883     return TRUE;
6884 }
6885
6886 static void
6887 remove_open_timeout (GtkTreeView *tree_view)
6888 {
6889   if (tree_view->priv->open_dest_timeout != 0)
6890     {
6891       g_source_remove (tree_view->priv->open_dest_timeout);
6892       tree_view->priv->open_dest_timeout = 0;
6893     }
6894 }
6895
6896
6897 static gint
6898 open_row_timeout (gpointer data)
6899 {
6900   GtkTreeView *tree_view = data;
6901   GtkTreePath *dest_path = NULL;
6902   GtkTreeViewDropPosition pos;
6903   gboolean result = FALSE;
6904
6905   gtk_tree_view_get_drag_dest_row (tree_view,
6906                                    &dest_path,
6907                                    &pos);
6908
6909   if (dest_path &&
6910       (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
6911        pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
6912     {
6913       gtk_tree_view_expand_row (tree_view, dest_path, FALSE);
6914       tree_view->priv->open_dest_timeout = 0;
6915
6916       gtk_tree_path_free (dest_path);
6917     }
6918   else
6919     {
6920       if (dest_path)
6921         gtk_tree_path_free (dest_path);
6922
6923       result = TRUE;
6924     }
6925
6926   return result;
6927 }
6928
6929 static gboolean
6930 scroll_row_timeout (gpointer data)
6931 {
6932   GtkTreeView *tree_view = data;
6933
6934   gtk_tree_view_vertical_autoscroll (tree_view);
6935
6936   if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
6937     gtk_tree_view_update_rubber_band (tree_view);
6938
6939   return TRUE;
6940 }
6941
6942 /* Returns TRUE if event should not be propagated to parent widgets */
6943 static gboolean
6944 set_destination_row (GtkTreeView    *tree_view,
6945                      GdkDragContext *context,
6946                      /* coordinates relative to the widget */
6947                      gint            x,
6948                      gint            y,
6949                      GdkDragAction  *suggested_action,
6950                      GdkAtom        *target)
6951 {
6952   GtkTreePath *path = NULL;
6953   GtkTreeViewDropPosition pos;
6954   GtkTreeViewDropPosition old_pos;
6955   TreeViewDragInfo *di;
6956   GtkWidget *widget;
6957   GtkTreePath *old_dest_path = NULL;
6958   gboolean can_drop = FALSE;
6959
6960   *suggested_action = 0;
6961   *target = GDK_NONE;
6962
6963   widget = GTK_WIDGET (tree_view);
6964
6965   di = get_info (tree_view);
6966
6967   if (di == NULL || y - TREE_VIEW_HEADER_HEIGHT (tree_view) < 0)
6968     {
6969       /* someone unset us as a drag dest, note that if
6970        * we return FALSE drag_leave isn't called
6971        */
6972
6973       gtk_tree_view_set_drag_dest_row (tree_view,
6974                                        NULL,
6975                                        GTK_TREE_VIEW_DROP_BEFORE);
6976
6977       remove_scroll_timeout (GTK_TREE_VIEW (widget));
6978       remove_open_timeout (GTK_TREE_VIEW (widget));
6979
6980       return FALSE; /* no longer a drop site */
6981     }
6982
6983   *target = gtk_drag_dest_find_target (widget, context,
6984                                        gtk_drag_dest_get_target_list (widget));
6985   if (*target == GDK_NONE)
6986     {
6987       return FALSE;
6988     }
6989
6990   if (!gtk_tree_view_get_dest_row_at_pos (tree_view,
6991                                           x, y,
6992                                           &path,
6993                                           &pos))
6994     {
6995       gint n_children;
6996       GtkTreeModel *model;
6997
6998       remove_open_timeout (tree_view);
6999
7000       /* the row got dropped on empty space, let's setup a special case
7001        */
7002
7003       if (path)
7004         gtk_tree_path_free (path);
7005
7006       model = gtk_tree_view_get_model (tree_view);
7007
7008       n_children = gtk_tree_model_iter_n_children (model, NULL);
7009       if (n_children)
7010         {
7011           pos = GTK_TREE_VIEW_DROP_AFTER;
7012           path = gtk_tree_path_new_from_indices (n_children - 1, -1);
7013         }
7014       else
7015         {
7016           pos = GTK_TREE_VIEW_DROP_BEFORE;
7017           path = gtk_tree_path_new_from_indices (0, -1);
7018         }
7019
7020       can_drop = TRUE;
7021
7022       goto out;
7023     }
7024
7025   g_assert (path);
7026
7027   /* If we left the current row's "open" zone, unset the timeout for
7028    * opening the row
7029    */
7030   gtk_tree_view_get_drag_dest_row (tree_view,
7031                                    &old_dest_path,
7032                                    &old_pos);
7033
7034   if (old_dest_path &&
7035       (gtk_tree_path_compare (path, old_dest_path) != 0 ||
7036        !(pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
7037          pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE)))
7038     remove_open_timeout (tree_view);
7039
7040   if (old_dest_path)
7041     gtk_tree_path_free (old_dest_path);
7042
7043   if (TRUE /* FIXME if the location droppable predicate */)
7044     {
7045       can_drop = TRUE;
7046     }
7047
7048 out:
7049   if (can_drop)
7050     {
7051       GtkWidget *source_widget;
7052
7053       *suggested_action = context->suggested_action;
7054       source_widget = gtk_drag_get_source_widget (context);
7055
7056       if (source_widget == widget)
7057         {
7058           /* Default to MOVE, unless the user has
7059            * pressed ctrl or shift to affect available actions
7060            */
7061           if ((context->actions & GDK_ACTION_MOVE) != 0)
7062             *suggested_action = GDK_ACTION_MOVE;
7063         }
7064
7065       gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7066                                        path, pos);
7067     }
7068   else
7069     {
7070       /* can't drop here */
7071       remove_open_timeout (tree_view);
7072
7073       gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7074                                        NULL,
7075                                        GTK_TREE_VIEW_DROP_BEFORE);
7076     }
7077
7078   if (path)
7079     gtk_tree_path_free (path);
7080
7081   return TRUE;
7082 }
7083
7084 static GtkTreePath*
7085 get_logical_dest_row (GtkTreeView *tree_view,
7086                       gboolean    *path_down_mode,
7087                       gboolean    *drop_append_mode)
7088 {
7089   /* adjust path to point to the row the drop goes in front of */
7090   GtkTreePath *path = NULL;
7091   GtkTreeViewDropPosition pos;
7092
7093   g_return_val_if_fail (path_down_mode != NULL, NULL);
7094   g_return_val_if_fail (drop_append_mode != NULL, NULL);
7095
7096   *path_down_mode = FALSE;
7097   *drop_append_mode = 0;
7098
7099   gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
7100
7101   if (path == NULL)
7102     return NULL;
7103
7104   if (pos == GTK_TREE_VIEW_DROP_BEFORE)
7105     ; /* do nothing */
7106   else if (pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE ||
7107            pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER)
7108     *path_down_mode = TRUE;
7109   else
7110     {
7111       GtkTreeIter iter;
7112       GtkTreeModel *model = gtk_tree_view_get_model (tree_view);
7113
7114       g_assert (pos == GTK_TREE_VIEW_DROP_AFTER);
7115
7116       if (!gtk_tree_model_get_iter (model, &iter, path) ||
7117           !gtk_tree_model_iter_next (model, &iter))
7118         *drop_append_mode = 1;
7119       else
7120         {
7121           *drop_append_mode = 0;
7122           gtk_tree_path_next (path);
7123         }
7124     }
7125
7126   return path;
7127 }
7128
7129 static gboolean
7130 gtk_tree_view_maybe_begin_dragging_row (GtkTreeView      *tree_view,
7131                                         GdkEventMotion   *event)
7132 {
7133   GtkWidget *widget = GTK_WIDGET (tree_view);
7134   GdkDragContext *context;
7135   TreeViewDragInfo *di;
7136   GtkTreePath *path = NULL;
7137   gint button;
7138   gint cell_x, cell_y;
7139   GtkTreeModel *model;
7140   gboolean retval = FALSE;
7141
7142   di = get_info (tree_view);
7143
7144   if (di == NULL || !di->source_set)
7145     goto out;
7146
7147   if (tree_view->priv->pressed_button < 0)
7148     goto out;
7149
7150   if (!gtk_drag_check_threshold (widget,
7151                                  tree_view->priv->press_start_x,
7152                                  tree_view->priv->press_start_y,
7153                                  event->x, event->y))
7154     goto out;
7155
7156   model = gtk_tree_view_get_model (tree_view);
7157
7158   if (model == NULL)
7159     goto out;
7160
7161   button = tree_view->priv->pressed_button;
7162   tree_view->priv->pressed_button = -1;
7163
7164   gtk_tree_view_get_path_at_pos (tree_view,
7165                                  tree_view->priv->press_start_x,
7166                                  tree_view->priv->press_start_y,
7167                                  &path,
7168                                  NULL,
7169                                  &cell_x,
7170                                  &cell_y);
7171
7172   if (path == NULL)
7173     goto out;
7174
7175   if (!GTK_IS_TREE_DRAG_SOURCE (model) ||
7176       !gtk_tree_drag_source_row_draggable (GTK_TREE_DRAG_SOURCE (model),
7177                                            path))
7178     goto out;
7179
7180   if (!(GDK_BUTTON1_MASK << (button - 1) & di->start_button_mask))
7181     goto out;
7182
7183   /* Now we can begin the drag */
7184
7185   retval = TRUE;
7186
7187   context = gtk_drag_begin (widget,
7188                             gtk_drag_source_get_target_list (widget),
7189                             di->source_actions,
7190                             button,
7191                             (GdkEvent*)event);
7192
7193   set_source_row (context, model, path);
7194
7195  out:
7196   if (path)
7197     gtk_tree_path_free (path);
7198
7199   return retval;
7200 }
7201
7202
7203 static void
7204 gtk_tree_view_drag_begin (GtkWidget      *widget,
7205                           GdkDragContext *context)
7206 {
7207   GtkTreeView *tree_view;
7208   GtkTreePath *path = NULL;
7209   gint cell_x, cell_y;
7210   GdkPixmap *row_pix;
7211   TreeViewDragInfo *di;
7212
7213   tree_view = GTK_TREE_VIEW (widget);
7214
7215   /* if the user uses a custom DND source impl, we don't set the icon here */
7216   di = get_info (tree_view);
7217
7218   if (di == NULL || !di->source_set)
7219     return;
7220
7221   gtk_tree_view_get_path_at_pos (tree_view,
7222                                  tree_view->priv->press_start_x,
7223                                  tree_view->priv->press_start_y,
7224                                  &path,
7225                                  NULL,
7226                                  &cell_x,
7227                                  &cell_y);
7228
7229   g_return_if_fail (path != NULL);
7230
7231   row_pix = gtk_tree_view_create_row_drag_icon (tree_view,
7232                                                 path);
7233
7234   gtk_drag_set_icon_pixmap (context,
7235                             gdk_drawable_get_colormap (row_pix),
7236                             row_pix,
7237                             NULL,
7238                             /* the + 1 is for the black border in the icon */
7239                             tree_view->priv->press_start_x + 1,
7240                             cell_y + 1);
7241
7242   g_object_unref (row_pix);
7243   gtk_tree_path_free (path);
7244 }
7245
7246 static void
7247 gtk_tree_view_drag_end (GtkWidget      *widget,
7248                         GdkDragContext *context)
7249 {
7250   /* do nothing */
7251 }
7252
7253 /* Default signal implementations for the drag signals */
7254 static void
7255 gtk_tree_view_drag_data_get (GtkWidget        *widget,
7256                              GdkDragContext   *context,
7257                              GtkSelectionData *selection_data,
7258                              guint             info,
7259                              guint             time)
7260 {
7261   GtkTreeView *tree_view;
7262   GtkTreeModel *model;
7263   TreeViewDragInfo *di;
7264   GtkTreePath *source_row;
7265
7266   tree_view = GTK_TREE_VIEW (widget);
7267
7268   model = gtk_tree_view_get_model (tree_view);
7269
7270   if (model == NULL)
7271     return;
7272
7273   di = get_info (GTK_TREE_VIEW (widget));
7274
7275   if (di == NULL)
7276     return;
7277
7278   source_row = get_source_row (context);
7279
7280   if (source_row == NULL)
7281     return;
7282
7283   /* We can implement the GTK_TREE_MODEL_ROW target generically for
7284    * any model; for DragSource models there are some other targets
7285    * we also support.
7286    */
7287
7288   if (GTK_IS_TREE_DRAG_SOURCE (model) &&
7289       gtk_tree_drag_source_drag_data_get (GTK_TREE_DRAG_SOURCE (model),
7290                                           source_row,
7291                                           selection_data))
7292     goto done;
7293
7294   /* If drag_data_get does nothing, try providing row data. */
7295   if (selection_data->target == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
7296     {
7297       gtk_tree_set_row_drag_data (selection_data,
7298                                   model,
7299                                   source_row);
7300     }
7301
7302  done:
7303   gtk_tree_path_free (source_row);
7304 }
7305
7306
7307 static void
7308 gtk_tree_view_drag_data_delete (GtkWidget      *widget,
7309                                 GdkDragContext *context)
7310 {
7311   TreeViewDragInfo *di;
7312   GtkTreeModel *model;
7313   GtkTreeView *tree_view;
7314   GtkTreePath *source_row;
7315
7316   tree_view = GTK_TREE_VIEW (widget);
7317   model = gtk_tree_view_get_model (tree_view);
7318
7319   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_SOURCE, "drag_data_delete"))
7320     return;
7321
7322   di = get_info (tree_view);
7323
7324   if (di == NULL)
7325     return;
7326
7327   source_row = get_source_row (context);
7328
7329   if (source_row == NULL)
7330     return;
7331
7332   gtk_tree_drag_source_drag_data_delete (GTK_TREE_DRAG_SOURCE (model),
7333                                          source_row);
7334
7335   gtk_tree_path_free (source_row);
7336
7337   set_source_row (context, NULL, NULL);
7338 }
7339
7340 static void
7341 gtk_tree_view_drag_leave (GtkWidget      *widget,
7342                           GdkDragContext *context,
7343                           guint             time)
7344 {
7345   /* unset any highlight row */
7346   gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7347                                    NULL,
7348                                    GTK_TREE_VIEW_DROP_BEFORE);
7349
7350   remove_scroll_timeout (GTK_TREE_VIEW (widget));
7351   remove_open_timeout (GTK_TREE_VIEW (widget));
7352 }
7353
7354
7355 static gboolean
7356 gtk_tree_view_drag_motion (GtkWidget        *widget,
7357                            GdkDragContext   *context,
7358                            /* coordinates relative to the widget */
7359                            gint              x,
7360                            gint              y,
7361                            guint             time)
7362 {
7363   gboolean empty;
7364   GtkTreePath *path = NULL;
7365   GtkTreeViewDropPosition pos;
7366   GtkTreeView *tree_view;
7367   GdkDragAction suggested_action = 0;
7368   GdkAtom target;
7369
7370   tree_view = GTK_TREE_VIEW (widget);
7371
7372   if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
7373     return FALSE;
7374
7375   gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
7376
7377   /* we only know this *after* set_desination_row */
7378   empty = tree_view->priv->empty_view_drop;
7379
7380   if (path == NULL && !empty)
7381     {
7382       /* Can't drop here. */
7383       gdk_drag_status (context, 0, time);
7384     }
7385   else
7386     {
7387       if (tree_view->priv->open_dest_timeout == 0 &&
7388           (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
7389            pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
7390         {
7391           tree_view->priv->open_dest_timeout =
7392             gdk_threads_add_timeout (AUTO_EXPAND_TIMEOUT, open_row_timeout, tree_view);
7393         }
7394       else
7395         {
7396           add_scroll_timeout (tree_view);
7397         }
7398
7399       if (target == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
7400         {
7401           /* Request data so we can use the source row when
7402            * determining whether to accept the drop
7403            */
7404           set_status_pending (context, suggested_action);
7405           gtk_drag_get_data (widget, context, target, time);
7406         }
7407       else
7408         {
7409           set_status_pending (context, 0);
7410           gdk_drag_status (context, suggested_action, time);
7411         }
7412     }
7413
7414   if (path)
7415     gtk_tree_path_free (path);
7416
7417   return TRUE;
7418 }
7419
7420
7421 static gboolean
7422 gtk_tree_view_drag_drop (GtkWidget        *widget,
7423                          GdkDragContext   *context,
7424                          /* coordinates relative to the widget */
7425                          gint              x,
7426                          gint              y,
7427                          guint             time)
7428 {
7429   GtkTreeView *tree_view;
7430   GtkTreePath *path;
7431   GdkDragAction suggested_action = 0;
7432   GdkAtom target = GDK_NONE;
7433   TreeViewDragInfo *di;
7434   GtkTreeModel *model;
7435   gboolean path_down_mode;
7436   gboolean drop_append_mode;
7437
7438   tree_view = GTK_TREE_VIEW (widget);
7439
7440   model = gtk_tree_view_get_model (tree_view);
7441
7442   remove_scroll_timeout (GTK_TREE_VIEW (widget));
7443   remove_open_timeout (GTK_TREE_VIEW (widget));
7444
7445   di = get_info (tree_view);
7446
7447   if (di == NULL)
7448     return FALSE;
7449
7450   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_drop"))
7451     return FALSE;
7452
7453   if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
7454     return FALSE;
7455
7456   path = get_logical_dest_row (tree_view, &path_down_mode, &drop_append_mode);
7457
7458   if (target != GDK_NONE && path != NULL)
7459     {
7460       /* in case a motion had requested drag data, change things so we
7461        * treat drag data receives as a drop.
7462        */
7463       set_status_pending (context, 0);
7464       set_dest_row (context, model, path,
7465                     path_down_mode, tree_view->priv->empty_view_drop,
7466                     drop_append_mode);
7467     }
7468
7469   if (path)
7470     gtk_tree_path_free (path);
7471
7472   /* Unset this thing */
7473   gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7474                                    NULL,
7475                                    GTK_TREE_VIEW_DROP_BEFORE);
7476
7477   if (target != GDK_NONE)
7478     {
7479       gtk_drag_get_data (widget, context, target, time);
7480       return TRUE;
7481     }
7482   else
7483     return FALSE;
7484 }
7485
7486 static void
7487 gtk_tree_view_drag_data_received (GtkWidget        *widget,
7488                                   GdkDragContext   *context,
7489                                   /* coordinates relative to the widget */
7490                                   gint              x,
7491                                   gint              y,
7492                                   GtkSelectionData *selection_data,
7493                                   guint             info,
7494                                   guint             time)
7495 {
7496   GtkTreePath *path;
7497   TreeViewDragInfo *di;
7498   gboolean accepted = FALSE;
7499   GtkTreeModel *model;
7500   GtkTreeView *tree_view;
7501   GtkTreePath *dest_row;
7502   GdkDragAction suggested_action;
7503   gboolean path_down_mode;
7504   gboolean drop_append_mode;
7505
7506   tree_view = GTK_TREE_VIEW (widget);
7507
7508   model = gtk_tree_view_get_model (tree_view);
7509
7510   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_data_received"))
7511     return;
7512
7513   di = get_info (tree_view);
7514
7515   if (di == NULL)
7516     return;
7517
7518   suggested_action = get_status_pending (context);
7519
7520   if (suggested_action)
7521     {
7522       /* We are getting this data due to a request in drag_motion,
7523        * rather than due to a request in drag_drop, so we are just
7524        * supposed to call drag_status, not actually paste in the
7525        * data.
7526        */
7527       path = get_logical_dest_row (tree_view, &path_down_mode,
7528                                    &drop_append_mode);
7529
7530       if (path == NULL)
7531         suggested_action = 0;
7532       else if (path_down_mode)
7533         gtk_tree_path_down (path);
7534
7535       if (suggested_action)
7536         {
7537           if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
7538                                                      path,
7539                                                      selection_data))
7540             {
7541               if (path_down_mode)
7542                 {
7543                   path_down_mode = FALSE;
7544                   gtk_tree_path_up (path);
7545
7546                   if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
7547                                                              path,
7548                                                              selection_data))
7549                     suggested_action = 0;
7550                 }
7551               else
7552                 suggested_action = 0;
7553             }
7554         }
7555
7556       gdk_drag_status (context, suggested_action, time);
7557
7558       if (path)
7559         gtk_tree_path_free (path);
7560
7561       /* If you can't drop, remove user drop indicator until the next motion */
7562       if (suggested_action == 0)
7563         gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7564                                          NULL,
7565                                          GTK_TREE_VIEW_DROP_BEFORE);
7566
7567       return;
7568     }
7569
7570   dest_row = get_dest_row (context, &path_down_mode);
7571
7572   if (dest_row == NULL)
7573     return;
7574
7575   if (selection_data->length >= 0)
7576     {
7577       if (path_down_mode)
7578         {
7579           gtk_tree_path_down (dest_row);
7580           if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
7581                                                      dest_row, selection_data))
7582             gtk_tree_path_up (dest_row);
7583         }
7584     }
7585
7586   if (selection_data->length >= 0)
7587     {
7588       if (gtk_tree_drag_dest_drag_data_received (GTK_TREE_DRAG_DEST (model),
7589                                                  dest_row,
7590                                                  selection_data))
7591         accepted = TRUE;
7592     }
7593
7594   gtk_drag_finish (context,
7595                    accepted,
7596                    (context->action == GDK_ACTION_MOVE),
7597                    time);
7598
7599   if (gtk_tree_path_get_depth (dest_row) == 1
7600       && gtk_tree_path_get_indices (dest_row)[0] == 0)
7601     {
7602       /* special special case drag to "0", scroll to first item */
7603       if (!tree_view->priv->scroll_to_path)
7604         gtk_tree_view_scroll_to_cell (tree_view, dest_row, NULL, FALSE, 0.0, 0.0);
7605     }
7606
7607   gtk_tree_path_free (dest_row);
7608
7609   /* drop dest_row */
7610   set_dest_row (context, NULL, NULL, FALSE, FALSE, FALSE);
7611 }
7612
7613
7614
7615 /* GtkContainer Methods
7616  */
7617
7618
7619 static void
7620 gtk_tree_view_remove (GtkContainer *container,
7621                       GtkWidget    *widget)
7622 {
7623   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
7624   GtkTreeViewChild *child = NULL;
7625   GList *tmp_list;
7626
7627   tmp_list = tree_view->priv->children;
7628   while (tmp_list)
7629     {
7630       child = tmp_list->data;
7631       if (child->widget == widget)
7632         {
7633           gtk_widget_unparent (widget);
7634
7635           tree_view->priv->children = g_list_remove_link (tree_view->priv->children, tmp_list);
7636           g_list_free_1 (tmp_list);
7637           g_slice_free (GtkTreeViewChild, child);
7638           return;
7639         }
7640
7641       tmp_list = tmp_list->next;
7642     }
7643
7644   tmp_list = tree_view->priv->columns;
7645
7646   while (tmp_list)
7647     {
7648       GtkTreeViewColumn *column;
7649       column = tmp_list->data;
7650       if (column->button == widget)
7651         {
7652           gtk_widget_unparent (widget);
7653           return;
7654         }
7655       tmp_list = tmp_list->next;
7656     }
7657 }
7658
7659 static void
7660 gtk_tree_view_forall (GtkContainer *container,
7661                       gboolean      include_internals,
7662                       GtkCallback   callback,
7663                       gpointer      callback_data)
7664 {
7665   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
7666   GtkTreeViewChild *child = NULL;
7667   GtkTreeViewColumn *column;
7668   GList *tmp_list;
7669
7670   tmp_list = tree_view->priv->children;
7671   while (tmp_list)
7672     {
7673       child = tmp_list->data;
7674       tmp_list = tmp_list->next;
7675
7676       (* callback) (child->widget, callback_data);
7677     }
7678   if (include_internals == FALSE)
7679     return;
7680
7681   for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
7682     {
7683       column = tmp_list->data;
7684
7685       if (column->button)
7686         (* callback) (column->button, callback_data);
7687     }
7688 }
7689
7690 /* Returns TRUE if the treeview contains no "special" (editable or activatable)
7691  * cells. If so we draw one big row-spanning focus rectangle.
7692  */
7693 static gboolean
7694 gtk_tree_view_has_special_cell (GtkTreeView *tree_view)
7695 {
7696   GList *list;
7697
7698   for (list = tree_view->priv->columns; list; list = list->next)
7699     {
7700       if (!((GtkTreeViewColumn *)list->data)->visible)
7701         continue;
7702       if (_gtk_tree_view_column_count_special_cells (list->data))
7703         return TRUE;
7704     }
7705
7706   return FALSE;
7707 }
7708
7709 static void
7710 column_sizing_notify (GObject    *object,
7711                       GParamSpec *pspec,
7712                       gpointer    data)
7713 {
7714   GtkTreeViewColumn *c = GTK_TREE_VIEW_COLUMN (object);
7715
7716   if (gtk_tree_view_column_get_sizing (c) != GTK_TREE_VIEW_COLUMN_FIXED)
7717     /* disable fixed height mode */
7718     g_object_set (data, "fixed-height-mode", FALSE, NULL);
7719 }
7720
7721 /**
7722  * gtk_tree_view_set_fixed_height_mode:
7723  * @tree_view: a #GtkTreeView 
7724  * @enable: %TRUE to enable fixed height mode
7725  * 
7726  * Enables or disables the fixed height mode of @tree_view. 
7727  * Fixed height mode speeds up #GtkTreeView by assuming that all 
7728  * rows have the same height. 
7729  * Only enable this option if all rows are the same height and all
7730  * columns are of type %GTK_TREE_VIEW_COLUMN_FIXED.
7731  *
7732  * Since: 2.6 
7733  **/
7734 void
7735 gtk_tree_view_set_fixed_height_mode (GtkTreeView *tree_view,
7736                                      gboolean     enable)
7737 {
7738   GList *l;
7739   
7740   enable = enable != FALSE;
7741
7742   if (enable == tree_view->priv->fixed_height_mode)
7743     return;
7744
7745   if (!enable)
7746     {
7747       tree_view->priv->fixed_height_mode = 0;
7748       tree_view->priv->fixed_height = -1;
7749
7750       /* force a revalidation */
7751       install_presize_handler (tree_view);
7752     }
7753   else 
7754     {
7755       /* make sure all columns are of type FIXED */
7756       for (l = tree_view->priv->columns; l; l = l->next)
7757         {
7758           GtkTreeViewColumn *c = l->data;
7759           
7760           g_return_if_fail (gtk_tree_view_column_get_sizing (c) == GTK_TREE_VIEW_COLUMN_FIXED);
7761         }
7762       
7763       /* yes, we really have to do this is in a separate loop */
7764       for (l = tree_view->priv->columns; l; l = l->next)
7765         g_signal_connect (l->data, "notify::sizing",
7766                           G_CALLBACK (column_sizing_notify), tree_view);
7767       
7768       tree_view->priv->fixed_height_mode = 1;
7769       tree_view->priv->fixed_height = -1;
7770       
7771       if (tree_view->priv->tree)
7772         initialize_fixed_height_mode (tree_view);
7773     }
7774
7775   g_object_notify (G_OBJECT (tree_view), "fixed-height-mode");
7776 }
7777
7778 /**
7779  * gtk_tree_view_get_fixed_height_mode:
7780  * @tree_view: a #GtkTreeView
7781  * 
7782  * Returns whether fixed height mode is turned on for @tree_view.
7783  * 
7784  * Return value: %TRUE if @tree_view is in fixed height mode
7785  * 
7786  * Since: 2.6
7787  **/
7788 gboolean
7789 gtk_tree_view_get_fixed_height_mode (GtkTreeView *tree_view)
7790 {
7791   return tree_view->priv->fixed_height_mode;
7792 }
7793
7794 /* Returns TRUE if the focus is within the headers, after the focus operation is
7795  * done
7796  */
7797 static gboolean
7798 gtk_tree_view_header_focus (GtkTreeView      *tree_view,
7799                             GtkDirectionType  dir,
7800                             gboolean          clamp_column_visible)
7801 {
7802   GtkWidget *focus_child;
7803
7804   GList *last_column, *first_column;
7805   GList *tmp_list;
7806   gboolean rtl;
7807
7808   if (! GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
7809     return FALSE;
7810
7811   focus_child = GTK_CONTAINER (tree_view)->focus_child;
7812
7813   first_column = tree_view->priv->columns;
7814   while (first_column)
7815     {
7816       if (GTK_WIDGET_CAN_FOCUS (GTK_TREE_VIEW_COLUMN (first_column->data)->button) &&
7817           GTK_TREE_VIEW_COLUMN (first_column->data)->visible &&
7818           (GTK_TREE_VIEW_COLUMN (first_column->data)->clickable ||
7819            GTK_TREE_VIEW_COLUMN (first_column->data)->reorderable))
7820         break;
7821       first_column = first_column->next;
7822     }
7823
7824   /* No headers are visible, or are focusable.  We can't focus in or out.
7825    */
7826   if (first_column == NULL)
7827     return FALSE;
7828
7829   last_column = g_list_last (tree_view->priv->columns);
7830   while (last_column)
7831     {
7832       if (GTK_WIDGET_CAN_FOCUS (GTK_TREE_VIEW_COLUMN (last_column->data)->button) &&
7833           GTK_TREE_VIEW_COLUMN (last_column->data)->visible &&
7834           (GTK_TREE_VIEW_COLUMN (last_column->data)->clickable ||
7835            GTK_TREE_VIEW_COLUMN (last_column->data)->reorderable))
7836         break;
7837       last_column = last_column->prev;
7838     }
7839
7840
7841   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
7842
7843   switch (dir)
7844     {
7845     case GTK_DIR_TAB_BACKWARD:
7846     case GTK_DIR_TAB_FORWARD:
7847     case GTK_DIR_UP:
7848     case GTK_DIR_DOWN:
7849       if (focus_child == NULL)
7850         {
7851           if (tree_view->priv->focus_column != NULL && GTK_WIDGET_CAN_FOCUS (tree_view->priv->focus_column->button))
7852             focus_child = tree_view->priv->focus_column->button;
7853           else
7854             focus_child = GTK_TREE_VIEW_COLUMN (first_column->data)->button;
7855           gtk_widget_grab_focus (focus_child);
7856           break;
7857         }
7858       return FALSE;
7859
7860     case GTK_DIR_LEFT:
7861     case GTK_DIR_RIGHT:
7862       if (focus_child == NULL)
7863         {
7864           if (tree_view->priv->focus_column != NULL)
7865             focus_child = tree_view->priv->focus_column->button;
7866           else if (dir == GTK_DIR_LEFT)
7867             focus_child = GTK_TREE_VIEW_COLUMN (last_column->data)->button;
7868           else
7869             focus_child = GTK_TREE_VIEW_COLUMN (first_column->data)->button;
7870           gtk_widget_grab_focus (focus_child);
7871           break;
7872         }
7873
7874       if (gtk_widget_child_focus (focus_child, dir))
7875         {
7876           /* The focus moves inside the button. */
7877           /* This is probably a great example of bad UI */
7878           break;
7879         }
7880
7881       /* We need to move the focus among the row of buttons. */
7882       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
7883         if (GTK_TREE_VIEW_COLUMN (tmp_list->data)->button == focus_child)
7884           break;
7885
7886       if ((tmp_list == first_column && dir == (rtl ? GTK_DIR_RIGHT : GTK_DIR_LEFT))
7887           || (tmp_list == last_column && dir == (rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT)))
7888         {
7889           gtk_widget_error_bell (GTK_WIDGET (tree_view));
7890           break;
7891         }
7892
7893       while (tmp_list)
7894         {
7895           GtkTreeViewColumn *column;
7896
7897           if (dir == (rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT))
7898             tmp_list = tmp_list->next;
7899           else
7900             tmp_list = tmp_list->prev;
7901
7902           if (tmp_list == NULL)
7903             {
7904               g_warning ("Internal button not found");
7905               break;
7906             }
7907           column = tmp_list->data;
7908           if (column->button &&
7909               column->visible &&
7910               GTK_WIDGET_CAN_FOCUS (column->button))
7911             {
7912               focus_child = column->button;
7913               gtk_widget_grab_focus (column->button);
7914               break;
7915             }
7916         }
7917       break;
7918     default:
7919       g_assert_not_reached ();
7920       break;
7921     }
7922
7923   /* if focus child is non-null, we assume it's been set to the current focus child
7924    */
7925   if (focus_child)
7926     {
7927       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
7928         if (GTK_TREE_VIEW_COLUMN (tmp_list->data)->button == focus_child)
7929           {
7930             tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
7931             break;
7932           }
7933
7934       if (clamp_column_visible)
7935         {
7936           gtk_tree_view_clamp_column_visible (tree_view,
7937                                               tree_view->priv->focus_column,
7938                                               FALSE);
7939         }
7940     }
7941
7942   return (focus_child != NULL);
7943 }
7944
7945 /* This function returns in 'path' the first focusable path, if the given path
7946  * is already focusable, it's the returned one.
7947  */
7948 static gboolean
7949 search_first_focusable_path (GtkTreeView  *tree_view,
7950                              GtkTreePath **path,
7951                              gboolean      search_forward,
7952                              GtkRBTree   **new_tree,
7953                              GtkRBNode   **new_node)
7954 {
7955   GtkRBTree *tree = NULL;
7956   GtkRBNode *node = NULL;
7957
7958   if (!path || !*path)
7959     return FALSE;
7960
7961   _gtk_tree_view_find_node (tree_view, *path, &tree, &node);
7962
7963   if (!tree || !node)
7964     return FALSE;
7965
7966   while (node && row_is_separator (tree_view, NULL, *path))
7967     {
7968       if (search_forward)
7969         _gtk_rbtree_next_full (tree, node, &tree, &node);
7970       else
7971         _gtk_rbtree_prev_full (tree, node, &tree, &node);
7972
7973       if (*path)
7974         gtk_tree_path_free (*path);
7975
7976       if (node)
7977         *path = _gtk_tree_view_find_path (tree_view, tree, node);
7978       else
7979         *path = NULL;
7980     }
7981
7982   if (new_tree)
7983     *new_tree = tree;
7984
7985   if (new_node)
7986     *new_node = node;
7987
7988   return (*path != NULL);
7989 }
7990
7991 static gint
7992 gtk_tree_view_focus (GtkWidget        *widget,
7993                      GtkDirectionType  direction)
7994 {
7995   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
7996   GtkContainer *container = GTK_CONTAINER (widget);
7997   GtkWidget *focus_child;
7998
7999   if (!GTK_WIDGET_IS_SENSITIVE (container) || !GTK_WIDGET_CAN_FOCUS (widget))
8000     return FALSE;
8001
8002   focus_child = container->focus_child;
8003
8004   gtk_tree_view_stop_editing (GTK_TREE_VIEW (widget), FALSE);
8005   /* Case 1.  Headers currently have focus. */
8006   if (focus_child)
8007     {
8008       switch (direction)
8009         {
8010         case GTK_DIR_LEFT:
8011         case GTK_DIR_RIGHT:
8012           gtk_tree_view_header_focus (tree_view, direction, TRUE);
8013           return TRUE;
8014         case GTK_DIR_TAB_BACKWARD:
8015         case GTK_DIR_UP:
8016           return FALSE;
8017         case GTK_DIR_TAB_FORWARD:
8018         case GTK_DIR_DOWN:
8019           gtk_widget_grab_focus (widget);
8020           return TRUE;
8021         default:
8022           g_assert_not_reached ();
8023           return FALSE;
8024         }
8025     }
8026
8027   /* Case 2. We don't have focus at all. */
8028   if (!GTK_WIDGET_HAS_FOCUS (container))
8029     {
8030       if (!gtk_tree_view_header_focus (tree_view, direction, FALSE))
8031         gtk_widget_grab_focus (widget);
8032       return TRUE;
8033     }
8034
8035   /* Case 3. We have focus already. */
8036   if (direction == GTK_DIR_TAB_BACKWARD)
8037     return (gtk_tree_view_header_focus (tree_view, direction, FALSE));
8038   else if (direction == GTK_DIR_TAB_FORWARD)
8039     return FALSE;
8040
8041   /* Other directions caught by the keybindings */
8042   gtk_widget_grab_focus (widget);
8043   return TRUE;
8044 }
8045
8046 static void
8047 gtk_tree_view_grab_focus (GtkWidget *widget)
8048 {
8049   GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->grab_focus (widget);
8050
8051   gtk_tree_view_focus_to_cursor (GTK_TREE_VIEW (widget));
8052 }
8053
8054 static void
8055 gtk_tree_view_style_set (GtkWidget *widget,
8056                          GtkStyle *previous_style)
8057 {
8058   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
8059   GList *list;
8060   GtkTreeViewColumn *column;
8061
8062   if (GTK_WIDGET_REALIZED (widget))
8063     {
8064       gdk_window_set_back_pixmap (widget->window, NULL, FALSE);
8065       gdk_window_set_background (tree_view->priv->bin_window, &widget->style->base[widget->state]);
8066       gtk_style_set_background (widget->style, tree_view->priv->header_window, GTK_STATE_NORMAL);
8067
8068       gtk_tree_view_set_grid_lines (tree_view, tree_view->priv->grid_lines);
8069       gtk_tree_view_set_enable_tree_lines (tree_view, tree_view->priv->tree_lines_enabled);
8070     }
8071
8072   gtk_widget_style_get (widget,
8073                         "expander-size", &tree_view->priv->expander_size,
8074                         NULL);
8075   tree_view->priv->expander_size += EXPANDER_EXTRA_PADDING;
8076
8077   for (list = tree_view->priv->columns; list; list = list->next)
8078     {
8079       column = list->data;
8080       _gtk_tree_view_column_cell_set_dirty (column, TRUE);
8081     }
8082
8083   tree_view->priv->fixed_height = -1;
8084   _gtk_rbtree_mark_invalid (tree_view->priv->tree);
8085
8086   gtk_widget_queue_resize (widget);
8087 }
8088
8089
8090 static void
8091 gtk_tree_view_set_focus_child (GtkContainer *container,
8092                                GtkWidget    *child)
8093 {
8094   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
8095   GList *list;
8096
8097   for (list = tree_view->priv->columns; list; list = list->next)
8098     {
8099       if (GTK_TREE_VIEW_COLUMN (list->data)->button == child)
8100         {
8101           tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (list->data);
8102           break;
8103         }
8104     }
8105
8106   GTK_CONTAINER_CLASS (gtk_tree_view_parent_class)->set_focus_child (container, child);
8107 }
8108
8109 static void
8110 gtk_tree_view_set_adjustments (GtkTreeView   *tree_view,
8111                                GtkAdjustment *hadj,
8112                                GtkAdjustment *vadj)
8113 {
8114   gboolean need_adjust = FALSE;
8115
8116   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8117
8118   if (hadj)
8119     g_return_if_fail (GTK_IS_ADJUSTMENT (hadj));
8120   else
8121     hadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
8122   if (vadj)
8123     g_return_if_fail (GTK_IS_ADJUSTMENT (vadj));
8124   else
8125     vadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
8126
8127   if (tree_view->priv->hadjustment && (tree_view->priv->hadjustment != hadj))
8128     {
8129       g_signal_handlers_disconnect_by_func (tree_view->priv->hadjustment,
8130                                             gtk_tree_view_adjustment_changed,
8131                                             tree_view);
8132       g_object_unref (tree_view->priv->hadjustment);
8133     }
8134
8135   if (tree_view->priv->vadjustment && (tree_view->priv->vadjustment != vadj))
8136     {
8137       g_signal_handlers_disconnect_by_func (tree_view->priv->vadjustment,
8138                                             gtk_tree_view_adjustment_changed,
8139                                             tree_view);
8140       g_object_unref (tree_view->priv->vadjustment);
8141     }
8142
8143   if (tree_view->priv->hadjustment != hadj)
8144     {
8145       tree_view->priv->hadjustment = hadj;
8146       g_object_ref_sink (tree_view->priv->hadjustment);
8147
8148       g_signal_connect (tree_view->priv->hadjustment, "value-changed",
8149                         G_CALLBACK (gtk_tree_view_adjustment_changed),
8150                         tree_view);
8151       need_adjust = TRUE;
8152     }
8153
8154   if (tree_view->priv->vadjustment != vadj)
8155     {
8156       tree_view->priv->vadjustment = vadj;
8157       g_object_ref_sink (tree_view->priv->vadjustment);
8158
8159       g_signal_connect (tree_view->priv->vadjustment, "value-changed",
8160                         G_CALLBACK (gtk_tree_view_adjustment_changed),
8161                         tree_view);
8162       need_adjust = TRUE;
8163     }
8164
8165   if (need_adjust)
8166     gtk_tree_view_adjustment_changed (NULL, tree_view);
8167 }
8168
8169
8170 static gboolean
8171 gtk_tree_view_real_move_cursor (GtkTreeView       *tree_view,
8172                                 GtkMovementStep    step,
8173                                 gint               count)
8174 {
8175   GdkModifierType state;
8176
8177   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
8178   g_return_val_if_fail (step == GTK_MOVEMENT_LOGICAL_POSITIONS ||
8179                         step == GTK_MOVEMENT_VISUAL_POSITIONS ||
8180                         step == GTK_MOVEMENT_DISPLAY_LINES ||
8181                         step == GTK_MOVEMENT_PAGES ||
8182                         step == GTK_MOVEMENT_BUFFER_ENDS, FALSE);
8183
8184   if (tree_view->priv->tree == NULL)
8185     return FALSE;
8186   if (!GTK_WIDGET_HAS_FOCUS (GTK_WIDGET (tree_view)))
8187     return FALSE;
8188
8189   gtk_tree_view_stop_editing (tree_view, FALSE);
8190   GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
8191   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
8192
8193   if (gtk_get_current_event_state (&state))
8194     {
8195       if ((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
8196         tree_view->priv->ctrl_pressed = TRUE;
8197       if ((state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
8198         tree_view->priv->shift_pressed = TRUE;
8199     }
8200   /* else we assume not pressed */
8201
8202   switch (step)
8203     {
8204       /* currently we make no distinction.  When we go bi-di, we need to */
8205     case GTK_MOVEMENT_LOGICAL_POSITIONS:
8206     case GTK_MOVEMENT_VISUAL_POSITIONS:
8207       gtk_tree_view_move_cursor_left_right (tree_view, count);
8208       break;
8209     case GTK_MOVEMENT_DISPLAY_LINES:
8210       gtk_tree_view_move_cursor_up_down (tree_view, count);
8211       break;
8212     case GTK_MOVEMENT_PAGES:
8213       gtk_tree_view_move_cursor_page_up_down (tree_view, count);
8214       break;
8215     case GTK_MOVEMENT_BUFFER_ENDS:
8216       gtk_tree_view_move_cursor_start_end (tree_view, count);
8217       break;
8218     default:
8219       g_assert_not_reached ();
8220     }
8221
8222   tree_view->priv->ctrl_pressed = FALSE;
8223   tree_view->priv->shift_pressed = FALSE;
8224
8225   return TRUE;
8226 }
8227
8228 static void
8229 gtk_tree_view_put (GtkTreeView *tree_view,
8230                    GtkWidget   *child_widget,
8231                    /* in bin_window coordinates */
8232                    gint         x,
8233                    gint         y,
8234                    gint         width,
8235                    gint         height)
8236 {
8237   GtkTreeViewChild *child;
8238   
8239   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8240   g_return_if_fail (GTK_IS_WIDGET (child_widget));
8241
8242   child = g_slice_new (GtkTreeViewChild);
8243
8244   child->widget = child_widget;
8245   child->x = x;
8246   child->y = y;
8247   child->width = width;
8248   child->height = height;
8249
8250   tree_view->priv->children = g_list_append (tree_view->priv->children, child);
8251
8252   if (GTK_WIDGET_REALIZED (tree_view))
8253     gtk_widget_set_parent_window (child->widget, tree_view->priv->bin_window);
8254   
8255   gtk_widget_set_parent (child_widget, GTK_WIDGET (tree_view));
8256 }
8257
8258 void
8259 _gtk_tree_view_child_move_resize (GtkTreeView *tree_view,
8260                                   GtkWidget   *widget,
8261                                   /* in tree coordinates */
8262                                   gint         x,
8263                                   gint         y,
8264                                   gint         width,
8265                                   gint         height)
8266 {
8267   GtkTreeViewChild *child = NULL;
8268   GList *list;
8269   GdkRectangle allocation;
8270
8271   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8272   g_return_if_fail (GTK_IS_WIDGET (widget));
8273
8274   for (list = tree_view->priv->children; list; list = list->next)
8275     {
8276       if (((GtkTreeViewChild *)list->data)->widget == widget)
8277         {
8278           child = list->data;
8279           break;
8280         }
8281     }
8282   if (child == NULL)
8283     return;
8284
8285   allocation.x = child->x = x;
8286   allocation.y = child->y = y;
8287   allocation.width = child->width = width;
8288   allocation.height = child->height = height;
8289
8290   if (GTK_WIDGET_REALIZED (widget))
8291     gtk_widget_size_allocate (widget, &allocation);
8292 }
8293
8294
8295 /* TreeModel Callbacks
8296  */
8297
8298 static void
8299 gtk_tree_view_row_changed (GtkTreeModel *model,
8300                            GtkTreePath  *path,
8301                            GtkTreeIter  *iter,
8302                            gpointer      data)
8303 {
8304   GtkTreeView *tree_view = (GtkTreeView *)data;
8305   GtkRBTree *tree;
8306   GtkRBNode *node;
8307   gboolean free_path = FALSE;
8308   GList *list;
8309   GtkTreePath *cursor_path;
8310
8311   g_return_if_fail (path != NULL || iter != NULL);
8312
8313   if (tree_view->priv->cursor != NULL)
8314     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
8315   else
8316     cursor_path = NULL;
8317
8318   if (tree_view->priv->edited_column &&
8319       (cursor_path == NULL || gtk_tree_path_compare (cursor_path, path) == 0))
8320     gtk_tree_view_stop_editing (tree_view, TRUE);
8321
8322   if (cursor_path != NULL)
8323     gtk_tree_path_free (cursor_path);
8324
8325   if (path == NULL)
8326     {
8327       path = gtk_tree_model_get_path (model, iter);
8328       free_path = TRUE;
8329     }
8330   else if (iter == NULL)
8331     gtk_tree_model_get_iter (model, iter, path);
8332
8333   if (_gtk_tree_view_find_node (tree_view,
8334                                 path,
8335                                 &tree,
8336                                 &node))
8337     /* We aren't actually showing the node */
8338     goto done;
8339
8340   if (tree == NULL)
8341     goto done;
8342
8343   if (tree_view->priv->fixed_height_mode
8344       && tree_view->priv->fixed_height >= 0)
8345     {
8346       _gtk_rbtree_node_set_height (tree, node, tree_view->priv->fixed_height);
8347       if (GTK_WIDGET_REALIZED (tree_view))
8348         gtk_tree_view_node_queue_redraw (tree_view, tree, node);
8349     }
8350   else
8351     {
8352       _gtk_rbtree_node_mark_invalid (tree, node);
8353       for (list = tree_view->priv->columns; list; list = list->next)
8354         {
8355           GtkTreeViewColumn *column;
8356
8357           column = list->data;
8358           if (! column->visible)
8359             continue;
8360
8361           if (column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
8362             {
8363               _gtk_tree_view_column_cell_set_dirty (column, TRUE);
8364             }
8365         }
8366     }
8367
8368  done:
8369   if (GTK_WIDGET_REALIZED (tree_view) && !tree_view->priv->fixed_height_mode)
8370     install_presize_handler (tree_view);
8371   if (free_path)
8372     gtk_tree_path_free (path);
8373 }
8374
8375 static void
8376 gtk_tree_view_row_inserted (GtkTreeModel *model,
8377                             GtkTreePath  *path,
8378                             GtkTreeIter  *iter,
8379                             gpointer      data)
8380 {
8381   GtkTreeView *tree_view = (GtkTreeView *) data;
8382   gint *indices;
8383   GtkRBTree *tmptree, *tree;
8384   GtkRBNode *tmpnode = NULL;
8385   gint depth;
8386   gint i = 0;
8387   gint height;
8388   gboolean free_path = FALSE;
8389   gboolean node_visible = TRUE;
8390
8391   g_return_if_fail (path != NULL || iter != NULL);
8392
8393   if (tree_view->priv->fixed_height_mode
8394       && tree_view->priv->fixed_height >= 0)
8395     height = tree_view->priv->fixed_height;
8396   else
8397     height = 0;
8398
8399   if (path == NULL)
8400     {
8401       path = gtk_tree_model_get_path (model, iter);
8402       free_path = TRUE;
8403     }
8404   else if (iter == NULL)
8405     gtk_tree_model_get_iter (model, iter, path);
8406
8407   if (tree_view->priv->tree == NULL)
8408     tree_view->priv->tree = _gtk_rbtree_new ();
8409
8410   tmptree = tree = tree_view->priv->tree;
8411
8412   /* Update all row-references */
8413   gtk_tree_row_reference_inserted (G_OBJECT (data), path);
8414   depth = gtk_tree_path_get_depth (path);
8415   indices = gtk_tree_path_get_indices (path);
8416
8417   /* First, find the parent tree */
8418   while (i < depth - 1)
8419     {
8420       if (tmptree == NULL)
8421         {
8422           /* We aren't showing the node */
8423           node_visible = FALSE;
8424           goto done;
8425         }
8426
8427       tmpnode = _gtk_rbtree_find_count (tmptree, indices[i] + 1);
8428       if (tmpnode == NULL)
8429         {
8430           g_warning ("A node was inserted with a parent that's not in the tree.\n" \
8431                      "This possibly means that a GtkTreeModel inserted a child node\n" \
8432                      "before the parent was inserted.");
8433           goto done;
8434         }
8435       else if (!GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_IS_PARENT))
8436         {
8437           /* FIXME enforce correct behavior on model, probably */
8438           /* In theory, the model should have emitted has_child_toggled here.  We
8439            * try to catch it anyway, just to be safe, in case the model hasn't.
8440            */
8441           GtkTreePath *tmppath = _gtk_tree_view_find_path (tree_view,
8442                                                            tree,
8443                                                            tmpnode);
8444           gtk_tree_view_row_has_child_toggled (model, tmppath, NULL, data);
8445           gtk_tree_path_free (tmppath);
8446           goto done;
8447         }
8448
8449       tmptree = tmpnode->children;
8450       tree = tmptree;
8451       i++;
8452     }
8453
8454   if (tree == NULL)
8455     {
8456       node_visible = FALSE;
8457       goto done;
8458     }
8459
8460   /* ref the node */
8461   gtk_tree_model_ref_node (tree_view->priv->model, iter);
8462   if (indices[depth - 1] == 0)
8463     {
8464       tmpnode = _gtk_rbtree_find_count (tree, 1);
8465       tmpnode = _gtk_rbtree_insert_before (tree, tmpnode, height, FALSE);
8466     }
8467   else
8468     {
8469       tmpnode = _gtk_rbtree_find_count (tree, indices[depth - 1]);
8470       tmpnode = _gtk_rbtree_insert_after (tree, tmpnode, height, FALSE);
8471     }
8472
8473  done:
8474   if (height > 0)
8475     {
8476       if (tree)
8477         _gtk_rbtree_node_mark_valid (tree, tmpnode);
8478
8479       if (node_visible && node_is_visible (tree_view, tree, tmpnode))
8480         gtk_widget_queue_resize (GTK_WIDGET (tree_view));
8481       else
8482         gtk_widget_queue_resize_no_redraw (GTK_WIDGET (tree_view));
8483     }
8484   else
8485     install_presize_handler (tree_view);
8486   if (free_path)
8487     gtk_tree_path_free (path);
8488 }
8489
8490 static void
8491 gtk_tree_view_row_has_child_toggled (GtkTreeModel *model,
8492                                      GtkTreePath  *path,
8493                                      GtkTreeIter  *iter,
8494                                      gpointer      data)
8495 {
8496   GtkTreeView *tree_view = (GtkTreeView *)data;
8497   GtkTreeIter real_iter;
8498   gboolean has_child;
8499   GtkRBTree *tree;
8500   GtkRBNode *node;
8501   gboolean free_path = FALSE;
8502
8503   g_return_if_fail (path != NULL || iter != NULL);
8504
8505   if (iter)
8506     real_iter = *iter;
8507
8508   if (path == NULL)
8509     {
8510       path = gtk_tree_model_get_path (model, iter);
8511       free_path = TRUE;
8512     }
8513   else if (iter == NULL)
8514     gtk_tree_model_get_iter (model, &real_iter, path);
8515
8516   if (_gtk_tree_view_find_node (tree_view,
8517                                 path,
8518                                 &tree,
8519                                 &node))
8520     /* We aren't actually showing the node */
8521     goto done;
8522
8523   if (tree == NULL)
8524     goto done;
8525
8526   has_child = gtk_tree_model_iter_has_child (model, &real_iter);
8527   /* Sanity check.
8528    */
8529   if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT) == has_child)
8530     goto done;
8531
8532   if (has_child)
8533     GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_PARENT);
8534   else
8535     GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_PARENT);
8536
8537   if (has_child && GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IS_LIST))
8538     {
8539       GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IS_LIST);
8540       if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS))
8541         {
8542           GList *list;
8543
8544           for (list = tree_view->priv->columns; list; list = list->next)
8545             if (GTK_TREE_VIEW_COLUMN (list->data)->visible)
8546               {
8547                 GTK_TREE_VIEW_COLUMN (list->data)->dirty = TRUE;
8548                 _gtk_tree_view_column_cell_set_dirty (GTK_TREE_VIEW_COLUMN (list->data), TRUE);
8549                 break;
8550               }
8551         }
8552       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
8553     }
8554   else
8555     {
8556       _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
8557     }
8558
8559  done:
8560   if (free_path)
8561     gtk_tree_path_free (path);
8562 }
8563
8564 static void
8565 count_children_helper (GtkRBTree *tree,
8566                        GtkRBNode *node,
8567                        gpointer   data)
8568 {
8569   if (node->children)
8570     _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, data);
8571   (*((gint *)data))++;
8572 }
8573
8574 static void
8575 check_selection_helper (GtkRBTree *tree,
8576                         GtkRBNode *node,
8577                         gpointer   data)
8578 {
8579   gint *value = (gint *)data;
8580
8581   *value = GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED);
8582
8583   if (node->children && !*value)
8584     _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, check_selection_helper, data);
8585 }
8586
8587 static void
8588 gtk_tree_view_row_deleted (GtkTreeModel *model,
8589                            GtkTreePath  *path,
8590                            gpointer      data)
8591 {
8592   GtkTreeView *tree_view = (GtkTreeView *)data;
8593   GtkRBTree *tree;
8594   GtkRBNode *node;
8595   GList *list;
8596   gint selection_changed = FALSE;
8597
8598   g_return_if_fail (path != NULL);
8599
8600   gtk_tree_row_reference_deleted (G_OBJECT (data), path);
8601
8602   if (_gtk_tree_view_find_node (tree_view, path, &tree, &node))
8603     return;
8604
8605   if (tree == NULL)
8606     return;
8607
8608   /* check if the selection has been changed */
8609   _gtk_rbtree_traverse (tree, node, G_POST_ORDER,
8610                         check_selection_helper, &selection_changed);
8611
8612   for (list = tree_view->priv->columns; list; list = list->next)
8613     if (((GtkTreeViewColumn *)list->data)->visible &&
8614         ((GtkTreeViewColumn *)list->data)->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
8615       _gtk_tree_view_column_cell_set_dirty ((GtkTreeViewColumn *)list->data, TRUE);
8616
8617   /* Ensure we don't have a dangling pointer to a dead node */
8618   ensure_unprelighted (tree_view);
8619
8620   /* Cancel editting if we've started */
8621   gtk_tree_view_stop_editing (tree_view, TRUE);
8622
8623   /* If we have a node expanded/collapsed timeout, remove it */
8624   remove_expand_collapse_timeout (tree_view);
8625
8626   if (tree_view->priv->destroy_count_func)
8627     {
8628       gint child_count = 0;
8629       if (node->children)
8630         _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, &child_count);
8631       tree_view->priv->destroy_count_func (tree_view, path, child_count, tree_view->priv->destroy_count_data);
8632     }
8633
8634   if (tree->root->count == 1)
8635     {
8636       if (tree_view->priv->tree == tree)
8637         tree_view->priv->tree = NULL;
8638
8639       _gtk_rbtree_remove (tree);
8640     }
8641   else
8642     {
8643       _gtk_rbtree_remove_node (tree, node);
8644     }
8645
8646   if (! gtk_tree_row_reference_valid (tree_view->priv->top_row))
8647     {
8648       gtk_tree_row_reference_free (tree_view->priv->top_row);
8649       tree_view->priv->top_row = NULL;
8650     }
8651
8652   install_scroll_sync_handler (tree_view);
8653
8654   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
8655
8656   if (selection_changed)
8657     g_signal_emit_by_name (tree_view->priv->selection, "changed");
8658 }
8659
8660 static void
8661 gtk_tree_view_rows_reordered (GtkTreeModel *model,
8662                               GtkTreePath  *parent,
8663                               GtkTreeIter  *iter,
8664                               gint         *new_order,
8665                               gpointer      data)
8666 {
8667   GtkTreeView *tree_view = GTK_TREE_VIEW (data);
8668   GtkRBTree *tree;
8669   GtkRBNode *node;
8670   gint len;
8671
8672   len = gtk_tree_model_iter_n_children (model, iter);
8673
8674   if (len < 2)
8675     return;
8676
8677   gtk_tree_row_reference_reordered (G_OBJECT (data),
8678                                     parent,
8679                                     iter,
8680                                     new_order);
8681
8682   if (_gtk_tree_view_find_node (tree_view,
8683                                 parent,
8684                                 &tree,
8685                                 &node))
8686     return;
8687
8688   /* We need to special case the parent path */
8689   if (tree == NULL)
8690     tree = tree_view->priv->tree;
8691   else
8692     tree = node->children;
8693
8694   if (tree == NULL)
8695     return;
8696
8697   if (tree_view->priv->edited_column)
8698     gtk_tree_view_stop_editing (tree_view, TRUE);
8699
8700   /* we need to be unprelighted */
8701   ensure_unprelighted (tree_view);
8702
8703   /* clear the timeout */
8704   cancel_arrow_animation (tree_view);
8705   
8706   _gtk_rbtree_reorder (tree, new_order, len);
8707
8708   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
8709
8710   gtk_tree_view_dy_to_top_row (tree_view);
8711 }
8712
8713
8714 /* Internal tree functions
8715  */
8716
8717
8718 static void
8719 gtk_tree_view_get_background_xrange (GtkTreeView       *tree_view,
8720                                      GtkRBTree         *tree,
8721                                      GtkTreeViewColumn *column,
8722                                      gint              *x1,
8723                                      gint              *x2)
8724 {
8725   GtkTreeViewColumn *tmp_column = NULL;
8726   gint total_width;
8727   GList *list;
8728   gboolean rtl;
8729
8730   if (x1)
8731     *x1 = 0;
8732
8733   if (x2)
8734     *x2 = 0;
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 (tmp_column == column)
8746         break;
8747
8748       if (tmp_column->visible)
8749         total_width += tmp_column->width;
8750     }
8751
8752   if (tmp_column != column)
8753     {
8754       g_warning (G_STRLOC": passed-in column isn't in the tree");
8755       return;
8756     }
8757
8758   if (x1)
8759     *x1 = total_width;
8760
8761   if (x2)
8762     {
8763       if (column->visible)
8764         *x2 = total_width + column->width;
8765       else
8766         *x2 = total_width; /* width of 0 */
8767     }
8768 }
8769 static void
8770 gtk_tree_view_get_arrow_xrange (GtkTreeView *tree_view,
8771                                 GtkRBTree   *tree,
8772                                 gint        *x1,
8773                                 gint        *x2)
8774 {
8775   gint x_offset = 0;
8776   GList *list;
8777   GtkTreeViewColumn *tmp_column = NULL;
8778   gint total_width;
8779   gboolean indent_expanders;
8780   gboolean rtl;
8781
8782   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
8783
8784   total_width = 0;
8785   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
8786        list;
8787        list = (rtl ? list->prev : list->next))
8788     {
8789       tmp_column = list->data;
8790
8791       if (gtk_tree_view_is_expander_column (tree_view, tmp_column))
8792         {
8793           if (rtl)
8794             x_offset = total_width + tmp_column->width - tree_view->priv->expander_size;
8795           else
8796             x_offset = total_width;
8797           break;
8798         }
8799
8800       if (tmp_column->visible)
8801         total_width += tmp_column->width;
8802     }
8803
8804   gtk_widget_style_get (GTK_WIDGET (tree_view),
8805                         "indent-expanders", &indent_expanders,
8806                         NULL);
8807
8808   if (indent_expanders)
8809     {
8810       if (rtl)
8811         x_offset -= tree_view->priv->expander_size * _gtk_rbtree_get_depth (tree);
8812       else
8813         x_offset += tree_view->priv->expander_size * _gtk_rbtree_get_depth (tree);
8814     }
8815
8816   *x1 = x_offset;
8817   
8818   if (tmp_column && tmp_column->visible)
8819     /* +1 because x2 isn't included in the range. */
8820     *x2 = *x1 + tree_view->priv->expander_size + 1;
8821   else
8822     *x2 = *x1;
8823 }
8824
8825 static void
8826 gtk_tree_view_build_tree (GtkTreeView *tree_view,
8827                           GtkRBTree   *tree,
8828                           GtkTreeIter *iter,
8829                           gint         depth,
8830                           gboolean     recurse)
8831 {
8832   GtkRBNode *temp = NULL;
8833   GtkTreePath *path = NULL;
8834   gboolean is_list = GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IS_LIST);
8835
8836   do
8837     {
8838       gtk_tree_model_ref_node (tree_view->priv->model, iter);
8839       temp = _gtk_rbtree_insert_after (tree, temp, 0, FALSE);
8840
8841       if (tree_view->priv->fixed_height > 0)
8842         {
8843           if (GTK_RBNODE_FLAG_SET (temp, GTK_RBNODE_INVALID))
8844             {
8845               _gtk_rbtree_node_set_height (tree, temp, tree_view->priv->fixed_height);
8846               _gtk_rbtree_node_mark_valid (tree, temp);
8847             }
8848         }
8849
8850       if (is_list)
8851         continue;
8852
8853       if (recurse)
8854         {
8855           GtkTreeIter child;
8856
8857           if (!path)
8858             path = gtk_tree_model_get_path (tree_view->priv->model, iter);
8859           else
8860             gtk_tree_path_next (path);
8861
8862           if (gtk_tree_model_iter_children (tree_view->priv->model, &child, iter))
8863             {
8864               gboolean expand;
8865
8866               g_signal_emit (tree_view, tree_view_signals[TEST_EXPAND_ROW], 0, iter, path, &expand);
8867
8868               if (gtk_tree_model_iter_has_child (tree_view->priv->model, iter)
8869                   && !expand)
8870                 {
8871                   temp->children = _gtk_rbtree_new ();
8872                   temp->children->parent_tree = tree;
8873                   temp->children->parent_node = temp;
8874                   gtk_tree_view_build_tree (tree_view, temp->children, &child, depth + 1, recurse);
8875                 }
8876             }
8877         }
8878
8879       if (gtk_tree_model_iter_has_child (tree_view->priv->model, iter))
8880         {
8881           if ((temp->flags&GTK_RBNODE_IS_PARENT) != GTK_RBNODE_IS_PARENT)
8882             temp->flags ^= GTK_RBNODE_IS_PARENT;
8883         }
8884     }
8885   while (gtk_tree_model_iter_next (tree_view->priv->model, iter));
8886
8887   if (path)
8888     gtk_tree_path_free (path);
8889 }
8890
8891 /* Make sure the node is visible vertically */
8892 static void
8893 gtk_tree_view_clamp_node_visible (GtkTreeView *tree_view,
8894                                   GtkRBTree   *tree,
8895                                   GtkRBNode   *node)
8896 {
8897   gint node_dy, height;
8898   GtkTreePath *path = NULL;
8899
8900   if (!GTK_WIDGET_REALIZED (tree_view))
8901     return;
8902
8903   /* just return if the node is visible, avoiding a costly expose */
8904   node_dy = _gtk_rbtree_node_find_offset (tree, node);
8905   height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
8906   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID)
8907       && node_dy >= tree_view->priv->vadjustment->value
8908       && node_dy + height <= (tree_view->priv->vadjustment->value
8909                               + tree_view->priv->vadjustment->page_size))
8910     return;
8911
8912   path = _gtk_tree_view_find_path (tree_view, tree, node);
8913   if (path)
8914     {
8915       /* We process updates because we want to clear old selected items when we scroll.
8916        * if this is removed, we get a "selection streak" at the bottom. */
8917       gdk_window_process_updates (tree_view->priv->bin_window, TRUE);
8918       gtk_tree_view_scroll_to_cell (tree_view, path, NULL, FALSE, 0.0, 0.0);
8919       gtk_tree_path_free (path);
8920     }
8921 }
8922
8923 static void
8924 gtk_tree_view_clamp_column_visible (GtkTreeView       *tree_view,
8925                                     GtkTreeViewColumn *column,
8926                                     gboolean           focus_to_cell)
8927 {
8928   gint x, width;
8929
8930   if (column == NULL)
8931     return;
8932
8933   x = column->button->allocation.x;
8934   width = column->button->allocation.width;
8935
8936   if (width > tree_view->priv->hadjustment->page_size)
8937     {
8938       /* The column is larger than the horizontal page size.  If the
8939        * column has cells which can be focussed individually, then we make
8940        * sure the cell which gets focus is fully visible (if even the
8941        * focus cell is bigger than the page size, we make sure the
8942        * left-hand side of the cell is visible).
8943        *
8944        * If the column does not have those so-called special cells, we
8945        * make sure the left-hand side of the column is visible.
8946        */
8947
8948       if (focus_to_cell && gtk_tree_view_has_special_cell (tree_view))
8949         {
8950           GtkTreePath *cursor_path;
8951           GdkRectangle background_area, cell_area, focus_area;
8952
8953           cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
8954
8955           gtk_tree_view_get_cell_area (tree_view,
8956                                        cursor_path, column, &cell_area);
8957           gtk_tree_view_get_background_area (tree_view,
8958                                              cursor_path, column,
8959                                              &background_area);
8960
8961           gtk_tree_path_free (cursor_path);
8962
8963           _gtk_tree_view_column_get_focus_area (column,
8964                                                 &background_area,
8965                                                 &cell_area,
8966                                                 &focus_area);
8967
8968           x = focus_area.x;
8969           width = focus_area.width;
8970
8971           if (width < tree_view->priv->hadjustment->page_size)
8972             {
8973               if ((tree_view->priv->hadjustment->value + tree_view->priv->hadjustment->page_size) < (x + width))
8974                 gtk_adjustment_set_value (tree_view->priv->hadjustment,
8975                                           x + width - tree_view->priv->hadjustment->page_size);
8976               else if (tree_view->priv->hadjustment->value > x)
8977                 gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
8978             }
8979         }
8980
8981       gtk_adjustment_set_value (tree_view->priv->hadjustment,
8982                                 CLAMP (x,
8983                                        tree_view->priv->hadjustment->lower,
8984                                        tree_view->priv->hadjustment->upper
8985                                        - tree_view->priv->hadjustment->page_size));
8986     }
8987   else
8988     {
8989       if ((tree_view->priv->hadjustment->value + tree_view->priv->hadjustment->page_size) < (x + width))
8990           gtk_adjustment_set_value (tree_view->priv->hadjustment,
8991                                     x + width - tree_view->priv->hadjustment->page_size);
8992       else if (tree_view->priv->hadjustment->value > x)
8993         gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
8994   }
8995 }
8996
8997 /* This function could be more efficient.  I'll optimize it if profiling seems
8998  * to imply that it is important */
8999 GtkTreePath *
9000 _gtk_tree_view_find_path (GtkTreeView *tree_view,
9001                           GtkRBTree   *tree,
9002                           GtkRBNode   *node)
9003 {
9004   GtkTreePath *path;
9005   GtkRBTree *tmp_tree;
9006   GtkRBNode *tmp_node, *last;
9007   gint count;
9008
9009   path = gtk_tree_path_new ();
9010
9011   g_return_val_if_fail (node != NULL, path);
9012   g_return_val_if_fail (node != tree->nil, path);
9013
9014   count = 1 + node->left->count;
9015
9016   last = node;
9017   tmp_node = node->parent;
9018   tmp_tree = tree;
9019   while (tmp_tree)
9020     {
9021       while (tmp_node != tmp_tree->nil)
9022         {
9023           if (tmp_node->right == last)
9024             count += 1 + tmp_node->left->count;
9025           last = tmp_node;
9026           tmp_node = tmp_node->parent;
9027         }
9028       gtk_tree_path_prepend_index (path, count - 1);
9029       last = tmp_tree->parent_node;
9030       tmp_tree = tmp_tree->parent_tree;
9031       if (last)
9032         {
9033           count = 1 + last->left->count;
9034           tmp_node = last->parent;
9035         }
9036     }
9037   return path;
9038 }
9039
9040 /* Returns TRUE if we ran out of tree before finding the path.  If the path is
9041  * invalid (ie. points to a node that's not in the tree), *tree and *node are
9042  * both set to NULL.
9043  */
9044 gboolean
9045 _gtk_tree_view_find_node (GtkTreeView  *tree_view,
9046                           GtkTreePath  *path,
9047                           GtkRBTree   **tree,
9048                           GtkRBNode   **node)
9049 {
9050   GtkRBNode *tmpnode = NULL;
9051   GtkRBTree *tmptree = tree_view->priv->tree;
9052   gint *indices = gtk_tree_path_get_indices (path);
9053   gint depth = gtk_tree_path_get_depth (path);
9054   gint i = 0;
9055
9056   *node = NULL;
9057   *tree = NULL;
9058
9059   if (depth == 0 || tmptree == NULL)
9060     return FALSE;
9061   do
9062     {
9063       tmpnode = _gtk_rbtree_find_count (tmptree, indices[i] + 1);
9064       ++i;
9065       if (tmpnode == NULL)
9066         {
9067           *tree = NULL;
9068           *node = NULL;
9069           return FALSE;
9070         }
9071       if (i >= depth)
9072         {
9073           *tree = tmptree;
9074           *node = tmpnode;
9075           return FALSE;
9076         }
9077       *tree = tmptree;
9078       *node = tmpnode;
9079       tmptree = tmpnode->children;
9080       if (tmptree == NULL)
9081         return TRUE;
9082     }
9083   while (1);
9084 }
9085
9086 static gboolean
9087 gtk_tree_view_is_expander_column (GtkTreeView       *tree_view,
9088                                   GtkTreeViewColumn *column)
9089 {
9090   GList *list;
9091
9092   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IS_LIST))
9093     return FALSE;
9094
9095   if (tree_view->priv->expander_column != NULL)
9096     {
9097       if (tree_view->priv->expander_column == column)
9098         return TRUE;
9099       return FALSE;
9100     }
9101   else
9102     {
9103       for (list = tree_view->priv->columns;
9104            list;
9105            list = list->next)
9106         if (((GtkTreeViewColumn *)list->data)->visible)
9107           break;
9108       if (list && list->data == column)
9109         return TRUE;
9110     }
9111   return FALSE;
9112 }
9113
9114 static void
9115 gtk_tree_view_add_move_binding (GtkBindingSet  *binding_set,
9116                                 guint           keyval,
9117                                 guint           modmask,
9118                                 gboolean        add_shifted_binding,
9119                                 GtkMovementStep step,
9120                                 gint            count)
9121 {
9122   
9123   gtk_binding_entry_add_signal (binding_set, keyval, modmask,
9124                                 "move-cursor", 2,
9125                                 G_TYPE_ENUM, step,
9126                                 G_TYPE_INT, count);
9127
9128   if (add_shifted_binding)
9129     gtk_binding_entry_add_signal (binding_set, keyval, GDK_SHIFT_MASK,
9130                                   "move-cursor", 2,
9131                                   G_TYPE_ENUM, step,
9132                                   G_TYPE_INT, count);
9133
9134   if ((modmask & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
9135    return;
9136
9137   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK | GDK_SHIFT_MASK,
9138                                 "move-cursor", 2,
9139                                 G_TYPE_ENUM, step,
9140                                 G_TYPE_INT, count);
9141
9142   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK,
9143                                 "move-cursor", 2,
9144                                 G_TYPE_ENUM, step,
9145                                 G_TYPE_INT, count);
9146 }
9147
9148 static gint
9149 gtk_tree_view_unref_tree_helper (GtkTreeModel *model,
9150                                  GtkTreeIter  *iter,
9151                                  GtkRBTree    *tree,
9152                                  GtkRBNode    *node)
9153 {
9154   gint retval = FALSE;
9155   do
9156     {
9157       g_return_val_if_fail (node != NULL, FALSE);
9158
9159       if (node->children)
9160         {
9161           GtkTreeIter child;
9162           GtkRBTree *new_tree;
9163           GtkRBNode *new_node;
9164
9165           new_tree = node->children;
9166           new_node = new_tree->root;
9167
9168           while (new_node && new_node->left != new_tree->nil)
9169             new_node = new_node->left;
9170
9171           if (!gtk_tree_model_iter_children (model, &child, iter))
9172             return FALSE;
9173
9174           retval = retval || gtk_tree_view_unref_tree_helper (model, &child, new_tree, new_node);
9175         }
9176
9177       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
9178         retval = TRUE;
9179       gtk_tree_model_unref_node (model, iter);
9180       node = _gtk_rbtree_next (tree, node);
9181     }
9182   while (gtk_tree_model_iter_next (model, iter));
9183
9184   return retval;
9185 }
9186
9187 static gint
9188 gtk_tree_view_unref_and_check_selection_tree (GtkTreeView *tree_view,
9189                                               GtkRBTree   *tree)
9190 {
9191   GtkTreeIter iter;
9192   GtkTreePath *path;
9193   GtkRBNode *node;
9194   gint retval;
9195
9196   if (!tree)
9197     return FALSE;
9198
9199   node = tree->root;
9200   while (node && node->left != tree->nil)
9201     node = node->left;
9202
9203   g_return_val_if_fail (node != NULL, FALSE);
9204   path = _gtk_tree_view_find_path (tree_view, tree, node);
9205   gtk_tree_model_get_iter (GTK_TREE_MODEL (tree_view->priv->model),
9206                            &iter, path);
9207   retval = gtk_tree_view_unref_tree_helper (GTK_TREE_MODEL (tree_view->priv->model), &iter, tree, node);
9208   gtk_tree_path_free (path);
9209
9210   return retval;
9211 }
9212
9213 static void
9214 gtk_tree_view_set_column_drag_info (GtkTreeView       *tree_view,
9215                                     GtkTreeViewColumn *column)
9216 {
9217   GtkTreeViewColumn *left_column;
9218   GtkTreeViewColumn *cur_column = NULL;
9219   GtkTreeViewColumnReorder *reorder;
9220   gboolean rtl;
9221   GList *tmp_list;
9222   gint left;
9223
9224   /* We want to precalculate the motion list such that we know what column slots
9225    * are available.
9226    */
9227   left_column = NULL;
9228   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
9229
9230   /* First, identify all possible drop spots */
9231   if (rtl)
9232     tmp_list = g_list_last (tree_view->priv->columns);
9233   else
9234     tmp_list = g_list_first (tree_view->priv->columns);
9235
9236   while (tmp_list)
9237     {
9238       cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
9239       tmp_list = rtl?g_list_previous (tmp_list):g_list_next (tmp_list);
9240
9241       if (cur_column->visible == FALSE)
9242         continue;
9243
9244       /* If it's not the column moving and func tells us to skip over the column, we continue. */
9245       if (left_column != column && cur_column != column &&
9246           tree_view->priv->column_drop_func &&
9247           ! tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
9248         {
9249           left_column = cur_column;
9250           continue;
9251         }
9252       reorder = g_slice_new0 (GtkTreeViewColumnReorder);
9253       reorder->left_column = left_column;
9254       left_column = reorder->right_column = cur_column;
9255
9256       tree_view->priv->column_drag_info = g_list_append (tree_view->priv->column_drag_info, reorder);
9257     }
9258
9259   /* Add the last one */
9260   if (tree_view->priv->column_drop_func == NULL ||
9261       ((left_column != column) &&
9262        tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data)))
9263     {
9264       reorder = g_slice_new0 (GtkTreeViewColumnReorder);
9265       reorder->left_column = left_column;
9266       reorder->right_column = NULL;
9267       tree_view->priv->column_drag_info = g_list_append (tree_view->priv->column_drag_info, reorder);
9268     }
9269
9270   /* We quickly check to see if it even makes sense to reorder columns. */
9271   /* If there is nothing that can be moved, then we return */
9272
9273   if (tree_view->priv->column_drag_info == NULL)
9274     return;
9275
9276   /* We know there are always 2 slots possbile, as you can always return column. */
9277   /* If that's all there is, return */
9278   if (tree_view->priv->column_drag_info->next == NULL || 
9279       (tree_view->priv->column_drag_info->next->next == NULL &&
9280        ((GtkTreeViewColumnReorder *)tree_view->priv->column_drag_info->data)->right_column == column &&
9281        ((GtkTreeViewColumnReorder *)tree_view->priv->column_drag_info->next->data)->left_column == column))
9282     {
9283       for (tmp_list = tree_view->priv->column_drag_info; tmp_list; tmp_list = tmp_list->next)
9284         g_slice_free (GtkTreeViewColumnReorder, tmp_list->data);
9285       g_list_free (tree_view->priv->column_drag_info);
9286       tree_view->priv->column_drag_info = NULL;
9287       return;
9288     }
9289   /* We fill in the ranges for the columns, now that we've isolated them */
9290   left = - TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER (tree_view);
9291
9292   for (tmp_list = tree_view->priv->column_drag_info; tmp_list; tmp_list = tmp_list->next)
9293     {
9294       reorder = (GtkTreeViewColumnReorder *) tmp_list->data;
9295
9296       reorder->left_align = left;
9297       if (tmp_list->next != NULL)
9298         {
9299           g_assert (tmp_list->next->data);
9300           left = reorder->right_align = (reorder->right_column->button->allocation.x +
9301                                          reorder->right_column->button->allocation.width +
9302                                          ((GtkTreeViewColumnReorder *)tmp_list->next->data)->left_column->button->allocation.x)/2;
9303         }
9304       else
9305         {
9306           gint width;
9307
9308           gdk_drawable_get_size (tree_view->priv->header_window, &width, NULL);
9309           reorder->right_align = width + TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER (tree_view);
9310         }
9311     }
9312 }
9313
9314 void
9315 _gtk_tree_view_column_start_drag (GtkTreeView       *tree_view,
9316                                   GtkTreeViewColumn *column)
9317 {
9318   GdkEvent *send_event;
9319   GtkAllocation allocation;
9320   gint x, y, width, height;
9321   GdkScreen *screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
9322   GdkDisplay *display = gdk_screen_get_display (screen);
9323
9324   g_return_if_fail (tree_view->priv->column_drag_info == NULL);
9325   g_return_if_fail (tree_view->priv->cur_reorder == NULL);
9326
9327   gtk_tree_view_set_column_drag_info (tree_view, column);
9328
9329   if (tree_view->priv->column_drag_info == NULL)
9330     return;
9331
9332   if (tree_view->priv->drag_window == NULL)
9333     {
9334       GdkWindowAttr attributes;
9335       guint attributes_mask;
9336
9337       attributes.window_type = GDK_WINDOW_CHILD;
9338       attributes.wclass = GDK_INPUT_OUTPUT;
9339       attributes.x = column->button->allocation.x;
9340       attributes.y = 0;
9341       attributes.width = column->button->allocation.width;
9342       attributes.height = column->button->allocation.height;
9343       attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
9344       attributes.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
9345       attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
9346       attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
9347
9348       tree_view->priv->drag_window = gdk_window_new (tree_view->priv->bin_window,
9349                                                      &attributes,
9350                                                      attributes_mask);
9351       gdk_window_set_user_data (tree_view->priv->drag_window, GTK_WIDGET (tree_view));
9352     }
9353
9354   gdk_display_pointer_ungrab (display, GDK_CURRENT_TIME);
9355   gdk_display_keyboard_ungrab (display, GDK_CURRENT_TIME);
9356
9357   gtk_grab_remove (column->button);
9358
9359   send_event = gdk_event_new (GDK_LEAVE_NOTIFY);
9360   send_event->crossing.send_event = TRUE;
9361   send_event->crossing.window = g_object_ref (GTK_BUTTON (column->button)->event_window);
9362   send_event->crossing.subwindow = NULL;
9363   send_event->crossing.detail = GDK_NOTIFY_ANCESTOR;
9364   send_event->crossing.time = GDK_CURRENT_TIME;
9365
9366   gtk_propagate_event (column->button, send_event);
9367   gdk_event_free (send_event);
9368
9369   send_event = gdk_event_new (GDK_BUTTON_RELEASE);
9370   send_event->button.window = g_object_ref (gdk_screen_get_root_window (screen));
9371   send_event->button.send_event = TRUE;
9372   send_event->button.time = GDK_CURRENT_TIME;
9373   send_event->button.x = -1;
9374   send_event->button.y = -1;
9375   send_event->button.axes = NULL;
9376   send_event->button.state = 0;
9377   send_event->button.button = 1;
9378   send_event->button.device = gdk_display_get_core_pointer (display);
9379   send_event->button.x_root = 0;
9380   send_event->button.y_root = 0;
9381
9382   gtk_propagate_event (column->button, send_event);
9383   gdk_event_free (send_event);
9384
9385   /* Kids, don't try this at home */
9386   g_object_ref (column->button);
9387   gtk_container_remove (GTK_CONTAINER (tree_view), column->button);
9388   gtk_widget_set_parent_window (column->button, tree_view->priv->drag_window);
9389   gtk_widget_set_parent (column->button, GTK_WIDGET (tree_view));
9390   g_object_unref (column->button);
9391
9392   tree_view->priv->drag_column_x = column->button->allocation.x;
9393   allocation = column->button->allocation;
9394   allocation.x = 0;
9395   gtk_widget_size_allocate (column->button, &allocation);
9396   gtk_widget_set_parent_window (column->button, tree_view->priv->drag_window);
9397
9398   tree_view->priv->drag_column = column;
9399   gdk_window_show (tree_view->priv->drag_window);
9400
9401   gdk_window_get_origin (tree_view->priv->header_window, &x, &y);
9402   gdk_drawable_get_size (tree_view->priv->header_window, &width, &height);
9403
9404   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
9405   while (gtk_events_pending ())
9406     gtk_main_iteration ();
9407
9408   GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG);
9409   gdk_pointer_grab (tree_view->priv->drag_window,
9410                     FALSE,
9411                     GDK_POINTER_MOTION_MASK|GDK_BUTTON_RELEASE_MASK,
9412                     NULL, NULL, GDK_CURRENT_TIME);
9413   gdk_keyboard_grab (tree_view->priv->drag_window,
9414                      FALSE,
9415                      GDK_CURRENT_TIME);
9416 }
9417
9418 static void
9419 gtk_tree_view_queue_draw_arrow (GtkTreeView        *tree_view,
9420                                 GtkRBTree          *tree,
9421                                 GtkRBNode          *node,
9422                                 const GdkRectangle *clip_rect)
9423 {
9424   GdkRectangle rect;
9425
9426   if (!GTK_WIDGET_REALIZED (tree_view))
9427     return;
9428
9429   rect.x = 0;
9430   rect.width = MAX (tree_view->priv->expander_size, MAX (tree_view->priv->width, GTK_WIDGET (tree_view)->allocation.width));
9431
9432   rect.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
9433   rect.height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
9434
9435   if (clip_rect)
9436     {
9437       GdkRectangle new_rect;
9438
9439       gdk_rectangle_intersect (clip_rect, &rect, &new_rect);
9440
9441       gdk_window_invalidate_rect (tree_view->priv->bin_window, &new_rect, TRUE);
9442     }
9443   else
9444     {
9445       gdk_window_invalidate_rect (tree_view->priv->bin_window, &rect, TRUE);
9446     }
9447 }
9448
9449 void
9450 _gtk_tree_view_queue_draw_node (GtkTreeView        *tree_view,
9451                                 GtkRBTree          *tree,
9452                                 GtkRBNode          *node,
9453                                 const GdkRectangle *clip_rect)
9454 {
9455   GdkRectangle rect;
9456
9457   if (!GTK_WIDGET_REALIZED (tree_view))
9458     return;
9459
9460   rect.x = 0;
9461   rect.width = MAX (tree_view->priv->width, GTK_WIDGET (tree_view)->allocation.width);
9462
9463   rect.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
9464   rect.height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
9465
9466   if (clip_rect)
9467     {
9468       GdkRectangle new_rect;
9469
9470       gdk_rectangle_intersect (clip_rect, &rect, &new_rect);
9471
9472       gdk_window_invalidate_rect (tree_view->priv->bin_window, &new_rect, TRUE);
9473     }
9474   else
9475     {
9476       gdk_window_invalidate_rect (tree_view->priv->bin_window, &rect, TRUE);
9477     }
9478 }
9479
9480 static void
9481 gtk_tree_view_queue_draw_path (GtkTreeView        *tree_view,
9482                                GtkTreePath        *path,
9483                                const GdkRectangle *clip_rect)
9484 {
9485   GtkRBTree *tree = NULL;
9486   GtkRBNode *node = NULL;
9487
9488   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
9489
9490   if (tree)
9491     _gtk_tree_view_queue_draw_node (tree_view, tree, node, clip_rect);
9492 }
9493
9494 /* x and y are the mouse position
9495  */
9496 static void
9497 gtk_tree_view_draw_arrow (GtkTreeView *tree_view,
9498                           GtkRBTree   *tree,
9499                           GtkRBNode   *node,
9500                           /* in bin_window coordinates */
9501                           gint         x,
9502                           gint         y)
9503 {
9504   GdkRectangle area;
9505   GtkStateType state;
9506   GtkWidget *widget;
9507   gint x_offset = 0;
9508   gint x2;
9509   gint vertical_separator;
9510   gint expander_size;
9511   GtkExpanderStyle expander_style;
9512
9513   gtk_widget_style_get (GTK_WIDGET (tree_view),
9514                         "vertical-separator", &vertical_separator,
9515                         NULL);
9516   expander_size = tree_view->priv->expander_size - EXPANDER_EXTRA_PADDING;
9517
9518   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
9519     return;
9520
9521   widget = GTK_WIDGET (tree_view);
9522
9523   gtk_tree_view_get_arrow_xrange (tree_view, tree, &x_offset, &x2);
9524
9525   area.x = x_offset;
9526   area.y = CELL_FIRST_PIXEL (tree_view, tree, node, vertical_separator);
9527   area.width = expander_size + 2;
9528   area.height = MAX (CELL_HEIGHT (node, vertical_separator), (expander_size - vertical_separator));
9529
9530   if (GTK_WIDGET_STATE (tree_view) == GTK_STATE_INSENSITIVE)
9531     {
9532       state = GTK_STATE_INSENSITIVE;
9533     }
9534   else if (node == tree_view->priv->button_pressed_node)
9535     {
9536       if (x >= area.x && x <= (area.x + area.width) &&
9537           y >= area.y && y <= (area.y + area.height))
9538         state = GTK_STATE_ACTIVE;
9539       else
9540         state = GTK_STATE_NORMAL;
9541     }
9542   else
9543     {
9544       if (node == tree_view->priv->prelight_node &&
9545           GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT))
9546         state = GTK_STATE_PRELIGHT;
9547       else
9548         state = GTK_STATE_NORMAL;
9549     }
9550
9551   if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_EXPANDED))
9552     expander_style = GTK_EXPANDER_SEMI_EXPANDED;
9553   else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_COLLAPSED))
9554     expander_style = GTK_EXPANDER_SEMI_COLLAPSED;
9555   else if (node->children != NULL)
9556     expander_style = GTK_EXPANDER_EXPANDED;
9557   else
9558     expander_style = GTK_EXPANDER_COLLAPSED;
9559
9560   gtk_paint_expander (widget->style,
9561                       tree_view->priv->bin_window,
9562                       state,
9563                       &area,
9564                       widget,
9565                       "treeview",
9566                       area.x + area.width / 2,
9567                       area.y + area.height / 2,
9568                       expander_style);
9569 }
9570
9571 static void
9572 gtk_tree_view_focus_to_cursor (GtkTreeView *tree_view)
9573
9574 {
9575   GtkTreePath *cursor_path;
9576
9577   if ((tree_view->priv->tree == NULL) ||
9578       (! GTK_WIDGET_REALIZED (tree_view)))
9579     return;
9580
9581   cursor_path = NULL;
9582   if (tree_view->priv->cursor)
9583     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
9584
9585   if (cursor_path == NULL)
9586     {
9587       /* Consult the selection before defaulting to the
9588        * first focusable element
9589        */
9590       GList *selected_rows;
9591       GtkTreeModel *model;
9592       GtkTreeSelection *selection;
9593
9594       selection = gtk_tree_view_get_selection (tree_view);
9595       selected_rows = gtk_tree_selection_get_selected_rows (selection, &model);
9596
9597       if (selected_rows)
9598         {
9599           cursor_path = gtk_tree_path_copy((const GtkTreePath *)(selected_rows->data));
9600           g_list_foreach (selected_rows, (GFunc)gtk_tree_path_free, NULL);
9601           g_list_free (selected_rows);
9602         }
9603       else
9604         {
9605           cursor_path = gtk_tree_path_new_first ();
9606           search_first_focusable_path (tree_view, &cursor_path,
9607                                        TRUE, NULL, NULL);
9608         }
9609
9610       gtk_tree_row_reference_free (tree_view->priv->cursor);
9611       tree_view->priv->cursor = NULL;
9612
9613       if (cursor_path)
9614         {
9615           if (tree_view->priv->selection->type == GTK_SELECTION_MULTIPLE)
9616             gtk_tree_view_real_set_cursor (tree_view, cursor_path, FALSE, FALSE);
9617           else
9618             gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE);
9619         }
9620     }
9621
9622   if (cursor_path)
9623     {
9624       GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
9625
9626       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
9627       gtk_tree_path_free (cursor_path);
9628
9629       if (tree_view->priv->focus_column == NULL)
9630         {
9631           GList *list;
9632           for (list = tree_view->priv->columns; list; list = list->next)
9633             {
9634               if (GTK_TREE_VIEW_COLUMN (list->data)->visible)
9635                 {
9636                   tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (list->data);
9637                   break;
9638                 }
9639             }
9640         }
9641     }
9642 }
9643
9644 static void
9645 gtk_tree_view_move_cursor_up_down (GtkTreeView *tree_view,
9646                                    gint         count)
9647 {
9648   gint selection_count;
9649   GtkRBTree *cursor_tree = NULL;
9650   GtkRBNode *cursor_node = NULL;
9651   GtkRBTree *new_cursor_tree = NULL;
9652   GtkRBNode *new_cursor_node = NULL;
9653   GtkTreePath *cursor_path = NULL;
9654   gboolean grab_focus = TRUE;
9655   gboolean selectable;
9656
9657   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
9658     return;
9659
9660   cursor_path = NULL;
9661   if (!gtk_tree_row_reference_valid (tree_view->priv->cursor))
9662     /* FIXME: we lost the cursor; should we get the first? */
9663     return;
9664
9665   cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
9666   _gtk_tree_view_find_node (tree_view, cursor_path,
9667                             &cursor_tree, &cursor_node);
9668
9669   if (cursor_tree == NULL)
9670     /* FIXME: we lost the cursor; should we get the first? */
9671     return;
9672
9673   selection_count = gtk_tree_selection_count_selected_rows (tree_view->priv->selection);
9674   selectable = _gtk_tree_selection_row_is_selectable (tree_view->priv->selection,
9675                                                       cursor_node,
9676                                                       cursor_path);
9677
9678   if (selection_count == 0
9679       && tree_view->priv->selection->type != GTK_SELECTION_NONE
9680       && !tree_view->priv->ctrl_pressed
9681       && selectable)
9682     {
9683       /* Don't move the cursor, but just select the current node */
9684       new_cursor_tree = cursor_tree;
9685       new_cursor_node = cursor_node;
9686     }
9687   else
9688     {
9689       if (count == -1)
9690         _gtk_rbtree_prev_full (cursor_tree, cursor_node,
9691                                &new_cursor_tree, &new_cursor_node);
9692       else
9693         _gtk_rbtree_next_full (cursor_tree, cursor_node,
9694                                &new_cursor_tree, &new_cursor_node);
9695     }
9696
9697   gtk_tree_path_free (cursor_path);
9698
9699   if (new_cursor_node)
9700     {
9701       cursor_path = _gtk_tree_view_find_path (tree_view,
9702                                               new_cursor_tree, new_cursor_node);
9703
9704       search_first_focusable_path (tree_view, &cursor_path,
9705                                    (count != -1),
9706                                    &new_cursor_tree,
9707                                    &new_cursor_node);
9708
9709       if (cursor_path)
9710         gtk_tree_path_free (cursor_path);
9711     }
9712
9713   /*
9714    * If the list has only one item and multi-selection is set then select
9715    * the row (if not yet selected).
9716    */
9717   if (tree_view->priv->selection->type == GTK_SELECTION_MULTIPLE &&
9718       new_cursor_node == NULL)
9719     {
9720       if (count == -1)
9721         _gtk_rbtree_next_full (cursor_tree, cursor_node,
9722                                &new_cursor_tree, &new_cursor_node);
9723       else
9724         _gtk_rbtree_prev_full (cursor_tree, cursor_node,
9725                                &new_cursor_tree, &new_cursor_node);
9726
9727       if (new_cursor_node == NULL
9728           && !GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_SELECTED))
9729         {
9730           new_cursor_node = cursor_node;
9731           new_cursor_tree = cursor_tree;
9732         }
9733       else
9734         {
9735           new_cursor_node = NULL;
9736         }
9737     }
9738
9739   if (new_cursor_node)
9740     {
9741       cursor_path = _gtk_tree_view_find_path (tree_view, new_cursor_tree, new_cursor_node);
9742       gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, TRUE);
9743       gtk_tree_path_free (cursor_path);
9744     }
9745   else
9746     {
9747       gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
9748
9749       if (!tree_view->priv->shift_pressed)
9750         {
9751           if (! gtk_widget_keynav_failed (GTK_WIDGET (tree_view),
9752                                           count < 0 ?
9753                                           GTK_DIR_UP : GTK_DIR_DOWN))
9754             {
9755               GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (tree_view));
9756
9757               if (toplevel)
9758                 gtk_widget_child_focus (toplevel,
9759                                         count < 0 ?
9760                                         GTK_DIR_TAB_BACKWARD :
9761                                         GTK_DIR_TAB_FORWARD);
9762
9763               grab_focus = FALSE;
9764             }
9765         }
9766       else
9767         {
9768           gtk_widget_error_bell (GTK_WIDGET (tree_view));
9769         }
9770     }
9771
9772   if (grab_focus)
9773     gtk_widget_grab_focus (GTK_WIDGET (tree_view));
9774 }
9775
9776 static void
9777 gtk_tree_view_move_cursor_page_up_down (GtkTreeView *tree_view,
9778                                         gint         count)
9779 {
9780   GtkRBTree *cursor_tree = NULL;
9781   GtkRBNode *cursor_node = NULL;
9782   GtkTreePath *old_cursor_path = NULL;
9783   GtkTreePath *cursor_path = NULL;
9784   GtkRBTree *start_cursor_tree = NULL;
9785   GtkRBNode *start_cursor_node = NULL;
9786   gint y;
9787   gint window_y;
9788   gint vertical_separator;
9789
9790   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
9791     return;
9792
9793   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
9794     old_cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
9795   else
9796     /* This is sorta weird.  Focus in should give us a cursor */
9797     return;
9798
9799   gtk_widget_style_get (GTK_WIDGET (tree_view), "vertical-separator", &vertical_separator, NULL);
9800   _gtk_tree_view_find_node (tree_view, old_cursor_path,
9801                             &cursor_tree, &cursor_node);
9802
9803   if (cursor_tree == NULL)
9804     {
9805       /* FIXME: we lost the cursor.  Should we try to get one? */
9806       gtk_tree_path_free (old_cursor_path);
9807       return;
9808     }
9809   g_return_if_fail (cursor_node != NULL);
9810
9811   y = _gtk_rbtree_node_find_offset (cursor_tree, cursor_node);
9812   window_y = RBTREE_Y_TO_TREE_WINDOW_Y (tree_view, y);
9813   y += tree_view->priv->cursor_offset;
9814   y += count * (int)tree_view->priv->vadjustment->page_increment;
9815   y = CLAMP (y, (gint)tree_view->priv->vadjustment->lower,  (gint)tree_view->priv->vadjustment->upper - vertical_separator);
9816
9817   if (y >= tree_view->priv->height)
9818     y = tree_view->priv->height - 1;
9819
9820   tree_view->priv->cursor_offset =
9821     _gtk_rbtree_find_offset (tree_view->priv->tree, y,
9822                              &cursor_tree, &cursor_node);
9823
9824   if (tree_view->priv->cursor_offset > BACKGROUND_HEIGHT (cursor_node))
9825     {
9826       _gtk_rbtree_next_full (cursor_tree, cursor_node,
9827                              &cursor_tree, &cursor_node);
9828       tree_view->priv->cursor_offset -= BACKGROUND_HEIGHT (cursor_node);
9829     }
9830
9831   y -= tree_view->priv->cursor_offset;
9832   cursor_path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
9833
9834   start_cursor_tree = cursor_tree;
9835   start_cursor_node = cursor_node;
9836
9837   if (! search_first_focusable_path (tree_view, &cursor_path,
9838                                      (count != -1),
9839                                      &cursor_tree, &cursor_node))
9840     {
9841       /* It looks like we reached the end of the view without finding
9842        * a focusable row.  We will step backwards to find the last
9843        * focusable row.
9844        */
9845       cursor_tree = start_cursor_tree;
9846       cursor_node = start_cursor_node;
9847       cursor_path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
9848
9849       search_first_focusable_path (tree_view, &cursor_path,
9850                                    (count == -1),
9851                                    &cursor_tree, &cursor_node);
9852     }
9853
9854   if (!cursor_path)
9855     goto cleanup;
9856
9857   /* update y */
9858   y = _gtk_rbtree_node_find_offset (cursor_tree, cursor_node);
9859
9860   gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE);
9861
9862   y -= window_y;
9863   gtk_tree_view_scroll_to_point (tree_view, -1, y);
9864   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
9865   _gtk_tree_view_queue_draw_node (tree_view, cursor_tree, cursor_node, NULL);
9866
9867   if (!gtk_tree_path_compare (old_cursor_path, cursor_path))
9868     gtk_widget_error_bell (GTK_WIDGET (tree_view));
9869
9870   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
9871
9872 cleanup:
9873   gtk_tree_path_free (old_cursor_path);
9874   gtk_tree_path_free (cursor_path);
9875 }
9876
9877 static void
9878 gtk_tree_view_move_cursor_left_right (GtkTreeView *tree_view,
9879                                       gint         count)
9880 {
9881   GtkRBTree *cursor_tree = NULL;
9882   GtkRBNode *cursor_node = NULL;
9883   GtkTreePath *cursor_path = NULL;
9884   GtkTreeViewColumn *column;
9885   GtkTreeIter iter;
9886   GList *list;
9887   gboolean found_column = FALSE;
9888   gboolean rtl;
9889
9890   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
9891
9892   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
9893     return;
9894
9895   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
9896     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
9897   else
9898     return;
9899
9900   _gtk_tree_view_find_node (tree_view, cursor_path, &cursor_tree, &cursor_node);
9901   if (cursor_tree == NULL)
9902     return;
9903   if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path) == FALSE)
9904     {
9905       gtk_tree_path_free (cursor_path);
9906       return;
9907     }
9908   gtk_tree_path_free (cursor_path);
9909
9910   list = rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns);
9911   if (tree_view->priv->focus_column)
9912     {
9913       for (; list; list = (rtl ? list->prev : list->next))
9914         {
9915           if (list->data == tree_view->priv->focus_column)
9916             break;
9917         }
9918     }
9919
9920   while (list)
9921     {
9922       gboolean left, right;
9923
9924       column = list->data;
9925       if (column->visible == FALSE)
9926         goto loop_end;
9927
9928       gtk_tree_view_column_cell_set_cell_data (column,
9929                                                tree_view->priv->model,
9930                                                &iter,
9931                                                GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_PARENT),
9932                                                cursor_node->children?TRUE:FALSE);
9933
9934       if (rtl)
9935         {
9936           right = list->prev ? TRUE : FALSE;
9937           left = list->next ? TRUE : FALSE;
9938         }
9939       else
9940         {
9941           left = list->prev ? TRUE : FALSE;
9942           right = list->next ? TRUE : FALSE;
9943         }
9944
9945       if (_gtk_tree_view_column_cell_focus (column, count, left, right))
9946         {
9947           tree_view->priv->focus_column = column;
9948           found_column = TRUE;
9949           break;
9950         }
9951     loop_end:
9952       if (count == 1)
9953         list = rtl ? list->prev : list->next;
9954       else
9955         list = rtl ? list->next : list->prev;
9956     }
9957
9958   if (found_column)
9959     {
9960       if (!gtk_tree_view_has_special_cell (tree_view))
9961         _gtk_tree_view_queue_draw_node (tree_view,
9962                                         cursor_tree,
9963                                         cursor_node,
9964                                         NULL);
9965       g_signal_emit (tree_view, tree_view_signals[CURSOR_CHANGED], 0);
9966       gtk_widget_grab_focus (GTK_WIDGET (tree_view));
9967     }
9968   else
9969     {
9970       gtk_widget_error_bell (GTK_WIDGET (tree_view));
9971     }
9972
9973   gtk_tree_view_clamp_column_visible (tree_view,
9974                                       tree_view->priv->focus_column, TRUE);
9975 }
9976
9977 static void
9978 gtk_tree_view_move_cursor_start_end (GtkTreeView *tree_view,
9979                                      gint         count)
9980 {
9981   GtkRBTree *cursor_tree;
9982   GtkRBNode *cursor_node;
9983   GtkTreePath *path;
9984   GtkTreePath *old_path;
9985
9986   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
9987     return;
9988
9989   g_return_if_fail (tree_view->priv->tree != NULL);
9990
9991   gtk_tree_view_get_cursor (tree_view, &old_path, NULL);
9992
9993   cursor_tree = tree_view->priv->tree;
9994   cursor_node = cursor_tree->root;
9995
9996   if (count == -1)
9997     {
9998       while (cursor_node && cursor_node->left != cursor_tree->nil)
9999         cursor_node = cursor_node->left;
10000
10001       /* Now go forward to find the first focusable row. */
10002       path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
10003       search_first_focusable_path (tree_view, &path,
10004                                    TRUE, &cursor_tree, &cursor_node);
10005     }
10006   else
10007     {
10008       do
10009         {
10010           while (cursor_node && cursor_node->right != cursor_tree->nil)
10011             cursor_node = cursor_node->right;
10012           if (cursor_node->children == NULL)
10013             break;
10014
10015           cursor_tree = cursor_node->children;
10016           cursor_node = cursor_tree->root;
10017         }
10018       while (1);
10019
10020       /* Now go backwards to find last focusable row. */
10021       path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
10022       search_first_focusable_path (tree_view, &path,
10023                                    FALSE, &cursor_tree, &cursor_node);
10024     }
10025
10026   if (!path)
10027     goto cleanup;
10028
10029   if (gtk_tree_path_compare (old_path, path))
10030     {
10031       gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
10032       gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10033     }
10034   else
10035     {
10036       gtk_widget_error_bell (GTK_WIDGET (tree_view));
10037     }
10038
10039 cleanup:
10040   gtk_tree_path_free (old_path);
10041   gtk_tree_path_free (path);
10042 }
10043
10044 static gboolean
10045 gtk_tree_view_real_select_all (GtkTreeView *tree_view)
10046 {
10047   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
10048     return FALSE;
10049
10050   if (tree_view->priv->selection->type != GTK_SELECTION_MULTIPLE)
10051     return FALSE;
10052
10053   gtk_tree_selection_select_all (tree_view->priv->selection);
10054
10055   return TRUE;
10056 }
10057
10058 static gboolean
10059 gtk_tree_view_real_unselect_all (GtkTreeView *tree_view)
10060 {
10061   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
10062     return FALSE;
10063
10064   if (tree_view->priv->selection->type != GTK_SELECTION_MULTIPLE)
10065     return FALSE;
10066
10067   gtk_tree_selection_unselect_all (tree_view->priv->selection);
10068
10069   return TRUE;
10070 }
10071
10072 static gboolean
10073 gtk_tree_view_real_select_cursor_row (GtkTreeView *tree_view,
10074                                       gboolean     start_editing)
10075 {
10076   GtkRBTree *new_tree = NULL;
10077   GtkRBNode *new_node = NULL;
10078   GtkRBTree *cursor_tree = NULL;
10079   GtkRBNode *cursor_node = NULL;
10080   GtkTreePath *cursor_path = NULL;
10081   GtkTreeSelectMode mode = 0;
10082
10083   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
10084     return FALSE;
10085
10086   if (tree_view->priv->cursor)
10087     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10088
10089   if (cursor_path == NULL)
10090     return FALSE;
10091
10092   _gtk_tree_view_find_node (tree_view, cursor_path,
10093                             &cursor_tree, &cursor_node);
10094
10095   if (cursor_tree == NULL)
10096     {
10097       gtk_tree_path_free (cursor_path);
10098       return FALSE;
10099     }
10100
10101   if (!tree_view->priv->shift_pressed && start_editing &&
10102       tree_view->priv->focus_column)
10103     {
10104       if (gtk_tree_view_start_editing (tree_view, cursor_path))
10105         {
10106           gtk_tree_path_free (cursor_path);
10107           return TRUE;
10108         }
10109     }
10110
10111   if (tree_view->priv->ctrl_pressed)
10112     mode |= GTK_TREE_SELECT_MODE_TOGGLE;
10113   if (tree_view->priv->shift_pressed)
10114     mode |= GTK_TREE_SELECT_MODE_EXTEND;
10115
10116   _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
10117                                             cursor_node,
10118                                             cursor_tree,
10119                                             cursor_path,
10120                                             mode,
10121                                             FALSE);
10122
10123   /* We bail out if the original (tree, node) don't exist anymore after
10124    * handling the selection-changed callback.  We do return TRUE because
10125    * the key press has been handled at this point.
10126    */
10127   _gtk_tree_view_find_node (tree_view, cursor_path, &new_tree, &new_node);
10128
10129   if (cursor_tree != new_tree || cursor_node != new_node)
10130     return FALSE;
10131
10132   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10133
10134   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10135   _gtk_tree_view_queue_draw_node (tree_view, cursor_tree, cursor_node, NULL);
10136
10137   if (!tree_view->priv->shift_pressed)
10138     gtk_tree_view_row_activated (tree_view, cursor_path,
10139                                  tree_view->priv->focus_column);
10140     
10141   gtk_tree_path_free (cursor_path);
10142
10143   return TRUE;
10144 }
10145
10146 static gboolean
10147 gtk_tree_view_real_toggle_cursor_row (GtkTreeView *tree_view)
10148 {
10149   GtkRBTree *new_tree = NULL;
10150   GtkRBNode *new_node = NULL;
10151   GtkRBTree *cursor_tree = NULL;
10152   GtkRBNode *cursor_node = NULL;
10153   GtkTreePath *cursor_path = NULL;
10154
10155   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
10156     return FALSE;
10157
10158   cursor_path = NULL;
10159   if (tree_view->priv->cursor)
10160     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10161
10162   if (cursor_path == NULL)
10163     return FALSE;
10164
10165   _gtk_tree_view_find_node (tree_view, cursor_path,
10166                             &cursor_tree, &cursor_node);
10167   if (cursor_tree == NULL)
10168     {
10169       gtk_tree_path_free (cursor_path);
10170       return FALSE;
10171     }
10172
10173   _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
10174                                             cursor_node,
10175                                             cursor_tree,
10176                                             cursor_path,
10177                                             GTK_TREE_SELECT_MODE_TOGGLE,
10178                                             FALSE);
10179
10180   /* We bail out if the original (tree, node) don't exist anymore after
10181    * handling the selection-changed callback.  We do return TRUE because
10182    * the key press has been handled at this point.
10183    */
10184   _gtk_tree_view_find_node (tree_view, cursor_path, &new_tree, &new_node);
10185
10186   if (cursor_tree != new_tree || cursor_node != new_node)
10187     return FALSE;
10188
10189   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10190
10191   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10192   gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10193   gtk_tree_path_free (cursor_path);
10194
10195   return TRUE;
10196 }
10197
10198 static gboolean
10199 gtk_tree_view_real_expand_collapse_cursor_row (GtkTreeView *tree_view,
10200                                                gboolean     logical,
10201                                                gboolean     expand,
10202                                                gboolean     open_all)
10203 {
10204   GtkTreePath *cursor_path = NULL;
10205   GtkRBTree *tree;
10206   GtkRBNode *node;
10207
10208   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
10209     return FALSE;
10210
10211   cursor_path = NULL;
10212   if (tree_view->priv->cursor)
10213     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10214
10215   if (cursor_path == NULL)
10216     return FALSE;
10217
10218   if (_gtk_tree_view_find_node (tree_view, cursor_path, &tree, &node))
10219     return FALSE;
10220
10221   /* Don't handle the event if we aren't an expander */
10222   if (!((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT))
10223     return FALSE;
10224
10225   if (!logical
10226       && gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL)
10227     expand = !expand;
10228
10229   if (expand)
10230     gtk_tree_view_real_expand_row (tree_view, cursor_path, tree, node, open_all, TRUE);
10231   else
10232     gtk_tree_view_real_collapse_row (tree_view, cursor_path, tree, node, TRUE);
10233
10234   gtk_tree_path_free (cursor_path);
10235
10236   return TRUE;
10237 }
10238
10239 static gboolean
10240 gtk_tree_view_real_select_cursor_parent (GtkTreeView *tree_view)
10241 {
10242   GtkRBTree *cursor_tree = NULL;
10243   GtkRBNode *cursor_node = NULL;
10244   GtkTreePath *cursor_path = NULL;
10245   GdkModifierType state;
10246
10247   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
10248     goto out;
10249
10250   cursor_path = NULL;
10251   if (tree_view->priv->cursor)
10252     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10253
10254   if (cursor_path == NULL)
10255     goto out;
10256
10257   _gtk_tree_view_find_node (tree_view, cursor_path,
10258                             &cursor_tree, &cursor_node);
10259   if (cursor_tree == NULL)
10260     {
10261       gtk_tree_path_free (cursor_path);
10262       goto out;
10263     }
10264
10265   if (cursor_tree->parent_node)
10266     {
10267       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10268       cursor_node = cursor_tree->parent_node;
10269       cursor_tree = cursor_tree->parent_tree;
10270
10271       gtk_tree_path_up (cursor_path);
10272
10273       if (gtk_get_current_event_state (&state))
10274         {
10275           if ((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
10276             tree_view->priv->ctrl_pressed = TRUE;
10277         }
10278
10279       gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE);
10280       gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10281
10282       gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10283       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10284       gtk_tree_path_free (cursor_path);
10285
10286       tree_view->priv->ctrl_pressed = FALSE;
10287
10288       return TRUE;
10289     }
10290
10291  out:
10292
10293   tree_view->priv->search_entry_avoid_unhandled_binding = TRUE;
10294   return FALSE;
10295 }
10296
10297 static gboolean
10298 gtk_tree_view_search_entry_flush_timeout (GtkTreeView *tree_view)
10299 {
10300   gtk_tree_view_search_dialog_hide (tree_view->priv->search_window, tree_view);
10301   tree_view->priv->typeselect_flush_timeout = 0;
10302
10303   return FALSE;
10304 }
10305
10306 /* Cut and paste from gtkwindow.c */
10307 static void
10308 send_focus_change (GtkWidget *widget,
10309                    gboolean   in)
10310 {
10311   GdkEvent *fevent = gdk_event_new (GDK_FOCUS_CHANGE);
10312
10313   g_object_ref (widget);
10314    
10315  if (in)
10316     GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
10317   else
10318     GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
10319
10320   fevent->focus_change.type = GDK_FOCUS_CHANGE;
10321   fevent->focus_change.window = g_object_ref (widget->window);
10322   fevent->focus_change.in = in;
10323   
10324   gtk_widget_event (widget, fevent);
10325   
10326   g_object_notify (G_OBJECT (widget), "has-focus");
10327
10328   g_object_unref (widget);
10329   gdk_event_free (fevent);
10330 }
10331
10332 static void
10333 gtk_tree_view_ensure_interactive_directory (GtkTreeView *tree_view)
10334 {
10335   GtkWidget *frame, *vbox, *toplevel;
10336   GdkScreen *screen;
10337
10338   if (tree_view->priv->search_custom_entry_set)
10339     return;
10340
10341   toplevel = gtk_widget_get_toplevel (GTK_WIDGET (tree_view));
10342   screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
10343
10344    if (tree_view->priv->search_window != NULL)
10345      {
10346        if (GTK_WINDOW (toplevel)->group)
10347          gtk_window_group_add_window (GTK_WINDOW (toplevel)->group,
10348                                       GTK_WINDOW (tree_view->priv->search_window));
10349        else if (GTK_WINDOW (tree_view->priv->search_window)->group)
10350          gtk_window_group_remove_window (GTK_WINDOW (tree_view->priv->search_window)->group,
10351                                          GTK_WINDOW (tree_view->priv->search_window));
10352        gtk_window_set_screen (GTK_WINDOW (tree_view->priv->search_window), screen);
10353        return;
10354      }
10355    
10356   tree_view->priv->search_window = gtk_window_new (GTK_WINDOW_POPUP);
10357   gtk_window_set_screen (GTK_WINDOW (tree_view->priv->search_window), screen);
10358
10359   if (GTK_WINDOW (toplevel)->group)
10360     gtk_window_group_add_window (GTK_WINDOW (toplevel)->group,
10361                                  GTK_WINDOW (tree_view->priv->search_window));
10362
10363   gtk_window_set_type_hint (GTK_WINDOW (tree_view->priv->search_window),
10364                             GDK_WINDOW_TYPE_HINT_UTILITY);
10365   gtk_window_set_modal (GTK_WINDOW (tree_view->priv->search_window), TRUE);
10366   g_signal_connect (tree_view->priv->search_window, "delete-event",
10367                     G_CALLBACK (gtk_tree_view_search_delete_event),
10368                     tree_view);
10369   g_signal_connect (tree_view->priv->search_window, "key-press-event",
10370                     G_CALLBACK (gtk_tree_view_search_key_press_event),
10371                     tree_view);
10372   g_signal_connect (tree_view->priv->search_window, "button-press-event",
10373                     G_CALLBACK (gtk_tree_view_search_button_press_event),
10374                     tree_view);
10375   g_signal_connect (tree_view->priv->search_window, "scroll-event",
10376                     G_CALLBACK (gtk_tree_view_search_scroll_event),
10377                     tree_view);
10378
10379   frame = gtk_frame_new (NULL);
10380   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
10381   gtk_widget_show (frame);
10382   gtk_container_add (GTK_CONTAINER (tree_view->priv->search_window), frame);
10383
10384   vbox = gtk_vbox_new (FALSE, 0);
10385   gtk_widget_show (vbox);
10386   gtk_container_add (GTK_CONTAINER (frame), vbox);
10387   gtk_container_set_border_width (GTK_CONTAINER (vbox), 3);
10388
10389   /* add entry */
10390   tree_view->priv->search_entry = gtk_entry_new ();
10391   gtk_widget_show (tree_view->priv->search_entry);
10392   g_signal_connect (tree_view->priv->search_entry, "populate-popup",
10393                     G_CALLBACK (gtk_tree_view_search_disable_popdown),
10394                     tree_view);
10395   g_signal_connect (tree_view->priv->search_entry,
10396                     "activate", G_CALLBACK (gtk_tree_view_search_activate),
10397                     tree_view);
10398   g_signal_connect (GTK_ENTRY (tree_view->priv->search_entry)->im_context,
10399                     "preedit-changed",
10400                     G_CALLBACK (gtk_tree_view_search_preedit_changed),
10401                     tree_view);
10402   gtk_container_add (GTK_CONTAINER (vbox),
10403                      tree_view->priv->search_entry);
10404
10405   gtk_widget_realize (tree_view->priv->search_entry);
10406 }
10407
10408 /* Pops up the interactive search entry.  If keybinding is TRUE then the user
10409  * started this by typing the start_interactive_search keybinding.  Otherwise, it came from 
10410  */
10411 static gboolean
10412 gtk_tree_view_real_start_interactive_search (GtkTreeView *tree_view,
10413                                              gboolean     keybinding)
10414 {
10415   /* We only start interactive search if we have focus or the columns
10416    * have focus.  If one of our children have focus, we don't want to
10417    * start the search.
10418    */
10419   GList *list;
10420   gboolean found_focus = FALSE;
10421   GtkWidgetClass *entry_parent_class;
10422   
10423   if (!tree_view->priv->enable_search && !keybinding)
10424     return FALSE;
10425
10426   if (tree_view->priv->search_custom_entry_set)
10427     return FALSE;
10428
10429   if (tree_view->priv->search_window != NULL &&
10430       GTK_WIDGET_VISIBLE (tree_view->priv->search_window))
10431     return TRUE;
10432
10433   for (list = tree_view->priv->columns; list; list = list->next)
10434     {
10435       GtkTreeViewColumn *column;
10436
10437       column = list->data;
10438       if (! column->visible)
10439         continue;
10440
10441       if (GTK_WIDGET_HAS_FOCUS (column->button))
10442         {
10443           found_focus = TRUE;
10444           break;
10445         }
10446     }
10447   
10448   if (GTK_WIDGET_HAS_FOCUS (tree_view))
10449     found_focus = TRUE;
10450
10451   if (!found_focus)
10452     return FALSE;
10453
10454   if (tree_view->priv->search_column < 0)
10455     return FALSE;
10456
10457   gtk_tree_view_ensure_interactive_directory (tree_view);
10458
10459   if (keybinding)
10460     gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
10461
10462   /* done, show it */
10463   tree_view->priv->search_position_func (tree_view, tree_view->priv->search_window, tree_view->priv->search_position_user_data);
10464   gtk_widget_show (tree_view->priv->search_window);
10465   if (tree_view->priv->search_entry_changed_id == 0)
10466     {
10467       tree_view->priv->search_entry_changed_id =
10468         g_signal_connect (tree_view->priv->search_entry, "changed",
10469                           G_CALLBACK (gtk_tree_view_search_init),
10470                           tree_view);
10471     }
10472
10473   tree_view->priv->typeselect_flush_timeout =
10474     gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
10475                    (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
10476                    tree_view);
10477
10478   /* Grab focus will select all the text.  We don't want that to happen, so we
10479    * call the parent instance and bypass the selection change.  This is probably
10480    * really non-kosher. */
10481   entry_parent_class = g_type_class_peek_parent (GTK_ENTRY_GET_CLASS (tree_view->priv->search_entry));
10482   (entry_parent_class->grab_focus) (tree_view->priv->search_entry);
10483
10484   /* send focus-in event */
10485   send_focus_change (tree_view->priv->search_entry, TRUE);
10486
10487   /* search first matching iter */
10488   gtk_tree_view_search_init (tree_view->priv->search_entry, tree_view);
10489
10490   return TRUE;
10491 }
10492
10493 static gboolean
10494 gtk_tree_view_start_interactive_search (GtkTreeView *tree_view)
10495 {
10496   return gtk_tree_view_real_start_interactive_search (tree_view, TRUE);
10497 }
10498
10499 /* this function returns the new width of the column being resized given
10500  * the column and x position of the cursor; the x cursor position is passed
10501  * in as a pointer and automagicly corrected if it's beyond min/max limits
10502  */
10503 static gint
10504 gtk_tree_view_new_column_width (GtkTreeView *tree_view,
10505                                 gint       i,
10506                                 gint      *x)
10507 {
10508   GtkTreeViewColumn *column;
10509   gint width;
10510   gboolean rtl;
10511
10512   /* first translate the x position from widget->window
10513    * to clist->clist_window
10514    */
10515   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
10516   column = g_list_nth (tree_view->priv->columns, i)->data;
10517   width = rtl ? (column->button->allocation.x + column->button->allocation.width - *x) : (*x - column->button->allocation.x);
10518  
10519   /* Clamp down the value */
10520   if (column->min_width == -1)
10521     width = MAX (column->button->requisition.width,
10522                  width);
10523   else
10524     width = MAX (column->min_width,
10525                  width);
10526   if (column->max_width != -1)
10527     width = MIN (width, column->max_width);
10528
10529   *x = rtl ? (column->button->allocation.x + column->button->allocation.width - width) : (column->button->allocation.x + width);
10530  
10531   return width;
10532 }
10533
10534
10535 /* FIXME this adjust_allocation is a big cut-and-paste from
10536  * GtkCList, needs to be some "official" way to do this
10537  * factored out.
10538  */
10539 typedef struct
10540 {
10541   GdkWindow *window;
10542   int dx;
10543   int dy;
10544 } ScrollData;
10545
10546 /* The window to which widget->window is relative */
10547 #define ALLOCATION_WINDOW(widget)               \
10548    (!gtk_widget_get_has_window (widget) ?               \
10549     (widget)->window :                          \
10550      gdk_window_get_parent ((widget)->window))
10551
10552 static void
10553 adjust_allocation_recurse (GtkWidget *widget,
10554                            gpointer   data)
10555 {
10556   ScrollData *scroll_data = data;
10557
10558   /* Need to really size allocate instead of just poking
10559    * into widget->allocation if the widget is not realized.
10560    * FIXME someone figure out why this was.
10561    */
10562   if (!GTK_WIDGET_REALIZED (widget))
10563     {
10564       if (GTK_WIDGET_VISIBLE (widget))
10565         {
10566           GdkRectangle tmp_rectangle = widget->allocation;
10567           tmp_rectangle.x += scroll_data->dx;
10568           tmp_rectangle.y += scroll_data->dy;
10569           
10570           gtk_widget_size_allocate (widget, &tmp_rectangle);
10571         }
10572     }
10573   else
10574     {
10575       if (ALLOCATION_WINDOW (widget) == scroll_data->window)
10576         {
10577           widget->allocation.x += scroll_data->dx;
10578           widget->allocation.y += scroll_data->dy;
10579           
10580           if (GTK_IS_CONTAINER (widget))
10581             gtk_container_forall (GTK_CONTAINER (widget),
10582                                   adjust_allocation_recurse,
10583                                   data);
10584         }
10585     }
10586 }
10587
10588 static void
10589 adjust_allocation (GtkWidget *widget,
10590                    int        dx,
10591                    int        dy)
10592 {
10593   ScrollData scroll_data;
10594
10595   if (GTK_WIDGET_REALIZED (widget))
10596     scroll_data.window = ALLOCATION_WINDOW (widget);
10597   else
10598     scroll_data.window = NULL;
10599     
10600   scroll_data.dx = dx;
10601   scroll_data.dy = dy;
10602   
10603   adjust_allocation_recurse (widget, &scroll_data);
10604 }
10605
10606 /* Callbacks */
10607 static void
10608 gtk_tree_view_adjustment_changed (GtkAdjustment *adjustment,
10609                                   GtkTreeView   *tree_view)
10610 {
10611   if (GTK_WIDGET_REALIZED (tree_view))
10612     {
10613       gint dy;
10614         
10615       gdk_window_move (tree_view->priv->bin_window,
10616                        - tree_view->priv->hadjustment->value,
10617                        TREE_VIEW_HEADER_HEIGHT (tree_view));
10618       gdk_window_move (tree_view->priv->header_window,
10619                        - tree_view->priv->hadjustment->value,
10620                        0);
10621       dy = tree_view->priv->dy - (int) tree_view->priv->vadjustment->value;
10622       if (dy)
10623         {
10624           if (tree_view->priv->tree)
10625             update_prelight (tree_view,
10626                              tree_view->priv->event_last_x,
10627                              tree_view->priv->event_last_y - dy);
10628
10629           if (tree_view->priv->edited_column &&
10630               GTK_IS_WIDGET (tree_view->priv->edited_column->editable_widget))
10631             {
10632               GList *list;
10633               GtkWidget *widget;
10634               GtkTreeViewChild *child = NULL;
10635
10636               widget = GTK_WIDGET (tree_view->priv->edited_column->editable_widget);
10637               adjust_allocation (widget, 0, dy); 
10638               
10639               for (list = tree_view->priv->children; list; list = list->next)
10640                 {
10641                   child = (GtkTreeViewChild *)list->data;
10642                   if (child->widget == widget)
10643                     {
10644                       child->y += dy;
10645                       break;
10646                     }
10647                 }
10648             }
10649         }
10650       gdk_window_scroll (tree_view->priv->bin_window, 0, dy);
10651
10652       if (tree_view->priv->dy != (int) tree_view->priv->vadjustment->value)
10653         {
10654           /* update our dy and top_row */
10655           tree_view->priv->dy = (int) tree_view->priv->vadjustment->value;
10656
10657           if (!tree_view->priv->in_top_row_to_dy)
10658             gtk_tree_view_dy_to_top_row (tree_view);
10659         }
10660
10661       gdk_window_process_updates (tree_view->priv->header_window, TRUE);
10662       gdk_window_process_updates (tree_view->priv->bin_window, TRUE);
10663     }
10664 }
10665
10666 \f
10667
10668 /* Public methods
10669  */
10670
10671 /**
10672  * gtk_tree_view_new:
10673  *
10674  * Creates a new #GtkTreeView widget.
10675  *
10676  * Return value: A newly created #GtkTreeView widget.
10677  **/
10678 GtkWidget *
10679 gtk_tree_view_new (void)
10680 {
10681   return g_object_new (GTK_TYPE_TREE_VIEW, NULL);
10682 }
10683
10684 /**
10685  * gtk_tree_view_new_with_model:
10686  * @model: the model.
10687  *
10688  * Creates a new #GtkTreeView widget with the model initialized to @model.
10689  *
10690  * Return value: A newly created #GtkTreeView widget.
10691  **/
10692 GtkWidget *
10693 gtk_tree_view_new_with_model (GtkTreeModel *model)
10694 {
10695   return g_object_new (GTK_TYPE_TREE_VIEW, "model", model, NULL);
10696 }
10697
10698 /* Public Accessors
10699  */
10700
10701 /**
10702  * gtk_tree_view_get_model:
10703  * @tree_view: a #GtkTreeView
10704  *
10705  * Returns the model the #GtkTreeView is based on.  Returns %NULL if the
10706  * model is unset.
10707  *
10708  * Return value: A #GtkTreeModel, or %NULL if none is currently being used.
10709  **/
10710 GtkTreeModel *
10711 gtk_tree_view_get_model (GtkTreeView *tree_view)
10712 {
10713   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
10714
10715   return tree_view->priv->model;
10716 }
10717
10718 /**
10719  * gtk_tree_view_set_model:
10720  * @tree_view: A #GtkTreeNode.
10721  * @model: (allow-none): The model.
10722  *
10723  * Sets the model for a #GtkTreeView.  If the @tree_view already has a model
10724  * set, it will remove it before setting the new model.  If @model is %NULL,
10725  * then it will unset the old model.
10726  **/
10727 void
10728 gtk_tree_view_set_model (GtkTreeView  *tree_view,
10729                          GtkTreeModel *model)
10730 {
10731   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
10732   g_return_if_fail (model == NULL || GTK_IS_TREE_MODEL (model));
10733
10734   if (model == tree_view->priv->model)
10735     return;
10736
10737   if (tree_view->priv->scroll_to_path)
10738     {
10739       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
10740       tree_view->priv->scroll_to_path = NULL;
10741     }
10742
10743   if (tree_view->priv->model)
10744     {
10745       GList *tmplist = tree_view->priv->columns;
10746
10747       gtk_tree_view_unref_and_check_selection_tree (tree_view, tree_view->priv->tree);
10748       gtk_tree_view_stop_editing (tree_view, TRUE);
10749
10750       remove_expand_collapse_timeout (tree_view);
10751
10752       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
10753                                             gtk_tree_view_row_changed,
10754                                             tree_view);
10755       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
10756                                             gtk_tree_view_row_inserted,
10757                                             tree_view);
10758       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
10759                                             gtk_tree_view_row_has_child_toggled,
10760                                             tree_view);
10761       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
10762                                             gtk_tree_view_row_deleted,
10763                                             tree_view);
10764       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
10765                                             gtk_tree_view_rows_reordered,
10766                                             tree_view);
10767
10768       for (; tmplist; tmplist = tmplist->next)
10769         _gtk_tree_view_column_unset_model (tmplist->data,
10770                                            tree_view->priv->model);
10771
10772       if (tree_view->priv->tree)
10773         gtk_tree_view_free_rbtree (tree_view);
10774
10775       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
10776       tree_view->priv->drag_dest_row = NULL;
10777       gtk_tree_row_reference_free (tree_view->priv->cursor);
10778       tree_view->priv->cursor = NULL;
10779       gtk_tree_row_reference_free (tree_view->priv->anchor);
10780       tree_view->priv->anchor = NULL;
10781       gtk_tree_row_reference_free (tree_view->priv->top_row);
10782       tree_view->priv->top_row = NULL;
10783       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
10784       tree_view->priv->scroll_to_path = NULL;
10785
10786       tree_view->priv->scroll_to_column = NULL;
10787
10788       g_object_unref (tree_view->priv->model);
10789
10790       tree_view->priv->search_column = -1;
10791       tree_view->priv->fixed_height_check = 0;
10792       tree_view->priv->fixed_height = -1;
10793       tree_view->priv->dy = tree_view->priv->top_row_dy = 0;
10794       tree_view->priv->last_button_x = -1;
10795       tree_view->priv->last_button_y = -1;
10796     }
10797
10798   tree_view->priv->model = model;
10799
10800   if (tree_view->priv->model)
10801     {
10802       gint i;
10803       GtkTreePath *path;
10804       GtkTreeIter iter;
10805       GtkTreeModelFlags flags;
10806
10807       if (tree_view->priv->search_column == -1)
10808         {
10809           for (i = 0; i < gtk_tree_model_get_n_columns (model); i++)
10810             {
10811               GType type = gtk_tree_model_get_column_type (model, i);
10812
10813               if (g_value_type_transformable (type, G_TYPE_STRING))
10814                 {
10815                   tree_view->priv->search_column = i;
10816                   break;
10817                 }
10818             }
10819         }
10820
10821       g_object_ref (tree_view->priv->model);
10822       g_signal_connect (tree_view->priv->model,
10823                         "row-changed",
10824                         G_CALLBACK (gtk_tree_view_row_changed),
10825                         tree_view);
10826       g_signal_connect (tree_view->priv->model,
10827                         "row-inserted",
10828                         G_CALLBACK (gtk_tree_view_row_inserted),
10829                         tree_view);
10830       g_signal_connect (tree_view->priv->model,
10831                         "row-has-child-toggled",
10832                         G_CALLBACK (gtk_tree_view_row_has_child_toggled),
10833                         tree_view);
10834       g_signal_connect (tree_view->priv->model,
10835                         "row-deleted",
10836                         G_CALLBACK (gtk_tree_view_row_deleted),
10837                         tree_view);
10838       g_signal_connect (tree_view->priv->model,
10839                         "rows-reordered",
10840                         G_CALLBACK (gtk_tree_view_rows_reordered),
10841                         tree_view);
10842
10843       flags = gtk_tree_model_get_flags (tree_view->priv->model);
10844       if ((flags & GTK_TREE_MODEL_LIST_ONLY) == GTK_TREE_MODEL_LIST_ONLY)
10845         GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_IS_LIST);
10846       else
10847         GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IS_LIST);
10848
10849       path = gtk_tree_path_new_first ();
10850       if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, path))
10851         {
10852           tree_view->priv->tree = _gtk_rbtree_new ();
10853           gtk_tree_view_build_tree (tree_view, tree_view->priv->tree, &iter, 1, FALSE);
10854         }
10855       gtk_tree_path_free (path);
10856
10857       /*  FIXME: do I need to do this? gtk_tree_view_create_buttons (tree_view); */
10858       install_presize_handler (tree_view);
10859     }
10860
10861   g_object_notify (G_OBJECT (tree_view), "model");
10862
10863   if (tree_view->priv->selection)
10864   _gtk_tree_selection_emit_changed (tree_view->priv->selection);
10865
10866   if (GTK_WIDGET_REALIZED (tree_view))
10867     gtk_widget_queue_resize (GTK_WIDGET (tree_view));
10868 }
10869
10870 /**
10871  * gtk_tree_view_get_selection:
10872  * @tree_view: A #GtkTreeView.
10873  *
10874  * Gets the #GtkTreeSelection associated with @tree_view.
10875  *
10876  * Return value: A #GtkTreeSelection object.
10877  **/
10878 GtkTreeSelection *
10879 gtk_tree_view_get_selection (GtkTreeView *tree_view)
10880 {
10881   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
10882
10883   return tree_view->priv->selection;
10884 }
10885
10886 /**
10887  * gtk_tree_view_get_hadjustment:
10888  * @tree_view: A #GtkTreeView
10889  *
10890  * Gets the #GtkAdjustment currently being used for the horizontal aspect.
10891  *
10892  * Return value: A #GtkAdjustment object, or %NULL if none is currently being
10893  * used.
10894  **/
10895 GtkAdjustment *
10896 gtk_tree_view_get_hadjustment (GtkTreeView *tree_view)
10897 {
10898   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
10899
10900   if (tree_view->priv->hadjustment == NULL)
10901     gtk_tree_view_set_hadjustment (tree_view, NULL);
10902
10903   return tree_view->priv->hadjustment;
10904 }
10905
10906 /**
10907  * gtk_tree_view_set_hadjustment:
10908  * @tree_view: A #GtkTreeView
10909  * @adjustment: The #GtkAdjustment to set, or %NULL
10910  *
10911  * Sets the #GtkAdjustment for the current horizontal aspect.
10912  **/
10913 void
10914 gtk_tree_view_set_hadjustment (GtkTreeView   *tree_view,
10915                                GtkAdjustment *adjustment)
10916 {
10917   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
10918
10919   gtk_tree_view_set_adjustments (tree_view,
10920                                  adjustment,
10921                                  tree_view->priv->vadjustment);
10922
10923   g_object_notify (G_OBJECT (tree_view), "hadjustment");
10924 }
10925
10926 /**
10927  * gtk_tree_view_get_vadjustment:
10928  * @tree_view: A #GtkTreeView
10929  *
10930  * Gets the #GtkAdjustment currently being used for the vertical aspect.
10931  *
10932  * Return value: A #GtkAdjustment object, or %NULL if none is currently being
10933  * used.
10934  **/
10935 GtkAdjustment *
10936 gtk_tree_view_get_vadjustment (GtkTreeView *tree_view)
10937 {
10938   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
10939
10940   if (tree_view->priv->vadjustment == NULL)
10941     gtk_tree_view_set_vadjustment (tree_view, NULL);
10942
10943   return tree_view->priv->vadjustment;
10944 }
10945
10946 /**
10947  * gtk_tree_view_set_vadjustment:
10948  * @tree_view: A #GtkTreeView
10949  * @adjustment: The #GtkAdjustment to set, or %NULL
10950  *
10951  * Sets the #GtkAdjustment for the current vertical aspect.
10952  **/
10953 void
10954 gtk_tree_view_set_vadjustment (GtkTreeView   *tree_view,
10955                                GtkAdjustment *adjustment)
10956 {
10957   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
10958
10959   gtk_tree_view_set_adjustments (tree_view,
10960                                  tree_view->priv->hadjustment,
10961                                  adjustment);
10962
10963   g_object_notify (G_OBJECT (tree_view), "vadjustment");
10964 }
10965
10966 /* Column and header operations */
10967
10968 /**
10969  * gtk_tree_view_get_headers_visible:
10970  * @tree_view: A #GtkTreeView.
10971  *
10972  * Returns %TRUE if the headers on the @tree_view are visible.
10973  *
10974  * Return value: Whether the headers are visible or not.
10975  **/
10976 gboolean
10977 gtk_tree_view_get_headers_visible (GtkTreeView *tree_view)
10978 {
10979   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
10980
10981   return GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE);
10982 }
10983
10984 /**
10985  * gtk_tree_view_set_headers_visible:
10986  * @tree_view: A #GtkTreeView.
10987  * @headers_visible: %TRUE if the headers are visible
10988  *
10989  * Sets the visibility state of the headers.
10990  **/
10991 void
10992 gtk_tree_view_set_headers_visible (GtkTreeView *tree_view,
10993                                    gboolean     headers_visible)
10994 {
10995   gint x, y;
10996   GList *list;
10997   GtkTreeViewColumn *column;
10998
10999   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11000
11001   headers_visible = !! headers_visible;
11002
11003   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE) == headers_visible)
11004     return;
11005
11006   if (headers_visible)
11007     GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE);
11008   else
11009     GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE);
11010
11011   if (GTK_WIDGET_REALIZED (tree_view))
11012     {
11013       gdk_window_get_position (tree_view->priv->bin_window, &x, &y);
11014       if (headers_visible)
11015         {
11016           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));
11017
11018           if (GTK_WIDGET_MAPPED (tree_view))
11019             gtk_tree_view_map_buttons (tree_view);
11020         }
11021       else
11022         {
11023           gdk_window_move_resize (tree_view->priv->bin_window, x, y, tree_view->priv->width, tree_view->priv->height);
11024
11025           for (list = tree_view->priv->columns; list; list = list->next)
11026             {
11027               column = list->data;
11028               gtk_widget_unmap (column->button);
11029             }
11030           gdk_window_hide (tree_view->priv->header_window);
11031         }
11032     }
11033
11034   tree_view->priv->vadjustment->page_size = GTK_WIDGET (tree_view)->allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view);
11035   tree_view->priv->vadjustment->page_increment = (GTK_WIDGET (tree_view)->allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view)) / 2;
11036   tree_view->priv->vadjustment->lower = 0;
11037   tree_view->priv->vadjustment->upper = tree_view->priv->height;
11038   gtk_adjustment_changed (tree_view->priv->vadjustment);
11039
11040   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11041
11042   g_object_notify (G_OBJECT (tree_view), "headers-visible");
11043 }
11044
11045 /**
11046  * gtk_tree_view_columns_autosize:
11047  * @tree_view: A #GtkTreeView.
11048  *
11049  * Resizes all columns to their optimal width. Only works after the
11050  * treeview has been realized.
11051  **/
11052 void
11053 gtk_tree_view_columns_autosize (GtkTreeView *tree_view)
11054 {
11055   gboolean dirty = FALSE;
11056   GList *list;
11057   GtkTreeViewColumn *column;
11058
11059   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11060
11061   for (list = tree_view->priv->columns; list; list = list->next)
11062     {
11063       column = list->data;
11064       if (column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
11065         continue;
11066       _gtk_tree_view_column_cell_set_dirty (column, TRUE);
11067       dirty = TRUE;
11068     }
11069
11070   if (dirty)
11071     gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11072 }
11073
11074 /**
11075  * gtk_tree_view_set_headers_clickable:
11076  * @tree_view: A #GtkTreeView.
11077  * @setting: %TRUE if the columns are clickable.
11078  *
11079  * Allow the column title buttons to be clicked.
11080  **/
11081 void
11082 gtk_tree_view_set_headers_clickable (GtkTreeView *tree_view,
11083                                      gboolean   setting)
11084 {
11085   GList *list;
11086
11087   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11088
11089   for (list = tree_view->priv->columns; list; list = list->next)
11090     gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (list->data), setting);
11091
11092   g_object_notify (G_OBJECT (tree_view), "headers-clickable");
11093 }
11094
11095
11096 /**
11097  * gtk_tree_view_get_headers_clickable:
11098  * @tree_view: A #GtkTreeView.
11099  *
11100  * Returns whether all header columns are clickable.
11101  *
11102  * Return value: %TRUE if all header columns are clickable, otherwise %FALSE
11103  *
11104  * Since: 2.10
11105  **/
11106 gboolean 
11107 gtk_tree_view_get_headers_clickable (GtkTreeView *tree_view)
11108 {
11109   GList *list;
11110   
11111   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
11112
11113   for (list = tree_view->priv->columns; list; list = list->next)
11114     if (!GTK_TREE_VIEW_COLUMN (list->data)->clickable)
11115       return FALSE;
11116
11117   return TRUE;
11118 }
11119
11120 /**
11121  * gtk_tree_view_set_rules_hint
11122  * @tree_view: a #GtkTreeView
11123  * @setting: %TRUE if the tree requires reading across rows
11124  *
11125  * This function tells GTK+ that the user interface for your
11126  * application requires users to read across tree rows and associate
11127  * cells with one another. By default, GTK+ will then render the tree
11128  * with alternating row colors. Do <emphasis>not</emphasis> use it
11129  * just because you prefer the appearance of the ruled tree; that's a
11130  * question for the theme. Some themes will draw tree rows in
11131  * alternating colors even when rules are turned off, and users who
11132  * prefer that appearance all the time can choose those themes. You
11133  * should call this function only as a <emphasis>semantic</emphasis>
11134  * hint to the theme engine that your tree makes alternating colors
11135  * useful from a functional standpoint (since it has lots of columns,
11136  * generally).
11137  *
11138  **/
11139 void
11140 gtk_tree_view_set_rules_hint (GtkTreeView  *tree_view,
11141                               gboolean      setting)
11142 {
11143   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11144
11145   setting = setting != FALSE;
11146
11147   if (tree_view->priv->has_rules != setting)
11148     {
11149       tree_view->priv->has_rules = setting;
11150       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
11151     }
11152
11153   g_object_notify (G_OBJECT (tree_view), "rules-hint");
11154 }
11155
11156 /**
11157  * gtk_tree_view_get_rules_hint
11158  * @tree_view: a #GtkTreeView
11159  *
11160  * Gets the setting set by gtk_tree_view_set_rules_hint().
11161  *
11162  * Return value: %TRUE if rules are useful for the user of this tree
11163  **/
11164 gboolean
11165 gtk_tree_view_get_rules_hint (GtkTreeView  *tree_view)
11166 {
11167   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
11168
11169   return tree_view->priv->has_rules;
11170 }
11171
11172 /* Public Column functions
11173  */
11174
11175 /**
11176  * gtk_tree_view_append_column:
11177  * @tree_view: A #GtkTreeView.
11178  * @column: The #GtkTreeViewColumn to add.
11179  *
11180  * Appends @column to the list of columns. If @tree_view has "fixed_height"
11181  * mode enabled, then @column must have its "sizing" property set to be
11182  * GTK_TREE_VIEW_COLUMN_FIXED.
11183  *
11184  * Return value: The number of columns in @tree_view after appending.
11185  **/
11186 gint
11187 gtk_tree_view_append_column (GtkTreeView       *tree_view,
11188                              GtkTreeViewColumn *column)
11189 {
11190   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11191   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
11192   g_return_val_if_fail (column->tree_view == NULL, -1);
11193
11194   return gtk_tree_view_insert_column (tree_view, column, -1);
11195 }
11196
11197
11198 /**
11199  * gtk_tree_view_remove_column:
11200  * @tree_view: A #GtkTreeView.
11201  * @column: The #GtkTreeViewColumn to remove.
11202  *
11203  * Removes @column from @tree_view.
11204  *
11205  * Return value: The number of columns in @tree_view after removing.
11206  **/
11207 gint
11208 gtk_tree_view_remove_column (GtkTreeView       *tree_view,
11209                              GtkTreeViewColumn *column)
11210 {
11211   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11212   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
11213   g_return_val_if_fail (column->tree_view == GTK_WIDGET (tree_view), -1);
11214
11215   if (tree_view->priv->focus_column == column)
11216     tree_view->priv->focus_column = NULL;
11217
11218   if (tree_view->priv->edited_column == column)
11219     {
11220       gtk_tree_view_stop_editing (tree_view, TRUE);
11221
11222       /* no need to, but just to be sure ... */
11223       tree_view->priv->edited_column = NULL;
11224     }
11225
11226   if (tree_view->priv->expander_column == column)
11227     tree_view->priv->expander_column = NULL;
11228
11229   g_signal_handlers_disconnect_by_func (column,
11230                                         G_CALLBACK (column_sizing_notify),
11231                                         tree_view);
11232
11233   _gtk_tree_view_column_unset_tree_view (column);
11234
11235   tree_view->priv->columns = g_list_remove (tree_view->priv->columns, column);
11236   tree_view->priv->n_columns--;
11237
11238   if (GTK_WIDGET_REALIZED (tree_view))
11239     {
11240       GList *list;
11241
11242       _gtk_tree_view_column_unrealize_button (column);
11243       for (list = tree_view->priv->columns; list; list = list->next)
11244         {
11245           GtkTreeViewColumn *tmp_column;
11246
11247           tmp_column = GTK_TREE_VIEW_COLUMN (list->data);
11248           if (tmp_column->visible)
11249             _gtk_tree_view_column_cell_set_dirty (tmp_column, TRUE);
11250         }
11251
11252       if (tree_view->priv->n_columns == 0 &&
11253           gtk_tree_view_get_headers_visible (tree_view))
11254         gdk_window_hide (tree_view->priv->header_window);
11255
11256       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11257     }
11258
11259   g_object_unref (column);
11260   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
11261
11262   return tree_view->priv->n_columns;
11263 }
11264
11265 /**
11266  * gtk_tree_view_insert_column:
11267  * @tree_view: A #GtkTreeView.
11268  * @column: The #GtkTreeViewColumn to be inserted.
11269  * @position: The position to insert @column in.
11270  *
11271  * This inserts the @column into the @tree_view at @position.  If @position is
11272  * -1, then the column is inserted at the end. If @tree_view has
11273  * "fixed_height" mode enabled, then @column must have its "sizing" property
11274  * set to be GTK_TREE_VIEW_COLUMN_FIXED.
11275  *
11276  * Return value: The number of columns in @tree_view after insertion.
11277  **/
11278 gint
11279 gtk_tree_view_insert_column (GtkTreeView       *tree_view,
11280                              GtkTreeViewColumn *column,
11281                              gint               position)
11282 {
11283   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11284   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
11285   g_return_val_if_fail (column->tree_view == NULL, -1);
11286
11287   if (tree_view->priv->fixed_height_mode)
11288     g_return_val_if_fail (gtk_tree_view_column_get_sizing (column)
11289                           == GTK_TREE_VIEW_COLUMN_FIXED, -1);
11290
11291   g_object_ref_sink (column);
11292
11293   if (tree_view->priv->n_columns == 0 &&
11294       GTK_WIDGET_REALIZED (tree_view) &&
11295       gtk_tree_view_get_headers_visible (tree_view))
11296     {
11297       gdk_window_show (tree_view->priv->header_window);
11298     }
11299
11300   g_signal_connect (column, "notify::sizing",
11301                     G_CALLBACK (column_sizing_notify), tree_view);
11302
11303   tree_view->priv->columns = g_list_insert (tree_view->priv->columns,
11304                                             column, position);
11305   tree_view->priv->n_columns++;
11306
11307   _gtk_tree_view_column_set_tree_view (column, tree_view);
11308
11309   if (GTK_WIDGET_REALIZED (tree_view))
11310     {
11311       GList *list;
11312
11313       _gtk_tree_view_column_realize_button (column);
11314
11315       for (list = tree_view->priv->columns; list; list = list->next)
11316         {
11317           column = GTK_TREE_VIEW_COLUMN (list->data);
11318           if (column->visible)
11319             _gtk_tree_view_column_cell_set_dirty (column, TRUE);
11320         }
11321       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11322     }
11323
11324   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
11325
11326   return tree_view->priv->n_columns;
11327 }
11328
11329 /**
11330  * gtk_tree_view_insert_column_with_attributes:
11331  * @tree_view: A #GtkTreeView
11332  * @position: The position to insert the new column in.
11333  * @title: The title to set the header to.
11334  * @cell: The #GtkCellRenderer.
11335  * @Varargs: A %NULL-terminated list of attributes.
11336  *
11337  * Creates a new #GtkTreeViewColumn and inserts it into the @tree_view at
11338  * @position.  If @position is -1, then the newly created column is inserted at
11339  * the end.  The column is initialized with the attributes given. If @tree_view
11340  * has "fixed_height" mode enabled, then the new column will have its sizing
11341  * property set to be GTK_TREE_VIEW_COLUMN_FIXED.
11342  *
11343  * Return value: The number of columns in @tree_view after insertion.
11344  **/
11345 gint
11346 gtk_tree_view_insert_column_with_attributes (GtkTreeView     *tree_view,
11347                                              gint             position,
11348                                              const gchar     *title,
11349                                              GtkCellRenderer *cell,
11350                                              ...)
11351 {
11352   GtkTreeViewColumn *column;
11353   gchar *attribute;
11354   va_list args;
11355   gint column_id;
11356
11357   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11358
11359   column = gtk_tree_view_column_new ();
11360   if (tree_view->priv->fixed_height_mode)
11361     gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
11362
11363   gtk_tree_view_column_set_title (column, title);
11364   gtk_tree_view_column_pack_start (column, cell, TRUE);
11365
11366   va_start (args, cell);
11367
11368   attribute = va_arg (args, gchar *);
11369
11370   while (attribute != NULL)
11371     {
11372       column_id = va_arg (args, gint);
11373       gtk_tree_view_column_add_attribute (column, cell, attribute, column_id);
11374       attribute = va_arg (args, gchar *);
11375     }
11376
11377   va_end (args);
11378
11379   gtk_tree_view_insert_column (tree_view, column, position);
11380
11381   return tree_view->priv->n_columns;
11382 }
11383
11384 /**
11385  * gtk_tree_view_insert_column_with_data_func:
11386  * @tree_view: a #GtkTreeView
11387  * @position: Position to insert, -1 for append
11388  * @title: column title
11389  * @cell: cell renderer for column
11390  * @func: function to set attributes of cell renderer
11391  * @data: data for @func
11392  * @dnotify: destroy notifier for @data
11393  *
11394  * Convenience function that inserts a new column into the #GtkTreeView
11395  * with the given cell renderer and a #GtkCellDataFunc to set cell renderer
11396  * attributes (normally using data from the model). See also
11397  * gtk_tree_view_column_set_cell_data_func(), gtk_tree_view_column_pack_start().
11398  * If @tree_view has "fixed_height" mode enabled, then the new column will have its
11399  * "sizing" property set to be GTK_TREE_VIEW_COLUMN_FIXED.
11400  *
11401  * Return value: number of columns in the tree view post-insert
11402  **/
11403 gint
11404 gtk_tree_view_insert_column_with_data_func  (GtkTreeView               *tree_view,
11405                                              gint                       position,
11406                                              const gchar               *title,
11407                                              GtkCellRenderer           *cell,
11408                                              GtkTreeCellDataFunc        func,
11409                                              gpointer                   data,
11410                                              GDestroyNotify             dnotify)
11411 {
11412   GtkTreeViewColumn *column;
11413
11414   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11415
11416   column = gtk_tree_view_column_new ();
11417   if (tree_view->priv->fixed_height_mode)
11418     gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
11419
11420   gtk_tree_view_column_set_title (column, title);
11421   gtk_tree_view_column_pack_start (column, cell, TRUE);
11422   gtk_tree_view_column_set_cell_data_func (column, cell, func, data, dnotify);
11423
11424   gtk_tree_view_insert_column (tree_view, column, position);
11425
11426   return tree_view->priv->n_columns;
11427 }
11428
11429 /**
11430  * gtk_tree_view_get_column:
11431  * @tree_view: A #GtkTreeView.
11432  * @n: The position of the column, counting from 0.
11433  *
11434  * Gets the #GtkTreeViewColumn at the given position in the #tree_view.
11435  *
11436  * Return value: The #GtkTreeViewColumn, or %NULL if the position is outside the
11437  * range of columns.
11438  **/
11439 GtkTreeViewColumn *
11440 gtk_tree_view_get_column (GtkTreeView *tree_view,
11441                           gint         n)
11442 {
11443   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11444
11445   if (n < 0 || n >= tree_view->priv->n_columns)
11446     return NULL;
11447
11448   if (tree_view->priv->columns == NULL)
11449     return NULL;
11450
11451   return GTK_TREE_VIEW_COLUMN (g_list_nth (tree_view->priv->columns, n)->data);
11452 }
11453
11454 /**
11455  * gtk_tree_view_get_columns:
11456  * @tree_view: A #GtkTreeView
11457  *
11458  * Returns a #GList of all the #GtkTreeViewColumn s currently in @tree_view.
11459  * The returned list must be freed with g_list_free ().
11460  *
11461  * Return value: (element-type GtkTreeViewColumn) (transfer container): A list of #GtkTreeViewColumn s
11462  **/
11463 GList *
11464 gtk_tree_view_get_columns (GtkTreeView *tree_view)
11465 {
11466   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11467
11468   return g_list_copy (tree_view->priv->columns);
11469 }
11470
11471 /**
11472  * gtk_tree_view_move_column_after:
11473  * @tree_view: A #GtkTreeView
11474  * @column: The #GtkTreeViewColumn to be moved.
11475  * @base_column: (allow-none): The #GtkTreeViewColumn to be moved relative to, or %NULL.
11476  *
11477  * Moves @column to be after to @base_column.  If @base_column is %NULL, then
11478  * @column is placed in the first position.
11479  **/
11480 void
11481 gtk_tree_view_move_column_after (GtkTreeView       *tree_view,
11482                                  GtkTreeViewColumn *column,
11483                                  GtkTreeViewColumn *base_column)
11484 {
11485   GList *column_list_el, *base_el = NULL;
11486
11487   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11488
11489   column_list_el = g_list_find (tree_view->priv->columns, column);
11490   g_return_if_fail (column_list_el != NULL);
11491
11492   if (base_column)
11493     {
11494       base_el = g_list_find (tree_view->priv->columns, base_column);
11495       g_return_if_fail (base_el != NULL);
11496     }
11497
11498   if (column_list_el->prev == base_el)
11499     return;
11500
11501   tree_view->priv->columns = g_list_remove_link (tree_view->priv->columns, column_list_el);
11502   if (base_el == NULL)
11503     {
11504       column_list_el->prev = NULL;
11505       column_list_el->next = tree_view->priv->columns;
11506       if (column_list_el->next)
11507         column_list_el->next->prev = column_list_el;
11508       tree_view->priv->columns = column_list_el;
11509     }
11510   else
11511     {
11512       column_list_el->prev = base_el;
11513       column_list_el->next = base_el->next;
11514       if (column_list_el->next)
11515         column_list_el->next->prev = column_list_el;
11516       base_el->next = column_list_el;
11517     }
11518
11519   if (GTK_WIDGET_REALIZED (tree_view))
11520     {
11521       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11522       gtk_tree_view_size_allocate_columns (GTK_WIDGET (tree_view), NULL);
11523     }
11524
11525   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
11526 }
11527
11528 /**
11529  * gtk_tree_view_set_expander_column:
11530  * @tree_view: A #GtkTreeView
11531  * @column: %NULL, or the column to draw the expander arrow at.
11532  *
11533  * Sets the column to draw the expander arrow at. It must be in @tree_view.  
11534  * If @column is %NULL, then the expander arrow is always at the first 
11535  * visible column.
11536  *
11537  * If you do not want expander arrow to appear in your tree, set the 
11538  * expander column to a hidden column.
11539  **/
11540 void
11541 gtk_tree_view_set_expander_column (GtkTreeView       *tree_view,
11542                                    GtkTreeViewColumn *column)
11543 {
11544   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11545   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
11546
11547   if (tree_view->priv->expander_column != column)
11548     {
11549       GList *list;
11550
11551       if (column)
11552         {
11553           /* Confirm that column is in tree_view */
11554           for (list = tree_view->priv->columns; list; list = list->next)
11555             if (list->data == column)
11556               break;
11557           g_return_if_fail (list != NULL);
11558         }
11559
11560       tree_view->priv->expander_column = column;
11561       g_object_notify (G_OBJECT (tree_view), "expander-column");
11562     }
11563 }
11564
11565 /**
11566  * gtk_tree_view_get_expander_column:
11567  * @tree_view: A #GtkTreeView
11568  *
11569  * Returns the column that is the current expander column.  This
11570  * column has the expander arrow drawn next to it.
11571  *
11572  * Return value: The expander column.
11573  **/
11574 GtkTreeViewColumn *
11575 gtk_tree_view_get_expander_column (GtkTreeView *tree_view)
11576 {
11577   GList *list;
11578
11579   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11580
11581   for (list = tree_view->priv->columns; list; list = list->next)
11582     if (gtk_tree_view_is_expander_column (tree_view, GTK_TREE_VIEW_COLUMN (list->data)))
11583       return (GtkTreeViewColumn *) list->data;
11584   return NULL;
11585 }
11586
11587
11588 /**
11589  * gtk_tree_view_set_column_drag_function:
11590  * @tree_view: A #GtkTreeView.
11591  * @func: A function to determine which columns are reorderable, or %NULL.
11592  * @user_data: User data to be passed to @func, or %NULL
11593  * @destroy: Destroy notifier for @user_data, or %NULL
11594  *
11595  * Sets a user function for determining where a column may be dropped when
11596  * dragged.  This function is called on every column pair in turn at the
11597  * beginning of a column drag to determine where a drop can take place.  The
11598  * arguments passed to @func are: the @tree_view, the #GtkTreeViewColumn being
11599  * dragged, the two #GtkTreeViewColumn s determining the drop spot, and
11600  * @user_data.  If either of the #GtkTreeViewColumn arguments for the drop spot
11601  * are %NULL, then they indicate an edge.  If @func is set to be %NULL, then
11602  * @tree_view reverts to the default behavior of allowing all columns to be
11603  * dropped everywhere.
11604  **/
11605 void
11606 gtk_tree_view_set_column_drag_function (GtkTreeView               *tree_view,
11607                                         GtkTreeViewColumnDropFunc  func,
11608                                         gpointer                   user_data,
11609                                         GDestroyNotify             destroy)
11610 {
11611   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11612
11613   if (tree_view->priv->column_drop_func_data_destroy)
11614     tree_view->priv->column_drop_func_data_destroy (tree_view->priv->column_drop_func_data);
11615
11616   tree_view->priv->column_drop_func = func;
11617   tree_view->priv->column_drop_func_data = user_data;
11618   tree_view->priv->column_drop_func_data_destroy = destroy;
11619 }
11620
11621 /**
11622  * gtk_tree_view_scroll_to_point:
11623  * @tree_view: a #GtkTreeView
11624  * @tree_x: X coordinate of new top-left pixel of visible area, or -1
11625  * @tree_y: Y coordinate of new top-left pixel of visible area, or -1
11626  *
11627  * Scrolls the tree view such that the top-left corner of the visible
11628  * area is @tree_x, @tree_y, where @tree_x and @tree_y are specified
11629  * in tree coordinates.  The @tree_view must be realized before
11630  * this function is called.  If it isn't, you probably want to be
11631  * using gtk_tree_view_scroll_to_cell().
11632  *
11633  * If either @tree_x or @tree_y are -1, then that direction isn't scrolled.
11634  **/
11635 void
11636 gtk_tree_view_scroll_to_point (GtkTreeView *tree_view,
11637                                gint         tree_x,
11638                                gint         tree_y)
11639 {
11640   GtkAdjustment *hadj;
11641   GtkAdjustment *vadj;
11642
11643   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11644   g_return_if_fail (GTK_WIDGET_REALIZED (tree_view));
11645
11646   hadj = tree_view->priv->hadjustment;
11647   vadj = tree_view->priv->vadjustment;
11648
11649   if (tree_x != -1)
11650     gtk_adjustment_set_value (hadj, CLAMP (tree_x, hadj->lower, hadj->upper - hadj->page_size));
11651   if (tree_y != -1)
11652     gtk_adjustment_set_value (vadj, CLAMP (tree_y, vadj->lower, vadj->upper - vadj->page_size));
11653 }
11654
11655 /**
11656  * gtk_tree_view_scroll_to_cell:
11657  * @tree_view: A #GtkTreeView.
11658  * @path: (allow-none): The path of the row to move to, or %NULL.
11659  * @column: (allow-none): The #GtkTreeViewColumn to move horizontally to, or %NULL.
11660  * @use_align: whether to use alignment arguments, or %FALSE.
11661  * @row_align: The vertical alignment of the row specified by @path.
11662  * @col_align: The horizontal alignment of the column specified by @column.
11663  *
11664  * Moves the alignments of @tree_view to the position specified by @column and
11665  * @path.  If @column is %NULL, then no horizontal scrolling occurs.  Likewise,
11666  * if @path is %NULL no vertical scrolling occurs.  At a minimum, one of @column
11667  * or @path need to be non-%NULL.  @row_align determines where the row is
11668  * placed, and @col_align determines where @column is placed.  Both are expected
11669  * to be between 0.0 and 1.0. 0.0 means left/top alignment, 1.0 means
11670  * right/bottom alignment, 0.5 means center.
11671  *
11672  * If @use_align is %FALSE, then the alignment arguments are ignored, and the
11673  * tree does the minimum amount of work to scroll the cell onto the screen.
11674  * This means that the cell will be scrolled to the edge closest to its current
11675  * position.  If the cell is currently visible on the screen, nothing is done.
11676  *
11677  * This function only works if the model is set, and @path is a valid row on the
11678  * model.  If the model changes before the @tree_view is realized, the centered
11679  * path will be modified to reflect this change.
11680  **/
11681 void
11682 gtk_tree_view_scroll_to_cell (GtkTreeView       *tree_view,
11683                               GtkTreePath       *path,
11684                               GtkTreeViewColumn *column,
11685                               gboolean           use_align,
11686                               gfloat             row_align,
11687                               gfloat             col_align)
11688 {
11689   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11690   g_return_if_fail (tree_view->priv->model != NULL);
11691   g_return_if_fail (tree_view->priv->tree != NULL);
11692   g_return_if_fail (row_align >= 0.0 && row_align <= 1.0);
11693   g_return_if_fail (col_align >= 0.0 && col_align <= 1.0);
11694   g_return_if_fail (path != NULL || column != NULL);
11695
11696 #if 0
11697   g_print ("gtk_tree_view_scroll_to_cell:\npath: %s\ncolumn: %s\nuse_align: %d\nrow_align: %f\ncol_align: %f\n",
11698            gtk_tree_path_to_string (path), column?"non-null":"null", use_align, row_align, col_align);
11699 #endif
11700   row_align = CLAMP (row_align, 0.0, 1.0);
11701   col_align = CLAMP (col_align, 0.0, 1.0);
11702
11703
11704   /* Note: Despite the benefits that come from having one code path for the
11705    * scrolling code, we short-circuit validate_visible_area's immplementation as
11706    * it is much slower than just going to the point.
11707    */
11708   if (! GTK_WIDGET_VISIBLE (tree_view) ||
11709       ! GTK_WIDGET_REALIZED (tree_view) ||
11710       GTK_WIDGET_ALLOC_NEEDED (tree_view) || 
11711       GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID))
11712     {
11713       if (tree_view->priv->scroll_to_path)
11714         gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
11715
11716       tree_view->priv->scroll_to_path = NULL;
11717       tree_view->priv->scroll_to_column = NULL;
11718
11719       if (path)
11720         tree_view->priv->scroll_to_path = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
11721       if (column)
11722         tree_view->priv->scroll_to_column = column;
11723       tree_view->priv->scroll_to_use_align = use_align;
11724       tree_view->priv->scroll_to_row_align = row_align;
11725       tree_view->priv->scroll_to_col_align = col_align;
11726
11727       install_presize_handler (tree_view);
11728     }
11729   else
11730     {
11731       GdkRectangle cell_rect;
11732       GdkRectangle vis_rect;
11733       gint dest_x, dest_y;
11734
11735       gtk_tree_view_get_background_area (tree_view, path, column, &cell_rect);
11736       gtk_tree_view_get_visible_rect (tree_view, &vis_rect);
11737
11738       cell_rect.y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, cell_rect.y);
11739
11740       dest_x = vis_rect.x;
11741       dest_y = vis_rect.y;
11742
11743       if (column)
11744         {
11745           if (use_align)
11746             {
11747               dest_x = cell_rect.x - ((vis_rect.width - cell_rect.width) * col_align);
11748             }
11749           else
11750             {
11751               if (cell_rect.x < vis_rect.x)
11752                 dest_x = cell_rect.x;
11753               if (cell_rect.x + cell_rect.width > vis_rect.x + vis_rect.width)
11754                 dest_x = cell_rect.x + cell_rect.width - vis_rect.width;
11755             }
11756         }
11757
11758       if (path)
11759         {
11760           if (use_align)
11761             {
11762               dest_y = cell_rect.y - ((vis_rect.height - cell_rect.height) * row_align);
11763               dest_y = MAX (dest_y, 0);
11764             }
11765           else
11766             {
11767               if (cell_rect.y < vis_rect.y)
11768                 dest_y = cell_rect.y;
11769               if (cell_rect.y + cell_rect.height > vis_rect.y + vis_rect.height)
11770                 dest_y = cell_rect.y + cell_rect.height - vis_rect.height;
11771             }
11772         }
11773
11774       gtk_tree_view_scroll_to_point (tree_view, dest_x, dest_y);
11775     }
11776 }
11777
11778 /**
11779  * gtk_tree_view_row_activated:
11780  * @tree_view: A #GtkTreeView
11781  * @path: The #GtkTreePath to be activated.
11782  * @column: The #GtkTreeViewColumn to be activated.
11783  *
11784  * Activates the cell determined by @path and @column.
11785  **/
11786 void
11787 gtk_tree_view_row_activated (GtkTreeView       *tree_view,
11788                              GtkTreePath       *path,
11789                              GtkTreeViewColumn *column)
11790 {
11791   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11792
11793   g_signal_emit (tree_view, tree_view_signals[ROW_ACTIVATED], 0, path, column);
11794 }
11795
11796
11797 static void
11798 gtk_tree_view_expand_all_emission_helper (GtkRBTree *tree,
11799                                           GtkRBNode *node,
11800                                           gpointer   data)
11801 {
11802   GtkTreeView *tree_view = data;
11803
11804   if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT &&
11805       node->children)
11806     {
11807       GtkTreePath *path;
11808       GtkTreeIter iter;
11809
11810       path = _gtk_tree_view_find_path (tree_view, tree, node);
11811       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
11812
11813       g_signal_emit (tree_view, tree_view_signals[ROW_EXPANDED], 0, &iter, path);
11814
11815       gtk_tree_path_free (path);
11816     }
11817
11818   if (node->children)
11819     _gtk_rbtree_traverse (node->children,
11820                           node->children->root,
11821                           G_PRE_ORDER,
11822                           gtk_tree_view_expand_all_emission_helper,
11823                           tree_view);
11824 }
11825
11826 /**
11827  * gtk_tree_view_expand_all:
11828  * @tree_view: A #GtkTreeView.
11829  *
11830  * Recursively expands all nodes in the @tree_view.
11831  **/
11832 void
11833 gtk_tree_view_expand_all (GtkTreeView *tree_view)
11834 {
11835   GtkTreePath *path;
11836   GtkRBTree *tree;
11837   GtkRBNode *node;
11838
11839   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11840
11841   if (tree_view->priv->tree == NULL)
11842     return;
11843
11844   path = gtk_tree_path_new_first ();
11845   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
11846
11847   while (node)
11848     {
11849       gtk_tree_view_real_expand_row (tree_view, path, tree, node, TRUE, FALSE);
11850       node = _gtk_rbtree_next (tree, node);
11851       gtk_tree_path_next (path);
11852   }
11853
11854   gtk_tree_path_free (path);
11855 }
11856
11857 /* Timeout to animate the expander during expands and collapses */
11858 static gboolean
11859 expand_collapse_timeout (gpointer data)
11860 {
11861   return do_expand_collapse (data);
11862 }
11863
11864 static void
11865 add_expand_collapse_timeout (GtkTreeView *tree_view,
11866                              GtkRBTree   *tree,
11867                              GtkRBNode   *node,
11868                              gboolean     expand)
11869 {
11870   if (tree_view->priv->expand_collapse_timeout != 0)
11871     return;
11872
11873   tree_view->priv->expand_collapse_timeout =
11874       gdk_threads_add_timeout (50, expand_collapse_timeout, tree_view);
11875   tree_view->priv->expanded_collapsed_tree = tree;
11876   tree_view->priv->expanded_collapsed_node = node;
11877
11878   if (expand)
11879     GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
11880   else
11881     GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
11882 }
11883
11884 static void
11885 remove_expand_collapse_timeout (GtkTreeView *tree_view)
11886 {
11887   if (tree_view->priv->expand_collapse_timeout)
11888     {
11889       g_source_remove (tree_view->priv->expand_collapse_timeout);
11890       tree_view->priv->expand_collapse_timeout = 0;
11891     }
11892
11893   if (tree_view->priv->expanded_collapsed_node != NULL)
11894     {
11895       GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_EXPANDED);
11896       GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_COLLAPSED);
11897
11898       tree_view->priv->expanded_collapsed_node = NULL;
11899     }
11900 }
11901
11902 static void
11903 cancel_arrow_animation (GtkTreeView *tree_view)
11904 {
11905   if (tree_view->priv->expand_collapse_timeout)
11906     {
11907       while (do_expand_collapse (tree_view));
11908
11909       remove_expand_collapse_timeout (tree_view);
11910     }
11911 }
11912
11913 static gboolean
11914 do_expand_collapse (GtkTreeView *tree_view)
11915 {
11916   GtkRBNode *node;
11917   GtkRBTree *tree;
11918   gboolean expanding;
11919   gboolean redraw;
11920
11921   redraw = FALSE;
11922   expanding = TRUE;
11923
11924   node = tree_view->priv->expanded_collapsed_node;
11925   tree = tree_view->priv->expanded_collapsed_tree;
11926
11927   if (node->children == NULL)
11928     expanding = FALSE;
11929
11930   if (expanding)
11931     {
11932       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_COLLAPSED))
11933         {
11934           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
11935           GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
11936
11937           redraw = TRUE;
11938
11939         }
11940       else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_EXPANDED))
11941         {
11942           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
11943
11944           redraw = TRUE;
11945         }
11946     }
11947   else
11948     {
11949       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_EXPANDED))
11950         {
11951           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
11952           GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
11953
11954           redraw = TRUE;
11955         }
11956       else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_COLLAPSED))
11957         {
11958           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
11959
11960           redraw = TRUE;
11961
11962         }
11963     }
11964
11965   if (redraw)
11966     {
11967       gtk_tree_view_queue_draw_arrow (tree_view, tree, node, NULL);
11968
11969       return TRUE;
11970     }
11971
11972   return FALSE;
11973 }
11974
11975 /**
11976  * gtk_tree_view_collapse_all:
11977  * @tree_view: A #GtkTreeView.
11978  *
11979  * Recursively collapses all visible, expanded nodes in @tree_view.
11980  **/
11981 void
11982 gtk_tree_view_collapse_all (GtkTreeView *tree_view)
11983 {
11984   GtkRBTree *tree;
11985   GtkRBNode *node;
11986   GtkTreePath *path;
11987   gint *indices;
11988
11989   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11990
11991   if (tree_view->priv->tree == NULL)
11992     return;
11993
11994   path = gtk_tree_path_new ();
11995   gtk_tree_path_down (path);
11996   indices = gtk_tree_path_get_indices (path);
11997
11998   tree = tree_view->priv->tree;
11999   node = tree->root;
12000   while (node && node->left != tree->nil)
12001     node = node->left;
12002
12003   while (node)
12004     {
12005       if (node->children)
12006         gtk_tree_view_real_collapse_row (tree_view, path, tree, node, FALSE);
12007       indices[0]++;
12008       node = _gtk_rbtree_next (tree, node);
12009     }
12010
12011   gtk_tree_path_free (path);
12012 }
12013
12014 /**
12015  * gtk_tree_view_expand_to_path:
12016  * @tree_view: A #GtkTreeView.
12017  * @path: path to a row.
12018  *
12019  * Expands the row at @path. This will also expand all parent rows of
12020  * @path as necessary.
12021  *
12022  * Since: 2.2
12023  **/
12024 void
12025 gtk_tree_view_expand_to_path (GtkTreeView *tree_view,
12026                               GtkTreePath *path)
12027 {
12028   gint i, depth;
12029   gint *indices;
12030   GtkTreePath *tmp;
12031
12032   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12033   g_return_if_fail (path != NULL);
12034
12035   depth = gtk_tree_path_get_depth (path);
12036   indices = gtk_tree_path_get_indices (path);
12037
12038   tmp = gtk_tree_path_new ();
12039   g_return_if_fail (tmp != NULL);
12040
12041   for (i = 0; i < depth; i++)
12042     {
12043       gtk_tree_path_append_index (tmp, indices[i]);
12044       gtk_tree_view_expand_row (tree_view, tmp, FALSE);
12045     }
12046
12047   gtk_tree_path_free (tmp);
12048 }
12049
12050 /* FIXME the bool return values for expand_row and collapse_row are
12051  * not analagous; they should be TRUE if the row had children and
12052  * was not already in the requested state.
12053  */
12054
12055
12056 static gboolean
12057 gtk_tree_view_real_expand_row (GtkTreeView *tree_view,
12058                                GtkTreePath *path,
12059                                GtkRBTree   *tree,
12060                                GtkRBNode   *node,
12061                                gboolean     open_all,
12062                                gboolean     animate)
12063 {
12064   GtkTreeIter iter;
12065   GtkTreeIter temp;
12066   gboolean expand;
12067
12068   if (animate)
12069     g_object_get (gtk_widget_get_settings (GTK_WIDGET (tree_view)),
12070                   "gtk-enable-animations", &animate,
12071                   NULL);
12072
12073   remove_auto_expand_timeout (tree_view);
12074
12075   if (node->children && !open_all)
12076     return FALSE;
12077
12078   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
12079     return FALSE;
12080
12081   gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
12082   if (! gtk_tree_model_iter_has_child (tree_view->priv->model, &iter))
12083     return FALSE;
12084
12085
12086    if (node->children && open_all)
12087     {
12088       gboolean retval = FALSE;
12089       GtkTreePath *tmp_path = gtk_tree_path_copy (path);
12090
12091       gtk_tree_path_append_index (tmp_path, 0);
12092       tree = node->children;
12093       node = tree->root;
12094       while (node->left != tree->nil)
12095         node = node->left;
12096       /* try to expand the children */
12097       do
12098         {
12099          gboolean t;
12100          t = gtk_tree_view_real_expand_row (tree_view, tmp_path, tree, node,
12101                                             TRUE, animate);
12102          if (t)
12103            retval = TRUE;
12104
12105          gtk_tree_path_next (tmp_path);
12106          node = _gtk_rbtree_next (tree, node);
12107        }
12108       while (node != NULL);
12109
12110       gtk_tree_path_free (tmp_path);
12111
12112       return retval;
12113     }
12114
12115   g_signal_emit (tree_view, tree_view_signals[TEST_EXPAND_ROW], 0, &iter, path, &expand);
12116
12117   if (!gtk_tree_model_iter_has_child (tree_view->priv->model, &iter))
12118     return FALSE;
12119
12120   if (expand)
12121     return FALSE;
12122
12123   node->children = _gtk_rbtree_new ();
12124   node->children->parent_tree = tree;
12125   node->children->parent_node = node;
12126
12127   gtk_tree_model_iter_children (tree_view->priv->model, &temp, &iter);
12128
12129   gtk_tree_view_build_tree (tree_view,
12130                             node->children,
12131                             &temp,
12132                             gtk_tree_path_get_depth (path) + 1,
12133                             open_all);
12134
12135   remove_expand_collapse_timeout (tree_view);
12136
12137   if (animate)
12138     add_expand_collapse_timeout (tree_view, tree, node, TRUE);
12139
12140   install_presize_handler (tree_view);
12141
12142   g_signal_emit (tree_view, tree_view_signals[ROW_EXPANDED], 0, &iter, path);
12143   if (open_all && node->children)
12144     {
12145       _gtk_rbtree_traverse (node->children,
12146                             node->children->root,
12147                             G_PRE_ORDER,
12148                             gtk_tree_view_expand_all_emission_helper,
12149                             tree_view);
12150     }
12151   return TRUE;
12152 }
12153
12154
12155 /**
12156  * gtk_tree_view_expand_row:
12157  * @tree_view: a #GtkTreeView
12158  * @path: path to a row
12159  * @open_all: whether to recursively expand, or just expand immediate children
12160  *
12161  * Opens the row so its children are visible.
12162  *
12163  * Return value: %TRUE if the row existed and had children
12164  **/
12165 gboolean
12166 gtk_tree_view_expand_row (GtkTreeView *tree_view,
12167                           GtkTreePath *path,
12168                           gboolean     open_all)
12169 {
12170   GtkRBTree *tree;
12171   GtkRBNode *node;
12172
12173   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12174   g_return_val_if_fail (tree_view->priv->model != NULL, FALSE);
12175   g_return_val_if_fail (path != NULL, FALSE);
12176
12177   if (_gtk_tree_view_find_node (tree_view,
12178                                 path,
12179                                 &tree,
12180                                 &node))
12181     return FALSE;
12182
12183   if (tree != NULL)
12184     return gtk_tree_view_real_expand_row (tree_view, path, tree, node, open_all, FALSE);
12185   else
12186     return FALSE;
12187 }
12188
12189 static gboolean
12190 gtk_tree_view_real_collapse_row (GtkTreeView *tree_view,
12191                                  GtkTreePath *path,
12192                                  GtkRBTree   *tree,
12193                                  GtkRBNode   *node,
12194                                  gboolean     animate)
12195 {
12196   GtkTreeIter iter;
12197   GtkTreeIter children;
12198   gboolean collapse;
12199   gint x, y;
12200   GList *list;
12201   GdkWindow *child, *parent;
12202
12203   if (animate)
12204     g_object_get (gtk_widget_get_settings (GTK_WIDGET (tree_view)),
12205                   "gtk-enable-animations", &animate,
12206                   NULL);
12207
12208   remove_auto_expand_timeout (tree_view);
12209
12210   if (node->children == NULL)
12211     return FALSE;
12212
12213   gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
12214
12215   g_signal_emit (tree_view, tree_view_signals[TEST_COLLAPSE_ROW], 0, &iter, path, &collapse);
12216
12217   if (collapse)
12218     return FALSE;
12219
12220   /* if the prelighted node is a child of us, we want to unprelight it.  We have
12221    * a chance to prelight the correct node below */
12222
12223   if (tree_view->priv->prelight_tree)
12224     {
12225       GtkRBTree *parent_tree;
12226       GtkRBNode *parent_node;
12227
12228       parent_tree = tree_view->priv->prelight_tree->parent_tree;
12229       parent_node = tree_view->priv->prelight_tree->parent_node;
12230       while (parent_tree)
12231         {
12232           if (parent_tree == tree && parent_node == node)
12233             {
12234               ensure_unprelighted (tree_view);
12235               break;
12236             }
12237           parent_node = parent_tree->parent_node;
12238           parent_tree = parent_tree->parent_tree;
12239         }
12240     }
12241
12242   TREE_VIEW_INTERNAL_ASSERT (gtk_tree_model_iter_children (tree_view->priv->model, &children, &iter), FALSE);
12243
12244   for (list = tree_view->priv->columns; list; list = list->next)
12245     {
12246       GtkTreeViewColumn *column = list->data;
12247
12248       if (column->visible == FALSE)
12249         continue;
12250       if (gtk_tree_view_column_get_sizing (column) == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
12251         _gtk_tree_view_column_cell_set_dirty (column, TRUE);
12252     }
12253
12254   if (tree_view->priv->destroy_count_func)
12255     {
12256       GtkTreePath *child_path;
12257       gint child_count = 0;
12258       child_path = gtk_tree_path_copy (path);
12259       gtk_tree_path_down (child_path);
12260       if (node->children)
12261         _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, &child_count);
12262       tree_view->priv->destroy_count_func (tree_view, child_path, child_count, tree_view->priv->destroy_count_data);
12263       gtk_tree_path_free (child_path);
12264     }
12265
12266   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
12267     {
12268       GtkTreePath *cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
12269
12270       if (gtk_tree_path_is_ancestor (path, cursor_path))
12271         {
12272           gtk_tree_row_reference_free (tree_view->priv->cursor);
12273           tree_view->priv->cursor = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
12274                                                                       tree_view->priv->model,
12275                                                                       path);
12276         }
12277       gtk_tree_path_free (cursor_path);
12278     }
12279
12280   if (gtk_tree_row_reference_valid (tree_view->priv->anchor))
12281     {
12282       GtkTreePath *anchor_path = gtk_tree_row_reference_get_path (tree_view->priv->anchor);
12283       if (gtk_tree_path_is_ancestor (path, anchor_path))
12284         {
12285           gtk_tree_row_reference_free (tree_view->priv->anchor);
12286           tree_view->priv->anchor = NULL;
12287         }
12288       gtk_tree_path_free (anchor_path);
12289     }
12290
12291   /* Stop a pending double click */
12292   tree_view->priv->last_button_x = -1;
12293   tree_view->priv->last_button_y = -1;
12294
12295   remove_expand_collapse_timeout (tree_view);
12296
12297   if (gtk_tree_view_unref_and_check_selection_tree (tree_view, node->children))
12298     {
12299       _gtk_rbtree_remove (node->children);
12300       g_signal_emit_by_name (tree_view->priv->selection, "changed");
12301     }
12302   else
12303     _gtk_rbtree_remove (node->children);
12304   
12305   if (animate)
12306     add_expand_collapse_timeout (tree_view, tree, node, FALSE);
12307   
12308   if (GTK_WIDGET_MAPPED (tree_view))
12309     {
12310       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
12311     }
12312
12313   g_signal_emit (tree_view, tree_view_signals[ROW_COLLAPSED], 0, &iter, path);
12314
12315   if (GTK_WIDGET_MAPPED (tree_view))
12316     {
12317       /* now that we've collapsed all rows, we want to try to set the prelight
12318        * again. To do this, we fake a motion event and send it to ourselves. */
12319
12320       child = tree_view->priv->bin_window;
12321       parent = gdk_window_get_parent (child);
12322
12323       if (gdk_window_get_pointer (parent, &x, &y, NULL) == child)
12324         {
12325           GdkEventMotion event;
12326           gint child_x, child_y;
12327
12328           gdk_window_get_position (child, &child_x, &child_y);
12329
12330           event.window = tree_view->priv->bin_window;
12331           event.x = x - child_x;
12332           event.y = y - child_y;
12333
12334           /* despite the fact this isn't a real event, I'm almost positive it will
12335            * never trigger a drag event.  maybe_drag is the only function that uses
12336            * more than just event.x and event.y. */
12337           gtk_tree_view_motion_bin_window (GTK_WIDGET (tree_view), &event);
12338         }
12339     }
12340
12341   return TRUE;
12342 }
12343
12344 /**
12345  * gtk_tree_view_collapse_row:
12346  * @tree_view: a #GtkTreeView
12347  * @path: path to a row in the @tree_view
12348  *
12349  * Collapses a row (hides its child rows, if they exist).
12350  *
12351  * Return value: %TRUE if the row was collapsed.
12352  **/
12353 gboolean
12354 gtk_tree_view_collapse_row (GtkTreeView *tree_view,
12355                             GtkTreePath *path)
12356 {
12357   GtkRBTree *tree;
12358   GtkRBNode *node;
12359
12360   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12361   g_return_val_if_fail (tree_view->priv->tree != NULL, FALSE);
12362   g_return_val_if_fail (path != NULL, FALSE);
12363
12364   if (_gtk_tree_view_find_node (tree_view,
12365                                 path,
12366                                 &tree,
12367                                 &node))
12368     return FALSE;
12369
12370   if (tree == NULL || node->children == NULL)
12371     return FALSE;
12372
12373   return gtk_tree_view_real_collapse_row (tree_view, path, tree, node, FALSE);
12374 }
12375
12376 static void
12377 gtk_tree_view_map_expanded_rows_helper (GtkTreeView            *tree_view,
12378                                         GtkRBTree              *tree,
12379                                         GtkTreePath            *path,
12380                                         GtkTreeViewMappingFunc  func,
12381                                         gpointer                user_data)
12382 {
12383   GtkRBNode *node;
12384
12385   if (tree == NULL || tree->root == NULL)
12386     return;
12387
12388   node = tree->root;
12389
12390   while (node && node->left != tree->nil)
12391     node = node->left;
12392
12393   while (node)
12394     {
12395       if (node->children)
12396         {
12397           (* func) (tree_view, path, user_data);
12398           gtk_tree_path_down (path);
12399           gtk_tree_view_map_expanded_rows_helper (tree_view, node->children, path, func, user_data);
12400           gtk_tree_path_up (path);
12401         }
12402       gtk_tree_path_next (path);
12403       node = _gtk_rbtree_next (tree, node);
12404     }
12405 }
12406
12407 /**
12408  * gtk_tree_view_map_expanded_rows:
12409  * @tree_view: A #GtkTreeView
12410  * @func: A function to be called
12411  * @data: User data to be passed to the function.
12412  *
12413  * Calls @func on all expanded rows.
12414  **/
12415 void
12416 gtk_tree_view_map_expanded_rows (GtkTreeView            *tree_view,
12417                                  GtkTreeViewMappingFunc  func,
12418                                  gpointer                user_data)
12419 {
12420   GtkTreePath *path;
12421
12422   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12423   g_return_if_fail (func != NULL);
12424
12425   path = gtk_tree_path_new_first ();
12426
12427   gtk_tree_view_map_expanded_rows_helper (tree_view,
12428                                           tree_view->priv->tree,
12429                                           path, func, user_data);
12430
12431   gtk_tree_path_free (path);
12432 }
12433
12434 /**
12435  * gtk_tree_view_row_expanded:
12436  * @tree_view: A #GtkTreeView.
12437  * @path: A #GtkTreePath to test expansion state.
12438  *
12439  * Returns %TRUE if the node pointed to by @path is expanded in @tree_view.
12440  *
12441  * Return value: %TRUE if #path is expanded.
12442  **/
12443 gboolean
12444 gtk_tree_view_row_expanded (GtkTreeView *tree_view,
12445                             GtkTreePath *path)
12446 {
12447   GtkRBTree *tree;
12448   GtkRBNode *node;
12449
12450   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12451   g_return_val_if_fail (path != NULL, FALSE);
12452
12453   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
12454
12455   if (node == NULL)
12456     return FALSE;
12457
12458   return (node->children != NULL);
12459 }
12460
12461 /**
12462  * gtk_tree_view_get_reorderable:
12463  * @tree_view: a #GtkTreeView
12464  *
12465  * Retrieves whether the user can reorder the tree via drag-and-drop. See
12466  * gtk_tree_view_set_reorderable().
12467  *
12468  * Return value: %TRUE if the tree can be reordered.
12469  **/
12470 gboolean
12471 gtk_tree_view_get_reorderable (GtkTreeView *tree_view)
12472 {
12473   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12474
12475   return tree_view->priv->reorderable;
12476 }
12477
12478 /**
12479  * gtk_tree_view_set_reorderable:
12480  * @tree_view: A #GtkTreeView.
12481  * @reorderable: %TRUE, if the tree can be reordered.
12482  *
12483  * This function is a convenience function to allow you to reorder
12484  * models that support the #GtkDragSourceIface and the
12485  * #GtkDragDestIface.  Both #GtkTreeStore and #GtkListStore support
12486  * these.  If @reorderable is %TRUE, then the user can reorder the
12487  * model by dragging and dropping rows. The developer can listen to
12488  * these changes by connecting to the model's row_inserted and
12489  * row_deleted signals. The reordering is implemented by setting up
12490  * the tree view as a drag source and destination. Therefore, drag and
12491  * drop can not be used in a reorderable view for any other purpose.
12492  *
12493  * This function does not give you any degree of control over the order -- any
12494  * reordering is allowed.  If more control is needed, you should probably
12495  * handle drag and drop manually.
12496  **/
12497 void
12498 gtk_tree_view_set_reorderable (GtkTreeView *tree_view,
12499                                gboolean     reorderable)
12500 {
12501   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12502
12503   reorderable = reorderable != FALSE;
12504
12505   if (tree_view->priv->reorderable == reorderable)
12506     return;
12507
12508   if (reorderable)
12509     {
12510       const GtkTargetEntry row_targets[] = {
12511         { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, 0 }
12512       };
12513
12514       gtk_tree_view_enable_model_drag_source (tree_view,
12515                                               GDK_BUTTON1_MASK,
12516                                               row_targets,
12517                                               G_N_ELEMENTS (row_targets),
12518                                               GDK_ACTION_MOVE);
12519       gtk_tree_view_enable_model_drag_dest (tree_view,
12520                                             row_targets,
12521                                             G_N_ELEMENTS (row_targets),
12522                                             GDK_ACTION_MOVE);
12523     }
12524   else
12525     {
12526       gtk_tree_view_unset_rows_drag_source (tree_view);
12527       gtk_tree_view_unset_rows_drag_dest (tree_view);
12528     }
12529
12530   tree_view->priv->reorderable = reorderable;
12531
12532   g_object_notify (G_OBJECT (tree_view), "reorderable");
12533 }
12534
12535 static void
12536 gtk_tree_view_real_set_cursor (GtkTreeView     *tree_view,
12537                                GtkTreePath     *path,
12538                                gboolean         clear_and_select,
12539                                gboolean         clamp_node)
12540 {
12541   GtkRBTree *tree = NULL;
12542   GtkRBNode *node = NULL;
12543
12544   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
12545     {
12546       GtkTreePath *cursor_path;
12547       cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
12548       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
12549       gtk_tree_path_free (cursor_path);
12550     }
12551
12552   gtk_tree_row_reference_free (tree_view->priv->cursor);
12553   tree_view->priv->cursor = NULL;
12554
12555   /* One cannot set the cursor on a separator.   Also, if
12556    * _gtk_tree_view_find_node returns TRUE, it ran out of tree
12557    * before finding the tree and node belonging to path.  The
12558    * path maps to a non-existing path and we will silently bail out.
12559    * We unset tree and node to avoid further processing.
12560    */
12561   if (!row_is_separator (tree_view, NULL, path)
12562       && _gtk_tree_view_find_node (tree_view, path, &tree, &node) == FALSE)
12563     {
12564       tree_view->priv->cursor =
12565           gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
12566                                             tree_view->priv->model,
12567                                             path);
12568     }
12569   else
12570     {
12571       tree = NULL;
12572       node = NULL;
12573     }
12574
12575   if (tree != NULL)
12576     {
12577       GtkRBTree *new_tree = NULL;
12578       GtkRBNode *new_node = NULL;
12579
12580       if (clear_and_select && !tree_view->priv->ctrl_pressed)
12581         {
12582           GtkTreeSelectMode mode = 0;
12583
12584           if (tree_view->priv->ctrl_pressed)
12585             mode |= GTK_TREE_SELECT_MODE_TOGGLE;
12586           if (tree_view->priv->shift_pressed)
12587             mode |= GTK_TREE_SELECT_MODE_EXTEND;
12588
12589           _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
12590                                                     node, tree, path, mode,
12591                                                     FALSE);
12592         }
12593
12594       /* We have to re-find tree and node here again, somebody might have
12595        * cleared the node or the whole tree in the GtkTreeSelection::changed
12596        * callback. If the nodes differ we bail out here.
12597        */
12598       _gtk_tree_view_find_node (tree_view, path, &new_tree, &new_node);
12599
12600       if (tree != new_tree || node != new_node)
12601         return;
12602
12603       if (clamp_node)
12604         {
12605           gtk_tree_view_clamp_node_visible (tree_view, tree, node);
12606           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
12607         }
12608     }
12609
12610   g_signal_emit (tree_view, tree_view_signals[CURSOR_CHANGED], 0);
12611 }
12612
12613 /**
12614  * gtk_tree_view_get_cursor:
12615  * @tree_view: A #GtkTreeView
12616  * @path: A pointer to be filled with the current cursor path, or %NULL
12617  * @focus_column: A pointer to be filled with the current focus column, or %NULL
12618  *
12619  * Fills in @path and @focus_column with the current path and focus column.  If
12620  * the cursor isn't currently set, then *@path will be %NULL.  If no column
12621  * currently has focus, then *@focus_column will be %NULL.
12622  *
12623  * The returned #GtkTreePath must be freed with gtk_tree_path_free() when
12624  * you are done with it.
12625  **/
12626 void
12627 gtk_tree_view_get_cursor (GtkTreeView        *tree_view,
12628                           GtkTreePath       **path,
12629                           GtkTreeViewColumn **focus_column)
12630 {
12631   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12632
12633   if (path)
12634     {
12635       if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
12636         *path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
12637       else
12638         *path = NULL;
12639     }
12640
12641   if (focus_column)
12642     {
12643       *focus_column = tree_view->priv->focus_column;
12644     }
12645 }
12646
12647 /**
12648  * gtk_tree_view_set_cursor:
12649  * @tree_view: A #GtkTreeView
12650  * @path: A #GtkTreePath
12651  * @focus_column: (allow-none): A #GtkTreeViewColumn, or %NULL
12652  * @start_editing: %TRUE if the specified cell should start being edited.
12653  *
12654  * Sets the current keyboard focus to be at @path, and selects it.  This is
12655  * useful when you want to focus the user's attention on a particular row.  If
12656  * @focus_column is not %NULL, then focus is given to the column specified by 
12657  * it. Additionally, if @focus_column is specified, and @start_editing is 
12658  * %TRUE, then editing should be started in the specified cell.  
12659  * This function is often followed by @gtk_widget_grab_focus (@tree_view) 
12660  * in order to give keyboard focus to the widget.  Please note that editing 
12661  * can only happen when the widget is realized.
12662  *
12663  * If @path is invalid for @model, the current cursor (if any) will be unset
12664  * and the function will return without failing.
12665  **/
12666 void
12667 gtk_tree_view_set_cursor (GtkTreeView       *tree_view,
12668                           GtkTreePath       *path,
12669                           GtkTreeViewColumn *focus_column,
12670                           gboolean           start_editing)
12671 {
12672   gtk_tree_view_set_cursor_on_cell (tree_view, path, focus_column,
12673                                     NULL, start_editing);
12674 }
12675
12676 /**
12677  * gtk_tree_view_set_cursor_on_cell:
12678  * @tree_view: A #GtkTreeView
12679  * @path: A #GtkTreePath
12680  * @focus_column: (allow-none): A #GtkTreeViewColumn, or %NULL
12681  * @focus_cell: (allow-none): A #GtkCellRenderer, or %NULL
12682  * @start_editing: %TRUE if the specified cell should start being edited.
12683  *
12684  * Sets the current keyboard focus to be at @path, and selects it.  This is
12685  * useful when you want to focus the user's attention on a particular row.  If
12686  * @focus_column is not %NULL, then focus is given to the column specified by
12687  * it. If @focus_column and @focus_cell are not %NULL, and @focus_column
12688  * contains 2 or more editable or activatable cells, then focus is given to
12689  * the cell specified by @focus_cell. Additionally, if @focus_column is
12690  * specified, and @start_editing is %TRUE, then editing should be started in
12691  * the specified cell.  This function is often followed by
12692  * @gtk_widget_grab_focus (@tree_view) in order to give keyboard focus to the
12693  * widget.  Please note that editing can only happen when the widget is
12694  * realized.
12695  *
12696  * If @path is invalid for @model, the current cursor (if any) will be unset
12697  * and the function will return without failing.
12698  *
12699  * Since: 2.2
12700  **/
12701 void
12702 gtk_tree_view_set_cursor_on_cell (GtkTreeView       *tree_view,
12703                                   GtkTreePath       *path,
12704                                   GtkTreeViewColumn *focus_column,
12705                                   GtkCellRenderer   *focus_cell,
12706                                   gboolean           start_editing)
12707 {
12708   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12709   g_return_if_fail (path != NULL);
12710   g_return_if_fail (focus_column == NULL || GTK_IS_TREE_VIEW_COLUMN (focus_column));
12711
12712   if (!tree_view->priv->model)
12713     return;
12714
12715   if (focus_cell)
12716     {
12717       g_return_if_fail (focus_column);
12718       g_return_if_fail (GTK_IS_CELL_RENDERER (focus_cell));
12719     }
12720
12721   /* cancel the current editing, if it exists */
12722   if (tree_view->priv->edited_column &&
12723       tree_view->priv->edited_column->editable_widget)
12724     gtk_tree_view_stop_editing (tree_view, TRUE);
12725
12726   gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
12727
12728   if (focus_column && focus_column->visible)
12729     {
12730       GList *list;
12731       gboolean column_in_tree = FALSE;
12732
12733       for (list = tree_view->priv->columns; list; list = list->next)
12734         if (list->data == focus_column)
12735           {
12736             column_in_tree = TRUE;
12737             break;
12738           }
12739       g_return_if_fail (column_in_tree);
12740       tree_view->priv->focus_column = focus_column;
12741       if (focus_cell)
12742         gtk_tree_view_column_focus_cell (focus_column, focus_cell);
12743       if (start_editing)
12744         gtk_tree_view_start_editing (tree_view, path);
12745     }
12746 }
12747
12748 /**
12749  * gtk_tree_view_get_bin_window:
12750  * @tree_view: A #GtkTreeView
12751  * 
12752  * Returns the window that @tree_view renders to.  This is used primarily to
12753  * compare to <literal>event->window</literal> to confirm that the event on
12754  * @tree_view is on the right window.
12755  * 
12756  * Return value: A #GdkWindow, or %NULL when @tree_view hasn't been realized yet
12757  **/
12758 GdkWindow *
12759 gtk_tree_view_get_bin_window (GtkTreeView *tree_view)
12760 {
12761   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
12762
12763   return tree_view->priv->bin_window;
12764 }
12765
12766 /**
12767  * gtk_tree_view_get_path_at_pos:
12768  * @tree_view: A #GtkTreeView.
12769  * @x: The x position to be identified (relative to bin_window).
12770  * @y: The y position to be identified (relative to bin_window).
12771  * @path: A pointer to a #GtkTreePath pointer to be filled in, or %NULL
12772  * @column: A pointer to a #GtkTreeViewColumn pointer to be filled in, or %NULL
12773  * @cell_x: A pointer where the X coordinate relative to the cell can be placed, or %NULL
12774  * @cell_y: A pointer where the Y coordinate relative to the cell can be placed, or %NULL
12775  *
12776  * Finds the path at the point (@x, @y), relative to bin_window coordinates
12777  * (please see gtk_tree_view_get_bin_window()).
12778  * That is, @x and @y are relative to an events coordinates. @x and @y must
12779  * come from an event on the @tree_view only where <literal>event->window ==
12780  * gtk_tree_view_get_bin_window (<!-- -->)</literal>. It is primarily for
12781  * things like popup menus. If @path is non-%NULL, then it will be filled
12782  * with the #GtkTreePath at that point.  This path should be freed with
12783  * gtk_tree_path_free().  If @column is non-%NULL, then it will be filled
12784  * with the column at that point.  @cell_x and @cell_y return the coordinates
12785  * relative to the cell background (i.e. the @background_area passed to
12786  * gtk_cell_renderer_render()).  This function is only meaningful if
12787  * @tree_view is realized.  Therefore this function will always return %FALSE
12788  * if @tree_view is not realized or does not have a model.
12789  *
12790  * For converting widget coordinates (eg. the ones you get from
12791  * GtkWidget::query-tooltip), please see
12792  * gtk_tree_view_convert_widget_to_bin_window_coords().
12793  *
12794  * Return value: %TRUE if a row exists at that coordinate.
12795  **/
12796 gboolean
12797 gtk_tree_view_get_path_at_pos (GtkTreeView        *tree_view,
12798                                gint                x,
12799                                gint                y,
12800                                GtkTreePath       **path,
12801                                GtkTreeViewColumn **column,
12802                                gint               *cell_x,
12803                                gint               *cell_y)
12804 {
12805   GtkRBTree *tree;
12806   GtkRBNode *node;
12807   gint y_offset;
12808
12809   g_return_val_if_fail (tree_view != NULL, FALSE);
12810
12811   if (path)
12812     *path = NULL;
12813   if (column)
12814     *column = NULL;
12815
12816   if (tree_view->priv->bin_window == NULL)
12817     return FALSE;
12818
12819   if (tree_view->priv->tree == NULL)
12820     return FALSE;
12821
12822   if (x > tree_view->priv->hadjustment->upper)
12823     return FALSE;
12824
12825   if (x < 0 || y < 0)
12826     return FALSE;
12827
12828   if (column || cell_x)
12829     {
12830       GtkTreeViewColumn *tmp_column;
12831       GtkTreeViewColumn *last_column = NULL;
12832       GList *list;
12833       gint remaining_x = x;
12834       gboolean found = FALSE;
12835       gboolean rtl;
12836
12837       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
12838       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
12839            list;
12840            list = (rtl ? list->prev : list->next))
12841         {
12842           tmp_column = list->data;
12843
12844           if (tmp_column->visible == FALSE)
12845             continue;
12846
12847           last_column = tmp_column;
12848           if (remaining_x <= tmp_column->width)
12849             {
12850               found = TRUE;
12851
12852               if (column)
12853                 *column = tmp_column;
12854
12855               if (cell_x)
12856                 *cell_x = remaining_x;
12857
12858               break;
12859             }
12860           remaining_x -= tmp_column->width;
12861         }
12862
12863       /* If found is FALSE and there is a last_column, then it the remainder
12864        * space is in that area
12865        */
12866       if (!found)
12867         {
12868           if (last_column)
12869             {
12870               if (column)
12871                 *column = last_column;
12872               
12873               if (cell_x)
12874                 *cell_x = last_column->width + remaining_x;
12875             }
12876           else
12877             {
12878               return FALSE;
12879             }
12880         }
12881     }
12882
12883   y_offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
12884                                       TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, y),
12885                                       &tree, &node);
12886
12887   if (tree == NULL)
12888     return FALSE;
12889
12890   if (cell_y)
12891     *cell_y = y_offset;
12892
12893   if (path)
12894     *path = _gtk_tree_view_find_path (tree_view, tree, node);
12895
12896   return TRUE;
12897 }
12898
12899
12900 /**
12901  * gtk_tree_view_get_cell_area:
12902  * @tree_view: a #GtkTreeView
12903  * @path: (allow-none): a #GtkTreePath for the row, or %NULL to get only horizontal coordinates
12904  * @column: (allow-none): a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordinates
12905  * @rect: rectangle to fill with cell rect
12906  *
12907  * Fills the bounding rectangle in bin_window coordinates for the cell at the
12908  * row specified by @path and the column specified by @column.  If @path is
12909  * %NULL, or points to a path not currently displayed, the @y and @height fields
12910  * of the rectangle will be filled with 0. If @column is %NULL, the @x and @width
12911  * fields will be filled with 0.  The sum of all cell rects does not cover the
12912  * entire tree; there are extra pixels in between rows, for example. The
12913  * returned rectangle is equivalent to the @cell_area passed to
12914  * gtk_cell_renderer_render().  This function is only valid if @tree_view is
12915  * realized.
12916  **/
12917 void
12918 gtk_tree_view_get_cell_area (GtkTreeView        *tree_view,
12919                              GtkTreePath        *path,
12920                              GtkTreeViewColumn  *column,
12921                              GdkRectangle       *rect)
12922 {
12923   GtkRBTree *tree = NULL;
12924   GtkRBNode *node = NULL;
12925   gint vertical_separator;
12926   gint horizontal_separator;
12927
12928   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12929   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
12930   g_return_if_fail (rect != NULL);
12931   g_return_if_fail (!column || column->tree_view == (GtkWidget *) tree_view);
12932   g_return_if_fail (GTK_WIDGET_REALIZED (tree_view));
12933
12934   gtk_widget_style_get (GTK_WIDGET (tree_view),
12935                         "vertical-separator", &vertical_separator,
12936                         "horizontal-separator", &horizontal_separator,
12937                         NULL);
12938
12939   rect->x = 0;
12940   rect->y = 0;
12941   rect->width = 0;
12942   rect->height = 0;
12943
12944   if (column)
12945     {
12946       rect->x = column->button->allocation.x + horizontal_separator/2;
12947       rect->width = column->button->allocation.width - horizontal_separator;
12948     }
12949
12950   if (path)
12951     {
12952       gboolean ret = _gtk_tree_view_find_node (tree_view, path, &tree, &node);
12953
12954       /* Get vertical coords */
12955       if ((!ret && tree == NULL) || ret)
12956         return;
12957
12958       rect->y = CELL_FIRST_PIXEL (tree_view, tree, node, vertical_separator);
12959       rect->height = MAX (CELL_HEIGHT (node, vertical_separator), tree_view->priv->expander_size - vertical_separator);
12960
12961       if (column &&
12962           gtk_tree_view_is_expander_column (tree_view, column))
12963         {
12964           gint depth = gtk_tree_path_get_depth (path);
12965           gboolean rtl;
12966
12967           rtl = gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL;
12968
12969           if (!rtl)
12970             rect->x += (depth - 1) * tree_view->priv->level_indentation;
12971           rect->width -= (depth - 1) * tree_view->priv->level_indentation;
12972
12973           if (TREE_VIEW_DRAW_EXPANDERS (tree_view))
12974             {
12975               if (!rtl)
12976                 rect->x += depth * tree_view->priv->expander_size;
12977               rect->width -= depth * tree_view->priv->expander_size;
12978             }
12979
12980           rect->width = MAX (rect->width, 0);
12981         }
12982     }
12983 }
12984
12985 /**
12986  * gtk_tree_view_get_background_area:
12987  * @tree_view: a #GtkTreeView
12988  * @path: a #GtkTreePath for the row, or %NULL to get only horizontal coordinates
12989  * @column: a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordiantes
12990  * @rect: rectangle to fill with cell background rect
12991  *
12992  * Fills the bounding rectangle in bin_window coordinates for the cell at the
12993  * row specified by @path and the column specified by @column.  If @path is
12994  * %NULL, or points to a node not found in the tree, the @y and @height fields of
12995  * the rectangle will be filled with 0. If @column is %NULL, the @x and @width
12996  * fields will be filled with 0.  The returned rectangle is equivalent to the
12997  * @background_area passed to gtk_cell_renderer_render().  These background
12998  * areas tile to cover the entire bin window.  Contrast with the @cell_area,
12999  * returned by gtk_tree_view_get_cell_area(), which returns only the cell
13000  * itself, excluding surrounding borders and the tree expander area.
13001  *
13002  **/
13003 void
13004 gtk_tree_view_get_background_area (GtkTreeView        *tree_view,
13005                                    GtkTreePath        *path,
13006                                    GtkTreeViewColumn  *column,
13007                                    GdkRectangle       *rect)
13008 {
13009   GtkRBTree *tree = NULL;
13010   GtkRBNode *node = NULL;
13011
13012   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13013   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
13014   g_return_if_fail (rect != NULL);
13015
13016   rect->x = 0;
13017   rect->y = 0;
13018   rect->width = 0;
13019   rect->height = 0;
13020
13021   if (path)
13022     {
13023       /* Get vertical coords */
13024
13025       if (!_gtk_tree_view_find_node (tree_view, path, &tree, &node) &&
13026           tree == NULL)
13027         return;
13028
13029       rect->y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
13030
13031       rect->height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
13032     }
13033
13034   if (column)
13035     {
13036       gint x2 = 0;
13037
13038       gtk_tree_view_get_background_xrange (tree_view, tree, column, &rect->x, &x2);
13039       rect->width = x2 - rect->x;
13040     }
13041 }
13042
13043 /**
13044  * gtk_tree_view_get_visible_rect:
13045  * @tree_view: a #GtkTreeView
13046  * @visible_rect: rectangle to fill
13047  *
13048  * Fills @visible_rect with the currently-visible region of the
13049  * buffer, in tree coordinates. Convert to bin_window coordinates with
13050  * gtk_tree_view_convert_tree_to_bin_window_coords().
13051  * Tree coordinates start at 0,0 for row 0 of the tree, and cover the entire
13052  * scrollable area of the tree.
13053  **/
13054 void
13055 gtk_tree_view_get_visible_rect (GtkTreeView  *tree_view,
13056                                 GdkRectangle *visible_rect)
13057 {
13058   GtkWidget *widget;
13059
13060   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13061
13062   widget = GTK_WIDGET (tree_view);
13063
13064   if (visible_rect)
13065     {
13066       visible_rect->x = tree_view->priv->hadjustment->value;
13067       visible_rect->y = tree_view->priv->vadjustment->value;
13068       visible_rect->width = widget->allocation.width;
13069       visible_rect->height = widget->allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view);
13070     }
13071 }
13072
13073 /**
13074  * gtk_tree_view_widget_to_tree_coords:
13075  * @tree_view: a #GtkTreeView
13076  * @wx: X coordinate relative to bin_window
13077  * @wy: Y coordinate relative to bin_window
13078  * @tx: return location for tree X coordinate
13079  * @ty: return location for tree Y coordinate
13080  *
13081  * Converts bin_window coordinates to coordinates for the
13082  * tree (the full scrollable area of the tree).
13083  *
13084  * Deprecated: 2.12: Due to historial reasons the name of this function is
13085  * incorrect.  For converting coordinates relative to the widget to
13086  * bin_window coordinates, please see
13087  * gtk_tree_view_convert_widget_to_bin_window_coords().
13088  *
13089  **/
13090 void
13091 gtk_tree_view_widget_to_tree_coords (GtkTreeView *tree_view,
13092                                       gint         wx,
13093                                       gint         wy,
13094                                       gint        *tx,
13095                                       gint        *ty)
13096 {
13097   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13098
13099   if (tx)
13100     *tx = wx + tree_view->priv->hadjustment->value;
13101   if (ty)
13102     *ty = wy + tree_view->priv->dy;
13103 }
13104
13105 /**
13106  * gtk_tree_view_tree_to_widget_coords:
13107  * @tree_view: a #GtkTreeView
13108  * @tx: tree X coordinate
13109  * @ty: tree Y coordinate
13110  * @wx: return location for X coordinate relative to bin_window
13111  * @wy: return location for Y coordinate relative to bin_window
13112  *
13113  * Converts tree coordinates (coordinates in full scrollable area of the tree)
13114  * to bin_window coordinates.
13115  *
13116  * Deprecated: 2.12: Due to historial reasons the name of this function is
13117  * incorrect.  For converting bin_window coordinates to coordinates relative
13118  * to bin_window, please see
13119  * gtk_tree_view_convert_bin_window_to_widget_coords().
13120  *
13121  **/
13122 void
13123 gtk_tree_view_tree_to_widget_coords (GtkTreeView *tree_view,
13124                                      gint         tx,
13125                                      gint         ty,
13126                                      gint        *wx,
13127                                      gint        *wy)
13128 {
13129   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13130
13131   if (wx)
13132     *wx = tx - tree_view->priv->hadjustment->value;
13133   if (wy)
13134     *wy = ty - tree_view->priv->dy;
13135 }
13136
13137
13138 /**
13139  * gtk_tree_view_convert_widget_to_tree_coords:
13140  * @tree_view: a #GtkTreeView
13141  * @wx: X coordinate relative to the widget
13142  * @wy: Y coordinate relative to the widget
13143  * @tx: return location for tree X coordinate
13144  * @ty: return location for tree Y coordinate
13145  *
13146  * Converts widget coordinates to coordinates for the
13147  * tree (the full scrollable area of the tree).
13148  *
13149  * Since: 2.12
13150  **/
13151 void
13152 gtk_tree_view_convert_widget_to_tree_coords (GtkTreeView *tree_view,
13153                                              gint         wx,
13154                                              gint         wy,
13155                                              gint        *tx,
13156                                              gint        *ty)
13157 {
13158   gint x, y;
13159
13160   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13161
13162   gtk_tree_view_convert_widget_to_bin_window_coords (tree_view,
13163                                                      wx, wy,
13164                                                      &x, &y);
13165   gtk_tree_view_convert_bin_window_to_tree_coords (tree_view,
13166                                                    x, y,
13167                                                    tx, ty);
13168 }
13169
13170 /**
13171  * gtk_tree_view_convert_tree_to_widget_coords:
13172  * @tree_view: a #GtkTreeView
13173  * @tx: X coordinate relative to the tree
13174  * @ty: Y coordinate relative to the tree
13175  * @wx: return location for widget X coordinate
13176  * @wy: return location for widget Y coordinate
13177  *
13178  * Converts tree coordinates (coordinates in full scrollable area of the tree)
13179  * to widget coordinates.
13180  *
13181  * Since: 2.12
13182  **/
13183 void
13184 gtk_tree_view_convert_tree_to_widget_coords (GtkTreeView *tree_view,
13185                                              gint         tx,
13186                                              gint         ty,
13187                                              gint        *wx,
13188                                              gint        *wy)
13189 {
13190   gint x, y;
13191
13192   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13193
13194   gtk_tree_view_convert_tree_to_bin_window_coords (tree_view,
13195                                                    tx, ty,
13196                                                    &x, &y);
13197   gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
13198                                                      x, y,
13199                                                      wx, wy);
13200 }
13201
13202 /**
13203  * gtk_tree_view_convert_widget_to_bin_window_coords:
13204  * @tree_view: a #GtkTreeView
13205  * @wx: X coordinate relative to the widget
13206  * @wy: Y coordinate relative to the widget
13207  * @bx: return location for bin_window X coordinate
13208  * @by: return location for bin_window Y coordinate
13209  *
13210  * Converts widget coordinates to coordinates for the bin_window
13211  * (see gtk_tree_view_get_bin_window()).
13212  *
13213  * Since: 2.12
13214  **/
13215 void
13216 gtk_tree_view_convert_widget_to_bin_window_coords (GtkTreeView *tree_view,
13217                                                    gint         wx,
13218                                                    gint         wy,
13219                                                    gint        *bx,
13220                                                    gint        *by)
13221 {
13222   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13223
13224   if (bx)
13225     *bx = wx + tree_view->priv->hadjustment->value;
13226   if (by)
13227     *by = wy - TREE_VIEW_HEADER_HEIGHT (tree_view);
13228 }
13229
13230 /**
13231  * gtk_tree_view_convert_bin_window_to_widget_coords:
13232  * @tree_view: a #GtkTreeView
13233  * @bx: bin_window X coordinate
13234  * @by: bin_window Y coordinate
13235  * @wx: return location for widget X coordinate
13236  * @wy: return location for widget Y coordinate
13237  *
13238  * Converts bin_window coordinates (see gtk_tree_view_get_bin_window())
13239  * to widget relative coordinates.
13240  *
13241  * Since: 2.12
13242  **/
13243 void
13244 gtk_tree_view_convert_bin_window_to_widget_coords (GtkTreeView *tree_view,
13245                                                    gint         bx,
13246                                                    gint         by,
13247                                                    gint        *wx,
13248                                                    gint        *wy)
13249 {
13250   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13251
13252   if (wx)
13253     *wx = bx - tree_view->priv->hadjustment->value;
13254   if (wy)
13255     *wy = by + TREE_VIEW_HEADER_HEIGHT (tree_view);
13256 }
13257
13258 /**
13259  * gtk_tree_view_convert_tree_to_bin_window_coords:
13260  * @tree_view: a #GtkTreeView
13261  * @tx: tree X coordinate
13262  * @ty: tree Y coordinate
13263  * @bx: return location for X coordinate relative to bin_window
13264  * @by: return location for Y coordinate relative to bin_window
13265  *
13266  * Converts tree coordinates (coordinates in full scrollable area of the tree)
13267  * to bin_window coordinates.
13268  *
13269  * Since: 2.12
13270  **/
13271 void
13272 gtk_tree_view_convert_tree_to_bin_window_coords (GtkTreeView *tree_view,
13273                                                  gint         tx,
13274                                                  gint         ty,
13275                                                  gint        *bx,
13276                                                  gint        *by)
13277 {
13278   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13279
13280   if (bx)
13281     *bx = tx;
13282   if (by)
13283     *by = ty - tree_view->priv->dy;
13284 }
13285
13286 /**
13287  * gtk_tree_view_convert_bin_window_to_tree_coords:
13288  * @tree_view: a #GtkTreeView
13289  * @bx: X coordinate relative to bin_window
13290  * @by: Y coordinate relative to bin_window
13291  * @tx: return location for tree X coordinate
13292  * @ty: return location for tree Y coordinate
13293  *
13294  * Converts bin_window coordinates to coordinates for the
13295  * tree (the full scrollable area of the tree).
13296  *
13297  * Since: 2.12
13298  **/
13299 void
13300 gtk_tree_view_convert_bin_window_to_tree_coords (GtkTreeView *tree_view,
13301                                                  gint         bx,
13302                                                  gint         by,
13303                                                  gint        *tx,
13304                                                  gint        *ty)
13305 {
13306   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13307
13308   if (tx)
13309     *tx = bx;
13310   if (ty)
13311     *ty = by + tree_view->priv->dy;
13312 }
13313
13314
13315
13316 /**
13317  * gtk_tree_view_get_visible_range:
13318  * @tree_view: A #GtkTreeView
13319  * @start_path: Return location for start of region, or %NULL.
13320  * @end_path: Return location for end of region, or %NULL.
13321  *
13322  * Sets @start_path and @end_path to be the first and last visible path.
13323  * Note that there may be invisible paths in between.
13324  *
13325  * The paths should be freed with gtk_tree_path_free() after use.
13326  *
13327  * Returns: %TRUE, if valid paths were placed in @start_path and @end_path.
13328  *
13329  * Since: 2.8
13330  **/
13331 gboolean
13332 gtk_tree_view_get_visible_range (GtkTreeView  *tree_view,
13333                                  GtkTreePath **start_path,
13334                                  GtkTreePath **end_path)
13335 {
13336   GtkRBTree *tree;
13337   GtkRBNode *node;
13338   gboolean retval;
13339   
13340   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
13341
13342   if (!tree_view->priv->tree)
13343     return FALSE;
13344
13345   retval = TRUE;
13346
13347   if (start_path)
13348     {
13349       _gtk_rbtree_find_offset (tree_view->priv->tree,
13350                                TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, 0),
13351                                &tree, &node);
13352       if (node)
13353         *start_path = _gtk_tree_view_find_path (tree_view, tree, node);
13354       else
13355         retval = FALSE;
13356     }
13357
13358   if (end_path)
13359     {
13360       gint y;
13361
13362       if (tree_view->priv->height < tree_view->priv->vadjustment->page_size)
13363         y = tree_view->priv->height - 1;
13364       else
13365         y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, tree_view->priv->vadjustment->page_size) - 1;
13366
13367       _gtk_rbtree_find_offset (tree_view->priv->tree, y, &tree, &node);
13368       if (node)
13369         *end_path = _gtk_tree_view_find_path (tree_view, tree, node);
13370       else
13371         retval = FALSE;
13372     }
13373
13374   return retval;
13375 }
13376
13377 static void
13378 unset_reorderable (GtkTreeView *tree_view)
13379 {
13380   if (tree_view->priv->reorderable)
13381     {
13382       tree_view->priv->reorderable = FALSE;
13383       g_object_notify (G_OBJECT (tree_view), "reorderable");
13384     }
13385 }
13386
13387 /**
13388  * gtk_tree_view_enable_model_drag_source:
13389  * @tree_view: a #GtkTreeView
13390  * @start_button_mask: Mask of allowed buttons to start drag
13391  * @targets: the table of targets that the drag will support
13392  * @n_targets: the number of items in @targets
13393  * @actions: the bitmask of possible actions for a drag from this
13394  *    widget
13395  *
13396  * Turns @tree_view into a drag source for automatic DND. Calling this
13397  * method sets #GtkTreeView:reorderable to %FALSE.
13398  **/
13399 void
13400 gtk_tree_view_enable_model_drag_source (GtkTreeView              *tree_view,
13401                                         GdkModifierType           start_button_mask,
13402                                         const GtkTargetEntry     *targets,
13403                                         gint                      n_targets,
13404                                         GdkDragAction             actions)
13405 {
13406   TreeViewDragInfo *di;
13407
13408   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13409
13410   gtk_drag_source_set (GTK_WIDGET (tree_view),
13411                        0,
13412                        targets,
13413                        n_targets,
13414                        actions);
13415
13416   di = ensure_info (tree_view);
13417
13418   di->start_button_mask = start_button_mask;
13419   di->source_actions = actions;
13420   di->source_set = TRUE;
13421
13422   unset_reorderable (tree_view);
13423 }
13424
13425 /**
13426  * gtk_tree_view_enable_model_drag_dest:
13427  * @tree_view: a #GtkTreeView
13428  * @targets: the table of targets that the drag will support
13429  * @n_targets: the number of items in @targets
13430  * @actions: the bitmask of possible actions for a drag from this
13431  *    widget
13432  * 
13433  * Turns @tree_view into a drop destination for automatic DND. Calling
13434  * this method sets #GtkTreeView:reorderable to %FALSE.
13435  **/
13436 void
13437 gtk_tree_view_enable_model_drag_dest (GtkTreeView              *tree_view,
13438                                       const GtkTargetEntry     *targets,
13439                                       gint                      n_targets,
13440                                       GdkDragAction             actions)
13441 {
13442   TreeViewDragInfo *di;
13443
13444   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13445
13446   gtk_drag_dest_set (GTK_WIDGET (tree_view),
13447                      0,
13448                      targets,
13449                      n_targets,
13450                      actions);
13451
13452   di = ensure_info (tree_view);
13453   di->dest_set = TRUE;
13454
13455   unset_reorderable (tree_view);
13456 }
13457
13458 /**
13459  * gtk_tree_view_unset_rows_drag_source:
13460  * @tree_view: a #GtkTreeView
13461  *
13462  * Undoes the effect of
13463  * gtk_tree_view_enable_model_drag_source(). Calling this method sets
13464  * #GtkTreeView:reorderable to %FALSE.
13465  **/
13466 void
13467 gtk_tree_view_unset_rows_drag_source (GtkTreeView *tree_view)
13468 {
13469   TreeViewDragInfo *di;
13470
13471   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13472
13473   di = get_info (tree_view);
13474
13475   if (di)
13476     {
13477       if (di->source_set)
13478         {
13479           gtk_drag_source_unset (GTK_WIDGET (tree_view));
13480           di->source_set = FALSE;
13481         }
13482
13483       if (!di->dest_set && !di->source_set)
13484         remove_info (tree_view);
13485     }
13486   
13487   unset_reorderable (tree_view);
13488 }
13489
13490 /**
13491  * gtk_tree_view_unset_rows_drag_dest:
13492  * @tree_view: a #GtkTreeView
13493  *
13494  * Undoes the effect of
13495  * gtk_tree_view_enable_model_drag_dest(). Calling this method sets
13496  * #GtkTreeView:reorderable to %FALSE.
13497  **/
13498 void
13499 gtk_tree_view_unset_rows_drag_dest (GtkTreeView *tree_view)
13500 {
13501   TreeViewDragInfo *di;
13502
13503   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13504
13505   di = get_info (tree_view);
13506
13507   if (di)
13508     {
13509       if (di->dest_set)
13510         {
13511           gtk_drag_dest_unset (GTK_WIDGET (tree_view));
13512           di->dest_set = FALSE;
13513         }
13514
13515       if (!di->dest_set && !di->source_set)
13516         remove_info (tree_view);
13517     }
13518
13519   unset_reorderable (tree_view);
13520 }
13521
13522 /**
13523  * gtk_tree_view_set_drag_dest_row:
13524  * @tree_view: a #GtkTreeView
13525  * @path: The path of the row to highlight, or %NULL.
13526  * @pos: Specifies whether to drop before, after or into the row
13527  * 
13528  * Sets the row that is highlighted for feedback.
13529  **/
13530 void
13531 gtk_tree_view_set_drag_dest_row (GtkTreeView            *tree_view,
13532                                  GtkTreePath            *path,
13533                                  GtkTreeViewDropPosition pos)
13534 {
13535   GtkTreePath *current_dest;
13536
13537   /* Note; this function is exported to allow a custom DND
13538    * implementation, so it can't touch TreeViewDragInfo
13539    */
13540
13541   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13542
13543   current_dest = NULL;
13544
13545   if (tree_view->priv->drag_dest_row)
13546     {
13547       current_dest = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
13548       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
13549     }
13550
13551   /* special case a drop on an empty model */
13552   tree_view->priv->empty_view_drop = 0;
13553
13554   if (pos == GTK_TREE_VIEW_DROP_BEFORE && path
13555       && gtk_tree_path_get_depth (path) == 1
13556       && gtk_tree_path_get_indices (path)[0] == 0)
13557     {
13558       gint n_children;
13559
13560       n_children = gtk_tree_model_iter_n_children (tree_view->priv->model,
13561                                                    NULL);
13562
13563       if (!n_children)
13564         tree_view->priv->empty_view_drop = 1;
13565     }
13566
13567   tree_view->priv->drag_dest_pos = pos;
13568
13569   if (path)
13570     {
13571       tree_view->priv->drag_dest_row =
13572         gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
13573       gtk_tree_view_queue_draw_path (tree_view, path, NULL);
13574     }
13575   else
13576     tree_view->priv->drag_dest_row = NULL;
13577
13578   if (current_dest)
13579     {
13580       GtkRBTree *tree, *new_tree;
13581       GtkRBNode *node, *new_node;
13582
13583       _gtk_tree_view_find_node (tree_view, current_dest, &tree, &node);
13584       _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
13585
13586       if (tree && node)
13587         {
13588           _gtk_rbtree_next_full (tree, node, &new_tree, &new_node);
13589           if (new_tree && new_node)
13590             _gtk_tree_view_queue_draw_node (tree_view, new_tree, new_node, NULL);
13591
13592           _gtk_rbtree_prev_full (tree, node, &new_tree, &new_node);
13593           if (new_tree && new_node)
13594             _gtk_tree_view_queue_draw_node (tree_view, new_tree, new_node, NULL);
13595         }
13596       gtk_tree_path_free (current_dest);
13597     }
13598 }
13599
13600 /**
13601  * gtk_tree_view_get_drag_dest_row:
13602  * @tree_view: a #GtkTreeView
13603  * @path: Return location for the path of the highlighted row, or %NULL.
13604  * @pos: Return location for the drop position, or %NULL
13605  * 
13606  * Gets information about the row that is highlighted for feedback.
13607  **/
13608 void
13609 gtk_tree_view_get_drag_dest_row (GtkTreeView              *tree_view,
13610                                  GtkTreePath             **path,
13611                                  GtkTreeViewDropPosition  *pos)
13612 {
13613   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13614
13615   if (path)
13616     {
13617       if (tree_view->priv->drag_dest_row)
13618         *path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
13619       else
13620         {
13621           if (tree_view->priv->empty_view_drop)
13622             *path = gtk_tree_path_new_from_indices (0, -1);
13623           else
13624             *path = NULL;
13625         }
13626     }
13627
13628   if (pos)
13629     *pos = tree_view->priv->drag_dest_pos;
13630 }
13631
13632 /**
13633  * gtk_tree_view_get_dest_row_at_pos:
13634  * @tree_view: a #GtkTreeView
13635  * @drag_x: the position to determine the destination row for
13636  * @drag_y: the position to determine the destination row for
13637  * @path: Return location for the path of the highlighted row, or %NULL.
13638  * @pos: Return location for the drop position, or %NULL
13639  * 
13640  * Determines the destination row for a given position.  @drag_x and
13641  * @drag_y are expected to be in widget coordinates.  This function is only
13642  * meaningful if @tree_view is realized.  Therefore this function will always
13643  * return %FALSE if @tree_view is not realized or does not have a model.
13644  * 
13645  * Return value: whether there is a row at the given position, %TRUE if this
13646  * is indeed the case.
13647  **/
13648 gboolean
13649 gtk_tree_view_get_dest_row_at_pos (GtkTreeView             *tree_view,
13650                                    gint                     drag_x,
13651                                    gint                     drag_y,
13652                                    GtkTreePath            **path,
13653                                    GtkTreeViewDropPosition *pos)
13654 {
13655   gint cell_y;
13656   gint bin_x, bin_y;
13657   gdouble offset_into_row;
13658   gdouble third;
13659   GdkRectangle cell;
13660   GtkTreeViewColumn *column = NULL;
13661   GtkTreePath *tmp_path = NULL;
13662
13663   /* Note; this function is exported to allow a custom DND
13664    * implementation, so it can't touch TreeViewDragInfo
13665    */
13666
13667   g_return_val_if_fail (tree_view != NULL, FALSE);
13668   g_return_val_if_fail (drag_x >= 0, FALSE);
13669   g_return_val_if_fail (drag_y >= 0, FALSE);
13670
13671   if (path)
13672     *path = NULL;
13673
13674   if (tree_view->priv->bin_window == NULL)
13675     return FALSE;
13676
13677   if (tree_view->priv->tree == NULL)
13678     return FALSE;
13679
13680   /* If in the top third of a row, we drop before that row; if
13681    * in the bottom third, drop after that row; if in the middle,
13682    * and the row has children, drop into the row.
13683    */
13684   gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, drag_x, drag_y,
13685                                                      &bin_x, &bin_y);
13686
13687   if (!gtk_tree_view_get_path_at_pos (tree_view,
13688                                       bin_x,
13689                                       bin_y,
13690                                       &tmp_path,
13691                                       &column,
13692                                       NULL,
13693                                       &cell_y))
13694     return FALSE;
13695
13696   gtk_tree_view_get_background_area (tree_view, tmp_path, column,
13697                                      &cell);
13698
13699   offset_into_row = cell_y;
13700
13701   if (path)
13702     *path = tmp_path;
13703   else
13704     gtk_tree_path_free (tmp_path);
13705
13706   tmp_path = NULL;
13707
13708   third = cell.height / 3.0;
13709
13710   if (pos)
13711     {
13712       if (offset_into_row < third)
13713         {
13714           *pos = GTK_TREE_VIEW_DROP_BEFORE;
13715         }
13716       else if (offset_into_row < (cell.height / 2.0))
13717         {
13718           *pos = GTK_TREE_VIEW_DROP_INTO_OR_BEFORE;
13719         }
13720       else if (offset_into_row < third * 2.0)
13721         {
13722           *pos = GTK_TREE_VIEW_DROP_INTO_OR_AFTER;
13723         }
13724       else
13725         {
13726           *pos = GTK_TREE_VIEW_DROP_AFTER;
13727         }
13728     }
13729
13730   return TRUE;
13731 }
13732
13733
13734
13735 /* KEEP IN SYNC WITH GTK_TREE_VIEW_BIN_EXPOSE */
13736 /**
13737  * gtk_tree_view_create_row_drag_icon:
13738  * @tree_view: a #GtkTreeView
13739  * @path: a #GtkTreePath in @tree_view
13740  *
13741  * Creates a #GdkPixmap representation of the row at @path.  
13742  * This image is used for a drag icon.
13743  *
13744  * Return value: a newly-allocated pixmap of the drag icon.
13745  **/
13746 GdkPixmap *
13747 gtk_tree_view_create_row_drag_icon (GtkTreeView  *tree_view,
13748                                     GtkTreePath  *path)
13749 {
13750   GtkTreeIter   iter;
13751   GtkRBTree    *tree;
13752   GtkRBNode    *node;
13753   gint cell_offset;
13754   GList *list;
13755   GdkRectangle background_area;
13756   GdkRectangle expose_area;
13757   GtkWidget *widget;
13758   gint depth;
13759   /* start drawing inside the black outline */
13760   gint x = 1, y = 1;
13761   GdkDrawable *drawable;
13762   gint bin_window_width;
13763   gboolean is_separator = FALSE;
13764   gboolean rtl;
13765
13766   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
13767   g_return_val_if_fail (path != NULL, NULL);
13768
13769   widget = GTK_WIDGET (tree_view);
13770
13771   if (!GTK_WIDGET_REALIZED (tree_view))
13772     return NULL;
13773
13774   depth = gtk_tree_path_get_depth (path);
13775
13776   _gtk_tree_view_find_node (tree_view,
13777                             path,
13778                             &tree,
13779                             &node);
13780
13781   if (tree == NULL)
13782     return NULL;
13783
13784   if (!gtk_tree_model_get_iter (tree_view->priv->model,
13785                                 &iter,
13786                                 path))
13787     return NULL;
13788   
13789   is_separator = row_is_separator (tree_view, &iter, NULL);
13790
13791   cell_offset = x;
13792
13793   background_area.y = y;
13794   background_area.height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
13795
13796   gdk_drawable_get_size (tree_view->priv->bin_window,
13797                          &bin_window_width, NULL);
13798
13799   drawable = gdk_pixmap_new (tree_view->priv->bin_window,
13800                              bin_window_width + 2,
13801                              background_area.height + 2,
13802                              -1);
13803
13804   expose_area.x = 0;
13805   expose_area.y = 0;
13806   expose_area.width = bin_window_width + 2;
13807   expose_area.height = background_area.height + 2;
13808
13809   gdk_draw_rectangle (drawable,
13810                       widget->style->base_gc [GTK_WIDGET_STATE (widget)],
13811                       TRUE,
13812                       0, 0,
13813                       bin_window_width + 2,
13814                       background_area.height + 2);
13815
13816   rtl = gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL;
13817
13818   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
13819       list;
13820       list = (rtl ? list->prev : list->next))
13821     {
13822       GtkTreeViewColumn *column = list->data;
13823       GdkRectangle cell_area;
13824       gint vertical_separator;
13825
13826       if (!column->visible)
13827         continue;
13828
13829       gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, &iter,
13830                                                GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
13831                                                node->children?TRUE:FALSE);
13832
13833       background_area.x = cell_offset;
13834       background_area.width = column->width;
13835
13836       gtk_widget_style_get (widget,
13837                             "vertical-separator", &vertical_separator,
13838                             NULL);
13839
13840       cell_area = background_area;
13841
13842       cell_area.y += vertical_separator / 2;
13843       cell_area.height -= vertical_separator;
13844
13845       if (gtk_tree_view_is_expander_column (tree_view, column))
13846         {
13847           if (!rtl)
13848             cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
13849           cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
13850
13851           if (TREE_VIEW_DRAW_EXPANDERS(tree_view))
13852             {
13853               if (!rtl)
13854                 cell_area.x += depth * tree_view->priv->expander_size;
13855               cell_area.width -= depth * tree_view->priv->expander_size;
13856             }
13857         }
13858
13859       if (gtk_tree_view_column_cell_is_visible (column))
13860         {
13861           if (is_separator)
13862             gtk_paint_hline (widget->style,
13863                              drawable,
13864                              GTK_STATE_NORMAL,
13865                              &cell_area,
13866                              widget,
13867                              NULL,
13868                              cell_area.x,
13869                              cell_area.x + cell_area.width,
13870                              cell_area.y + cell_area.height / 2);
13871           else
13872             _gtk_tree_view_column_cell_render (column,
13873                                                drawable,
13874                                                &background_area,
13875                                                &cell_area,
13876                                                &expose_area,
13877                                                0);
13878         }
13879       cell_offset += column->width;
13880     }
13881
13882   gdk_draw_rectangle (drawable,
13883                       widget->style->black_gc,
13884                       FALSE,
13885                       0, 0,
13886                       bin_window_width + 1,
13887                       background_area.height + 1);
13888
13889   return drawable;
13890 }
13891
13892
13893 /**
13894  * gtk_tree_view_set_destroy_count_func:
13895  * @tree_view: A #GtkTreeView
13896  * @func: Function to be called when a view row is destroyed, or %NULL
13897  * @data: User data to be passed to @func, or %NULL
13898  * @destroy: Destroy notifier for @data, or %NULL
13899  *
13900  * This function should almost never be used.  It is meant for private use by
13901  * ATK for determining the number of visible children that are removed when the
13902  * user collapses a row, or a row is deleted.
13903  **/
13904 void
13905 gtk_tree_view_set_destroy_count_func (GtkTreeView             *tree_view,
13906                                       GtkTreeDestroyCountFunc  func,
13907                                       gpointer                 data,
13908                                       GDestroyNotify           destroy)
13909 {
13910   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13911
13912   if (tree_view->priv->destroy_count_destroy)
13913     tree_view->priv->destroy_count_destroy (tree_view->priv->destroy_count_data);
13914
13915   tree_view->priv->destroy_count_func = func;
13916   tree_view->priv->destroy_count_data = data;
13917   tree_view->priv->destroy_count_destroy = destroy;
13918 }
13919
13920
13921 /*
13922  * Interactive search
13923  */
13924
13925 /**
13926  * gtk_tree_view_set_enable_search:
13927  * @tree_view: A #GtkTreeView
13928  * @enable_search: %TRUE, if the user can search interactively
13929  *
13930  * If @enable_search is set, then the user can type in text to search through
13931  * the tree interactively (this is sometimes called "typeahead find").
13932  * 
13933  * Note that even if this is %FALSE, the user can still initiate a search 
13934  * using the "start-interactive-search" key binding.
13935  */
13936 void
13937 gtk_tree_view_set_enable_search (GtkTreeView *tree_view,
13938                                  gboolean     enable_search)
13939 {
13940   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13941
13942   enable_search = !!enable_search;
13943   
13944   if (tree_view->priv->enable_search != enable_search)
13945     {
13946        tree_view->priv->enable_search = enable_search;
13947        g_object_notify (G_OBJECT (tree_view), "enable-search");
13948     }
13949 }
13950
13951 /**
13952  * gtk_tree_view_get_enable_search:
13953  * @tree_view: A #GtkTreeView
13954  *
13955  * Returns whether or not the tree allows to start interactive searching 
13956  * by typing in text.
13957  *
13958  * Return value: whether or not to let the user search interactively
13959  */
13960 gboolean
13961 gtk_tree_view_get_enable_search (GtkTreeView *tree_view)
13962 {
13963   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
13964
13965   return tree_view->priv->enable_search;
13966 }
13967
13968
13969 /**
13970  * gtk_tree_view_get_search_column:
13971  * @tree_view: A #GtkTreeView
13972  *
13973  * Gets the column searched on by the interactive search code.
13974  *
13975  * Return value: the column the interactive search code searches in.
13976  */
13977 gint
13978 gtk_tree_view_get_search_column (GtkTreeView *tree_view)
13979 {
13980   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
13981
13982   return (tree_view->priv->search_column);
13983 }
13984
13985 /**
13986  * gtk_tree_view_set_search_column:
13987  * @tree_view: A #GtkTreeView
13988  * @column: the column of the model to search in, or -1 to disable searching
13989  *
13990  * Sets @column as the column where the interactive search code should
13991  * search in for the current model. 
13992  * 
13993  * If the search column is set, users can use the "start-interactive-search"
13994  * key binding to bring up search popup. The enable-search property controls
13995  * whether simply typing text will also start an interactive search.
13996  *
13997  * Note that @column refers to a column of the current model. The search 
13998  * column is reset to -1 when the model is changed.
13999  */
14000 void
14001 gtk_tree_view_set_search_column (GtkTreeView *tree_view,
14002                                  gint         column)
14003 {
14004   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14005   g_return_if_fail (column >= -1);
14006
14007   if (tree_view->priv->search_column == column)
14008     return;
14009
14010   tree_view->priv->search_column = column;
14011   g_object_notify (G_OBJECT (tree_view), "search-column");
14012 }
14013
14014 /**
14015  * gtk_tree_view_get_search_equal_func:
14016  * @tree_view: A #GtkTreeView
14017  *
14018  * Returns the compare function currently in use.
14019  *
14020  * Return value: the currently used compare function for the search code.
14021  */
14022
14023 GtkTreeViewSearchEqualFunc
14024 gtk_tree_view_get_search_equal_func (GtkTreeView *tree_view)
14025 {
14026   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14027
14028   return tree_view->priv->search_equal_func;
14029 }
14030
14031 /**
14032  * gtk_tree_view_set_search_equal_func:
14033  * @tree_view: A #GtkTreeView
14034  * @search_equal_func: the compare function to use during the search
14035  * @search_user_data: user data to pass to @search_equal_func, or %NULL
14036  * @search_destroy: Destroy notifier for @search_user_data, or %NULL
14037  *
14038  * Sets the compare function for the interactive search capabilities; note
14039  * that somewhat like strcmp() returning 0 for equality
14040  * #GtkTreeViewSearchEqualFunc returns %FALSE on matches.
14041  **/
14042 void
14043 gtk_tree_view_set_search_equal_func (GtkTreeView                *tree_view,
14044                                      GtkTreeViewSearchEqualFunc  search_equal_func,
14045                                      gpointer                    search_user_data,
14046                                      GDestroyNotify              search_destroy)
14047 {
14048   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14049   g_return_if_fail (search_equal_func != NULL);
14050
14051   if (tree_view->priv->search_destroy)
14052     tree_view->priv->search_destroy (tree_view->priv->search_user_data);
14053
14054   tree_view->priv->search_equal_func = search_equal_func;
14055   tree_view->priv->search_user_data = search_user_data;
14056   tree_view->priv->search_destroy = search_destroy;
14057   if (tree_view->priv->search_equal_func == NULL)
14058     tree_view->priv->search_equal_func = gtk_tree_view_search_equal_func;
14059 }
14060
14061 /**
14062  * gtk_tree_view_get_search_entry:
14063  * @tree_view: A #GtkTreeView
14064  *
14065  * Returns the #GtkEntry which is currently in use as interactive search
14066  * entry for @tree_view.  In case the built-in entry is being used, %NULL
14067  * will be returned.
14068  *
14069  * Return value: the entry currently in use as search entry.
14070  *
14071  * Since: 2.10
14072  */
14073 GtkEntry *
14074 gtk_tree_view_get_search_entry (GtkTreeView *tree_view)
14075 {
14076   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14077
14078   if (tree_view->priv->search_custom_entry_set)
14079     return GTK_ENTRY (tree_view->priv->search_entry);
14080
14081   return NULL;
14082 }
14083
14084 /**
14085  * gtk_tree_view_set_search_entry:
14086  * @tree_view: A #GtkTreeView
14087  * @entry: (allow-none): the entry the interactive search code of @tree_view should use or %NULL
14088  *
14089  * Sets the entry which the interactive search code will use for this
14090  * @tree_view.  This is useful when you want to provide a search entry
14091  * in our interface at all time at a fixed position.  Passing %NULL for
14092  * @entry will make the interactive search code use the built-in popup
14093  * entry again.
14094  *
14095  * Since: 2.10
14096  */
14097 void
14098 gtk_tree_view_set_search_entry (GtkTreeView *tree_view,
14099                                 GtkEntry    *entry)
14100 {
14101   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14102   g_return_if_fail (entry == NULL || GTK_IS_ENTRY (entry));
14103
14104   if (tree_view->priv->search_custom_entry_set)
14105     {
14106       if (tree_view->priv->search_entry_changed_id)
14107         {
14108           g_signal_handler_disconnect (tree_view->priv->search_entry,
14109                                        tree_view->priv->search_entry_changed_id);
14110           tree_view->priv->search_entry_changed_id = 0;
14111         }
14112       g_signal_handlers_disconnect_by_func (tree_view->priv->search_entry,
14113                                             G_CALLBACK (gtk_tree_view_search_key_press_event),
14114                                             tree_view);
14115
14116       g_object_unref (tree_view->priv->search_entry);
14117     }
14118   else if (tree_view->priv->search_window)
14119     {
14120       gtk_widget_destroy (tree_view->priv->search_window);
14121
14122       tree_view->priv->search_window = NULL;
14123     }
14124
14125   if (entry)
14126     {
14127       tree_view->priv->search_entry = g_object_ref (entry);
14128       tree_view->priv->search_custom_entry_set = TRUE;
14129
14130       if (tree_view->priv->search_entry_changed_id == 0)
14131         {
14132           tree_view->priv->search_entry_changed_id =
14133             g_signal_connect (tree_view->priv->search_entry, "changed",
14134                               G_CALLBACK (gtk_tree_view_search_init),
14135                               tree_view);
14136         }
14137       
14138         g_signal_connect (tree_view->priv->search_entry, "key-press-event",
14139                           G_CALLBACK (gtk_tree_view_search_key_press_event),
14140                           tree_view);
14141
14142         gtk_tree_view_search_init (tree_view->priv->search_entry, tree_view);
14143     }
14144   else
14145     {
14146       tree_view->priv->search_entry = NULL;
14147       tree_view->priv->search_custom_entry_set = FALSE;
14148     }
14149 }
14150
14151 /**
14152  * gtk_tree_view_set_search_position_func:
14153  * @tree_view: A #GtkTreeView
14154  * @func: the function to use to position the search dialog, or %NULL
14155  *    to use the default search position function
14156  * @data: user data to pass to @func, or %NULL
14157  * @destroy: Destroy notifier for @data, or %NULL
14158  *
14159  * Sets the function to use when positioning the search dialog.
14160  *
14161  * Since: 2.10
14162  **/
14163 void
14164 gtk_tree_view_set_search_position_func (GtkTreeView                   *tree_view,
14165                                         GtkTreeViewSearchPositionFunc  func,
14166                                         gpointer                       user_data,
14167                                         GDestroyNotify                 destroy)
14168 {
14169   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14170
14171   if (tree_view->priv->search_position_destroy)
14172     tree_view->priv->search_position_destroy (tree_view->priv->search_position_user_data);
14173
14174   tree_view->priv->search_position_func = func;
14175   tree_view->priv->search_position_user_data = user_data;
14176   tree_view->priv->search_position_destroy = destroy;
14177   if (tree_view->priv->search_position_func == NULL)
14178     tree_view->priv->search_position_func = gtk_tree_view_search_position_func;
14179 }
14180
14181 /**
14182  * gtk_tree_view_get_search_position_func:
14183  * @tree_view: A #GtkTreeView
14184  *
14185  * Returns the positioning function currently in use.
14186  *
14187  * Return value: the currently used function for positioning the search dialog.
14188  *
14189  * Since: 2.10
14190  */
14191 GtkTreeViewSearchPositionFunc
14192 gtk_tree_view_get_search_position_func (GtkTreeView *tree_view)
14193 {
14194   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14195
14196   return tree_view->priv->search_position_func;
14197 }
14198
14199
14200 static void
14201 gtk_tree_view_search_dialog_hide (GtkWidget   *search_dialog,
14202                                   GtkTreeView *tree_view)
14203 {
14204   if (tree_view->priv->disable_popdown)
14205     return;
14206
14207   if (tree_view->priv->search_entry_changed_id)
14208     {
14209       g_signal_handler_disconnect (tree_view->priv->search_entry,
14210                                    tree_view->priv->search_entry_changed_id);
14211       tree_view->priv->search_entry_changed_id = 0;
14212     }
14213   if (tree_view->priv->typeselect_flush_timeout)
14214     {
14215       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14216       tree_view->priv->typeselect_flush_timeout = 0;
14217     }
14218         
14219   if (GTK_WIDGET_VISIBLE (search_dialog))
14220     {
14221       /* send focus-in event */
14222       send_focus_change (GTK_WIDGET (tree_view->priv->search_entry), FALSE);
14223       gtk_widget_hide (search_dialog);
14224       gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
14225       send_focus_change (GTK_WIDGET (tree_view), TRUE);
14226     }
14227 }
14228
14229 static void
14230 gtk_tree_view_search_position_func (GtkTreeView *tree_view,
14231                                     GtkWidget   *search_dialog,
14232                                     gpointer     user_data)
14233 {
14234   gint x, y;
14235   gint tree_x, tree_y;
14236   gint tree_width, tree_height;
14237   GdkWindow *tree_window = GTK_WIDGET (tree_view)->window;
14238   GdkScreen *screen = gdk_drawable_get_screen (tree_window);
14239   GtkRequisition requisition;
14240   gint monitor_num;
14241   GdkRectangle monitor;
14242
14243   monitor_num = gdk_screen_get_monitor_at_window (screen, tree_window);
14244   gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
14245
14246   gtk_widget_realize (search_dialog);
14247
14248   gdk_window_get_origin (tree_window, &tree_x, &tree_y);
14249   gdk_drawable_get_size (tree_window,
14250                          &tree_width,
14251                          &tree_height);
14252   gtk_widget_size_request (search_dialog, &requisition);
14253
14254   if (tree_x + tree_width > gdk_screen_get_width (screen))
14255     x = gdk_screen_get_width (screen) - requisition.width;
14256   else if (tree_x + tree_width - requisition.width < 0)
14257     x = 0;
14258   else
14259     x = tree_x + tree_width - requisition.width;
14260
14261   if (tree_y + tree_height + requisition.height > gdk_screen_get_height (screen))
14262     y = gdk_screen_get_height (screen) - requisition.height;
14263   else if (tree_y + tree_height < 0) /* isn't really possible ... */
14264     y = 0;
14265   else
14266     y = tree_y + tree_height;
14267
14268   gtk_window_move (GTK_WINDOW (search_dialog), x, y);
14269 }
14270
14271 static void
14272 gtk_tree_view_search_disable_popdown (GtkEntry *entry,
14273                                       GtkMenu  *menu,
14274                                       gpointer  data)
14275 {
14276   GtkTreeView *tree_view = (GtkTreeView *)data;
14277
14278   tree_view->priv->disable_popdown = 1;
14279   g_signal_connect (menu, "hide",
14280                     G_CALLBACK (gtk_tree_view_search_enable_popdown), data);
14281 }
14282
14283 /* Because we're visible but offscreen, we just set a flag in the preedit
14284  * callback.
14285  */
14286 static void
14287 gtk_tree_view_search_preedit_changed (GtkIMContext *im_context,
14288                                       GtkTreeView  *tree_view)
14289 {
14290   tree_view->priv->imcontext_changed = 1;
14291   if (tree_view->priv->typeselect_flush_timeout)
14292     {
14293       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14294       tree_view->priv->typeselect_flush_timeout =
14295         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
14296                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
14297                        tree_view);
14298     }
14299
14300 }
14301
14302 static void
14303 gtk_tree_view_search_activate (GtkEntry    *entry,
14304                                GtkTreeView *tree_view)
14305 {
14306   GtkTreePath *path;
14307   GtkRBNode *node;
14308   GtkRBTree *tree;
14309
14310   gtk_tree_view_search_dialog_hide (tree_view->priv->search_window,
14311                                     tree_view);
14312
14313   /* If we have a row selected and it's the cursor row, we activate
14314    * the row XXX */
14315   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
14316     {
14317       path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
14318       
14319       _gtk_tree_view_find_node (tree_view, path, &tree, &node);
14320       
14321       if (node && GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
14322         gtk_tree_view_row_activated (tree_view, path, tree_view->priv->focus_column);
14323       
14324       gtk_tree_path_free (path);
14325     }
14326 }
14327
14328 static gboolean
14329 gtk_tree_view_real_search_enable_popdown (gpointer data)
14330 {
14331   GtkTreeView *tree_view = (GtkTreeView *)data;
14332
14333   tree_view->priv->disable_popdown = 0;
14334
14335   return FALSE;
14336 }
14337
14338 static void
14339 gtk_tree_view_search_enable_popdown (GtkWidget *widget,
14340                                      gpointer   data)
14341 {
14342   gdk_threads_add_timeout_full (G_PRIORITY_HIGH, 200, gtk_tree_view_real_search_enable_popdown, g_object_ref (data), g_object_unref);
14343 }
14344
14345 static gboolean
14346 gtk_tree_view_search_delete_event (GtkWidget *widget,
14347                                    GdkEventAny *event,
14348                                    GtkTreeView *tree_view)
14349 {
14350   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
14351
14352   gtk_tree_view_search_dialog_hide (widget, tree_view);
14353
14354   return TRUE;
14355 }
14356
14357 static gboolean
14358 gtk_tree_view_search_button_press_event (GtkWidget *widget,
14359                                          GdkEventButton *event,
14360                                          GtkTreeView *tree_view)
14361 {
14362   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
14363
14364   gtk_tree_view_search_dialog_hide (widget, tree_view);
14365
14366   if (event->window == tree_view->priv->bin_window)
14367     gtk_tree_view_button_press (GTK_WIDGET (tree_view), event);
14368
14369   return TRUE;
14370 }
14371
14372 static gboolean
14373 gtk_tree_view_search_scroll_event (GtkWidget *widget,
14374                                    GdkEventScroll *event,
14375                                    GtkTreeView *tree_view)
14376 {
14377   gboolean retval = FALSE;
14378
14379   if (event->direction == GDK_SCROLL_UP)
14380     {
14381       gtk_tree_view_search_move (widget, tree_view, TRUE);
14382       retval = TRUE;
14383     }
14384   else if (event->direction == GDK_SCROLL_DOWN)
14385     {
14386       gtk_tree_view_search_move (widget, tree_view, FALSE);
14387       retval = TRUE;
14388     }
14389
14390   /* renew the flush timeout */
14391   if (retval && tree_view->priv->typeselect_flush_timeout
14392       && !tree_view->priv->search_custom_entry_set)
14393     {
14394       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14395       tree_view->priv->typeselect_flush_timeout =
14396         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
14397                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
14398                        tree_view);
14399     }
14400
14401   return retval;
14402 }
14403
14404 static gboolean
14405 gtk_tree_view_search_key_press_event (GtkWidget *widget,
14406                                       GdkEventKey *event,
14407                                       GtkTreeView *tree_view)
14408 {
14409   gboolean retval = FALSE;
14410
14411   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
14412   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
14413
14414   /* close window and cancel the search */
14415   if (!tree_view->priv->search_custom_entry_set
14416       && (event->keyval == GDK_Escape ||
14417           event->keyval == GDK_Tab ||
14418             event->keyval == GDK_KP_Tab ||
14419             event->keyval == GDK_ISO_Left_Tab))
14420     {
14421       gtk_tree_view_search_dialog_hide (widget, tree_view);
14422       return TRUE;
14423     }
14424
14425   /* select previous matching iter */
14426   if (event->keyval == GDK_Up || event->keyval == GDK_KP_Up)
14427     {
14428       if (!gtk_tree_view_search_move (widget, tree_view, TRUE))
14429         gtk_widget_error_bell (widget);
14430
14431       retval = TRUE;
14432     }
14433
14434   if (((event->state & (GTK_DEFAULT_ACCEL_MOD_MASK | GDK_SHIFT_MASK)) == (GTK_DEFAULT_ACCEL_MOD_MASK | GDK_SHIFT_MASK))
14435       && (event->keyval == GDK_g || event->keyval == GDK_G))
14436     {
14437       if (!gtk_tree_view_search_move (widget, tree_view, TRUE))
14438         gtk_widget_error_bell (widget);
14439
14440       retval = TRUE;
14441     }
14442
14443   /* select next matching iter */
14444   if (event->keyval == GDK_Down || event->keyval == GDK_KP_Down)
14445     {
14446       if (!gtk_tree_view_search_move (widget, tree_view, FALSE))
14447         gtk_widget_error_bell (widget);
14448
14449       retval = TRUE;
14450     }
14451
14452   if (((event->state & (GTK_DEFAULT_ACCEL_MOD_MASK | GDK_SHIFT_MASK)) == GTK_DEFAULT_ACCEL_MOD_MASK)
14453       && (event->keyval == GDK_g || event->keyval == GDK_G))
14454     {
14455       if (!gtk_tree_view_search_move (widget, tree_view, FALSE))
14456         gtk_widget_error_bell (widget);
14457
14458       retval = TRUE;
14459     }
14460
14461   /* renew the flush timeout */
14462   if (retval && tree_view->priv->typeselect_flush_timeout
14463       && !tree_view->priv->search_custom_entry_set)
14464     {
14465       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14466       tree_view->priv->typeselect_flush_timeout =
14467         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
14468                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
14469                        tree_view);
14470     }
14471
14472   return retval;
14473 }
14474
14475 /*  this function returns FALSE if there is a search string but
14476  *  nothing was found, and TRUE otherwise.
14477  */
14478 static gboolean
14479 gtk_tree_view_search_move (GtkWidget   *window,
14480                            GtkTreeView *tree_view,
14481                            gboolean     up)
14482 {
14483   gboolean ret;
14484   gint len;
14485   gint count = 0;
14486   const gchar *text;
14487   GtkTreeIter iter;
14488   GtkTreeModel *model;
14489   GtkTreeSelection *selection;
14490
14491   text = gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry));
14492
14493   g_return_val_if_fail (text != NULL, FALSE);
14494
14495   len = strlen (text);
14496
14497   if (up && tree_view->priv->selected_iter == 1)
14498     return strlen (text) < 1;
14499
14500   len = strlen (text);
14501
14502   if (len < 1)
14503     return TRUE;
14504
14505   model = gtk_tree_view_get_model (tree_view);
14506   selection = gtk_tree_view_get_selection (tree_view);
14507
14508   /* search */
14509   gtk_tree_selection_unselect_all (selection);
14510   if (!gtk_tree_model_get_iter_first (model, &iter))
14511     return TRUE;
14512
14513   ret = gtk_tree_view_search_iter (model, selection, &iter, text,
14514                                    &count, up?((tree_view->priv->selected_iter) - 1):((tree_view->priv->selected_iter + 1)));
14515
14516   if (ret)
14517     {
14518       /* found */
14519       tree_view->priv->selected_iter += up?(-1):(1);
14520       return TRUE;
14521     }
14522   else
14523     {
14524       /* return to old iter */
14525       count = 0;
14526       gtk_tree_model_get_iter_first (model, &iter);
14527       gtk_tree_view_search_iter (model, selection,
14528                                  &iter, text,
14529                                  &count, tree_view->priv->selected_iter);
14530       return FALSE;
14531     }
14532 }
14533
14534 static gboolean
14535 gtk_tree_view_search_equal_func (GtkTreeModel *model,
14536                                  gint          column,
14537                                  const gchar  *key,
14538                                  GtkTreeIter  *iter,
14539                                  gpointer      search_data)
14540 {
14541   gboolean retval = TRUE;
14542   const gchar *str;
14543   gchar *normalized_string;
14544   gchar *normalized_key;
14545   gchar *case_normalized_string = NULL;
14546   gchar *case_normalized_key = NULL;
14547   GValue value = {0,};
14548   GValue transformed = {0,};
14549
14550   gtk_tree_model_get_value (model, iter, column, &value);
14551
14552   g_value_init (&transformed, G_TYPE_STRING);
14553
14554   if (!g_value_transform (&value, &transformed))
14555     {
14556       g_value_unset (&value);
14557       return TRUE;
14558     }
14559
14560   g_value_unset (&value);
14561
14562   str = g_value_get_string (&transformed);
14563   if (!str)
14564     {
14565       g_value_unset (&transformed);
14566       return TRUE;
14567     }
14568
14569   normalized_string = g_utf8_normalize (str, -1, G_NORMALIZE_ALL);
14570   normalized_key = g_utf8_normalize (key, -1, G_NORMALIZE_ALL);
14571
14572   if (normalized_string && normalized_key)
14573     {
14574       case_normalized_string = g_utf8_casefold (normalized_string, -1);
14575       case_normalized_key = g_utf8_casefold (normalized_key, -1);
14576
14577       if (strncmp (case_normalized_key, case_normalized_string, strlen (case_normalized_key)) == 0)
14578         retval = FALSE;
14579     }
14580
14581   g_value_unset (&transformed);
14582   g_free (normalized_key);
14583   g_free (normalized_string);
14584   g_free (case_normalized_key);
14585   g_free (case_normalized_string);
14586
14587   return retval;
14588 }
14589
14590 static gboolean
14591 gtk_tree_view_search_iter (GtkTreeModel     *model,
14592                            GtkTreeSelection *selection,
14593                            GtkTreeIter      *iter,
14594                            const gchar      *text,
14595                            gint             *count,
14596                            gint              n)
14597 {
14598   GtkRBTree *tree = NULL;
14599   GtkRBNode *node = NULL;
14600   GtkTreePath *path;
14601
14602   GtkTreeView *tree_view = gtk_tree_selection_get_tree_view (selection);
14603
14604   path = gtk_tree_model_get_path (model, iter);
14605   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
14606
14607   do
14608     {
14609       if (! tree_view->priv->search_equal_func (model, tree_view->priv->search_column, text, iter, tree_view->priv->search_user_data))
14610         {
14611           (*count)++;
14612           if (*count == n)
14613             {
14614               gtk_tree_view_scroll_to_cell (tree_view, path, NULL,
14615                                             TRUE, 0.5, 0.0);
14616               gtk_tree_selection_select_iter (selection, iter);
14617               gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
14618
14619               if (path)
14620                 gtk_tree_path_free (path);
14621
14622               return TRUE;
14623             }
14624         }
14625
14626       if (node->children)
14627         {
14628           gboolean has_child;
14629           GtkTreeIter tmp;
14630
14631           tree = node->children;
14632           node = tree->root;
14633
14634           while (node->left != tree->nil)
14635             node = node->left;
14636
14637           tmp = *iter;
14638           has_child = gtk_tree_model_iter_children (model, iter, &tmp);
14639           gtk_tree_path_down (path);
14640
14641           /* sanity check */
14642           TREE_VIEW_INTERNAL_ASSERT (has_child, FALSE);
14643         }
14644       else
14645         {
14646           gboolean done = FALSE;
14647
14648           do
14649             {
14650               node = _gtk_rbtree_next (tree, node);
14651
14652               if (node)
14653                 {
14654                   gboolean has_next;
14655
14656                   has_next = gtk_tree_model_iter_next (model, iter);
14657
14658                   done = TRUE;
14659                   gtk_tree_path_next (path);
14660
14661                   /* sanity check */
14662                   TREE_VIEW_INTERNAL_ASSERT (has_next, FALSE);
14663                 }
14664               else
14665                 {
14666                   gboolean has_parent;
14667                   GtkTreeIter tmp_iter = *iter;
14668
14669                   node = tree->parent_node;
14670                   tree = tree->parent_tree;
14671
14672                   if (!tree)
14673                     {
14674                       if (path)
14675                         gtk_tree_path_free (path);
14676
14677                       /* we've run out of tree, done with this func */
14678                       return FALSE;
14679                     }
14680
14681                   has_parent = gtk_tree_model_iter_parent (model,
14682                                                            iter,
14683                                                            &tmp_iter);
14684                   gtk_tree_path_up (path);
14685
14686                   /* sanity check */
14687                   TREE_VIEW_INTERNAL_ASSERT (has_parent, FALSE);
14688                 }
14689             }
14690           while (!done);
14691         }
14692     }
14693   while (1);
14694
14695   return FALSE;
14696 }
14697
14698 static void
14699 gtk_tree_view_search_init (GtkWidget   *entry,
14700                            GtkTreeView *tree_view)
14701 {
14702   gint ret;
14703   gint count = 0;
14704   const gchar *text;
14705   GtkTreeIter iter;
14706   GtkTreeModel *model;
14707   GtkTreeSelection *selection;
14708
14709   g_return_if_fail (GTK_IS_ENTRY (entry));
14710   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14711
14712   text = gtk_entry_get_text (GTK_ENTRY (entry));
14713
14714   model = gtk_tree_view_get_model (tree_view);
14715   selection = gtk_tree_view_get_selection (tree_view);
14716
14717   /* search */
14718   gtk_tree_selection_unselect_all (selection);
14719   if (tree_view->priv->typeselect_flush_timeout
14720       && !tree_view->priv->search_custom_entry_set)
14721     {
14722       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14723       tree_view->priv->typeselect_flush_timeout =
14724         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
14725                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
14726                        tree_view);
14727     }
14728
14729   if (*text == '\0')
14730     return;
14731
14732   if (!gtk_tree_model_get_iter_first (model, &iter))
14733     return;
14734
14735   ret = gtk_tree_view_search_iter (model, selection,
14736                                    &iter, text,
14737                                    &count, 1);
14738
14739   if (ret)
14740     tree_view->priv->selected_iter = 1;
14741 }
14742
14743 static void
14744 gtk_tree_view_remove_widget (GtkCellEditable *cell_editable,
14745                              GtkTreeView     *tree_view)
14746 {
14747   if (tree_view->priv->edited_column == NULL)
14748     return;
14749
14750   _gtk_tree_view_column_stop_editing (tree_view->priv->edited_column);
14751   tree_view->priv->edited_column = NULL;
14752
14753   if (GTK_WIDGET_HAS_FOCUS (cell_editable))
14754     gtk_widget_grab_focus (GTK_WIDGET (tree_view));
14755
14756   g_signal_handlers_disconnect_by_func (cell_editable,
14757                                         gtk_tree_view_remove_widget,
14758                                         tree_view);
14759
14760   gtk_container_remove (GTK_CONTAINER (tree_view),
14761                         GTK_WIDGET (cell_editable));  
14762
14763   /* FIXME should only redraw a single node */
14764   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
14765 }
14766
14767 static gboolean
14768 gtk_tree_view_start_editing (GtkTreeView *tree_view,
14769                              GtkTreePath *cursor_path)
14770 {
14771   GtkTreeIter iter;
14772   GdkRectangle background_area;
14773   GdkRectangle cell_area;
14774   GtkCellEditable *editable_widget = NULL;
14775   gchar *path_string;
14776   guint flags = 0; /* can be 0, as the flags are primarily for rendering */
14777   gint retval = FALSE;
14778   GtkRBTree *cursor_tree;
14779   GtkRBNode *cursor_node;
14780
14781   g_assert (tree_view->priv->focus_column);
14782
14783   if (! GTK_WIDGET_REALIZED (tree_view))
14784     return FALSE;
14785
14786   if (_gtk_tree_view_find_node (tree_view, cursor_path, &cursor_tree, &cursor_node) ||
14787       cursor_node == NULL)
14788     return FALSE;
14789
14790   path_string = gtk_tree_path_to_string (cursor_path);
14791   gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path);
14792
14793   validate_row (tree_view, cursor_tree, cursor_node, &iter, cursor_path);
14794
14795   gtk_tree_view_column_cell_set_cell_data (tree_view->priv->focus_column,
14796                                            tree_view->priv->model,
14797                                            &iter,
14798                                            GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_PARENT),
14799                                            cursor_node->children?TRUE:FALSE);
14800   gtk_tree_view_get_background_area (tree_view,
14801                                      cursor_path,
14802                                      tree_view->priv->focus_column,
14803                                      &background_area);
14804   gtk_tree_view_get_cell_area (tree_view,
14805                                cursor_path,
14806                                tree_view->priv->focus_column,
14807                                &cell_area);
14808
14809   if (_gtk_tree_view_column_cell_event (tree_view->priv->focus_column,
14810                                         &editable_widget,
14811                                         NULL,
14812                                         path_string,
14813                                         &background_area,
14814                                         &cell_area,
14815                                         flags))
14816     {
14817       retval = TRUE;
14818       if (editable_widget != NULL)
14819         {
14820           gint left, right;
14821           GdkRectangle area;
14822           GtkCellRenderer *cell;
14823
14824           area = cell_area;
14825           cell = _gtk_tree_view_column_get_edited_cell (tree_view->priv->focus_column);
14826
14827           _gtk_tree_view_column_get_neighbor_sizes (tree_view->priv->focus_column, cell, &left, &right);
14828
14829           area.x += left;
14830           area.width -= right + left;
14831
14832           gtk_tree_view_real_start_editing (tree_view,
14833                                             tree_view->priv->focus_column,
14834                                             cursor_path,
14835                                             editable_widget,
14836                                             &area,
14837                                             NULL,
14838                                             flags);
14839         }
14840
14841     }
14842   g_free (path_string);
14843   return retval;
14844 }
14845
14846 static void
14847 gtk_tree_view_real_start_editing (GtkTreeView       *tree_view,
14848                                   GtkTreeViewColumn *column,
14849                                   GtkTreePath       *path,
14850                                   GtkCellEditable   *cell_editable,
14851                                   GdkRectangle      *cell_area,
14852                                   GdkEvent          *event,
14853                                   guint              flags)
14854 {
14855   gint pre_val = tree_view->priv->vadjustment->value;
14856   GtkRequisition requisition;
14857
14858   tree_view->priv->edited_column = column;
14859   _gtk_tree_view_column_start_editing (column, GTK_CELL_EDITABLE (cell_editable));
14860
14861   gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
14862   cell_area->y += pre_val - (int)tree_view->priv->vadjustment->value;
14863
14864   gtk_widget_size_request (GTK_WIDGET (cell_editable), &requisition);
14865
14866   GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
14867
14868   if (requisition.height < cell_area->height)
14869     {
14870       gint diff = cell_area->height - requisition.height;
14871       gtk_tree_view_put (tree_view,
14872                          GTK_WIDGET (cell_editable),
14873                          cell_area->x, cell_area->y + diff/2,
14874                          cell_area->width, requisition.height);
14875     }
14876   else
14877     {
14878       gtk_tree_view_put (tree_view,
14879                          GTK_WIDGET (cell_editable),
14880                          cell_area->x, cell_area->y,
14881                          cell_area->width, cell_area->height);
14882     }
14883
14884   gtk_cell_editable_start_editing (GTK_CELL_EDITABLE (cell_editable),
14885                                    (GdkEvent *)event);
14886
14887   gtk_widget_grab_focus (GTK_WIDGET (cell_editable));
14888   g_signal_connect (cell_editable, "remove-widget",
14889                     G_CALLBACK (gtk_tree_view_remove_widget), tree_view);
14890 }
14891
14892 static void
14893 gtk_tree_view_stop_editing (GtkTreeView *tree_view,
14894                             gboolean     cancel_editing)
14895 {
14896   GtkTreeViewColumn *column;
14897   GtkCellRenderer *cell;
14898
14899   if (tree_view->priv->edited_column == NULL)
14900     return;
14901
14902   /*
14903    * This is very evil. We need to do this, because
14904    * gtk_cell_editable_editing_done may trigger gtk_tree_view_row_changed
14905    * later on. If gtk_tree_view_row_changed notices
14906    * tree_view->priv->edited_column != NULL, it'll call
14907    * gtk_tree_view_stop_editing again. Bad things will happen then.
14908    *
14909    * Please read that again if you intend to modify anything here.
14910    */
14911
14912   column = tree_view->priv->edited_column;
14913   tree_view->priv->edited_column = NULL;
14914
14915   cell = _gtk_tree_view_column_get_edited_cell (column);
14916   gtk_cell_renderer_stop_editing (cell, cancel_editing);
14917
14918   if (!cancel_editing)
14919     gtk_cell_editable_editing_done (column->editable_widget);
14920
14921   tree_view->priv->edited_column = column;
14922
14923   gtk_cell_editable_remove_widget (column->editable_widget);
14924 }
14925
14926
14927 /**
14928  * gtk_tree_view_set_hover_selection:
14929  * @tree_view: a #GtkTreeView
14930  * @hover: %TRUE to enable hover selection mode
14931  *
14932  * Enables of disables the hover selection mode of @tree_view.
14933  * Hover selection makes the selected row follow the pointer.
14934  * Currently, this works only for the selection modes 
14935  * %GTK_SELECTION_SINGLE and %GTK_SELECTION_BROWSE.
14936  * 
14937  * Since: 2.6
14938  **/
14939 void     
14940 gtk_tree_view_set_hover_selection (GtkTreeView *tree_view,
14941                                    gboolean     hover)
14942 {
14943   hover = hover != FALSE;
14944
14945   if (hover != tree_view->priv->hover_selection)
14946     {
14947       tree_view->priv->hover_selection = hover;
14948
14949       g_object_notify (G_OBJECT (tree_view), "hover-selection");
14950     }
14951 }
14952
14953 /**
14954  * gtk_tree_view_get_hover_selection:
14955  * @tree_view: a #GtkTreeView
14956  * 
14957  * Returns whether hover selection mode is turned on for @tree_view.
14958  * 
14959  * Return value: %TRUE if @tree_view is in hover selection mode
14960  *
14961  * Since: 2.6 
14962  **/
14963 gboolean 
14964 gtk_tree_view_get_hover_selection (GtkTreeView *tree_view)
14965 {
14966   return tree_view->priv->hover_selection;
14967 }
14968
14969 /**
14970  * gtk_tree_view_set_hover_expand:
14971  * @tree_view: a #GtkTreeView
14972  * @expand: %TRUE to enable hover selection mode
14973  *
14974  * Enables of disables the hover expansion mode of @tree_view.
14975  * Hover expansion makes rows expand or collapse if the pointer 
14976  * moves over them.
14977  * 
14978  * Since: 2.6
14979  **/
14980 void     
14981 gtk_tree_view_set_hover_expand (GtkTreeView *tree_view,
14982                                 gboolean     expand)
14983 {
14984   expand = expand != FALSE;
14985
14986   if (expand != tree_view->priv->hover_expand)
14987     {
14988       tree_view->priv->hover_expand = expand;
14989
14990       g_object_notify (G_OBJECT (tree_view), "hover-expand");
14991     }
14992 }
14993
14994 /**
14995  * gtk_tree_view_get_hover_expand:
14996  * @tree_view: a #GtkTreeView
14997  * 
14998  * Returns whether hover expansion mode is turned on for @tree_view.
14999  * 
15000  * Return value: %TRUE if @tree_view is in hover expansion mode
15001  *
15002  * Since: 2.6 
15003  **/
15004 gboolean 
15005 gtk_tree_view_get_hover_expand (GtkTreeView *tree_view)
15006 {
15007   return tree_view->priv->hover_expand;
15008 }
15009
15010 /**
15011  * gtk_tree_view_set_rubber_banding:
15012  * @tree_view: a #GtkTreeView
15013  * @enable: %TRUE to enable rubber banding
15014  *
15015  * Enables or disables rubber banding in @tree_view.  If the selection mode
15016  * is #GTK_SELECTION_MULTIPLE, rubber banding will allow the user to select
15017  * multiple rows by dragging the mouse.
15018  * 
15019  * Since: 2.10
15020  **/
15021 void
15022 gtk_tree_view_set_rubber_banding (GtkTreeView *tree_view,
15023                                   gboolean     enable)
15024 {
15025   enable = enable != FALSE;
15026
15027   if (enable != tree_view->priv->rubber_banding_enable)
15028     {
15029       tree_view->priv->rubber_banding_enable = enable;
15030
15031       g_object_notify (G_OBJECT (tree_view), "rubber-banding");
15032     }
15033 }
15034
15035 /**
15036  * gtk_tree_view_get_rubber_banding:
15037  * @tree_view: a #GtkTreeView
15038  * 
15039  * Returns whether rubber banding is turned on for @tree_view.  If the
15040  * selection mode is #GTK_SELECTION_MULTIPLE, rubber banding will allow the
15041  * user to select multiple rows by dragging the mouse.
15042  * 
15043  * Return value: %TRUE if rubber banding in @tree_view is enabled.
15044  *
15045  * Since: 2.10
15046  **/
15047 gboolean
15048 gtk_tree_view_get_rubber_banding (GtkTreeView *tree_view)
15049 {
15050   return tree_view->priv->rubber_banding_enable;
15051 }
15052
15053 /**
15054  * gtk_tree_view_is_rubber_banding_active:
15055  * @tree_view: a #GtkTreeView
15056  * 
15057  * Returns whether a rubber banding operation is currently being done
15058  * in @tree_view.
15059  *
15060  * Return value: %TRUE if a rubber banding operation is currently being
15061  * done in @tree_view.
15062  *
15063  * Since: 2.12
15064  **/
15065 gboolean
15066 gtk_tree_view_is_rubber_banding_active (GtkTreeView *tree_view)
15067 {
15068   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15069
15070   if (tree_view->priv->rubber_banding_enable
15071       && tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
15072     return TRUE;
15073
15074   return FALSE;
15075 }
15076
15077 /**
15078  * gtk_tree_view_get_row_separator_func:
15079  * @tree_view: a #GtkTreeView
15080  * 
15081  * Returns the current row separator function.
15082  * 
15083  * Return value: the current row separator function.
15084  *
15085  * Since: 2.6
15086  **/
15087 GtkTreeViewRowSeparatorFunc 
15088 gtk_tree_view_get_row_separator_func (GtkTreeView *tree_view)
15089 {
15090   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
15091
15092   return tree_view->priv->row_separator_func;
15093 }
15094
15095 /**
15096  * gtk_tree_view_set_row_separator_func:
15097  * @tree_view: a #GtkTreeView
15098  * @func: a #GtkTreeViewRowSeparatorFunc
15099  * @data: user data to pass to @func, or %NULL
15100  * @destroy: destroy notifier for @data, or %NULL
15101  * 
15102  * Sets the row separator function, which is used to determine
15103  * whether a row should be drawn as a separator. If the row separator
15104  * function is %NULL, no separators are drawn. This is the default value.
15105  *
15106  * Since: 2.6
15107  **/
15108 void
15109 gtk_tree_view_set_row_separator_func (GtkTreeView                 *tree_view,
15110                                       GtkTreeViewRowSeparatorFunc  func,
15111                                       gpointer                     data,
15112                                       GDestroyNotify               destroy)
15113 {
15114   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15115
15116   if (tree_view->priv->row_separator_destroy)
15117     tree_view->priv->row_separator_destroy (tree_view->priv->row_separator_data);
15118
15119   tree_view->priv->row_separator_func = func;
15120   tree_view->priv->row_separator_data = data;
15121   tree_view->priv->row_separator_destroy = destroy;
15122
15123   /* Have the tree recalculate heights */
15124   _gtk_rbtree_mark_invalid (tree_view->priv->tree);
15125   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
15126 }
15127
15128   
15129 static void
15130 gtk_tree_view_grab_notify (GtkWidget *widget,
15131                            gboolean   was_grabbed)
15132 {
15133   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
15134
15135   tree_view->priv->in_grab = !was_grabbed;
15136
15137   if (!was_grabbed)
15138     {
15139       tree_view->priv->pressed_button = -1;
15140
15141       if (tree_view->priv->rubber_band_status)
15142         gtk_tree_view_stop_rubber_band (tree_view);
15143     }
15144 }
15145
15146 static void
15147 gtk_tree_view_state_changed (GtkWidget      *widget,
15148                              GtkStateType    previous_state)
15149 {
15150   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
15151
15152   if (GTK_WIDGET_REALIZED (widget))
15153     {
15154       gdk_window_set_back_pixmap (widget->window, NULL, FALSE);
15155       gdk_window_set_background (tree_view->priv->bin_window, &widget->style->base[widget->state]);
15156     }
15157
15158   gtk_widget_queue_draw (widget);
15159 }
15160
15161 /**
15162  * gtk_tree_view_get_grid_lines:
15163  * @tree_view: a #GtkTreeView
15164  *
15165  * Returns which grid lines are enabled in @tree_view.
15166  *
15167  * Return value: a #GtkTreeViewGridLines value indicating which grid lines
15168  * are enabled.
15169  *
15170  * Since: 2.10
15171  */
15172 GtkTreeViewGridLines
15173 gtk_tree_view_get_grid_lines (GtkTreeView *tree_view)
15174 {
15175   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
15176
15177   return tree_view->priv->grid_lines;
15178 }
15179
15180 /**
15181  * gtk_tree_view_set_grid_lines:
15182  * @tree_view: a #GtkTreeView
15183  * @grid_lines: a #GtkTreeViewGridLines value indicating which grid lines to
15184  * enable.
15185  *
15186  * Sets which grid lines to draw in @tree_view.
15187  *
15188  * Since: 2.10
15189  */
15190 void
15191 gtk_tree_view_set_grid_lines (GtkTreeView           *tree_view,
15192                               GtkTreeViewGridLines   grid_lines)
15193 {
15194   GtkTreeViewPrivate *priv;
15195   GtkWidget *widget;
15196   GtkTreeViewGridLines old_grid_lines;
15197
15198   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15199
15200   priv = tree_view->priv;
15201   widget = GTK_WIDGET (tree_view);
15202
15203   old_grid_lines = priv->grid_lines;
15204   priv->grid_lines = grid_lines;
15205   
15206   if (GTK_WIDGET_REALIZED (widget))
15207     {
15208       if (grid_lines == GTK_TREE_VIEW_GRID_LINES_NONE &&
15209           priv->grid_line_gc)
15210         {
15211           g_object_unref (priv->grid_line_gc);
15212           priv->grid_line_gc = NULL;
15213         }
15214       
15215       if (grid_lines != GTK_TREE_VIEW_GRID_LINES_NONE && 
15216           !priv->grid_line_gc)
15217         {
15218           gint line_width;
15219           gint8 *dash_list;
15220
15221           gtk_widget_style_get (widget,
15222                                 "grid-line-width", &line_width,
15223                                 "grid-line-pattern", (gchar *)&dash_list,
15224                                 NULL);
15225       
15226           priv->grid_line_gc = gdk_gc_new (widget->window);
15227           gdk_gc_copy (priv->grid_line_gc, widget->style->black_gc);
15228           
15229           gdk_gc_set_line_attributes (priv->grid_line_gc, line_width,
15230                                       GDK_LINE_ON_OFF_DASH,
15231                                       GDK_CAP_BUTT, GDK_JOIN_MITER);
15232           gdk_gc_set_dashes (priv->grid_line_gc, 0, dash_list, 2);
15233
15234           g_free (dash_list);
15235         }      
15236     }
15237
15238   if (old_grid_lines != grid_lines)
15239     {
15240       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15241       
15242       g_object_notify (G_OBJECT (tree_view), "enable-grid-lines");
15243     }
15244 }
15245
15246 /**
15247  * gtk_tree_view_get_enable_tree_lines:
15248  * @tree_view: a #GtkTreeView.
15249  *
15250  * Returns whether or not tree lines are drawn in @tree_view.
15251  *
15252  * Return value: %TRUE if tree lines are drawn in @tree_view, %FALSE
15253  * otherwise.
15254  *
15255  * Since: 2.10
15256  */
15257 gboolean
15258 gtk_tree_view_get_enable_tree_lines (GtkTreeView *tree_view)
15259 {
15260   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15261
15262   return tree_view->priv->tree_lines_enabled;
15263 }
15264
15265 /**
15266  * gtk_tree_view_set_enable_tree_lines:
15267  * @tree_view: a #GtkTreeView
15268  * @enabled: %TRUE to enable tree line drawing, %FALSE otherwise.
15269  *
15270  * Sets whether to draw lines interconnecting the expanders in @tree_view.
15271  * This does not have any visible effects for lists.
15272  *
15273  * Since: 2.10
15274  */
15275 void
15276 gtk_tree_view_set_enable_tree_lines (GtkTreeView *tree_view,
15277                                      gboolean     enabled)
15278 {
15279   GtkTreeViewPrivate *priv;
15280   GtkWidget *widget;
15281   gboolean was_enabled;
15282
15283   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15284
15285   enabled = enabled != FALSE;
15286
15287   priv = tree_view->priv;
15288   widget = GTK_WIDGET (tree_view);
15289
15290   was_enabled = priv->tree_lines_enabled;
15291
15292   priv->tree_lines_enabled = enabled;
15293
15294   if (GTK_WIDGET_REALIZED (widget))
15295     {
15296       if (!enabled && priv->tree_line_gc)
15297         {
15298           g_object_unref (priv->tree_line_gc);
15299           priv->tree_line_gc = NULL;
15300         }
15301       
15302       if (enabled && !priv->tree_line_gc)
15303         {
15304           gint line_width;
15305           gint8 *dash_list;
15306           gtk_widget_style_get (widget,
15307                                 "tree-line-width", &line_width,
15308                                 "tree-line-pattern", (gchar *)&dash_list,
15309                                 NULL);
15310           
15311           priv->tree_line_gc = gdk_gc_new (widget->window);
15312           gdk_gc_copy (priv->tree_line_gc, widget->style->black_gc);
15313           
15314           gdk_gc_set_line_attributes (priv->tree_line_gc, line_width,
15315                                       GDK_LINE_ON_OFF_DASH,
15316                                       GDK_CAP_BUTT, GDK_JOIN_MITER);
15317           gdk_gc_set_dashes (priv->tree_line_gc, 0, dash_list, 2);
15318
15319           g_free (dash_list);
15320         }
15321     }
15322
15323   if (was_enabled != enabled)
15324     {
15325       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15326
15327       g_object_notify (G_OBJECT (tree_view), "enable-tree-lines");
15328     }
15329 }
15330
15331
15332 /**
15333  * gtk_tree_view_set_show_expanders:
15334  * @tree_view: a #GtkTreeView
15335  * @enabled: %TRUE to enable expander drawing, %FALSE otherwise.
15336  *
15337  * Sets whether to draw and enable expanders and indent child rows in
15338  * @tree_view.  When disabled there will be no expanders visible in trees
15339  * and there will be no way to expand and collapse rows by default.  Also
15340  * note that hiding the expanders will disable the default indentation.  You
15341  * can set a custom indentation in this case using
15342  * gtk_tree_view_set_level_indentation().
15343  * This does not have any visible effects for lists.
15344  *
15345  * Since: 2.12
15346  */
15347 void
15348 gtk_tree_view_set_show_expanders (GtkTreeView *tree_view,
15349                                   gboolean     enabled)
15350 {
15351   gboolean was_enabled;
15352
15353   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15354
15355   enabled = enabled != FALSE;
15356   was_enabled = GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS);
15357
15358   if (enabled)
15359     GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS);
15360   else
15361     GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS);
15362
15363   if (enabled != was_enabled)
15364     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15365 }
15366
15367 /**
15368  * gtk_tree_view_get_show_expanders:
15369  * @tree_view: a #GtkTreeView.
15370  *
15371  * Returns whether or not expanders are drawn in @tree_view.
15372  *
15373  * Return value: %TRUE if expanders are drawn in @tree_view, %FALSE
15374  * otherwise.
15375  *
15376  * Since: 2.12
15377  */
15378 gboolean
15379 gtk_tree_view_get_show_expanders (GtkTreeView *tree_view)
15380 {
15381   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15382
15383   return GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS);
15384 }
15385
15386 /**
15387  * gtk_tree_view_set_level_indentation:
15388  * @tree_view: a #GtkTreeView
15389  * @indentation: the amount, in pixels, of extra indentation in @tree_view.
15390  *
15391  * Sets the amount of extra indentation for child levels to use in @tree_view
15392  * in addition to the default indentation.  The value should be specified in
15393  * pixels, a value of 0 disables this feature and in this case only the default
15394  * indentation will be used.
15395  * This does not have any visible effects for lists.
15396  *
15397  * Since: 2.12
15398  */
15399 void
15400 gtk_tree_view_set_level_indentation (GtkTreeView *tree_view,
15401                                      gint         indentation)
15402 {
15403   tree_view->priv->level_indentation = indentation;
15404
15405   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15406 }
15407
15408 /**
15409  * gtk_tree_view_get_level_indentation:
15410  * @tree_view: a #GtkTreeView.
15411  *
15412  * Returns the amount, in pixels, of extra indentation for child levels
15413  * in @tree_view.
15414  *
15415  * Return value: the amount of extra indentation for child levels in
15416  * @tree_view.  A return value of 0 means that this feature is disabled.
15417  *
15418  * Since: 2.12
15419  */
15420 gint
15421 gtk_tree_view_get_level_indentation (GtkTreeView *tree_view)
15422 {
15423   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
15424
15425   return tree_view->priv->level_indentation;
15426 }
15427
15428 /**
15429  * gtk_tree_view_set_tooltip_row:
15430  * @tree_view: a #GtkTreeView
15431  * @tooltip: a #GtkTooltip
15432  * @path: a #GtkTreePath
15433  *
15434  * Sets the tip area of @tooltip to be the area covered by the row at @path.
15435  * See also gtk_tree_view_set_tooltip_column() for a simpler alternative.
15436  * See also gtk_tooltip_set_tip_area().
15437  *
15438  * Since: 2.12
15439  */
15440 void
15441 gtk_tree_view_set_tooltip_row (GtkTreeView *tree_view,
15442                                GtkTooltip  *tooltip,
15443                                GtkTreePath *path)
15444 {
15445   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15446   g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
15447
15448   gtk_tree_view_set_tooltip_cell (tree_view, tooltip, path, NULL, NULL);
15449 }
15450
15451 /**
15452  * gtk_tree_view_set_tooltip_cell:
15453  * @tree_view: a #GtkTreeView
15454  * @tooltip: a #GtkTooltip
15455  * @path: a #GtkTreePath or %NULL
15456  * @column: a #GtkTreeViewColumn or %NULL
15457  * @cell: a #GtkCellRenderer or %NULL
15458  *
15459  * Sets the tip area of @tooltip to the area @path, @column and @cell have
15460  * in common.  For example if @path is %NULL and @column is set, the tip
15461  * area will be set to the full area covered by @column.  See also
15462  * gtk_tooltip_set_tip_area().
15463  *
15464  * Note that if @path is not specified and @cell is set and part of a column
15465  * containing the expander, the tooltip might not show and hide at the correct
15466  * position.  In such cases @path must be set to the current node under the
15467  * mouse cursor for this function to operate correctly.
15468  *
15469  * See also gtk_tree_view_set_tooltip_column() for a simpler alternative.
15470  *
15471  * Since: 2.12
15472  */
15473 void
15474 gtk_tree_view_set_tooltip_cell (GtkTreeView       *tree_view,
15475                                 GtkTooltip        *tooltip,
15476                                 GtkTreePath       *path,
15477                                 GtkTreeViewColumn *column,
15478                                 GtkCellRenderer   *cell)
15479 {
15480   GdkRectangle rect;
15481
15482   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15483   g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
15484   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
15485   g_return_if_fail (cell == NULL || GTK_IS_CELL_RENDERER (cell));
15486
15487   /* Determine x values. */
15488   if (column && cell)
15489     {
15490       GdkRectangle tmp;
15491       gint start, width;
15492
15493       /* We always pass in path here, whether it is NULL or not.
15494        * For cells in expander columns path must be specified so that
15495        * we can correctly account for the indentation.  This also means
15496        * that the tooltip is constrained vertically by the "Determine y
15497        * values" code below; this is not a real problem since cells actually
15498        * don't stretch vertically in constrast to columns.
15499        */
15500       gtk_tree_view_get_cell_area (tree_view, path, column, &tmp);
15501       gtk_tree_view_column_cell_get_position (column, cell, &start, &width);
15502
15503       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
15504                                                          tmp.x + start, 0,
15505                                                          &rect.x, NULL);
15506       rect.width = width;
15507     }
15508   else if (column)
15509     {
15510       GdkRectangle tmp;
15511
15512       gtk_tree_view_get_background_area (tree_view, NULL, column, &tmp);
15513       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
15514                                                          tmp.x, 0,
15515                                                          &rect.x, NULL);
15516       rect.width = tmp.width;
15517     }
15518   else
15519     {
15520       rect.x = 0;
15521       rect.width = GTK_WIDGET (tree_view)->allocation.width;
15522     }
15523
15524   /* Determine y values. */
15525   if (path)
15526     {
15527       GdkRectangle tmp;
15528
15529       gtk_tree_view_get_background_area (tree_view, path, NULL, &tmp);
15530       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
15531                                                          0, tmp.y,
15532                                                          NULL, &rect.y);
15533       rect.height = tmp.height;
15534     }
15535   else
15536     {
15537       rect.y = 0;
15538       rect.height = tree_view->priv->vadjustment->page_size;
15539     }
15540
15541   gtk_tooltip_set_tip_area (tooltip, &rect);
15542 }
15543
15544 /**
15545  * gtk_tree_view_get_tooltip_context:
15546  * @tree_view: a #GtkTreeView
15547  * @x: the x coordinate (relative to widget coordinates)
15548  * @y: the y coordinate (relative to widget coordinates)
15549  * @keyboard_tip: whether this is a keyboard tooltip or not
15550  * @model: a pointer to receive a #GtkTreeModel or %NULL
15551  * @path: a pointer to receive a #GtkTreePath or %NULL
15552  * @iter: a pointer to receive a #GtkTreeIter or %NULL
15553  *
15554  * This function is supposed to be used in a #GtkWidget::query-tooltip
15555  * signal handler for #GtkTreeView.  The @x, @y and @keyboard_tip values
15556  * which are received in the signal handler, should be passed to this
15557  * function without modification.
15558  *
15559  * The return value indicates whether there is a tree view row at the given
15560  * coordinates (%TRUE) or not (%FALSE) for mouse tooltips.  For keyboard
15561  * tooltips the row returned will be the cursor row.  When %TRUE, then any of
15562  * @model, @path and @iter which have been provided will be set to point to
15563  * that row and the corresponding model.  @x and @y will always be converted
15564  * to be relative to @tree_view's bin_window if @keyboard_tooltip is %FALSE.
15565  *
15566  * Return value: whether or not the given tooltip context points to a row.
15567  *
15568  * Since: 2.12
15569  */
15570 gboolean
15571 gtk_tree_view_get_tooltip_context (GtkTreeView   *tree_view,
15572                                    gint          *x,
15573                                    gint          *y,
15574                                    gboolean       keyboard_tip,
15575                                    GtkTreeModel **model,
15576                                    GtkTreePath  **path,
15577                                    GtkTreeIter   *iter)
15578 {
15579   GtkTreePath *tmppath = NULL;
15580
15581   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15582   g_return_val_if_fail (x != NULL, FALSE);
15583   g_return_val_if_fail (y != NULL, FALSE);
15584
15585   if (keyboard_tip)
15586     {
15587       gtk_tree_view_get_cursor (tree_view, &tmppath, NULL);
15588
15589       if (!tmppath)
15590         return FALSE;
15591     }
15592   else
15593     {
15594       gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, *x, *y,
15595                                                          x, y);
15596
15597       if (!gtk_tree_view_get_path_at_pos (tree_view, *x, *y,
15598                                           &tmppath, NULL, NULL, NULL))
15599         return FALSE;
15600     }
15601
15602   if (model)
15603     *model = gtk_tree_view_get_model (tree_view);
15604
15605   if (iter)
15606     gtk_tree_model_get_iter (gtk_tree_view_get_model (tree_view),
15607                              iter, tmppath);
15608
15609   if (path)
15610     *path = tmppath;
15611   else
15612     gtk_tree_path_free (tmppath);
15613
15614   return TRUE;
15615 }
15616
15617 static gboolean
15618 gtk_tree_view_set_tooltip_query_cb (GtkWidget  *widget,
15619                                     gint        x,
15620                                     gint        y,
15621                                     gboolean    keyboard_tip,
15622                                     GtkTooltip *tooltip,
15623                                     gpointer    data)
15624 {
15625   GValue value = { 0, };
15626   GValue transformed = { 0, };
15627   GtkTreeIter iter;
15628   GtkTreePath *path;
15629   GtkTreeModel *model;
15630   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
15631
15632   if (!gtk_tree_view_get_tooltip_context (GTK_TREE_VIEW (widget),
15633                                           &x, &y,
15634                                           keyboard_tip,
15635                                           &model, &path, &iter))
15636     return FALSE;
15637
15638   gtk_tree_model_get_value (model, &iter,
15639                             tree_view->priv->tooltip_column, &value);
15640
15641   g_value_init (&transformed, G_TYPE_STRING);
15642
15643   if (!g_value_transform (&value, &transformed))
15644     {
15645       g_value_unset (&value);
15646       gtk_tree_path_free (path);
15647
15648       return FALSE;
15649     }
15650
15651   g_value_unset (&value);
15652
15653   if (!g_value_get_string (&transformed))
15654     {
15655       g_value_unset (&transformed);
15656       gtk_tree_path_free (path);
15657
15658       return FALSE;
15659     }
15660
15661   gtk_tooltip_set_markup (tooltip, g_value_get_string (&transformed));
15662   gtk_tree_view_set_tooltip_row (tree_view, tooltip, path);
15663
15664   gtk_tree_path_free (path);
15665   g_value_unset (&transformed);
15666
15667   return TRUE;
15668 }
15669
15670 /**
15671  * gtk_tree_view_set_tooltip_column:
15672  * @tree_view: a #GtkTreeView
15673  * @column: an integer, which is a valid column number for @tree_view's model
15674  *
15675  * If you only plan to have simple (text-only) tooltips on full rows, you
15676  * can use this function to have #GtkTreeView handle these automatically
15677  * for you. @column should be set to the column in @tree_view's model
15678  * containing the tooltip texts, or -1 to disable this feature.
15679  *
15680  * When enabled, #GtkWidget::has-tooltip will be set to %TRUE and
15681  * @tree_view will connect a #GtkWidget::query-tooltip signal handler.
15682  *
15683  * Note that the signal handler sets the text with gtk_tooltip_set_markup(),
15684  * so &amp;, &lt;, etc have to be escaped in the text.
15685  *
15686  * Since: 2.12
15687  */
15688 void
15689 gtk_tree_view_set_tooltip_column (GtkTreeView *tree_view,
15690                                   gint         column)
15691 {
15692   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15693
15694   if (column == tree_view->priv->tooltip_column)
15695     return;
15696
15697   if (column == -1)
15698     {
15699       g_signal_handlers_disconnect_by_func (tree_view,
15700                                             gtk_tree_view_set_tooltip_query_cb,
15701                                             NULL);
15702       gtk_widget_set_has_tooltip (GTK_WIDGET (tree_view), FALSE);
15703     }
15704   else
15705     {
15706       if (tree_view->priv->tooltip_column == -1)
15707         {
15708           g_signal_connect (tree_view, "query-tooltip",
15709                             G_CALLBACK (gtk_tree_view_set_tooltip_query_cb), NULL);
15710           gtk_widget_set_has_tooltip (GTK_WIDGET (tree_view), TRUE);
15711         }
15712     }
15713
15714   tree_view->priv->tooltip_column = column;
15715   g_object_notify (G_OBJECT (tree_view), "tooltip-column");
15716 }
15717
15718 /**
15719  * gtk_tree_view_get_tooltip_column:
15720  * @tree_view: a #GtkTreeView
15721  *
15722  * Returns the column of @tree_view's model which is being used for
15723  * displaying tooltips on @tree_view's rows.
15724  *
15725  * Return value: the index of the tooltip column that is currently being
15726  * used, or -1 if this is disabled.
15727  *
15728  * Since: 2.12
15729  */
15730 gint
15731 gtk_tree_view_get_tooltip_column (GtkTreeView *tree_view)
15732 {
15733   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
15734
15735   return tree_view->priv->tooltip_column;
15736 }
15737
15738 static void
15739 gtk_tree_view_extended_layout_get_desired_size (GtkExtendedLayout *layout,
15740                                                 GtkRequisition    *minimal_size,
15741                                                 GtkRequisition    *desired_size)
15742 {
15743   GtkTreeView *tree_view;
15744   gint natural_width = 0;
15745   GList *column_iter;
15746   GtkRequisition requisition;
15747
15748   tree_view = GTK_TREE_VIEW (layout);
15749
15750   gtk_widget_size_request (GTK_WIDGET (layout), &requisition);
15751
15752   for (column_iter = tree_view->priv->columns; column_iter; column_iter = column_iter->next)
15753     {
15754       GtkTreeViewColumn *column = column_iter->data;
15755
15756       if (!column->visible)
15757         continue;
15758
15759       natural_width += gtk_tree_view_get_real_natural_width_from_column (tree_view, column);
15760     }
15761
15762   if (minimal_size)
15763     *minimal_size = requisition;
15764
15765   if (desired_size)
15766     {
15767       desired_size->height = requisition.height;
15768       desired_size->width = natural_width;
15769     }
15770 }
15771
15772 static void
15773 gtk_tree_view_extended_layout_init (GtkExtendedLayoutIface *iface)
15774 {
15775   iface->get_desired_size = gtk_tree_view_extended_layout_get_desired_size;
15776 }
15777
15778
15779 #define __GTK_TREE_VIEW_C__
15780 #include "gtkaliasdef.c"