]> Pileus Git - ~andy/gtk/blob - gtk/gtktreeview.c
Revert dd511e825aef9edada30107b3d891d496cc39fd8
[~andy/gtk] / gtk / gtktreeview.c
1 /* gtktreeview.c
2  * Copyright (C) 2000  Red Hat, Inc.,  Jonathan Blandford <jrb@redhat.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20
21 #include "config.h"
22 #include <string.h>
23 #include <gdk/gdkkeysyms.h>
24
25 #include "gtktreeview.h"
26 #include "gtkrbtree.h"
27 #include "gtktreednd.h"
28 #include "gtktreeprivate.h"
29 #include "gtkcellrenderer.h"
30 #include "gtkmain.h"
31 #include "gtkmarshalers.h"
32 #include "gtkbuildable.h"
33 #include "gtkbutton.h"
34 #include "gtkalignment.h"
35 #include "gtklabel.h"
36 #include "gtkhbox.h"
37 #include "gtkvbox.h"
38 #include "gtkarrow.h"
39 #include "gtkintl.h"
40 #include "gtkbindings.h"
41 #include "gtkcontainer.h"
42 #include "gtkentry.h"
43 #include "gtkframe.h"
44 #include "gtktreemodelsort.h"
45 #include "gtktooltip.h"
46 #include "gtkprivate.h"
47 #include "gtkalias.h"
48
49 #define GTK_TREE_VIEW_PRIORITY_VALIDATE (GDK_PRIORITY_REDRAW + 5)
50 #define GTK_TREE_VIEW_PRIORITY_SCROLL_SYNC (GTK_TREE_VIEW_PRIORITY_VALIDATE + 2)
51 #define GTK_TREE_VIEW_TIME_MS_PER_IDLE 30
52 #define SCROLL_EDGE_SIZE 15
53 #define EXPANDER_EXTRA_PADDING 4
54 #define GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT 5000
55 #define AUTO_EXPAND_TIMEOUT 500
56
57 /* The "background" areas of all rows/cells add up to cover the entire tree.
58  * The background includes all inter-row and inter-cell spacing.
59  * The "cell" areas are the cell_area passed in to gtk_cell_renderer_render(),
60  * i.e. just the cells, no spacing.
61  */
62
63 #define BACKGROUND_HEIGHT(node) (GTK_RBNODE_GET_HEIGHT (node))
64 #define CELL_HEIGHT(node, separator) ((BACKGROUND_HEIGHT (node)) - (separator))
65
66 /* Translate from bin_window coordinates to rbtree (tree coordinates) and
67  * vice versa.
68  */
69 #define TREE_WINDOW_Y_TO_RBTREE_Y(tree_view,y) ((y) + tree_view->priv->dy)
70 #define RBTREE_Y_TO_TREE_WINDOW_Y(tree_view,y) ((y) - tree_view->priv->dy)
71
72 /* This is in bin_window coordinates */
73 #define BACKGROUND_FIRST_PIXEL(tree_view,tree,node) (RBTREE_Y_TO_TREE_WINDOW_Y (tree_view, _gtk_rbtree_node_find_offset ((tree), (node))))
74 #define CELL_FIRST_PIXEL(tree_view,tree,node,separator) (BACKGROUND_FIRST_PIXEL (tree_view,tree,node) + separator/2)
75
76 #define ROW_HEIGHT(tree_view,height) \
77   ((height > 0) ? (height) : (tree_view)->priv->expander_size)
78
79
80 typedef struct _GtkTreeViewChild GtkTreeViewChild;
81 struct _GtkTreeViewChild
82 {
83   GtkWidget *widget;
84   gint x;
85   gint y;
86   gint width;
87   gint height;
88 };
89
90
91 typedef struct _TreeViewDragInfo TreeViewDragInfo;
92 struct _TreeViewDragInfo
93 {
94   GdkModifierType start_button_mask;
95   GtkTargetList *_unused_source_target_list;
96   GdkDragAction source_actions;
97
98   GtkTargetList *_unused_dest_target_list;
99
100   guint source_set : 1;
101   guint dest_set : 1;
102 };
103
104
105 /* Signals */
106 enum
107 {
108   ROW_ACTIVATED,
109   TEST_EXPAND_ROW,
110   TEST_COLLAPSE_ROW,
111   ROW_EXPANDED,
112   ROW_COLLAPSED,
113   COLUMNS_CHANGED,
114   CURSOR_CHANGED,
115   MOVE_CURSOR,
116   SELECT_ALL,
117   UNSELECT_ALL,
118   SELECT_CURSOR_ROW,
119   TOGGLE_CURSOR_ROW,
120   EXPAND_COLLAPSE_CURSOR_ROW,
121   SELECT_CURSOR_PARENT,
122   START_INTERACTIVE_SEARCH,
123   LAST_SIGNAL
124 };
125
126 /* Properties */
127 enum {
128   PROP_0,
129   PROP_MODEL,
130   PROP_HADJUSTMENT,
131   PROP_VADJUSTMENT,
132   PROP_HEADERS_VISIBLE,
133   PROP_HEADERS_CLICKABLE,
134   PROP_EXPANDER_COLUMN,
135   PROP_REORDERABLE,
136   PROP_RULES_HINT,
137   PROP_ENABLE_SEARCH,
138   PROP_SEARCH_COLUMN,
139   PROP_FIXED_HEIGHT_MODE,
140   PROP_HOVER_SELECTION,
141   PROP_HOVER_EXPAND,
142   PROP_SHOW_EXPANDERS,
143   PROP_LEVEL_INDENTATION,
144   PROP_RUBBER_BANDING,
145   PROP_ENABLE_GRID_LINES,
146   PROP_ENABLE_TREE_LINES,
147   PROP_TOOLTIP_COLUMN
148 };
149
150 /* object signals */
151 static void     gtk_tree_view_finalize             (GObject          *object);
152 static void     gtk_tree_view_set_property         (GObject         *object,
153                                                     guint            prop_id,
154                                                     const GValue    *value,
155                                                     GParamSpec      *pspec);
156 static void     gtk_tree_view_get_property         (GObject         *object,
157                                                     guint            prop_id,
158                                                     GValue          *value,
159                                                     GParamSpec      *pspec);
160
161 /* gtkobject signals */
162 static void     gtk_tree_view_destroy              (GtkObject        *object);
163
164 /* gtkwidget signals */
165 static void     gtk_tree_view_realize              (GtkWidget        *widget);
166 static void     gtk_tree_view_unrealize            (GtkWidget        *widget);
167 static void     gtk_tree_view_map                  (GtkWidget        *widget);
168 static void     gtk_tree_view_size_request         (GtkWidget        *widget,
169                                                     GtkRequisition   *requisition);
170 static void     gtk_tree_view_size_allocate        (GtkWidget        *widget,
171                                                     GtkAllocation    *allocation);
172 static gboolean gtk_tree_view_expose               (GtkWidget        *widget,
173                                                     GdkEventExpose   *event);
174 static gboolean gtk_tree_view_key_press            (GtkWidget        *widget,
175                                                     GdkEventKey      *event);
176 static gboolean gtk_tree_view_key_release          (GtkWidget        *widget,
177                                                     GdkEventKey      *event);
178 static gboolean gtk_tree_view_motion               (GtkWidget        *widget,
179                                                     GdkEventMotion   *event);
180 static gboolean gtk_tree_view_enter_notify         (GtkWidget        *widget,
181                                                     GdkEventCrossing *event);
182 static gboolean gtk_tree_view_leave_notify         (GtkWidget        *widget,
183                                                     GdkEventCrossing *event);
184 static gboolean gtk_tree_view_button_press         (GtkWidget        *widget,
185                                                     GdkEventButton   *event);
186 static gboolean gtk_tree_view_button_release       (GtkWidget        *widget,
187                                                     GdkEventButton   *event);
188 static gboolean gtk_tree_view_grab_broken          (GtkWidget          *widget,
189                                                     GdkEventGrabBroken *event);
190 #if 0
191 static gboolean gtk_tree_view_configure            (GtkWidget         *widget,
192                                                     GdkEventConfigure *event);
193 #endif
194
195 static void     gtk_tree_view_set_focus_child      (GtkContainer     *container,
196                                                     GtkWidget        *child);
197 static gint     gtk_tree_view_focus_out            (GtkWidget        *widget,
198                                                     GdkEventFocus    *event);
199 static gint     gtk_tree_view_focus                (GtkWidget        *widget,
200                                                     GtkDirectionType  direction);
201 static void     gtk_tree_view_grab_focus           (GtkWidget        *widget);
202 static void     gtk_tree_view_style_set            (GtkWidget        *widget,
203                                                     GtkStyle         *previous_style);
204 static void     gtk_tree_view_grab_notify          (GtkWidget        *widget,
205                                                     gboolean          was_grabbed);
206 static void     gtk_tree_view_state_changed        (GtkWidget        *widget,
207                                                     GtkStateType      previous_state);
208
209 /* container signals */
210 static void     gtk_tree_view_remove               (GtkContainer     *container,
211                                                     GtkWidget        *widget);
212 static void     gtk_tree_view_forall               (GtkContainer     *container,
213                                                     gboolean          include_internals,
214                                                     GtkCallback       callback,
215                                                     gpointer          callback_data);
216
217 /* Source side drag signals */
218 static void gtk_tree_view_drag_begin       (GtkWidget        *widget,
219                                             GdkDragContext   *context);
220 static void gtk_tree_view_drag_end         (GtkWidget        *widget,
221                                             GdkDragContext   *context);
222 static void gtk_tree_view_drag_data_get    (GtkWidget        *widget,
223                                             GdkDragContext   *context,
224                                             GtkSelectionData *selection_data,
225                                             guint             info,
226                                             guint             time);
227 static void gtk_tree_view_drag_data_delete (GtkWidget        *widget,
228                                             GdkDragContext   *context);
229
230 /* Target side drag signals */
231 static void     gtk_tree_view_drag_leave         (GtkWidget        *widget,
232                                                   GdkDragContext   *context,
233                                                   guint             time);
234 static gboolean gtk_tree_view_drag_motion        (GtkWidget        *widget,
235                                                   GdkDragContext   *context,
236                                                   gint              x,
237                                                   gint              y,
238                                                   guint             time);
239 static gboolean gtk_tree_view_drag_drop          (GtkWidget        *widget,
240                                                   GdkDragContext   *context,
241                                                   gint              x,
242                                                   gint              y,
243                                                   guint             time);
244 static void     gtk_tree_view_drag_data_received (GtkWidget        *widget,
245                                                   GdkDragContext   *context,
246                                                   gint              x,
247                                                   gint              y,
248                                                   GtkSelectionData *selection_data,
249                                                   guint             info,
250                                                   guint             time);
251
252 /* tree_model signals */
253 static void gtk_tree_view_set_adjustments                 (GtkTreeView     *tree_view,
254                                                            GtkAdjustment   *hadj,
255                                                            GtkAdjustment   *vadj);
256 static gboolean gtk_tree_view_real_move_cursor            (GtkTreeView     *tree_view,
257                                                            GtkMovementStep  step,
258                                                            gint             count);
259 static gboolean gtk_tree_view_real_select_all             (GtkTreeView     *tree_view);
260 static gboolean gtk_tree_view_real_unselect_all           (GtkTreeView     *tree_view);
261 static gboolean gtk_tree_view_real_select_cursor_row      (GtkTreeView     *tree_view,
262                                                            gboolean         start_editing);
263 static gboolean gtk_tree_view_real_toggle_cursor_row      (GtkTreeView     *tree_view);
264 static gboolean gtk_tree_view_real_expand_collapse_cursor_row (GtkTreeView     *tree_view,
265                                                                gboolean         logical,
266                                                                gboolean         expand,
267                                                                gboolean         open_all);
268 static gboolean gtk_tree_view_real_select_cursor_parent   (GtkTreeView     *tree_view);
269 static void gtk_tree_view_row_changed                     (GtkTreeModel    *model,
270                                                            GtkTreePath     *path,
271                                                            GtkTreeIter     *iter,
272                                                            gpointer         data);
273 static void gtk_tree_view_row_inserted                    (GtkTreeModel    *model,
274                                                            GtkTreePath     *path,
275                                                            GtkTreeIter     *iter,
276                                                            gpointer         data);
277 static void gtk_tree_view_row_has_child_toggled           (GtkTreeModel    *model,
278                                                            GtkTreePath     *path,
279                                                            GtkTreeIter     *iter,
280                                                            gpointer         data);
281 static void gtk_tree_view_row_deleted                     (GtkTreeModel    *model,
282                                                            GtkTreePath     *path,
283                                                            gpointer         data);
284 static void gtk_tree_view_rows_reordered                  (GtkTreeModel    *model,
285                                                            GtkTreePath     *parent,
286                                                            GtkTreeIter     *iter,
287                                                            gint            *new_order,
288                                                            gpointer         data);
289
290 /* Incremental reflow */
291 static gboolean validate_row             (GtkTreeView *tree_view,
292                                           GtkRBTree   *tree,
293                                           GtkRBNode   *node,
294                                           GtkTreeIter *iter,
295                                           GtkTreePath *path);
296 static void     validate_visible_area    (GtkTreeView *tree_view);
297 static gboolean validate_rows_handler    (GtkTreeView *tree_view);
298 static gboolean do_validate_rows         (GtkTreeView *tree_view,
299                                           gboolean     size_request);
300 static gboolean validate_rows            (GtkTreeView *tree_view);
301 static gboolean presize_handler_callback (gpointer     data);
302 static void     install_presize_handler  (GtkTreeView *tree_view);
303 static void     install_scroll_sync_handler (GtkTreeView *tree_view);
304 static void     gtk_tree_view_set_top_row   (GtkTreeView *tree_view,
305                                              GtkTreePath *path,
306                                              gint         offset);
307 static void     gtk_tree_view_dy_to_top_row (GtkTreeView *tree_view);
308 static void     gtk_tree_view_top_row_to_dy (GtkTreeView *tree_view);
309 static void     invalidate_empty_focus      (GtkTreeView *tree_view);
310
311 /* Internal functions */
312 static gboolean gtk_tree_view_is_expander_column             (GtkTreeView        *tree_view,
313                                                               GtkTreeViewColumn  *column);
314 static void     gtk_tree_view_add_move_binding               (GtkBindingSet      *binding_set,
315                                                               guint               keyval,
316                                                               guint               modmask,
317                                                               gboolean            add_shifted_binding,
318                                                               GtkMovementStep     step,
319                                                               gint                count);
320 static gint     gtk_tree_view_unref_and_check_selection_tree (GtkTreeView        *tree_view,
321                                                               GtkRBTree          *tree);
322 static void     gtk_tree_view_queue_draw_path                (GtkTreeView        *tree_view,
323                                                               GtkTreePath        *path,
324                                                               const GdkRectangle *clip_rect);
325 static void     gtk_tree_view_queue_draw_arrow               (GtkTreeView        *tree_view,
326                                                               GtkRBTree          *tree,
327                                                               GtkRBNode          *node,
328                                                               const GdkRectangle *clip_rect);
329 static void     gtk_tree_view_draw_arrow                     (GtkTreeView        *tree_view,
330                                                               GtkRBTree          *tree,
331                                                               GtkRBNode          *node,
332                                                               gint                x,
333                                                               gint                y);
334 static void     gtk_tree_view_get_arrow_xrange               (GtkTreeView        *tree_view,
335                                                               GtkRBTree          *tree,
336                                                               gint               *x1,
337                                                               gint               *x2);
338 static gint     gtk_tree_view_new_column_width               (GtkTreeView        *tree_view,
339                                                               gint                i,
340                                                               gint               *x);
341 static void     gtk_tree_view_adjustment_changed             (GtkAdjustment      *adjustment,
342                                                               GtkTreeView        *tree_view);
343 static void     gtk_tree_view_build_tree                     (GtkTreeView        *tree_view,
344                                                               GtkRBTree          *tree,
345                                                               GtkTreeIter        *iter,
346                                                               gint                depth,
347                                                               gboolean            recurse);
348 static void     gtk_tree_view_clamp_node_visible             (GtkTreeView        *tree_view,
349                                                               GtkRBTree          *tree,
350                                                               GtkRBNode          *node);
351 static void     gtk_tree_view_clamp_column_visible           (GtkTreeView        *tree_view,
352                                                               GtkTreeViewColumn  *column,
353                                                               gboolean            focus_to_cell);
354 static gboolean gtk_tree_view_maybe_begin_dragging_row       (GtkTreeView        *tree_view,
355                                                               GdkEventMotion     *event);
356 static void     gtk_tree_view_focus_to_cursor                (GtkTreeView        *tree_view);
357 static void     gtk_tree_view_move_cursor_up_down            (GtkTreeView        *tree_view,
358                                                               gint                count);
359 static void     gtk_tree_view_move_cursor_page_up_down       (GtkTreeView        *tree_view,
360                                                               gint                count);
361 static void     gtk_tree_view_move_cursor_left_right         (GtkTreeView        *tree_view,
362                                                               gint                count);
363 static void     gtk_tree_view_move_cursor_start_end          (GtkTreeView        *tree_view,
364                                                               gint                count);
365 static gboolean gtk_tree_view_real_collapse_row              (GtkTreeView        *tree_view,
366                                                               GtkTreePath        *path,
367                                                               GtkRBTree          *tree,
368                                                               GtkRBNode          *node,
369                                                               gboolean            animate);
370 static gboolean gtk_tree_view_real_expand_row                (GtkTreeView        *tree_view,
371                                                               GtkTreePath        *path,
372                                                               GtkRBTree          *tree,
373                                                               GtkRBNode          *node,
374                                                               gboolean            open_all,
375                                                               gboolean            animate);
376 static void     gtk_tree_view_real_set_cursor                (GtkTreeView        *tree_view,
377                                                               GtkTreePath        *path,
378                                                               gboolean            clear_and_select,
379                                                               gboolean            clamp_node);
380 static gboolean gtk_tree_view_has_special_cell               (GtkTreeView        *tree_view);
381 static void     column_sizing_notify                         (GObject            *object,
382                                                               GParamSpec         *pspec,
383                                                               gpointer            data);
384 static gboolean expand_collapse_timeout                      (gpointer            data);
385 static void     add_expand_collapse_timeout                  (GtkTreeView        *tree_view,
386                                                               GtkRBTree          *tree,
387                                                               GtkRBNode          *node,
388                                                               gboolean            expand);
389 static void     remove_expand_collapse_timeout               (GtkTreeView        *tree_view);
390 static void     cancel_arrow_animation                       (GtkTreeView        *tree_view);
391 static gboolean do_expand_collapse                           (GtkTreeView        *tree_view);
392 static void     gtk_tree_view_stop_rubber_band               (GtkTreeView        *tree_view);
393
394 /* interactive search */
395 static void     gtk_tree_view_ensure_interactive_directory (GtkTreeView *tree_view);
396 static void     gtk_tree_view_search_dialog_hide     (GtkWidget        *search_dialog,
397                                                          GtkTreeView      *tree_view);
398 static void     gtk_tree_view_search_position_func      (GtkTreeView      *tree_view,
399                                                          GtkWidget        *search_dialog,
400                                                          gpointer          user_data);
401 static void     gtk_tree_view_search_disable_popdown    (GtkEntry         *entry,
402                                                          GtkMenu          *menu,
403                                                          gpointer          data);
404 static void     gtk_tree_view_search_preedit_changed    (GtkIMContext     *im_context,
405                                                          GtkTreeView      *tree_view);
406 static void     gtk_tree_view_search_activate           (GtkEntry         *entry,
407                                                          GtkTreeView      *tree_view);
408 static gboolean gtk_tree_view_real_search_enable_popdown(gpointer          data);
409 static void     gtk_tree_view_search_enable_popdown     (GtkWidget        *widget,
410                                                          gpointer          data);
411 static gboolean gtk_tree_view_search_delete_event       (GtkWidget        *widget,
412                                                          GdkEventAny      *event,
413                                                          GtkTreeView      *tree_view);
414 static gboolean gtk_tree_view_search_button_press_event (GtkWidget        *widget,
415                                                          GdkEventButton   *event,
416                                                          GtkTreeView      *tree_view);
417 static gboolean gtk_tree_view_search_scroll_event       (GtkWidget        *entry,
418                                                          GdkEventScroll   *event,
419                                                          GtkTreeView      *tree_view);
420 static gboolean gtk_tree_view_search_key_press_event    (GtkWidget        *entry,
421                                                          GdkEventKey      *event,
422                                                          GtkTreeView      *tree_view);
423 static gboolean gtk_tree_view_search_move               (GtkWidget        *window,
424                                                          GtkTreeView      *tree_view,
425                                                          gboolean          up);
426 static gboolean gtk_tree_view_search_equal_func         (GtkTreeModel     *model,
427                                                          gint              column,
428                                                          const gchar      *key,
429                                                          GtkTreeIter      *iter,
430                                                          gpointer          search_data);
431 static gboolean gtk_tree_view_search_iter               (GtkTreeModel     *model,
432                                                          GtkTreeSelection *selection,
433                                                          GtkTreeIter      *iter,
434                                                          const gchar      *text,
435                                                          gint             *count,
436                                                          gint              n);
437 static void     gtk_tree_view_search_init               (GtkWidget        *entry,
438                                                          GtkTreeView      *tree_view);
439 static void     gtk_tree_view_put                       (GtkTreeView      *tree_view,
440                                                          GtkWidget        *child_widget,
441                                                          gint              x,
442                                                          gint              y,
443                                                          gint              width,
444                                                          gint              height);
445 static gboolean gtk_tree_view_start_editing             (GtkTreeView      *tree_view,
446                                                          GtkTreePath      *cursor_path);
447 static void gtk_tree_view_real_start_editing (GtkTreeView       *tree_view,
448                                               GtkTreeViewColumn *column,
449                                               GtkTreePath       *path,
450                                               GtkCellEditable   *cell_editable,
451                                               GdkRectangle      *cell_area,
452                                               GdkEvent          *event,
453                                               guint              flags);
454 static void gtk_tree_view_stop_editing                  (GtkTreeView *tree_view,
455                                                          gboolean     cancel_editing);
456 static gboolean gtk_tree_view_real_start_interactive_search (GtkTreeView *tree_view,
457                                                              gboolean     keybinding);
458 static gboolean gtk_tree_view_start_interactive_search      (GtkTreeView *tree_view);
459 static GtkTreeViewColumn *gtk_tree_view_get_drop_column (GtkTreeView       *tree_view,
460                                                          GtkTreeViewColumn *column,
461                                                          gint               drop_position);
462
463 /* GtkBuildable */
464 static void gtk_tree_view_buildable_add_child (GtkBuildable *tree_view,
465                                                GtkBuilder  *builder,
466                                                GObject     *child,
467                                                const gchar *type);
468 static void gtk_tree_view_buildable_init      (GtkBuildableIface *iface);
469
470
471 static gboolean scroll_row_timeout                   (gpointer     data);
472 static void     add_scroll_timeout                   (GtkTreeView *tree_view);
473 static void     remove_scroll_timeout                (GtkTreeView *tree_view);
474
475 static guint tree_view_signals [LAST_SIGNAL] = { 0 };
476
477 \f
478
479 /* GType Methods
480  */
481
482 G_DEFINE_TYPE_WITH_CODE (GtkTreeView, gtk_tree_view, GTK_TYPE_CONTAINER,
483                          G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
484                                                 gtk_tree_view_buildable_init))
485
486 static void
487 gtk_tree_view_class_init (GtkTreeViewClass *class)
488 {
489   GObjectClass *o_class;
490   GtkObjectClass *object_class;
491   GtkWidgetClass *widget_class;
492   GtkContainerClass *container_class;
493   GtkBindingSet *binding_set;
494
495   binding_set = gtk_binding_set_by_class (class);
496
497   o_class = (GObjectClass *) class;
498   object_class = (GtkObjectClass *) class;
499   widget_class = (GtkWidgetClass *) class;
500   container_class = (GtkContainerClass *) class;
501
502   /* GObject signals */
503   o_class->set_property = gtk_tree_view_set_property;
504   o_class->get_property = gtk_tree_view_get_property;
505   o_class->finalize = gtk_tree_view_finalize;
506
507   /* GtkObject signals */
508   object_class->destroy = gtk_tree_view_destroy;
509
510   /* GtkWidget signals */
511   widget_class->map = gtk_tree_view_map;
512   widget_class->realize = gtk_tree_view_realize;
513   widget_class->unrealize = gtk_tree_view_unrealize;
514   widget_class->size_request = gtk_tree_view_size_request;
515   widget_class->size_allocate = gtk_tree_view_size_allocate;
516   widget_class->button_press_event = gtk_tree_view_button_press;
517   widget_class->button_release_event = gtk_tree_view_button_release;
518   widget_class->grab_broken_event = gtk_tree_view_grab_broken;
519   /*widget_class->configure_event = gtk_tree_view_configure;*/
520   widget_class->motion_notify_event = gtk_tree_view_motion;
521   widget_class->expose_event = gtk_tree_view_expose;
522   widget_class->key_press_event = gtk_tree_view_key_press;
523   widget_class->key_release_event = gtk_tree_view_key_release;
524   widget_class->enter_notify_event = gtk_tree_view_enter_notify;
525   widget_class->leave_notify_event = gtk_tree_view_leave_notify;
526   widget_class->focus_out_event = gtk_tree_view_focus_out;
527   widget_class->drag_begin = gtk_tree_view_drag_begin;
528   widget_class->drag_end = gtk_tree_view_drag_end;
529   widget_class->drag_data_get = gtk_tree_view_drag_data_get;
530   widget_class->drag_data_delete = gtk_tree_view_drag_data_delete;
531   widget_class->drag_leave = gtk_tree_view_drag_leave;
532   widget_class->drag_motion = gtk_tree_view_drag_motion;
533   widget_class->drag_drop = gtk_tree_view_drag_drop;
534   widget_class->drag_data_received = gtk_tree_view_drag_data_received;
535   widget_class->focus = gtk_tree_view_focus;
536   widget_class->grab_focus = gtk_tree_view_grab_focus;
537   widget_class->style_set = gtk_tree_view_style_set;
538   widget_class->grab_notify = gtk_tree_view_grab_notify;
539   widget_class->state_changed = gtk_tree_view_state_changed;
540
541   /* GtkContainer signals */
542   container_class->remove = gtk_tree_view_remove;
543   container_class->forall = gtk_tree_view_forall;
544   container_class->set_focus_child = gtk_tree_view_set_focus_child;
545
546   class->set_scroll_adjustments = gtk_tree_view_set_adjustments;
547   class->move_cursor = gtk_tree_view_real_move_cursor;
548   class->select_all = gtk_tree_view_real_select_all;
549   class->unselect_all = gtk_tree_view_real_unselect_all;
550   class->select_cursor_row = gtk_tree_view_real_select_cursor_row;
551   class->toggle_cursor_row = gtk_tree_view_real_toggle_cursor_row;
552   class->expand_collapse_cursor_row = gtk_tree_view_real_expand_collapse_cursor_row;
553   class->select_cursor_parent = gtk_tree_view_real_select_cursor_parent;
554   class->start_interactive_search = gtk_tree_view_start_interactive_search;
555
556   /* Properties */
557
558   g_object_class_install_property (o_class,
559                                    PROP_MODEL,
560                                    g_param_spec_object ("model",
561                                                         P_("TreeView Model"),
562                                                         P_("The model for the tree view"),
563                                                         GTK_TYPE_TREE_MODEL,
564                                                         GTK_PARAM_READWRITE));
565
566   g_object_class_install_property (o_class,
567                                    PROP_HADJUSTMENT,
568                                    g_param_spec_object ("hadjustment",
569                                                         P_("Horizontal Adjustment"),
570                                                         P_("Horizontal Adjustment for the widget"),
571                                                         GTK_TYPE_ADJUSTMENT,
572                                                         GTK_PARAM_READWRITE));
573
574   g_object_class_install_property (o_class,
575                                    PROP_VADJUSTMENT,
576                                    g_param_spec_object ("vadjustment",
577                                                         P_("Vertical Adjustment"),
578                                                         P_("Vertical Adjustment for the widget"),
579                                                         GTK_TYPE_ADJUSTMENT,
580                                                         GTK_PARAM_READWRITE));
581
582   g_object_class_install_property (o_class,
583                                    PROP_HEADERS_VISIBLE,
584                                    g_param_spec_boolean ("headers-visible",
585                                                          P_("Headers Visible"),
586                                                          P_("Show the column header buttons"),
587                                                          TRUE,
588                                                          GTK_PARAM_READWRITE));
589
590   g_object_class_install_property (o_class,
591                                    PROP_HEADERS_CLICKABLE,
592                                    g_param_spec_boolean ("headers-clickable",
593                                                          P_("Headers Clickable"),
594                                                          P_("Column headers respond to click events"),
595                                                          TRUE,
596                                                          GTK_PARAM_READWRITE));
597
598   g_object_class_install_property (o_class,
599                                    PROP_EXPANDER_COLUMN,
600                                    g_param_spec_object ("expander-column",
601                                                         P_("Expander Column"),
602                                                         P_("Set the column for the expander column"),
603                                                         GTK_TYPE_TREE_VIEW_COLUMN,
604                                                         GTK_PARAM_READWRITE));
605
606   g_object_class_install_property (o_class,
607                                    PROP_REORDERABLE,
608                                    g_param_spec_boolean ("reorderable",
609                                                          P_("Reorderable"),
610                                                          P_("View is reorderable"),
611                                                          FALSE,
612                                                          GTK_PARAM_READWRITE));
613
614   g_object_class_install_property (o_class,
615                                    PROP_RULES_HINT,
616                                    g_param_spec_boolean ("rules-hint",
617                                                          P_("Rules Hint"),
618                                                          P_("Set a hint to the theme engine to draw rows in alternating colors"),
619                                                          FALSE,
620                                                          GTK_PARAM_READWRITE));
621
622     g_object_class_install_property (o_class,
623                                      PROP_ENABLE_SEARCH,
624                                      g_param_spec_boolean ("enable-search",
625                                                            P_("Enable Search"),
626                                                            P_("View allows user to search through columns interactively"),
627                                                            TRUE,
628                                                            GTK_PARAM_READWRITE));
629
630     g_object_class_install_property (o_class,
631                                      PROP_SEARCH_COLUMN,
632                                      g_param_spec_int ("search-column",
633                                                        P_("Search Column"),
634                                                        P_("Model column to search through during interactive search"),
635                                                        -1,
636                                                        G_MAXINT,
637                                                        -1,
638                                                        GTK_PARAM_READWRITE));
639
640     /**
641      * GtkTreeView:fixed-height-mode:
642      *
643      * Setting the ::fixed-height-mode property to %TRUE speeds up 
644      * #GtkTreeView by assuming that all rows have the same height. 
645      * Only enable this option if all rows are the same height.  
646      * Please see gtk_tree_view_set_fixed_height_mode() for more 
647      * information on this option.
648      *
649      * Since: 2.4
650      **/
651     g_object_class_install_property (o_class,
652                                      PROP_FIXED_HEIGHT_MODE,
653                                      g_param_spec_boolean ("fixed-height-mode",
654                                                            P_("Fixed Height Mode"),
655                                                            P_("Speeds up GtkTreeView by assuming that all rows have the same height"),
656                                                            FALSE,
657                                                            GTK_PARAM_READWRITE));
658     
659     /**
660      * GtkTreeView:hover-selection:
661      * 
662      * Enables of disables the hover selection mode of @tree_view.
663      * Hover selection makes the selected row follow the pointer.
664      * Currently, this works only for the selection modes 
665      * %GTK_SELECTION_SINGLE and %GTK_SELECTION_BROWSE.
666      *
667      * This mode is primarily intended for treeviews in popups, e.g.
668      * in #GtkComboBox or #GtkEntryCompletion.
669      *
670      * Since: 2.6
671      */
672     g_object_class_install_property (o_class,
673                                      PROP_HOVER_SELECTION,
674                                      g_param_spec_boolean ("hover-selection",
675                                                            P_("Hover Selection"),
676                                                            P_("Whether the selection should follow the pointer"),
677                                                            FALSE,
678                                                            GTK_PARAM_READWRITE));
679
680     /**
681      * GtkTreeView:hover-expand:
682      * 
683      * Enables of disables the hover expansion mode of @tree_view.
684      * Hover expansion makes rows expand or collapse if the pointer moves 
685      * over them.
686      *
687      * This mode is primarily intended for treeviews in popups, e.g.
688      * in #GtkComboBox or #GtkEntryCompletion.
689      *
690      * Since: 2.6
691      */
692     g_object_class_install_property (o_class,
693                                      PROP_HOVER_EXPAND,
694                                      g_param_spec_boolean ("hover-expand",
695                                                            P_("Hover Expand"),
696                                                            P_("Whether rows should be expanded/collapsed when the pointer moves over them"),
697                                                            FALSE,
698                                                            GTK_PARAM_READWRITE));
699
700     /**
701      * GtkTreeView:show-expanders:
702      *
703      * %TRUE if the view has expanders.
704      *
705      * Since: 2.12
706      */
707     g_object_class_install_property (o_class,
708                                      PROP_SHOW_EXPANDERS,
709                                      g_param_spec_boolean ("show-expanders",
710                                                            P_("Show Expanders"),
711                                                            P_("View has expanders"),
712                                                            TRUE,
713                                                            GTK_PARAM_READWRITE));
714
715     /**
716      * GtkTreeView:level-indentation:
717      *
718      * Extra indentation for each level.
719      *
720      * Since: 2.12
721      */
722     g_object_class_install_property (o_class,
723                                      PROP_LEVEL_INDENTATION,
724                                      g_param_spec_int ("level-indentation",
725                                                        P_("Level Indentation"),
726                                                        P_("Extra indentation for each level"),
727                                                        0,
728                                                        G_MAXINT,
729                                                        0,
730                                                        GTK_PARAM_READWRITE));
731
732     g_object_class_install_property (o_class,
733                                      PROP_RUBBER_BANDING,
734                                      g_param_spec_boolean ("rubber-banding",
735                                                            P_("Rubber Banding"),
736                                                            P_("Whether to enable selection of multiple items by dragging the mouse pointer"),
737                                                            FALSE,
738                                                            GTK_PARAM_READWRITE));
739
740     g_object_class_install_property (o_class,
741                                      PROP_ENABLE_GRID_LINES,
742                                      g_param_spec_enum ("enable-grid-lines",
743                                                         P_("Enable Grid Lines"),
744                                                         P_("Whether grid lines should be drawn in the tree view"),
745                                                         GTK_TYPE_TREE_VIEW_GRID_LINES,
746                                                         GTK_TREE_VIEW_GRID_LINES_NONE,
747                                                         GTK_PARAM_READWRITE));
748
749     g_object_class_install_property (o_class,
750                                      PROP_ENABLE_TREE_LINES,
751                                      g_param_spec_boolean ("enable-tree-lines",
752                                                            P_("Enable Tree Lines"),
753                                                            P_("Whether tree lines should be drawn in the tree view"),
754                                                            FALSE,
755                                                            GTK_PARAM_READWRITE));
756
757     g_object_class_install_property (o_class,
758                                      PROP_TOOLTIP_COLUMN,
759                                      g_param_spec_int ("tooltip-column",
760                                                        P_("Tooltip Column"),
761                                                        P_("The column in the model containing the tooltip texts for the rows"),
762                                                        -1,
763                                                        G_MAXINT,
764                                                        -1,
765                                                        GTK_PARAM_READWRITE));
766
767   /* Style properties */
768 #define _TREE_VIEW_EXPANDER_SIZE 12
769 #define _TREE_VIEW_VERTICAL_SEPARATOR 2
770 #define _TREE_VIEW_HORIZONTAL_SEPARATOR 2
771
772   gtk_widget_class_install_style_property (widget_class,
773                                            g_param_spec_int ("expander-size",
774                                                              P_("Expander Size"),
775                                                              P_("Size of the expander arrow"),
776                                                              0,
777                                                              G_MAXINT,
778                                                              _TREE_VIEW_EXPANDER_SIZE,
779                                                              GTK_PARAM_READABLE));
780
781   gtk_widget_class_install_style_property (widget_class,
782                                            g_param_spec_int ("vertical-separator",
783                                                              P_("Vertical Separator Width"),
784                                                              P_("Vertical space between cells.  Must be an even number"),
785                                                              0,
786                                                              G_MAXINT,
787                                                              _TREE_VIEW_VERTICAL_SEPARATOR,
788                                                              GTK_PARAM_READABLE));
789
790   gtk_widget_class_install_style_property (widget_class,
791                                            g_param_spec_int ("horizontal-separator",
792                                                              P_("Horizontal Separator Width"),
793                                                              P_("Horizontal space between cells.  Must be an even number"),
794                                                              0,
795                                                              G_MAXINT,
796                                                              _TREE_VIEW_HORIZONTAL_SEPARATOR,
797                                                              GTK_PARAM_READABLE));
798
799   gtk_widget_class_install_style_property (widget_class,
800                                            g_param_spec_boolean ("allow-rules",
801                                                                  P_("Allow Rules"),
802                                                                  P_("Allow drawing of alternating color rows"),
803                                                                  TRUE,
804                                                                  GTK_PARAM_READABLE));
805
806   gtk_widget_class_install_style_property (widget_class,
807                                            g_param_spec_boolean ("indent-expanders",
808                                                                  P_("Indent Expanders"),
809                                                                  P_("Make the expanders indented"),
810                                                                  TRUE,
811                                                                  GTK_PARAM_READABLE));
812
813   gtk_widget_class_install_style_property (widget_class,
814                                            g_param_spec_boxed ("even-row-color",
815                                                                P_("Even Row Color"),
816                                                                P_("Color to use for even rows"),
817                                                                GDK_TYPE_COLOR,
818                                                                GTK_PARAM_READABLE));
819
820   gtk_widget_class_install_style_property (widget_class,
821                                            g_param_spec_boxed ("odd-row-color",
822                                                                P_("Odd Row Color"),
823                                                                P_("Color to use for odd rows"),
824                                                                GDK_TYPE_COLOR,
825                                                                GTK_PARAM_READABLE));
826
827   gtk_widget_class_install_style_property (widget_class,
828                                            g_param_spec_boolean ("row-ending-details",
829                                                                  P_("Row Ending details"),
830                                                                  P_("Enable extended row background theming"),
831                                                                  FALSE,
832                                                                  GTK_PARAM_READABLE));
833
834   gtk_widget_class_install_style_property (widget_class,
835                                            g_param_spec_int ("grid-line-width",
836                                                              P_("Grid line width"),
837                                                              P_("Width, in pixels, of the tree view grid lines"),
838                                                              0, G_MAXINT, 1,
839                                                              GTK_PARAM_READABLE));
840
841   gtk_widget_class_install_style_property (widget_class,
842                                            g_param_spec_int ("tree-line-width",
843                                                              P_("Tree line width"),
844                                                              P_("Width, in pixels, of the tree view lines"),
845                                                              0, G_MAXINT, 1,
846                                                              GTK_PARAM_READABLE));
847
848   gtk_widget_class_install_style_property (widget_class,
849                                            g_param_spec_string ("grid-line-pattern",
850                                                                 P_("Grid line pattern"),
851                                                                 P_("Dash pattern used to draw the tree view grid lines"),
852                                                                 "\1\1",
853                                                                 GTK_PARAM_READABLE));
854
855   gtk_widget_class_install_style_property (widget_class,
856                                            g_param_spec_string ("tree-line-pattern",
857                                                                 P_("Tree line pattern"),
858                                                                 P_("Dash pattern used to draw the tree view lines"),
859                                                                 "\1\1",
860                                                                 GTK_PARAM_READABLE));
861
862   /* Signals */
863   /**
864    * GtkTreeView::set-scroll-adjustments
865    * @horizontal: the horizontal #GtkAdjustment
866    * @vertical: the vertical #GtkAdjustment
867    *
868    * Set the scroll adjustments for the tree view. Usually scrolled containers
869    * like #GtkScrolledWindow will emit this signal to connect two instances
870    * of #GtkScrollbar to the scroll directions of the #GtkTreeView.
871    */
872   widget_class->set_scroll_adjustments_signal =
873     g_signal_new (I_("set-scroll-adjustments"),
874                   G_TYPE_FROM_CLASS (o_class),
875                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
876                   G_STRUCT_OFFSET (GtkTreeViewClass, set_scroll_adjustments),
877                   NULL, NULL,
878                   _gtk_marshal_VOID__OBJECT_OBJECT,
879                   G_TYPE_NONE, 2,
880                   GTK_TYPE_ADJUSTMENT,
881                   GTK_TYPE_ADJUSTMENT);
882
883   /**
884    * GtkTreeView::row-activated:
885    * @tree_view: the object on which the signal is emitted
886    * @path: the #GtkTreePath for the activated row
887    * @column: the #GtkTreeViewColumn in which the activation occurred
888    *
889    * The "row-activated" signal is emitted when the method
890    * gtk_tree_view_row_activated() is called or the user double clicks 
891    * a treeview row. It is also emitted when a non-editable row is 
892    * selected and one of the keys: Space, Shift+Space, Return or 
893    * Enter is pressed.
894    * 
895    * For selection handling refer to the <link linkend="TreeWidget">tree 
896    * widget conceptual overview</link> as well as #GtkTreeSelection.
897    */
898   tree_view_signals[ROW_ACTIVATED] =
899     g_signal_new (I_("row-activated"),
900                   G_TYPE_FROM_CLASS (o_class),
901                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
902                   G_STRUCT_OFFSET (GtkTreeViewClass, row_activated),
903                   NULL, NULL,
904                   _gtk_marshal_VOID__BOXED_OBJECT,
905                   G_TYPE_NONE, 2,
906                   GTK_TYPE_TREE_PATH,
907                   GTK_TYPE_TREE_VIEW_COLUMN);
908
909   /**
910    * GtkTreeView::test-expand-row:
911    * @tree_view: the object on which the signal is emitted
912    * @iter: the tree iter of the row to expand
913    * @path: a tree path that points to the row 
914    * 
915    * The given row is about to be expanded (show its children nodes). Use this
916    * signal if you need to control the expandability of individual rows.
917    *
918    * Returns: %FALSE to allow expansion, %TRUE to reject
919    */
920   tree_view_signals[TEST_EXPAND_ROW] =
921     g_signal_new (I_("test-expand-row"),
922                   G_TYPE_FROM_CLASS (o_class),
923                   G_SIGNAL_RUN_LAST,
924                   G_STRUCT_OFFSET (GtkTreeViewClass, test_expand_row),
925                   _gtk_boolean_handled_accumulator, NULL,
926                   _gtk_marshal_BOOLEAN__BOXED_BOXED,
927                   G_TYPE_BOOLEAN, 2,
928                   GTK_TYPE_TREE_ITER,
929                   GTK_TYPE_TREE_PATH);
930
931   /**
932    * GtkTreeView::test-collapse-row:
933    * @tree_view: the object on which the signal is emitted
934    * @iter: the tree iter of the row to collapse
935    * @path: a tree path that points to the row 
936    * 
937    * The given row is about to be collapsed (hide its children nodes). Use this
938    * signal if you need to control the collapsibility of individual rows.
939    *
940    * Returns: %FALSE to allow collapsing, %TRUE to reject
941    */
942   tree_view_signals[TEST_COLLAPSE_ROW] =
943     g_signal_new (I_("test-collapse-row"),
944                   G_TYPE_FROM_CLASS (o_class),
945                   G_SIGNAL_RUN_LAST,
946                   G_STRUCT_OFFSET (GtkTreeViewClass, test_collapse_row),
947                   _gtk_boolean_handled_accumulator, NULL,
948                   _gtk_marshal_BOOLEAN__BOXED_BOXED,
949                   G_TYPE_BOOLEAN, 2,
950                   GTK_TYPE_TREE_ITER,
951                   GTK_TYPE_TREE_PATH);
952
953   /**
954    * GtkTreeView::row-expanded:
955    * @tree_view: the object on which the signal is emitted
956    * @iter: the tree iter of the expanded row
957    * @path: a tree path that points to the row 
958    * 
959    * The given row has been expanded (child nodes are shown).
960    */
961   tree_view_signals[ROW_EXPANDED] =
962     g_signal_new (I_("row-expanded"),
963                   G_TYPE_FROM_CLASS (o_class),
964                   G_SIGNAL_RUN_LAST,
965                   G_STRUCT_OFFSET (GtkTreeViewClass, row_expanded),
966                   NULL, NULL,
967                   _gtk_marshal_VOID__BOXED_BOXED,
968                   G_TYPE_NONE, 2,
969                   GTK_TYPE_TREE_ITER,
970                   GTK_TYPE_TREE_PATH);
971
972   /**
973    * GtkTreeView::row-collapsed:
974    * @tree_view: the object on which the signal is emitted
975    * @iter: the tree iter of the collapsed row
976    * @path: a tree path that points to the row 
977    * 
978    * The given row has been collapsed (child nodes are hidden).
979    */
980   tree_view_signals[ROW_COLLAPSED] =
981     g_signal_new (I_("row-collapsed"),
982                   G_TYPE_FROM_CLASS (o_class),
983                   G_SIGNAL_RUN_LAST,
984                   G_STRUCT_OFFSET (GtkTreeViewClass, row_collapsed),
985                   NULL, NULL,
986                   _gtk_marshal_VOID__BOXED_BOXED,
987                   G_TYPE_NONE, 2,
988                   GTK_TYPE_TREE_ITER,
989                   GTK_TYPE_TREE_PATH);
990
991   /**
992    * GtkTreeView::columns-changed:
993    * @tree_view: the object on which the signal is emitted 
994    * 
995    * The number of columns of the treeview has changed.
996    */
997   tree_view_signals[COLUMNS_CHANGED] =
998     g_signal_new (I_("columns-changed"),
999                   G_TYPE_FROM_CLASS (o_class),
1000                   G_SIGNAL_RUN_LAST,
1001                   G_STRUCT_OFFSET (GtkTreeViewClass, columns_changed),
1002                   NULL, NULL,
1003                   _gtk_marshal_VOID__VOID,
1004                   G_TYPE_NONE, 0);
1005
1006   /**
1007    * GtkTreeView::cursor-changed:
1008    * @tree_view: the object on which the signal is emitted
1009    * 
1010    * The position of the cursor (focused cell) has changed.
1011    */
1012   tree_view_signals[CURSOR_CHANGED] =
1013     g_signal_new (I_("cursor-changed"),
1014                   G_TYPE_FROM_CLASS (o_class),
1015                   G_SIGNAL_RUN_LAST,
1016                   G_STRUCT_OFFSET (GtkTreeViewClass, cursor_changed),
1017                   NULL, NULL,
1018                   _gtk_marshal_VOID__VOID,
1019                   G_TYPE_NONE, 0);
1020
1021   tree_view_signals[MOVE_CURSOR] =
1022     g_signal_new (I_("move-cursor"),
1023                   G_TYPE_FROM_CLASS (object_class),
1024                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1025                   G_STRUCT_OFFSET (GtkTreeViewClass, move_cursor),
1026                   NULL, NULL,
1027                   _gtk_marshal_BOOLEAN__ENUM_INT,
1028                   G_TYPE_BOOLEAN, 2,
1029                   GTK_TYPE_MOVEMENT_STEP,
1030                   G_TYPE_INT);
1031
1032   tree_view_signals[SELECT_ALL] =
1033     g_signal_new (I_("select-all"),
1034                   G_TYPE_FROM_CLASS (object_class),
1035                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1036                   G_STRUCT_OFFSET (GtkTreeViewClass, select_all),
1037                   NULL, NULL,
1038                   _gtk_marshal_BOOLEAN__VOID,
1039                   G_TYPE_BOOLEAN, 0);
1040
1041   tree_view_signals[UNSELECT_ALL] =
1042     g_signal_new (I_("unselect-all"),
1043                   G_TYPE_FROM_CLASS (object_class),
1044                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1045                   G_STRUCT_OFFSET (GtkTreeViewClass, unselect_all),
1046                   NULL, NULL,
1047                   _gtk_marshal_BOOLEAN__VOID,
1048                   G_TYPE_BOOLEAN, 0);
1049
1050   tree_view_signals[SELECT_CURSOR_ROW] =
1051     g_signal_new (I_("select-cursor-row"),
1052                   G_TYPE_FROM_CLASS (object_class),
1053                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1054                   G_STRUCT_OFFSET (GtkTreeViewClass, select_cursor_row),
1055                   NULL, NULL,
1056                   _gtk_marshal_BOOLEAN__BOOLEAN,
1057                   G_TYPE_BOOLEAN, 1,
1058                   G_TYPE_BOOLEAN);
1059
1060   tree_view_signals[TOGGLE_CURSOR_ROW] =
1061     g_signal_new (I_("toggle-cursor-row"),
1062                   G_TYPE_FROM_CLASS (object_class),
1063                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1064                   G_STRUCT_OFFSET (GtkTreeViewClass, toggle_cursor_row),
1065                   NULL, NULL,
1066                   _gtk_marshal_BOOLEAN__VOID,
1067                   G_TYPE_BOOLEAN, 0);
1068
1069   tree_view_signals[EXPAND_COLLAPSE_CURSOR_ROW] =
1070     g_signal_new (I_("expand-collapse-cursor-row"),
1071                   G_TYPE_FROM_CLASS (object_class),
1072                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1073                   G_STRUCT_OFFSET (GtkTreeViewClass, expand_collapse_cursor_row),
1074                   NULL, NULL,
1075                   _gtk_marshal_BOOLEAN__BOOLEAN_BOOLEAN_BOOLEAN,
1076                   G_TYPE_BOOLEAN, 3,
1077                   G_TYPE_BOOLEAN,
1078                   G_TYPE_BOOLEAN,
1079                   G_TYPE_BOOLEAN);
1080
1081   tree_view_signals[SELECT_CURSOR_PARENT] =
1082     g_signal_new (I_("select-cursor-parent"),
1083                   G_TYPE_FROM_CLASS (object_class),
1084                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1085                   G_STRUCT_OFFSET (GtkTreeViewClass, select_cursor_parent),
1086                   NULL, NULL,
1087                   _gtk_marshal_BOOLEAN__VOID,
1088                   G_TYPE_BOOLEAN, 0);
1089
1090   tree_view_signals[START_INTERACTIVE_SEARCH] =
1091     g_signal_new (I_("start-interactive-search"),
1092                   G_TYPE_FROM_CLASS (object_class),
1093                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1094                   G_STRUCT_OFFSET (GtkTreeViewClass, start_interactive_search),
1095                   NULL, NULL,
1096                   _gtk_marshal_BOOLEAN__VOID,
1097                   G_TYPE_BOOLEAN, 0);
1098
1099   /* Key bindings */
1100   gtk_tree_view_add_move_binding (binding_set, GDK_Up, 0, TRUE,
1101                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
1102   gtk_tree_view_add_move_binding (binding_set, GDK_KP_Up, 0, TRUE,
1103                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
1104
1105   gtk_tree_view_add_move_binding (binding_set, GDK_Down, 0, TRUE,
1106                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
1107   gtk_tree_view_add_move_binding (binding_set, GDK_KP_Down, 0, TRUE,
1108                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
1109
1110   gtk_tree_view_add_move_binding (binding_set, GDK_p, GDK_CONTROL_MASK, FALSE,
1111                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
1112
1113   gtk_tree_view_add_move_binding (binding_set, GDK_n, GDK_CONTROL_MASK, FALSE,
1114                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
1115
1116   gtk_tree_view_add_move_binding (binding_set, GDK_Home, 0, TRUE,
1117                                   GTK_MOVEMENT_BUFFER_ENDS, -1);
1118   gtk_tree_view_add_move_binding (binding_set, GDK_KP_Home, 0, TRUE,
1119                                   GTK_MOVEMENT_BUFFER_ENDS, -1);
1120
1121   gtk_tree_view_add_move_binding (binding_set, GDK_End, 0, TRUE,
1122                                   GTK_MOVEMENT_BUFFER_ENDS, 1);
1123   gtk_tree_view_add_move_binding (binding_set, GDK_KP_End, 0, TRUE,
1124                                   GTK_MOVEMENT_BUFFER_ENDS, 1);
1125
1126   gtk_tree_view_add_move_binding (binding_set, GDK_Page_Up, 0, TRUE,
1127                                   GTK_MOVEMENT_PAGES, -1);
1128   gtk_tree_view_add_move_binding (binding_set, GDK_KP_Page_Up, 0, TRUE,
1129                                   GTK_MOVEMENT_PAGES, -1);
1130
1131   gtk_tree_view_add_move_binding (binding_set, GDK_Page_Down, 0, TRUE,
1132                                   GTK_MOVEMENT_PAGES, 1);
1133   gtk_tree_view_add_move_binding (binding_set, GDK_KP_Page_Down, 0, TRUE,
1134                                   GTK_MOVEMENT_PAGES, 1);
1135
1136
1137   gtk_binding_entry_add_signal (binding_set, GDK_Right, 0, "move-cursor", 2,
1138                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1139                                 G_TYPE_INT, 1);
1140
1141   gtk_binding_entry_add_signal (binding_set, GDK_Left, 0, "move-cursor", 2,
1142                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1143                                 G_TYPE_INT, -1);
1144
1145   gtk_binding_entry_add_signal (binding_set, GDK_KP_Right, 0, "move-cursor", 2,
1146                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1147                                 G_TYPE_INT, 1);
1148
1149   gtk_binding_entry_add_signal (binding_set, GDK_KP_Left, 0, "move-cursor", 2,
1150                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1151                                 G_TYPE_INT, -1);
1152
1153   gtk_binding_entry_add_signal (binding_set, GDK_Right, GDK_CONTROL_MASK,
1154                                 "move-cursor", 2,
1155                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1156                                 G_TYPE_INT, 1);
1157
1158   gtk_binding_entry_add_signal (binding_set, GDK_Left, GDK_CONTROL_MASK,
1159                                 "move-cursor", 2,
1160                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1161                                 G_TYPE_INT, -1);
1162
1163   gtk_binding_entry_add_signal (binding_set, GDK_KP_Right, GDK_CONTROL_MASK,
1164                                 "move-cursor", 2,
1165                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1166                                 G_TYPE_INT, 1);
1167
1168   gtk_binding_entry_add_signal (binding_set, GDK_KP_Left, GDK_CONTROL_MASK,
1169                                 "move-cursor", 2,
1170                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1171                                 G_TYPE_INT, -1);
1172
1173   gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_CONTROL_MASK, "toggle-cursor-row", 0);
1174   gtk_binding_entry_add_signal (binding_set, GDK_KP_Space, GDK_CONTROL_MASK, "toggle-cursor-row", 0);
1175
1176   gtk_binding_entry_add_signal (binding_set, GDK_a, GDK_CONTROL_MASK, "select-all", 0);
1177   gtk_binding_entry_add_signal (binding_set, GDK_slash, GDK_CONTROL_MASK, "select-all", 0);
1178
1179   gtk_binding_entry_add_signal (binding_set, GDK_A, GDK_CONTROL_MASK | GDK_SHIFT_MASK, "unselect-all", 0);
1180   gtk_binding_entry_add_signal (binding_set, GDK_backslash, GDK_CONTROL_MASK, "unselect-all", 0);
1181
1182   gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_SHIFT_MASK, "select-cursor-row", 1,
1183                                 G_TYPE_BOOLEAN, TRUE);
1184   gtk_binding_entry_add_signal (binding_set, GDK_KP_Space, GDK_SHIFT_MASK, "select-cursor-row", 1,
1185                                 G_TYPE_BOOLEAN, TRUE);
1186
1187   gtk_binding_entry_add_signal (binding_set, GDK_space, 0, "select-cursor-row", 1,
1188                                 G_TYPE_BOOLEAN, TRUE);
1189   gtk_binding_entry_add_signal (binding_set, GDK_KP_Space, 0, "select-cursor-row", 1,
1190                                 G_TYPE_BOOLEAN, TRUE);
1191   gtk_binding_entry_add_signal (binding_set, GDK_Return, 0, "select-cursor-row", 1,
1192                                 G_TYPE_BOOLEAN, TRUE);
1193   gtk_binding_entry_add_signal (binding_set, GDK_ISO_Enter, 0, "select-cursor-row", 1,
1194                                 G_TYPE_BOOLEAN, TRUE);
1195   gtk_binding_entry_add_signal (binding_set, GDK_KP_Enter, 0, "select-cursor-row", 1,
1196                                 G_TYPE_BOOLEAN, TRUE);
1197
1198   /* expand and collapse rows */
1199   gtk_binding_entry_add_signal (binding_set, GDK_plus, 0, "expand-collapse-cursor-row", 3,
1200                                 G_TYPE_BOOLEAN, TRUE,
1201                                 G_TYPE_BOOLEAN, TRUE,
1202                                 G_TYPE_BOOLEAN, FALSE);
1203
1204   gtk_binding_entry_add_signal (binding_set, GDK_asterisk, 0,
1205                                 "expand-collapse-cursor-row", 3,
1206                                 G_TYPE_BOOLEAN, TRUE,
1207                                 G_TYPE_BOOLEAN, TRUE,
1208                                 G_TYPE_BOOLEAN, TRUE);
1209   gtk_binding_entry_add_signal (binding_set, GDK_KP_Multiply, 0,
1210                                 "expand-collapse-cursor-row", 3,
1211                                 G_TYPE_BOOLEAN, TRUE,
1212                                 G_TYPE_BOOLEAN, TRUE,
1213                                 G_TYPE_BOOLEAN, TRUE);
1214
1215   gtk_binding_entry_add_signal (binding_set, GDK_slash, 0,
1216                                 "expand-collapse-cursor-row", 3,
1217                                 G_TYPE_BOOLEAN, TRUE,
1218                                 G_TYPE_BOOLEAN, FALSE,
1219                                 G_TYPE_BOOLEAN, FALSE);
1220   gtk_binding_entry_add_signal (binding_set, GDK_KP_Divide, 0,
1221                                 "expand-collapse-cursor-row", 3,
1222                                 G_TYPE_BOOLEAN, TRUE,
1223                                 G_TYPE_BOOLEAN, FALSE,
1224                                 G_TYPE_BOOLEAN, FALSE);
1225
1226   /* Not doable on US keyboards */
1227   gtk_binding_entry_add_signal (binding_set, GDK_plus, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1228                                 G_TYPE_BOOLEAN, TRUE,
1229                                 G_TYPE_BOOLEAN, TRUE,
1230                                 G_TYPE_BOOLEAN, TRUE);
1231   gtk_binding_entry_add_signal (binding_set, GDK_KP_Add, 0, "expand-collapse-cursor-row", 3,
1232                                 G_TYPE_BOOLEAN, TRUE,
1233                                 G_TYPE_BOOLEAN, TRUE,
1234                                 G_TYPE_BOOLEAN, FALSE);
1235   gtk_binding_entry_add_signal (binding_set, GDK_KP_Add, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1236                                 G_TYPE_BOOLEAN, TRUE,
1237                                 G_TYPE_BOOLEAN, TRUE,
1238                                 G_TYPE_BOOLEAN, TRUE);
1239   gtk_binding_entry_add_signal (binding_set, GDK_KP_Add, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1240                                 G_TYPE_BOOLEAN, TRUE,
1241                                 G_TYPE_BOOLEAN, TRUE,
1242                                 G_TYPE_BOOLEAN, TRUE);
1243   gtk_binding_entry_add_signal (binding_set, GDK_Right, GDK_SHIFT_MASK,
1244                                 "expand-collapse-cursor-row", 3,
1245                                 G_TYPE_BOOLEAN, FALSE,
1246                                 G_TYPE_BOOLEAN, TRUE,
1247                                 G_TYPE_BOOLEAN, TRUE);
1248   gtk_binding_entry_add_signal (binding_set, GDK_KP_Right, GDK_SHIFT_MASK,
1249                                 "expand-collapse-cursor-row", 3,
1250                                 G_TYPE_BOOLEAN, FALSE,
1251                                 G_TYPE_BOOLEAN, TRUE,
1252                                 G_TYPE_BOOLEAN, TRUE);
1253   gtk_binding_entry_add_signal (binding_set, GDK_Right,
1254                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1255                                 "expand-collapse-cursor-row", 3,
1256                                 G_TYPE_BOOLEAN, FALSE,
1257                                 G_TYPE_BOOLEAN, TRUE,
1258                                 G_TYPE_BOOLEAN, TRUE);
1259   gtk_binding_entry_add_signal (binding_set, GDK_KP_Right,
1260                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1261                                 "expand-collapse-cursor-row", 3,
1262                                 G_TYPE_BOOLEAN, FALSE,
1263                                 G_TYPE_BOOLEAN, TRUE,
1264                                 G_TYPE_BOOLEAN, TRUE);
1265
1266   gtk_binding_entry_add_signal (binding_set, GDK_minus, 0, "expand-collapse-cursor-row", 3,
1267                                 G_TYPE_BOOLEAN, TRUE,
1268                                 G_TYPE_BOOLEAN, FALSE,
1269                                 G_TYPE_BOOLEAN, FALSE);
1270   gtk_binding_entry_add_signal (binding_set, GDK_minus, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1271                                 G_TYPE_BOOLEAN, TRUE,
1272                                 G_TYPE_BOOLEAN, FALSE,
1273                                 G_TYPE_BOOLEAN, TRUE);
1274   gtk_binding_entry_add_signal (binding_set, GDK_KP_Subtract, 0, "expand-collapse-cursor-row", 3,
1275                                 G_TYPE_BOOLEAN, TRUE,
1276                                 G_TYPE_BOOLEAN, FALSE,
1277                                 G_TYPE_BOOLEAN, FALSE);
1278   gtk_binding_entry_add_signal (binding_set, GDK_KP_Subtract, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1279                                 G_TYPE_BOOLEAN, TRUE,
1280                                 G_TYPE_BOOLEAN, FALSE,
1281                                 G_TYPE_BOOLEAN, TRUE);
1282   gtk_binding_entry_add_signal (binding_set, GDK_Left, GDK_SHIFT_MASK,
1283                                 "expand-collapse-cursor-row", 3,
1284                                 G_TYPE_BOOLEAN, FALSE,
1285                                 G_TYPE_BOOLEAN, FALSE,
1286                                 G_TYPE_BOOLEAN, TRUE);
1287   gtk_binding_entry_add_signal (binding_set, GDK_KP_Left, GDK_SHIFT_MASK,
1288                                 "expand-collapse-cursor-row", 3,
1289                                 G_TYPE_BOOLEAN, FALSE,
1290                                 G_TYPE_BOOLEAN, FALSE,
1291                                 G_TYPE_BOOLEAN, TRUE);
1292   gtk_binding_entry_add_signal (binding_set, GDK_Left,
1293                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1294                                 "expand-collapse-cursor-row", 3,
1295                                 G_TYPE_BOOLEAN, FALSE,
1296                                 G_TYPE_BOOLEAN, FALSE,
1297                                 G_TYPE_BOOLEAN, TRUE);
1298   gtk_binding_entry_add_signal (binding_set, GDK_KP_Left,
1299                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1300                                 "expand-collapse-cursor-row", 3,
1301                                 G_TYPE_BOOLEAN, FALSE,
1302                                 G_TYPE_BOOLEAN, FALSE,
1303                                 G_TYPE_BOOLEAN, TRUE);
1304
1305   gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, 0, "select-cursor-parent", 0);
1306   gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, GDK_CONTROL_MASK, "select-cursor-parent", 0);
1307
1308   gtk_binding_entry_add_signal (binding_set, GDK_f, GDK_CONTROL_MASK, "start-interactive-search", 0);
1309
1310   gtk_binding_entry_add_signal (binding_set, GDK_F, GDK_CONTROL_MASK, "start-interactive-search", 0);
1311
1312   g_type_class_add_private (o_class, sizeof (GtkTreeViewPrivate));
1313 }
1314
1315 static void
1316 gtk_tree_view_buildable_init (GtkBuildableIface *iface)
1317 {
1318   iface->add_child = gtk_tree_view_buildable_add_child;
1319 }
1320
1321 static void
1322 gtk_tree_view_init (GtkTreeView *tree_view)
1323 {
1324   tree_view->priv = G_TYPE_INSTANCE_GET_PRIVATE (tree_view, GTK_TYPE_TREE_VIEW, GtkTreeViewPrivate);
1325
1326   GTK_WIDGET_SET_FLAGS (tree_view, GTK_CAN_FOCUS);
1327
1328   gtk_widget_set_redraw_on_allocate (GTK_WIDGET (tree_view), FALSE);
1329
1330   tree_view->priv->flags =  GTK_TREE_VIEW_SHOW_EXPANDERS
1331                             | GTK_TREE_VIEW_DRAW_KEYFOCUS
1332                             | GTK_TREE_VIEW_HEADERS_VISIBLE;
1333
1334   /* We need some padding */
1335   tree_view->priv->dy = 0;
1336   tree_view->priv->cursor_offset = 0;
1337   tree_view->priv->n_columns = 0;
1338   tree_view->priv->header_height = 1;
1339   tree_view->priv->x_drag = 0;
1340   tree_view->priv->drag_pos = -1;
1341   tree_view->priv->header_has_focus = FALSE;
1342   tree_view->priv->pressed_button = -1;
1343   tree_view->priv->press_start_x = -1;
1344   tree_view->priv->press_start_y = -1;
1345   tree_view->priv->reorderable = FALSE;
1346   tree_view->priv->presize_handler_timer = 0;
1347   tree_view->priv->scroll_sync_timer = 0;
1348   tree_view->priv->fixed_height = -1;
1349   tree_view->priv->fixed_height_mode = FALSE;
1350   tree_view->priv->fixed_height_check = 0;
1351   gtk_tree_view_set_adjustments (tree_view, NULL, NULL);
1352   tree_view->priv->selection = _gtk_tree_selection_new_with_tree_view (tree_view);
1353   tree_view->priv->enable_search = TRUE;
1354   tree_view->priv->search_column = -1;
1355   tree_view->priv->search_position_func = gtk_tree_view_search_position_func;
1356   tree_view->priv->search_equal_func = gtk_tree_view_search_equal_func;
1357   tree_view->priv->search_custom_entry_set = FALSE;
1358   tree_view->priv->typeselect_flush_timeout = 0;
1359   tree_view->priv->init_hadjust_value = TRUE;    
1360   tree_view->priv->width = 0;
1361           
1362   tree_view->priv->hover_selection = FALSE;
1363   tree_view->priv->hover_expand = FALSE;
1364
1365   tree_view->priv->level_indentation = 0;
1366
1367   tree_view->priv->rubber_banding_enable = FALSE;
1368
1369   tree_view->priv->grid_lines = GTK_TREE_VIEW_GRID_LINES_NONE;
1370   tree_view->priv->tree_lines_enabled = FALSE;
1371
1372   tree_view->priv->tooltip_column = -1;
1373
1374   tree_view->priv->post_validation_flag = FALSE;
1375
1376   tree_view->priv->last_button_x = -1;
1377   tree_view->priv->last_button_y = -1;
1378 }
1379
1380 \f
1381
1382 /* GObject Methods
1383  */
1384
1385 static void
1386 gtk_tree_view_set_property (GObject         *object,
1387                             guint            prop_id,
1388                             const GValue    *value,
1389                             GParamSpec      *pspec)
1390 {
1391   GtkTreeView *tree_view;
1392
1393   tree_view = GTK_TREE_VIEW (object);
1394
1395   switch (prop_id)
1396     {
1397     case PROP_MODEL:
1398       gtk_tree_view_set_model (tree_view, g_value_get_object (value));
1399       break;
1400     case PROP_HADJUSTMENT:
1401       gtk_tree_view_set_hadjustment (tree_view, g_value_get_object (value));
1402       break;
1403     case PROP_VADJUSTMENT:
1404       gtk_tree_view_set_vadjustment (tree_view, g_value_get_object (value));
1405       break;
1406     case PROP_HEADERS_VISIBLE:
1407       gtk_tree_view_set_headers_visible (tree_view, g_value_get_boolean (value));
1408       break;
1409     case PROP_HEADERS_CLICKABLE:
1410       gtk_tree_view_set_headers_clickable (tree_view, g_value_get_boolean (value));
1411       break;
1412     case PROP_EXPANDER_COLUMN:
1413       gtk_tree_view_set_expander_column (tree_view, g_value_get_object (value));
1414       break;
1415     case PROP_REORDERABLE:
1416       gtk_tree_view_set_reorderable (tree_view, g_value_get_boolean (value));
1417       break;
1418     case PROP_RULES_HINT:
1419       gtk_tree_view_set_rules_hint (tree_view, g_value_get_boolean (value));
1420       break;
1421     case PROP_ENABLE_SEARCH:
1422       gtk_tree_view_set_enable_search (tree_view, g_value_get_boolean (value));
1423       break;
1424     case PROP_SEARCH_COLUMN:
1425       gtk_tree_view_set_search_column (tree_view, g_value_get_int (value));
1426       break;
1427     case PROP_FIXED_HEIGHT_MODE:
1428       gtk_tree_view_set_fixed_height_mode (tree_view, g_value_get_boolean (value));
1429       break;
1430     case PROP_HOVER_SELECTION:
1431       tree_view->priv->hover_selection = g_value_get_boolean (value);
1432       break;
1433     case PROP_HOVER_EXPAND:
1434       tree_view->priv->hover_expand = g_value_get_boolean (value);
1435       break;
1436     case PROP_SHOW_EXPANDERS:
1437       gtk_tree_view_set_show_expanders (tree_view, g_value_get_boolean (value));
1438       break;
1439     case PROP_LEVEL_INDENTATION:
1440       tree_view->priv->level_indentation = g_value_get_int (value);
1441       break;
1442     case PROP_RUBBER_BANDING:
1443       tree_view->priv->rubber_banding_enable = g_value_get_boolean (value);
1444       break;
1445     case PROP_ENABLE_GRID_LINES:
1446       gtk_tree_view_set_grid_lines (tree_view, g_value_get_enum (value));
1447       break;
1448     case PROP_ENABLE_TREE_LINES:
1449       gtk_tree_view_set_enable_tree_lines (tree_view, g_value_get_boolean (value));
1450       break;
1451     case PROP_TOOLTIP_COLUMN:
1452       gtk_tree_view_set_tooltip_column (tree_view, g_value_get_int (value));
1453       break;
1454     default:
1455       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1456       break;
1457     }
1458 }
1459
1460 static void
1461 gtk_tree_view_get_property (GObject    *object,
1462                             guint       prop_id,
1463                             GValue     *value,
1464                             GParamSpec *pspec)
1465 {
1466   GtkTreeView *tree_view;
1467
1468   tree_view = GTK_TREE_VIEW (object);
1469
1470   switch (prop_id)
1471     {
1472     case PROP_MODEL:
1473       g_value_set_object (value, tree_view->priv->model);
1474       break;
1475     case PROP_HADJUSTMENT:
1476       g_value_set_object (value, tree_view->priv->hadjustment);
1477       break;
1478     case PROP_VADJUSTMENT:
1479       g_value_set_object (value, tree_view->priv->vadjustment);
1480       break;
1481     case PROP_HEADERS_VISIBLE:
1482       g_value_set_boolean (value, gtk_tree_view_get_headers_visible (tree_view));
1483       break;
1484     case PROP_HEADERS_CLICKABLE:
1485       g_value_set_boolean (value, gtk_tree_view_get_headers_clickable (tree_view));
1486       break;
1487     case PROP_EXPANDER_COLUMN:
1488       g_value_set_object (value, tree_view->priv->expander_column);
1489       break;
1490     case PROP_REORDERABLE:
1491       g_value_set_boolean (value, tree_view->priv->reorderable);
1492       break;
1493     case PROP_RULES_HINT:
1494       g_value_set_boolean (value, tree_view->priv->has_rules);
1495       break;
1496     case PROP_ENABLE_SEARCH:
1497       g_value_set_boolean (value, tree_view->priv->enable_search);
1498       break;
1499     case PROP_SEARCH_COLUMN:
1500       g_value_set_int (value, tree_view->priv->search_column);
1501       break;
1502     case PROP_FIXED_HEIGHT_MODE:
1503       g_value_set_boolean (value, tree_view->priv->fixed_height_mode);
1504       break;
1505     case PROP_HOVER_SELECTION:
1506       g_value_set_boolean (value, tree_view->priv->hover_selection);
1507       break;
1508     case PROP_HOVER_EXPAND:
1509       g_value_set_boolean (value, tree_view->priv->hover_expand);
1510       break;
1511     case PROP_SHOW_EXPANDERS:
1512       g_value_set_boolean (value, GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS));
1513       break;
1514     case PROP_LEVEL_INDENTATION:
1515       g_value_set_int (value, tree_view->priv->level_indentation);
1516       break;
1517     case PROP_RUBBER_BANDING:
1518       g_value_set_boolean (value, tree_view->priv->rubber_banding_enable);
1519       break;
1520     case PROP_ENABLE_GRID_LINES:
1521       g_value_set_enum (value, tree_view->priv->grid_lines);
1522       break;
1523     case PROP_ENABLE_TREE_LINES:
1524       g_value_set_boolean (value, tree_view->priv->tree_lines_enabled);
1525       break;
1526     case PROP_TOOLTIP_COLUMN:
1527       g_value_set_int (value, tree_view->priv->tooltip_column);
1528       break;
1529     default:
1530       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1531       break;
1532     }
1533 }
1534
1535 static void
1536 gtk_tree_view_finalize (GObject *object)
1537 {
1538   G_OBJECT_CLASS (gtk_tree_view_parent_class)->finalize (object);
1539 }
1540
1541 \f
1542
1543 static void
1544 gtk_tree_view_buildable_add_child (GtkBuildable *tree_view,
1545                                    GtkBuilder  *builder,
1546                                    GObject     *child,
1547                                    const gchar *type)
1548 {
1549   gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), GTK_TREE_VIEW_COLUMN (child));
1550 }
1551
1552 /* GtkObject Methods
1553  */
1554
1555 static void
1556 gtk_tree_view_free_rbtree (GtkTreeView *tree_view)
1557 {
1558   _gtk_rbtree_free (tree_view->priv->tree);
1559   
1560   tree_view->priv->tree = NULL;
1561   tree_view->priv->button_pressed_node = NULL;
1562   tree_view->priv->button_pressed_tree = NULL;
1563   tree_view->priv->prelight_tree = NULL;
1564   tree_view->priv->prelight_node = NULL;
1565   tree_view->priv->expanded_collapsed_node = NULL;
1566   tree_view->priv->expanded_collapsed_tree = NULL;
1567 }
1568
1569 static void
1570 gtk_tree_view_destroy (GtkObject *object)
1571 {
1572   GtkTreeView *tree_view = GTK_TREE_VIEW (object);
1573   GList *list;
1574
1575   gtk_tree_view_stop_editing (tree_view, TRUE);
1576
1577   if (tree_view->priv->columns != NULL)
1578     {
1579       list = tree_view->priv->columns;
1580       while (list)
1581         {
1582           GtkTreeViewColumn *column;
1583           column = GTK_TREE_VIEW_COLUMN (list->data);
1584           list = list->next;
1585           gtk_tree_view_remove_column (tree_view, column);
1586         }
1587       tree_view->priv->columns = NULL;
1588     }
1589
1590   if (tree_view->priv->tree != NULL)
1591     {
1592       gtk_tree_view_unref_and_check_selection_tree (tree_view, tree_view->priv->tree);
1593
1594       gtk_tree_view_free_rbtree (tree_view);
1595     }
1596
1597   if (tree_view->priv->selection != NULL)
1598     {
1599       _gtk_tree_selection_set_tree_view (tree_view->priv->selection, NULL);
1600       g_object_unref (tree_view->priv->selection);
1601       tree_view->priv->selection = NULL;
1602     }
1603
1604   if (tree_view->priv->scroll_to_path != NULL)
1605     {
1606       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
1607       tree_view->priv->scroll_to_path = NULL;
1608     }
1609
1610   if (tree_view->priv->drag_dest_row != NULL)
1611     {
1612       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
1613       tree_view->priv->drag_dest_row = NULL;
1614     }
1615
1616   if (tree_view->priv->top_row != NULL)
1617     {
1618       gtk_tree_row_reference_free (tree_view->priv->top_row);
1619       tree_view->priv->top_row = NULL;
1620     }
1621
1622   if (tree_view->priv->column_drop_func_data &&
1623       tree_view->priv->column_drop_func_data_destroy)
1624     {
1625       tree_view->priv->column_drop_func_data_destroy (tree_view->priv->column_drop_func_data);
1626       tree_view->priv->column_drop_func_data = NULL;
1627     }
1628
1629   if (tree_view->priv->destroy_count_destroy &&
1630       tree_view->priv->destroy_count_data)
1631     {
1632       tree_view->priv->destroy_count_destroy (tree_view->priv->destroy_count_data);
1633       tree_view->priv->destroy_count_data = NULL;
1634     }
1635
1636   gtk_tree_row_reference_free (tree_view->priv->cursor);
1637   tree_view->priv->cursor = NULL;
1638
1639   gtk_tree_row_reference_free (tree_view->priv->anchor);
1640   tree_view->priv->anchor = NULL;
1641
1642   /* destroy interactive search dialog */
1643   if (tree_view->priv->search_window)
1644     {
1645       gtk_widget_destroy (tree_view->priv->search_window);
1646       tree_view->priv->search_window = NULL;
1647       tree_view->priv->search_entry = NULL;
1648       if (tree_view->priv->typeselect_flush_timeout)
1649         {
1650           g_source_remove (tree_view->priv->typeselect_flush_timeout);
1651           tree_view->priv->typeselect_flush_timeout = 0;
1652         }
1653     }
1654
1655   if (tree_view->priv->search_destroy && tree_view->priv->search_user_data)
1656     {
1657       tree_view->priv->search_destroy (tree_view->priv->search_user_data);
1658       tree_view->priv->search_user_data = NULL;
1659     }
1660
1661   if (tree_view->priv->search_position_destroy && tree_view->priv->search_position_user_data)
1662     {
1663       tree_view->priv->search_position_destroy (tree_view->priv->search_position_user_data);
1664       tree_view->priv->search_position_user_data = NULL;
1665     }
1666
1667   if (tree_view->priv->row_separator_destroy && tree_view->priv->row_separator_data)
1668     {
1669       tree_view->priv->row_separator_destroy (tree_view->priv->row_separator_data);
1670       tree_view->priv->row_separator_data = NULL;
1671     }
1672   
1673   gtk_tree_view_set_model (tree_view, NULL);
1674
1675   if (tree_view->priv->hadjustment)
1676     {
1677       g_object_unref (tree_view->priv->hadjustment);
1678       tree_view->priv->hadjustment = NULL;
1679     }
1680   if (tree_view->priv->vadjustment)
1681     {
1682       g_object_unref (tree_view->priv->vadjustment);
1683       tree_view->priv->vadjustment = NULL;
1684     }
1685
1686   GTK_OBJECT_CLASS (gtk_tree_view_parent_class)->destroy (object);
1687 }
1688
1689 \f
1690
1691 /* GtkWidget Methods
1692  */
1693
1694 /* GtkWidget::map helper */
1695 static void
1696 gtk_tree_view_map_buttons (GtkTreeView *tree_view)
1697 {
1698   GList *list;
1699
1700   g_return_if_fail (GTK_WIDGET_MAPPED (tree_view));
1701
1702   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
1703     {
1704       GtkTreeViewColumn *column;
1705
1706       for (list = tree_view->priv->columns; list; list = list->next)
1707         {
1708           column = list->data;
1709           if (GTK_WIDGET_VISIBLE (column->button) &&
1710               !GTK_WIDGET_MAPPED (column->button))
1711             gtk_widget_map (column->button);
1712         }
1713       for (list = tree_view->priv->columns; list; list = list->next)
1714         {
1715           column = list->data;
1716           if (column->visible == FALSE)
1717             continue;
1718           if (column->resizable)
1719             {
1720               gdk_window_raise (column->window);
1721               gdk_window_show (column->window);
1722             }
1723           else
1724             gdk_window_hide (column->window);
1725         }
1726       gdk_window_show (tree_view->priv->header_window);
1727     }
1728 }
1729
1730 static void
1731 gtk_tree_view_map (GtkWidget *widget)
1732 {
1733   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
1734   GList *tmp_list;
1735
1736   GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
1737
1738   tmp_list = tree_view->priv->children;
1739   while (tmp_list)
1740     {
1741       GtkTreeViewChild *child = tmp_list->data;
1742       tmp_list = tmp_list->next;
1743
1744       if (GTK_WIDGET_VISIBLE (child->widget))
1745         {
1746           if (!GTK_WIDGET_MAPPED (child->widget))
1747             gtk_widget_map (child->widget);
1748         }
1749     }
1750   gdk_window_show (tree_view->priv->bin_window);
1751
1752   gtk_tree_view_map_buttons (tree_view);
1753
1754   gdk_window_show (widget->window);
1755 }
1756
1757 static void
1758 gtk_tree_view_realize (GtkWidget *widget)
1759 {
1760   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
1761   GList *tmp_list;
1762   GdkWindowAttr attributes;
1763   gint attributes_mask;
1764
1765   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
1766
1767   /* Make the main, clipping window */
1768   attributes.window_type = GDK_WINDOW_CHILD;
1769   attributes.x = widget->allocation.x;
1770   attributes.y = widget->allocation.y;
1771   attributes.width = widget->allocation.width;
1772   attributes.height = widget->allocation.height;
1773   attributes.wclass = GDK_INPUT_OUTPUT;
1774   attributes.visual = gtk_widget_get_visual (widget);
1775   attributes.colormap = gtk_widget_get_colormap (widget);
1776   attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK;
1777
1778   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
1779
1780   widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
1781                                    &attributes, attributes_mask);
1782   gdk_window_set_user_data (widget->window, widget);
1783
1784   /* Make the window for the tree */
1785   attributes.x = 0;
1786   attributes.y = TREE_VIEW_HEADER_HEIGHT (tree_view);
1787   attributes.width = MAX (tree_view->priv->width, widget->allocation.width);
1788   attributes.height = widget->allocation.height;
1789   attributes.event_mask = (GDK_EXPOSURE_MASK |
1790                            GDK_SCROLL_MASK |
1791                            GDK_POINTER_MOTION_MASK |
1792                            GDK_ENTER_NOTIFY_MASK |
1793                            GDK_LEAVE_NOTIFY_MASK |
1794                            GDK_BUTTON_PRESS_MASK |
1795                            GDK_BUTTON_RELEASE_MASK |
1796                            gtk_widget_get_events (widget));
1797
1798   tree_view->priv->bin_window = gdk_window_new (widget->window,
1799                                                 &attributes, attributes_mask);
1800   gdk_window_set_user_data (tree_view->priv->bin_window, widget);
1801
1802   /* Make the column header window */
1803   attributes.x = 0;
1804   attributes.y = 0;
1805   attributes.width = MAX (tree_view->priv->width, widget->allocation.width);
1806   attributes.height = tree_view->priv->header_height;
1807   attributes.event_mask = (GDK_EXPOSURE_MASK |
1808                            GDK_SCROLL_MASK |
1809                            GDK_BUTTON_PRESS_MASK |
1810                            GDK_BUTTON_RELEASE_MASK |
1811                            GDK_KEY_PRESS_MASK |
1812                            GDK_KEY_RELEASE_MASK |
1813                            gtk_widget_get_events (widget));
1814
1815   tree_view->priv->header_window = gdk_window_new (widget->window,
1816                                                    &attributes, attributes_mask);
1817   gdk_window_set_user_data (tree_view->priv->header_window, widget);
1818
1819   /* Add them all up. */
1820   widget->style = gtk_style_attach (widget->style, widget->window);
1821   gdk_window_set_back_pixmap (widget->window, NULL, FALSE);
1822   gdk_window_set_background (tree_view->priv->bin_window, &widget->style->base[widget->state]);
1823   gtk_style_set_background (widget->style, tree_view->priv->header_window, GTK_STATE_NORMAL);
1824
1825   tmp_list = tree_view->priv->children;
1826   while (tmp_list)
1827     {
1828       GtkTreeViewChild *child = tmp_list->data;
1829       tmp_list = tmp_list->next;
1830
1831       gtk_widget_set_parent_window (child->widget, tree_view->priv->bin_window);
1832     }
1833
1834   for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
1835     _gtk_tree_view_column_realize_button (GTK_TREE_VIEW_COLUMN (tmp_list->data));
1836
1837   /* Need to call those here, since they create GCs */
1838   gtk_tree_view_set_grid_lines (tree_view, tree_view->priv->grid_lines);
1839   gtk_tree_view_set_enable_tree_lines (tree_view, tree_view->priv->tree_lines_enabled);
1840
1841   install_presize_handler (tree_view); 
1842 }
1843
1844 static void
1845 gtk_tree_view_unrealize (GtkWidget *widget)
1846 {
1847   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
1848   GtkTreeViewPrivate *priv = tree_view->priv;
1849   GList *list;
1850
1851   if (priv->scroll_timeout != 0)
1852     {
1853       g_source_remove (priv->scroll_timeout);
1854       priv->scroll_timeout = 0;
1855     }
1856
1857   if (priv->auto_expand_timeout != 0)
1858     {
1859       g_source_remove (priv->auto_expand_timeout);
1860       priv->auto_expand_timeout = 0;
1861     }
1862
1863   if (priv->open_dest_timeout != 0)
1864     {
1865       g_source_remove (priv->open_dest_timeout);
1866       priv->open_dest_timeout = 0;
1867     }
1868
1869   remove_expand_collapse_timeout (tree_view);
1870   
1871   if (priv->presize_handler_timer != 0)
1872     {
1873       g_source_remove (priv->presize_handler_timer);
1874       priv->presize_handler_timer = 0;
1875     }
1876
1877   if (priv->validate_rows_timer != 0)
1878     {
1879       g_source_remove (priv->validate_rows_timer);
1880       priv->validate_rows_timer = 0;
1881     }
1882
1883   if (priv->scroll_sync_timer != 0)
1884     {
1885       g_source_remove (priv->scroll_sync_timer);
1886       priv->scroll_sync_timer = 0;
1887     }
1888
1889   if (priv->typeselect_flush_timeout)
1890     {
1891       g_source_remove (priv->typeselect_flush_timeout);
1892       priv->typeselect_flush_timeout = 0;
1893     }
1894   
1895   for (list = priv->columns; list; list = list->next)
1896     _gtk_tree_view_column_unrealize_button (GTK_TREE_VIEW_COLUMN (list->data));
1897
1898   gdk_window_set_user_data (priv->bin_window, NULL);
1899   gdk_window_destroy (priv->bin_window);
1900   priv->bin_window = NULL;
1901
1902   gdk_window_set_user_data (priv->header_window, NULL);
1903   gdk_window_destroy (priv->header_window);
1904   priv->header_window = NULL;
1905
1906   if (priv->drag_window)
1907     {
1908       gdk_window_set_user_data (priv->drag_window, NULL);
1909       gdk_window_destroy (priv->drag_window);
1910       priv->drag_window = NULL;
1911     }
1912
1913   if (priv->drag_highlight_window)
1914     {
1915       gdk_window_set_user_data (priv->drag_highlight_window, NULL);
1916       gdk_window_destroy (priv->drag_highlight_window);
1917       priv->drag_highlight_window = NULL;
1918     }
1919
1920   if (priv->tree_line_gc)
1921     {
1922       g_object_unref (priv->tree_line_gc);
1923       priv->tree_line_gc = NULL;
1924     }
1925
1926   if (priv->grid_line_gc)
1927     {
1928       g_object_unref (priv->grid_line_gc);
1929       priv->grid_line_gc = NULL;
1930     }
1931
1932   GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->unrealize (widget);
1933 }
1934
1935 /* GtkWidget::size_request helper */
1936 static void
1937 gtk_tree_view_size_request_columns (GtkTreeView *tree_view)
1938 {
1939   GList *list;
1940
1941   tree_view->priv->header_height = 0;
1942
1943   if (tree_view->priv->model)
1944     {
1945       for (list = tree_view->priv->columns; list; list = list->next)
1946         {
1947           GtkRequisition requisition;
1948           GtkTreeViewColumn *column = list->data;
1949
1950           if (column->button == NULL)
1951             continue;
1952
1953           column = list->data;
1954           
1955           gtk_widget_size_request (column->button, &requisition);
1956           column->button_request = requisition.width;
1957           tree_view->priv->header_height = MAX (tree_view->priv->header_height, requisition.height);
1958         }
1959     }
1960 }
1961
1962
1963 /* Called only by ::size_request */
1964 static void
1965 gtk_tree_view_update_size (GtkTreeView *tree_view)
1966 {
1967   GList *list;
1968   GtkTreeViewColumn *column;
1969   gint i;
1970
1971   if (tree_view->priv->model == NULL)
1972     {
1973       tree_view->priv->width = 0;
1974       tree_view->priv->prev_width = 0;                   
1975       tree_view->priv->height = 0;
1976       return;
1977     }
1978
1979   tree_view->priv->prev_width = tree_view->priv->width;  
1980   tree_view->priv->width = 0;
1981
1982   /* keep this in sync with size_allocate below */
1983   for (list = tree_view->priv->columns, i = 0; list; list = list->next, i++)
1984     {
1985       gint real_requested_width = 0;
1986       column = list->data;
1987       if (!column->visible)
1988         continue;
1989
1990       if (column->use_resized_width)
1991         {
1992           real_requested_width = column->resized_width;
1993         }
1994       else if (column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
1995         {
1996           real_requested_width = column->fixed_width;
1997         }
1998       else if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
1999         {
2000           real_requested_width = MAX (column->requested_width, column->button_request);
2001         }
2002       else
2003         {
2004           real_requested_width = column->requested_width;
2005         }
2006
2007       if (column->min_width != -1)
2008         real_requested_width = MAX (real_requested_width, column->min_width);
2009       if (column->max_width != -1)
2010         real_requested_width = MIN (real_requested_width, column->max_width);
2011
2012       tree_view->priv->width += real_requested_width;
2013     }
2014
2015   if (tree_view->priv->tree == NULL)
2016     tree_view->priv->height = 0;
2017   else
2018     tree_view->priv->height = tree_view->priv->tree->root->offset;
2019 }
2020
2021 static void
2022 gtk_tree_view_size_request (GtkWidget      *widget,
2023                             GtkRequisition *requisition)
2024 {
2025   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2026   GList *tmp_list;
2027
2028   /* we validate some rows initially just to make sure we have some size. 
2029    * In practice, with a lot of static lists, this should get a good width.
2030    */
2031   do_validate_rows (tree_view, FALSE);
2032   gtk_tree_view_size_request_columns (tree_view);
2033   gtk_tree_view_update_size (GTK_TREE_VIEW (widget));
2034
2035   requisition->width = tree_view->priv->width;
2036   requisition->height = tree_view->priv->height + TREE_VIEW_HEADER_HEIGHT (tree_view);
2037
2038   tmp_list = tree_view->priv->children;
2039
2040   while (tmp_list)
2041     {
2042       GtkTreeViewChild *child = tmp_list->data;
2043       GtkRequisition child_requisition;
2044
2045       tmp_list = tmp_list->next;
2046
2047       if (GTK_WIDGET_VISIBLE (child->widget))
2048         gtk_widget_size_request (child->widget, &child_requisition);
2049     }
2050 }
2051
2052
2053 static void
2054 invalidate_column (GtkTreeView       *tree_view,
2055                    GtkTreeViewColumn *column)
2056 {
2057   gint column_offset = 0;
2058   GList *list;
2059   GtkWidget *widget = GTK_WIDGET (tree_view);
2060   gboolean rtl;
2061
2062   if (!GTK_WIDGET_REALIZED (widget))
2063     return;
2064
2065   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2066   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
2067        list;
2068        list = (rtl ? list->prev : list->next))
2069     {
2070       GtkTreeViewColumn *tmpcolumn = list->data;
2071       if (tmpcolumn == column)
2072         {
2073           GdkRectangle invalid_rect;
2074           
2075           invalid_rect.x = column_offset;
2076           invalid_rect.y = 0;
2077           invalid_rect.width = column->width;
2078           invalid_rect.height = widget->allocation.height;
2079           
2080           gdk_window_invalidate_rect (widget->window, &invalid_rect, TRUE);
2081           break;
2082         }
2083       
2084       column_offset += tmpcolumn->width;
2085     }
2086 }
2087
2088 static void
2089 invalidate_last_column (GtkTreeView *tree_view)
2090 {
2091   GList *last_column;
2092   gboolean rtl;
2093
2094   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2095
2096   for (last_column = (rtl ? g_list_first (tree_view->priv->columns) : g_list_last (tree_view->priv->columns));
2097        last_column;
2098        last_column = (rtl ? last_column->next : last_column->prev))
2099     {
2100       if (GTK_TREE_VIEW_COLUMN (last_column->data)->visible)
2101         {
2102           invalidate_column (tree_view, last_column->data);
2103           return;
2104         }
2105     }
2106 }
2107
2108 static gint
2109 gtk_tree_view_get_real_requested_width_from_column (GtkTreeView       *tree_view,
2110                                                     GtkTreeViewColumn *column)
2111 {
2112   gint real_requested_width;
2113
2114   if (column->use_resized_width)
2115     {
2116       real_requested_width = column->resized_width;
2117     }
2118   else if (column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
2119     {
2120       real_requested_width = column->fixed_width;
2121     }
2122   else if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
2123     {
2124       real_requested_width = MAX (column->requested_width, column->button_request);
2125     }
2126   else
2127     {
2128       real_requested_width = column->requested_width;
2129       if (real_requested_width < 0)
2130         real_requested_width = 0;
2131     }
2132
2133   if (column->min_width != -1)
2134     real_requested_width = MAX (real_requested_width, column->min_width);
2135   if (column->max_width != -1)
2136     real_requested_width = MIN (real_requested_width, column->max_width);
2137
2138   return real_requested_width;
2139 }
2140
2141 /* GtkWidget::size_allocate helper */
2142 static void
2143 gtk_tree_view_size_allocate_columns (GtkWidget *widget,
2144                                      gboolean  *width_changed)
2145 {
2146   GtkTreeView *tree_view;
2147   GList *list, *first_column, *last_column;
2148   GtkTreeViewColumn *column;
2149   GtkAllocation allocation;
2150   gint width = 0;
2151   gint extra, extra_per_column, extra_for_last;
2152   gint full_requested_width = 0;
2153   gint number_of_expand_columns = 0;
2154   gboolean column_changed = FALSE;
2155   gboolean rtl;
2156   gboolean update_expand;
2157   
2158   tree_view = GTK_TREE_VIEW (widget);
2159
2160   for (last_column = g_list_last (tree_view->priv->columns);
2161        last_column && !(GTK_TREE_VIEW_COLUMN (last_column->data)->visible);
2162        last_column = last_column->prev)
2163     ;
2164   if (last_column == NULL)
2165     return;
2166
2167   for (first_column = g_list_first (tree_view->priv->columns);
2168        first_column && !(GTK_TREE_VIEW_COLUMN (first_column->data)->visible);
2169        first_column = first_column->next)
2170     ;
2171
2172   allocation.y = 0;
2173   allocation.height = tree_view->priv->header_height;
2174
2175   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
2176
2177   /* find out how many extra space and expandable columns we have */
2178   for (list = tree_view->priv->columns; list != last_column->next; list = list->next)
2179     {
2180       column = (GtkTreeViewColumn *)list->data;
2181
2182       if (!column->visible)
2183         continue;
2184
2185       full_requested_width += gtk_tree_view_get_real_requested_width_from_column (tree_view, column);
2186
2187       if (column->expand)
2188         number_of_expand_columns++;
2189     }
2190
2191   /* Only update the expand value if the width of the widget has changed,
2192    * or the number of expand columns has changed, or if there are no expand
2193    * columns, or if we didn't have an size-allocation yet after the
2194    * last validated node.
2195    */
2196   update_expand = (width_changed && *width_changed == TRUE)
2197       || number_of_expand_columns != tree_view->priv->last_number_of_expand_columns
2198       || number_of_expand_columns == 0
2199       || tree_view->priv->post_validation_flag == TRUE;
2200
2201   tree_view->priv->post_validation_flag = FALSE;
2202
2203   if (!update_expand)
2204     {
2205       extra = tree_view->priv->last_extra_space;
2206       extra_for_last = MAX (widget->allocation.width - full_requested_width - extra, 0);
2207     }
2208   else
2209     {
2210       extra = MAX (widget->allocation.width - full_requested_width, 0);
2211       extra_for_last = 0;
2212
2213       tree_view->priv->last_extra_space = extra;
2214     }
2215
2216   if (number_of_expand_columns > 0)
2217     extra_per_column = extra/number_of_expand_columns;
2218   else
2219     extra_per_column = 0;
2220
2221   if (update_expand)
2222     {
2223       tree_view->priv->last_extra_space_per_column = extra_per_column;
2224       tree_view->priv->last_number_of_expand_columns = number_of_expand_columns;
2225     }
2226
2227   for (list = (rtl ? last_column : first_column); 
2228        list != (rtl ? first_column->prev : last_column->next);
2229        list = (rtl ? list->prev : list->next)) 
2230     {
2231       gint real_requested_width = 0;
2232       gint old_width;
2233
2234       column = list->data;
2235       old_width = column->width;
2236
2237       if (!column->visible)
2238         continue;
2239
2240       /* We need to handle the dragged button specially.
2241        */
2242       if (column == tree_view->priv->drag_column)
2243         {
2244           GtkAllocation drag_allocation;
2245           gdk_drawable_get_size (tree_view->priv->drag_window,
2246                                  &(drag_allocation.width),
2247                                  &(drag_allocation.height));
2248           drag_allocation.x = 0;
2249           drag_allocation.y = 0;
2250           gtk_widget_size_allocate (tree_view->priv->drag_column->button,
2251                                     &drag_allocation);
2252           width += drag_allocation.width;
2253           continue;
2254         }
2255
2256       real_requested_width = gtk_tree_view_get_real_requested_width_from_column (tree_view, column);
2257
2258       allocation.x = width;
2259       column->width = real_requested_width;
2260
2261       if (column->expand)
2262         {
2263           if (number_of_expand_columns == 1)
2264             {
2265               /* We add the remander to the last column as
2266                * */
2267               column->width += extra;
2268             }
2269           else
2270             {
2271               column->width += extra_per_column;
2272               extra -= extra_per_column;
2273               number_of_expand_columns --;
2274             }
2275         }
2276       else if (number_of_expand_columns == 0 &&
2277                list == last_column)
2278         {
2279           column->width += extra;
2280         }
2281
2282       /* In addition to expand, the last column can get even more
2283        * extra space so all available space is filled up.
2284        */
2285       if (extra_for_last > 0 && list == last_column)
2286         column->width += extra_for_last;
2287
2288       g_object_notify (G_OBJECT (column), "width");
2289
2290       allocation.width = column->width;
2291       width += column->width;
2292
2293       if (column->width > old_width)
2294         column_changed = TRUE;
2295
2296       gtk_widget_size_allocate (column->button, &allocation);
2297
2298       if (column->window)
2299         gdk_window_move_resize (column->window,
2300                                 allocation.x + (rtl ? 0 : allocation.width) - TREE_VIEW_DRAG_WIDTH/2,
2301                                 allocation.y,
2302                                 TREE_VIEW_DRAG_WIDTH, allocation.height);
2303     }
2304
2305   /* We change the width here.  The user might have been resizing columns,
2306    * so the total width of the tree view changes.
2307    */
2308   tree_view->priv->width = width;
2309   if (width_changed)
2310     *width_changed = TRUE;
2311
2312   if (column_changed)
2313     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
2314 }
2315
2316
2317 static void
2318 gtk_tree_view_size_allocate (GtkWidget     *widget,
2319                              GtkAllocation *allocation)
2320 {
2321   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2322   GList *tmp_list;
2323   gboolean width_changed = FALSE;
2324   gint old_width = widget->allocation.width;
2325
2326   if (allocation->width != widget->allocation.width)
2327     width_changed = TRUE;
2328
2329   widget->allocation = *allocation;
2330
2331   tmp_list = tree_view->priv->children;
2332
2333   while (tmp_list)
2334     {
2335       GtkAllocation allocation;
2336
2337       GtkTreeViewChild *child = tmp_list->data;
2338       tmp_list = tmp_list->next;
2339
2340       /* totally ignore our child's requisition */
2341       allocation.x = child->x;
2342       allocation.y = child->y;
2343       allocation.width = child->width;
2344       allocation.height = child->height;
2345       gtk_widget_size_allocate (child->widget, &allocation);
2346     }
2347
2348   /* We size-allocate the columns first because the width of the
2349    * tree view (used in updating the adjustments below) might change.
2350    */
2351   gtk_tree_view_size_allocate_columns (widget, &width_changed);
2352
2353   tree_view->priv->hadjustment->page_size = allocation->width;
2354   tree_view->priv->hadjustment->page_increment = allocation->width * 0.9;
2355   tree_view->priv->hadjustment->step_increment = allocation->width * 0.1;
2356   tree_view->priv->hadjustment->lower = 0;
2357   tree_view->priv->hadjustment->upper = MAX (tree_view->priv->hadjustment->page_size, tree_view->priv->width);
2358
2359   if (gtk_widget_get_direction(widget) == GTK_TEXT_DIR_RTL)   
2360     {
2361       if (allocation->width < tree_view->priv->width)
2362         {
2363           if (tree_view->priv->init_hadjust_value)
2364             {
2365               tree_view->priv->hadjustment->value = MAX (tree_view->priv->width - allocation->width, 0);
2366               tree_view->priv->init_hadjust_value = FALSE;
2367             }
2368           else if (allocation->width != old_width)
2369             {
2370               tree_view->priv->hadjustment->value = CLAMP (tree_view->priv->hadjustment->value - allocation->width + old_width, 0, tree_view->priv->width - allocation->width);
2371             }
2372           else
2373             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);
2374         }
2375       else
2376         {
2377           tree_view->priv->hadjustment->value = 0;
2378           tree_view->priv->init_hadjust_value = TRUE;
2379         }
2380     }
2381   else
2382     if (tree_view->priv->hadjustment->value + allocation->width > tree_view->priv->width)
2383       tree_view->priv->hadjustment->value = MAX (tree_view->priv->width - allocation->width, 0);
2384
2385   gtk_adjustment_changed (tree_view->priv->hadjustment);
2386
2387   tree_view->priv->vadjustment->page_size = allocation->height - TREE_VIEW_HEADER_HEIGHT (tree_view);
2388   tree_view->priv->vadjustment->step_increment = tree_view->priv->vadjustment->page_size * 0.1;
2389   tree_view->priv->vadjustment->page_increment = tree_view->priv->vadjustment->page_size * 0.9;
2390   tree_view->priv->vadjustment->lower = 0;
2391   tree_view->priv->vadjustment->upper = MAX (tree_view->priv->vadjustment->page_size, tree_view->priv->height);
2392
2393   gtk_adjustment_changed (tree_view->priv->vadjustment);
2394
2395   /* now the adjustments and window sizes are in sync, we can sync toprow/dy again */
2396   if (tree_view->priv->height <= tree_view->priv->vadjustment->page_size)
2397     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
2398   else if (tree_view->priv->vadjustment->value + tree_view->priv->vadjustment->page_size > tree_view->priv->height)
2399     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment),
2400                               tree_view->priv->height - tree_view->priv->vadjustment->page_size);
2401   else if (gtk_tree_row_reference_valid (tree_view->priv->top_row))
2402     gtk_tree_view_top_row_to_dy (tree_view);
2403   else
2404     gtk_tree_view_dy_to_top_row (tree_view);
2405   
2406   if (GTK_WIDGET_REALIZED (widget))
2407     {
2408       gdk_window_move_resize (widget->window,
2409                               allocation->x, allocation->y,
2410                               allocation->width, allocation->height);
2411       gdk_window_move_resize (tree_view->priv->header_window,
2412                               - (gint) tree_view->priv->hadjustment->value,
2413                               0,
2414                               MAX (tree_view->priv->width, allocation->width),
2415                               tree_view->priv->header_height);
2416       gdk_window_move_resize (tree_view->priv->bin_window,
2417                               - (gint) tree_view->priv->hadjustment->value,
2418                               TREE_VIEW_HEADER_HEIGHT (tree_view),
2419                               MAX (tree_view->priv->width, allocation->width),
2420                               allocation->height - TREE_VIEW_HEADER_HEIGHT (tree_view));
2421     }
2422
2423   if (tree_view->priv->tree == NULL)
2424     invalidate_empty_focus (tree_view);
2425
2426   if (GTK_WIDGET_REALIZED (widget))
2427     {
2428       gboolean has_expand_column = FALSE;
2429       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
2430         {
2431           if (gtk_tree_view_column_get_expand (GTK_TREE_VIEW_COLUMN (tmp_list->data)))
2432             {
2433               has_expand_column = TRUE;
2434               break;
2435             }
2436         }
2437
2438       /* This little hack only works if we have an LTR locale, and no column has the  */
2439       if (width_changed)
2440         {
2441           if (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_LTR &&
2442               ! has_expand_column)
2443             invalidate_last_column (tree_view);
2444           else
2445             gtk_widget_queue_draw (widget);
2446         }
2447     }
2448 }
2449
2450 /* Grabs the focus and unsets the GTK_TREE_VIEW_DRAW_KEYFOCUS flag */
2451 static void
2452 grab_focus_and_unset_draw_keyfocus (GtkTreeView *tree_view)
2453 {
2454   if (GTK_WIDGET_CAN_FOCUS (tree_view) && !GTK_WIDGET_HAS_FOCUS (tree_view))
2455     gtk_widget_grab_focus (GTK_WIDGET (tree_view));
2456   GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
2457 }
2458
2459 static inline gboolean
2460 row_is_separator (GtkTreeView *tree_view,
2461                   GtkTreeIter *iter,
2462                   GtkTreePath *path)
2463 {
2464   gboolean is_separator = FALSE;
2465
2466   if (tree_view->priv->row_separator_func)
2467     {
2468       GtkTreeIter tmpiter;
2469
2470       if (iter)
2471         tmpiter = *iter;
2472       else
2473         gtk_tree_model_get_iter (tree_view->priv->model, &tmpiter, path);
2474
2475       is_separator = tree_view->priv->row_separator_func (tree_view->priv->model,
2476                                                           &tmpiter,
2477                                                           tree_view->priv->row_separator_data);
2478     }
2479
2480   return is_separator;
2481 }
2482
2483 static gboolean
2484 gtk_tree_view_button_press (GtkWidget      *widget,
2485                             GdkEventButton *event)
2486 {
2487   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2488   GList *list;
2489   GtkTreeViewColumn *column = NULL;
2490   gint i;
2491   GdkRectangle background_area;
2492   GdkRectangle cell_area;
2493   gint vertical_separator;
2494   gint horizontal_separator;
2495   gboolean path_is_selectable;
2496   gboolean rtl;
2497
2498   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
2499   gtk_tree_view_stop_editing (tree_view, FALSE);
2500   gtk_widget_style_get (widget,
2501                         "vertical-separator", &vertical_separator,
2502                         "horizontal-separator", &horizontal_separator,
2503                         NULL);
2504
2505
2506   /* Because grab_focus can cause reentrancy, we delay grab_focus until after
2507    * we're done handling the button press.
2508    */
2509
2510   if (event->window == tree_view->priv->bin_window)
2511     {
2512       GtkRBNode *node;
2513       GtkRBTree *tree;
2514       GtkTreePath *path;
2515       gchar *path_string;
2516       gint depth;
2517       gint new_y;
2518       gint y_offset;
2519       gint dval;
2520       gint pre_val, aft_val;
2521       GtkTreeViewColumn *column = NULL;
2522       GtkCellRenderer *focus_cell = NULL;
2523       gint column_handled_click = FALSE;
2524       gboolean row_double_click = FALSE;
2525       gboolean rtl;
2526       gboolean node_selected;
2527
2528       /* Empty tree? */
2529       if (tree_view->priv->tree == NULL)
2530         {
2531           grab_focus_and_unset_draw_keyfocus (tree_view);
2532           return TRUE;
2533         }
2534
2535       /* are we in an arrow? */
2536       if (tree_view->priv->prelight_node &&
2537           GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT) &&
2538           TREE_VIEW_DRAW_EXPANDERS (tree_view))
2539         {
2540           if (event->button == 1)
2541             {
2542               gtk_grab_add (widget);
2543               tree_view->priv->button_pressed_node = tree_view->priv->prelight_node;
2544               tree_view->priv->button_pressed_tree = tree_view->priv->prelight_tree;
2545               gtk_tree_view_draw_arrow (GTK_TREE_VIEW (widget),
2546                                         tree_view->priv->prelight_tree,
2547                                         tree_view->priv->prelight_node,
2548                                         event->x,
2549                                         event->y);
2550             }
2551
2552           grab_focus_and_unset_draw_keyfocus (tree_view);
2553           return TRUE;
2554         }
2555
2556       /* find the node that was clicked */
2557       new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
2558       if (new_y < 0)
2559         new_y = 0;
2560       y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
2561
2562       if (node == NULL)
2563         {
2564           /* We clicked in dead space */
2565           grab_focus_and_unset_draw_keyfocus (tree_view);
2566           return TRUE;
2567         }
2568
2569       /* Get the path and the node */
2570       path = _gtk_tree_view_find_path (tree_view, tree, node);
2571       path_is_selectable = !row_is_separator (tree_view, NULL, path);
2572
2573       if (!path_is_selectable)
2574         {
2575           gtk_tree_path_free (path);
2576           grab_focus_and_unset_draw_keyfocus (tree_view);
2577           return TRUE;
2578         }
2579
2580       depth = gtk_tree_path_get_depth (path);
2581       background_area.y = y_offset + event->y;
2582       background_area.height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
2583       background_area.x = 0;
2584
2585
2586       /* Let the column have a chance at selecting it. */
2587       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2588       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
2589            list; list = (rtl ? list->prev : list->next))
2590         {
2591           GtkTreeViewColumn *candidate = list->data;
2592
2593           if (!candidate->visible)
2594             continue;
2595
2596           background_area.width = candidate->width;
2597           if ((background_area.x > (gint) event->x) ||
2598               (background_area.x + background_area.width <= (gint) event->x))
2599             {
2600               background_area.x += background_area.width;
2601               continue;
2602             }
2603
2604           /* we found the focus column */
2605           column = candidate;
2606           cell_area = background_area;
2607           cell_area.width -= horizontal_separator;
2608           cell_area.height -= vertical_separator;
2609           cell_area.x += horizontal_separator/2;
2610           cell_area.y += vertical_separator/2;
2611           if (gtk_tree_view_is_expander_column (tree_view, column))
2612             {
2613               if (!rtl)
2614                 cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
2615               cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
2616
2617               if (TREE_VIEW_DRAW_EXPANDERS (tree_view))
2618                 {
2619                   if (!rtl)
2620                     cell_area.x += depth * tree_view->priv->expander_size;
2621                   cell_area.width -= depth * tree_view->priv->expander_size;
2622                 }
2623             }
2624           break;
2625         }
2626
2627       if (column == NULL)
2628         {
2629           gtk_tree_path_free (path);
2630           grab_focus_and_unset_draw_keyfocus (tree_view);
2631           return FALSE;
2632         }
2633
2634       tree_view->priv->focus_column = column;
2635
2636       /* decide if we edit */
2637       if (event->type == GDK_BUTTON_PRESS && event->button == 1 &&
2638           !(event->state & gtk_accelerator_get_default_mod_mask ()))
2639         {
2640           GtkTreePath *anchor;
2641           GtkTreeIter iter;
2642
2643           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
2644           gtk_tree_view_column_cell_set_cell_data (column,
2645                                                    tree_view->priv->model,
2646                                                    &iter,
2647                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
2648                                                    node->children?TRUE:FALSE);
2649
2650           if (tree_view->priv->anchor)
2651             anchor = gtk_tree_row_reference_get_path (tree_view->priv->anchor);
2652           else
2653             anchor = NULL;
2654
2655           if ((anchor && !gtk_tree_path_compare (anchor, path))
2656               || !_gtk_tree_view_column_has_editable_cell (column))
2657             {
2658               GtkCellEditable *cell_editable = NULL;
2659
2660               /* FIXME: get the right flags */
2661               guint flags = 0;
2662
2663               path_string = gtk_tree_path_to_string (path);
2664
2665               if (_gtk_tree_view_column_cell_event (column,
2666                                                     &cell_editable,
2667                                                     (GdkEvent *)event,
2668                                                     path_string,
2669                                                     &background_area,
2670                                                     &cell_area, flags))
2671                 {
2672                   if (cell_editable != NULL)
2673                     {
2674                       gint left, right;
2675                       GdkRectangle area;
2676
2677                       area = cell_area;
2678                       _gtk_tree_view_column_get_neighbor_sizes (column, _gtk_tree_view_column_get_edited_cell (column), &left, &right);
2679
2680                       area.x += left;
2681                       area.width -= right + left;
2682
2683                       gtk_tree_view_real_start_editing (tree_view,
2684                                                         column,
2685                                                         path,
2686                                                         cell_editable,
2687                                                         &area,
2688                                                         (GdkEvent *)event,
2689                                                         flags);
2690                       g_free (path_string);
2691                       gtk_tree_path_free (path);
2692                       gtk_tree_path_free (anchor);
2693                       return TRUE;
2694                     }
2695                   column_handled_click = TRUE;
2696                 }
2697               g_free (path_string);
2698             }
2699           if (anchor)
2700             gtk_tree_path_free (anchor);
2701         }
2702
2703       /* select */
2704       node_selected = GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED);
2705       pre_val = tree_view->priv->vadjustment->value;
2706
2707       /* we only handle selection modifications on the first button press
2708        */
2709       if (event->type == GDK_BUTTON_PRESS)
2710         {
2711           if ((event->state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
2712             tree_view->priv->ctrl_pressed = TRUE;
2713           if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
2714             tree_view->priv->shift_pressed = TRUE;
2715
2716           focus_cell = _gtk_tree_view_column_get_cell_at_pos (column, event->x - background_area.x);
2717           if (focus_cell)
2718             gtk_tree_view_column_focus_cell (column, focus_cell);
2719
2720           if (event->state & GDK_CONTROL_MASK)
2721             {
2722               gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
2723               gtk_tree_view_real_toggle_cursor_row (tree_view);
2724             }
2725           else if (event->state & GDK_SHIFT_MASK)
2726             {
2727               gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
2728               gtk_tree_view_real_select_cursor_row (tree_view, FALSE);
2729             }
2730           else
2731             {
2732               gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
2733             }
2734
2735           tree_view->priv->ctrl_pressed = FALSE;
2736           tree_view->priv->shift_pressed = FALSE;
2737         }
2738
2739       /* the treeview may have been scrolled because of _set_cursor,
2740        * correct here
2741        */
2742
2743       aft_val = tree_view->priv->vadjustment->value;
2744       dval = pre_val - aft_val;
2745
2746       cell_area.y += dval;
2747       background_area.y += dval;
2748
2749       /* Save press to possibly begin a drag
2750        */
2751       if (!column_handled_click &&
2752           !tree_view->priv->in_grab &&
2753           tree_view->priv->pressed_button < 0)
2754         {
2755           tree_view->priv->pressed_button = event->button;
2756           tree_view->priv->press_start_x = event->x;
2757           tree_view->priv->press_start_y = event->y;
2758
2759           if (tree_view->priv->rubber_banding_enable
2760               && !node_selected
2761               && tree_view->priv->selection->type == GTK_SELECTION_MULTIPLE)
2762             {
2763               tree_view->priv->press_start_y += tree_view->priv->dy;
2764               tree_view->priv->rubber_band_x = event->x;
2765               tree_view->priv->rubber_band_y = event->y + tree_view->priv->dy;
2766               tree_view->priv->rubber_band_status = RUBBER_BAND_MAYBE_START;
2767
2768               if ((event->state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
2769                 tree_view->priv->rubber_band_ctrl = TRUE;
2770               if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
2771                 tree_view->priv->rubber_band_shift = TRUE;
2772             }
2773         }
2774
2775       /* Test if a double click happened on the same row. */
2776       if (event->button == 1 && event->type == GDK_BUTTON_PRESS)
2777         {
2778           if (tree_view->priv->last_button_x != -1)
2779             {
2780               int double_click_time, double_click_distance;
2781
2782               g_object_get (gtk_settings_get_default (),
2783                             "gtk-double-click-time", &double_click_time,
2784                             "gtk-double-click-distance", &double_click_distance,
2785                             NULL);
2786
2787               /* Same conditions as _gdk_event_button_generate */
2788               if ((event->time < tree_view->priv->last_button_time + double_click_time) &&
2789                   (ABS (event->x - tree_view->priv->last_button_x) <= double_click_distance) &&
2790                   (ABS (event->y - tree_view->priv->last_button_y) <= double_click_distance))
2791                 {
2792                   /* We do no longer compare paths of this row and the
2793                    * row clicked previously.  We use the double click
2794                    * distance to decide whether this is a valid click,
2795                    * allowing the mouse to slightly move over another row.
2796                    */
2797                   row_double_click = TRUE;
2798                 }
2799
2800               tree_view->priv->last_button_time = 0;
2801               tree_view->priv->last_button_x = -1;
2802               tree_view->priv->last_button_y = -1;
2803             }
2804           else
2805             {
2806               tree_view->priv->last_button_time = event->time;
2807               tree_view->priv->last_button_x = event->x;
2808               tree_view->priv->last_button_y = event->y;
2809             }
2810         }
2811
2812       if (row_double_click)
2813         {
2814           gtk_grab_remove (widget);
2815           gtk_tree_view_row_activated (tree_view, path, column);
2816
2817           if (tree_view->priv->pressed_button == event->button)
2818             tree_view->priv->pressed_button = -1;
2819         }
2820
2821       gtk_tree_path_free (path);
2822
2823       /* If we activated the row through a double click we don't want to grab
2824        * focus back, as moving focus to another widget is pretty common.
2825        */
2826       if (!row_double_click)
2827         grab_focus_and_unset_draw_keyfocus (tree_view);
2828
2829       return TRUE;
2830     }
2831
2832   /* We didn't click in the window.  Let's check to see if we clicked on a column resize window.
2833    */
2834   for (i = 0, list = tree_view->priv->columns; list; list = list->next, i++)
2835     {
2836       column = list->data;
2837       if (event->window == column->window &&
2838           column->resizable &&
2839           column->window)
2840         {
2841           gpointer drag_data;
2842
2843           if (event->type == GDK_2BUTTON_PRESS &&
2844               gtk_tree_view_column_get_sizing (column) != GTK_TREE_VIEW_COLUMN_AUTOSIZE)
2845             {
2846               column->use_resized_width = FALSE;
2847               _gtk_tree_view_column_autosize (tree_view, column);
2848               return TRUE;
2849             }
2850
2851           if (gdk_pointer_grab (column->window, FALSE,
2852                                 GDK_POINTER_MOTION_HINT_MASK |
2853                                 GDK_BUTTON1_MOTION_MASK |
2854                                 GDK_BUTTON_RELEASE_MASK,
2855                                 NULL, NULL, event->time))
2856             return FALSE;
2857
2858           gtk_grab_add (widget);
2859           GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE);
2860           column->resized_width = column->width - tree_view->priv->last_extra_space_per_column;
2861
2862           /* block attached dnd signal handler */
2863           drag_data = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
2864           if (drag_data)
2865             g_signal_handlers_block_matched (widget,
2866                                              G_SIGNAL_MATCH_DATA,
2867                                              0, 0, NULL, NULL,
2868                                              drag_data);
2869
2870           tree_view->priv->drag_pos = i;
2871           tree_view->priv->x_drag = column->button->allocation.x + (rtl ? 0 : column->button->allocation.width);
2872
2873           if (!GTK_WIDGET_HAS_FOCUS (widget))
2874             gtk_widget_grab_focus (widget);
2875
2876           return TRUE;
2877         }
2878     }
2879   return FALSE;
2880 }
2881
2882 /* GtkWidget::button_release_event helper */
2883 static gboolean
2884 gtk_tree_view_button_release_drag_column (GtkWidget      *widget,
2885                                           GdkEventButton *event)
2886 {
2887   GtkTreeView *tree_view;
2888   GList *l;
2889   gboolean rtl;
2890
2891   tree_view = GTK_TREE_VIEW (widget);
2892
2893   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
2894   gdk_display_pointer_ungrab (gtk_widget_get_display (widget), GDK_CURRENT_TIME);
2895   gdk_display_keyboard_ungrab (gtk_widget_get_display (widget), GDK_CURRENT_TIME);
2896
2897   /* Move the button back */
2898   g_object_ref (tree_view->priv->drag_column->button);
2899   gtk_container_remove (GTK_CONTAINER (tree_view), tree_view->priv->drag_column->button);
2900   gtk_widget_set_parent_window (tree_view->priv->drag_column->button, tree_view->priv->header_window);
2901   gtk_widget_set_parent (tree_view->priv->drag_column->button, GTK_WIDGET (tree_view));
2902   g_object_unref (tree_view->priv->drag_column->button);
2903   gtk_widget_queue_resize (widget);
2904   if (tree_view->priv->drag_column->resizable)
2905     {
2906       gdk_window_raise (tree_view->priv->drag_column->window);
2907       gdk_window_show (tree_view->priv->drag_column->window);
2908     }
2909   else
2910     gdk_window_hide (tree_view->priv->drag_column->window);
2911
2912   gtk_widget_grab_focus (tree_view->priv->drag_column->button);
2913
2914   if (rtl)
2915     {
2916       if (tree_view->priv->cur_reorder &&
2917           tree_view->priv->cur_reorder->right_column != tree_view->priv->drag_column)
2918         gtk_tree_view_move_column_after (tree_view, tree_view->priv->drag_column,
2919                                          tree_view->priv->cur_reorder->right_column);
2920     }
2921   else
2922     {
2923       if (tree_view->priv->cur_reorder &&
2924           tree_view->priv->cur_reorder->left_column != tree_view->priv->drag_column)
2925         gtk_tree_view_move_column_after (tree_view, tree_view->priv->drag_column,
2926                                          tree_view->priv->cur_reorder->left_column);
2927     }
2928   tree_view->priv->drag_column = NULL;
2929   gdk_window_hide (tree_view->priv->drag_window);
2930
2931   for (l = tree_view->priv->column_drag_info; l != NULL; l = l->next)
2932     g_slice_free (GtkTreeViewColumnReorder, l->data);
2933   g_list_free (tree_view->priv->column_drag_info);
2934   tree_view->priv->column_drag_info = NULL;
2935   tree_view->priv->cur_reorder = NULL;
2936
2937   if (tree_view->priv->drag_highlight_window)
2938     gdk_window_hide (tree_view->priv->drag_highlight_window);
2939
2940   /* Reset our flags */
2941   tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_UNSET;
2942   GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG);
2943
2944   return TRUE;
2945 }
2946
2947 /* GtkWidget::button_release_event helper */
2948 static gboolean
2949 gtk_tree_view_button_release_column_resize (GtkWidget      *widget,
2950                                             GdkEventButton *event)
2951 {
2952   GtkTreeView *tree_view;
2953   gpointer drag_data;
2954
2955   tree_view = GTK_TREE_VIEW (widget);
2956
2957   tree_view->priv->drag_pos = -1;
2958
2959   /* unblock attached dnd signal handler */
2960   drag_data = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
2961   if (drag_data)
2962     g_signal_handlers_unblock_matched (widget,
2963                                        G_SIGNAL_MATCH_DATA,
2964                                        0, 0, NULL, NULL,
2965                                        drag_data);
2966
2967   GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE);
2968   gtk_grab_remove (widget);
2969   gdk_display_pointer_ungrab (gdk_drawable_get_display (event->window),
2970                               event->time);
2971   return TRUE;
2972 }
2973
2974 static gboolean
2975 gtk_tree_view_button_release (GtkWidget      *widget,
2976                               GdkEventButton *event)
2977 {
2978   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2979
2980   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
2981     return gtk_tree_view_button_release_drag_column (widget, event);
2982
2983   if (tree_view->priv->rubber_band_status)
2984     gtk_tree_view_stop_rubber_band (tree_view);
2985
2986   if (tree_view->priv->pressed_button == event->button)
2987     tree_view->priv->pressed_button = -1;
2988
2989   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE))
2990     return gtk_tree_view_button_release_column_resize (widget, event);
2991
2992   if (tree_view->priv->button_pressed_node == NULL)
2993     return FALSE;
2994
2995   if (event->button == 1)
2996     {
2997       gtk_grab_remove (widget);
2998       if (tree_view->priv->button_pressed_node == tree_view->priv->prelight_node &&
2999           GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT))
3000         {
3001           GtkTreePath *path = NULL;
3002
3003           path = _gtk_tree_view_find_path (tree_view,
3004                                            tree_view->priv->button_pressed_tree,
3005                                            tree_view->priv->button_pressed_node);
3006           /* Actually activate the node */
3007           if (tree_view->priv->button_pressed_node->children == NULL)
3008             gtk_tree_view_real_expand_row (tree_view, path,
3009                                            tree_view->priv->button_pressed_tree,
3010                                            tree_view->priv->button_pressed_node,
3011                                            FALSE, TRUE);
3012           else
3013             gtk_tree_view_real_collapse_row (GTK_TREE_VIEW (widget), path,
3014                                              tree_view->priv->button_pressed_tree,
3015                                              tree_view->priv->button_pressed_node, TRUE);
3016           gtk_tree_path_free (path);
3017         }
3018
3019       tree_view->priv->button_pressed_tree = NULL;
3020       tree_view->priv->button_pressed_node = NULL;
3021     }
3022
3023   return TRUE;
3024 }
3025
3026 static gboolean
3027 gtk_tree_view_grab_broken (GtkWidget          *widget,
3028                            GdkEventGrabBroken *event)
3029 {
3030   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
3031
3032   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
3033     gtk_tree_view_button_release_drag_column (widget, (GdkEventButton *)event);
3034
3035   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE))
3036     gtk_tree_view_button_release_column_resize (widget, (GdkEventButton *)event);
3037
3038   return TRUE;
3039 }
3040
3041 #if 0
3042 static gboolean
3043 gtk_tree_view_configure (GtkWidget *widget,
3044                          GdkEventConfigure *event)
3045 {
3046   GtkTreeView *tree_view;
3047
3048   tree_view = GTK_TREE_VIEW (widget);
3049   tree_view->priv->search_position_func (tree_view, tree_view->priv->search_window);
3050
3051   return FALSE;
3052 }
3053 #endif
3054
3055 /* GtkWidget::motion_event function set.
3056  */
3057
3058 static gboolean
3059 coords_are_over_arrow (GtkTreeView *tree_view,
3060                        GtkRBTree   *tree,
3061                        GtkRBNode   *node,
3062                        /* these are in bin window coords */
3063                        gint         x,
3064                        gint         y)
3065 {
3066   GdkRectangle arrow;
3067   gint x2;
3068
3069   if (!GTK_WIDGET_REALIZED (tree_view))
3070     return FALSE;
3071
3072   if ((node->flags & GTK_RBNODE_IS_PARENT) == 0)
3073     return FALSE;
3074
3075   arrow.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
3076
3077   arrow.height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
3078
3079   gtk_tree_view_get_arrow_xrange (tree_view, tree, &arrow.x, &x2);
3080
3081   arrow.width = x2 - arrow.x;
3082
3083   return (x >= arrow.x &&
3084           x < (arrow.x + arrow.width) &&
3085           y >= arrow.y &&
3086           y < (arrow.y + arrow.height));
3087 }
3088
3089 static gboolean
3090 auto_expand_timeout (gpointer data)
3091 {
3092   GtkTreeView *tree_view = GTK_TREE_VIEW (data);
3093   GtkTreePath *path;
3094
3095   if (tree_view->priv->prelight_node)
3096     {
3097       path = _gtk_tree_view_find_path (tree_view,
3098                                        tree_view->priv->prelight_tree,
3099                                        tree_view->priv->prelight_node);   
3100
3101       if (tree_view->priv->prelight_node->children)
3102         gtk_tree_view_collapse_row (tree_view, path);
3103       else
3104         gtk_tree_view_expand_row (tree_view, path, FALSE);
3105
3106       gtk_tree_path_free (path);
3107     }
3108
3109   tree_view->priv->auto_expand_timeout = 0;
3110
3111   return FALSE;
3112 }
3113
3114 static void
3115 remove_auto_expand_timeout (GtkTreeView *tree_view)
3116 {
3117   if (tree_view->priv->auto_expand_timeout != 0)
3118     {
3119       g_source_remove (tree_view->priv->auto_expand_timeout);
3120       tree_view->priv->auto_expand_timeout = 0;
3121     }
3122 }
3123
3124 static void
3125 do_prelight (GtkTreeView *tree_view,
3126              GtkRBTree   *tree,
3127              GtkRBNode   *node,
3128              /* these are in bin_window coords */
3129              gint         x,
3130              gint         y)
3131 {
3132   if (tree_view->priv->prelight_tree == tree &&
3133       tree_view->priv->prelight_node == node)
3134     {
3135       /*  We are still on the same node,
3136           but we might need to take care of the arrow  */
3137
3138       if (tree && node && TREE_VIEW_DRAW_EXPANDERS (tree_view))
3139         {
3140           gboolean over_arrow;
3141           gboolean flag_set;
3142
3143           over_arrow = coords_are_over_arrow (tree_view, tree, node, x, y);
3144           flag_set = GTK_TREE_VIEW_FLAG_SET (tree_view,
3145                                              GTK_TREE_VIEW_ARROW_PRELIT);
3146
3147           if (over_arrow != flag_set)
3148             {
3149               if (over_arrow)
3150                 GTK_TREE_VIEW_SET_FLAG (tree_view,
3151                                         GTK_TREE_VIEW_ARROW_PRELIT);
3152               else
3153                 GTK_TREE_VIEW_UNSET_FLAG (tree_view,
3154                                           GTK_TREE_VIEW_ARROW_PRELIT);
3155
3156               gtk_tree_view_draw_arrow (tree_view, tree, node, x, y);
3157             }
3158         }
3159
3160       return;
3161     }
3162
3163   if (tree_view->priv->prelight_tree && tree_view->priv->prelight_node)
3164     {
3165       /*  Unprelight the old node and arrow  */
3166
3167       GTK_RBNODE_UNSET_FLAG (tree_view->priv->prelight_node,
3168                              GTK_RBNODE_IS_PRELIT);
3169
3170       if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT)
3171           && TREE_VIEW_DRAW_EXPANDERS (tree_view))
3172         {
3173           GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_ARROW_PRELIT);
3174           
3175           gtk_tree_view_draw_arrow (tree_view,
3176                                     tree_view->priv->prelight_tree,
3177                                     tree_view->priv->prelight_node,
3178                                     x,
3179                                     y);
3180         }
3181
3182       _gtk_tree_view_queue_draw_node (tree_view,
3183                                       tree_view->priv->prelight_tree,
3184                                       tree_view->priv->prelight_node,
3185                                       NULL);
3186     }
3187
3188
3189   if (tree_view->priv->hover_expand)
3190     remove_auto_expand_timeout (tree_view);
3191
3192   /*  Set the new prelight values  */
3193   tree_view->priv->prelight_node = node;
3194   tree_view->priv->prelight_tree = tree;
3195
3196   if (!node || !tree)
3197     return;
3198
3199   /*  Prelight the new node and arrow  */
3200
3201   if (TREE_VIEW_DRAW_EXPANDERS (tree_view)
3202       && coords_are_over_arrow (tree_view, tree, node, x, y))
3203     {
3204       GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_ARROW_PRELIT);
3205
3206       gtk_tree_view_draw_arrow (tree_view, tree, node, x, y);
3207     }
3208
3209   GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_PRELIT);
3210
3211   _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
3212
3213   if (tree_view->priv->hover_expand)
3214     {
3215       tree_view->priv->auto_expand_timeout = 
3216         gdk_threads_add_timeout (AUTO_EXPAND_TIMEOUT, auto_expand_timeout, tree_view);
3217     }
3218 }
3219
3220 static void
3221 prelight_or_select (GtkTreeView *tree_view,
3222                     GtkRBTree   *tree,
3223                     GtkRBNode   *node,
3224                     /* these are in bin_window coords */
3225                     gint         x,
3226                     gint         y)
3227 {
3228   GtkSelectionMode mode = gtk_tree_selection_get_mode (tree_view->priv->selection);
3229   
3230   if (tree_view->priv->hover_selection &&
3231       (mode == GTK_SELECTION_SINGLE || mode == GTK_SELECTION_BROWSE) &&
3232       !(tree_view->priv->edited_column &&
3233         tree_view->priv->edited_column->editable_widget))
3234     {
3235       if (node)
3236         {
3237           if (!GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
3238             {
3239               GtkTreePath *path;
3240               
3241               path = _gtk_tree_view_find_path (tree_view, tree, node);
3242               gtk_tree_selection_select_path (tree_view->priv->selection, path);
3243               if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
3244                 {
3245                   GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
3246                   gtk_tree_view_real_set_cursor (tree_view, path, FALSE, FALSE);
3247                 }
3248               gtk_tree_path_free (path);
3249             }
3250         }
3251
3252       else if (mode == GTK_SELECTION_SINGLE)
3253         gtk_tree_selection_unselect_all (tree_view->priv->selection);
3254     }
3255
3256     do_prelight (tree_view, tree, node, x, y);
3257 }
3258
3259 static void
3260 ensure_unprelighted (GtkTreeView *tree_view)
3261 {
3262   do_prelight (tree_view,
3263                NULL, NULL,
3264                -1000, -1000); /* coords not possibly over an arrow */
3265
3266   g_assert (tree_view->priv->prelight_node == NULL);
3267 }
3268
3269
3270
3271
3272 /* Our motion arrow is either a box (in the case of the original spot)
3273  * or an arrow.  It is expander_size wide.
3274  */
3275 /*
3276  * 11111111111111
3277  * 01111111111110
3278  * 00111111111100
3279  * 00011111111000
3280  * 00001111110000
3281  * 00000111100000
3282  * 00000111100000
3283  * 00000111100000
3284  * ~ ~ ~ ~ ~ ~ ~
3285  * 00000111100000
3286  * 00000111100000
3287  * 00000111100000
3288  * 00001111110000
3289  * 00011111111000
3290  * 00111111111100
3291  * 01111111111110
3292  * 11111111111111
3293  */
3294
3295 static void
3296 gtk_tree_view_motion_draw_column_motion_arrow (GtkTreeView *tree_view)
3297 {
3298   GtkTreeViewColumnReorder *reorder = tree_view->priv->cur_reorder;
3299   GtkWidget *widget = GTK_WIDGET (tree_view);
3300   GdkBitmap *mask = NULL;
3301   gint x;
3302   gint y;
3303   gint width;
3304   gint height;
3305   gint arrow_type = DRAG_COLUMN_WINDOW_STATE_UNSET;
3306   GdkWindowAttr attributes;
3307   guint attributes_mask;
3308
3309   if (!reorder ||
3310       reorder->left_column == tree_view->priv->drag_column ||
3311       reorder->right_column == tree_view->priv->drag_column)
3312     arrow_type = DRAG_COLUMN_WINDOW_STATE_ORIGINAL;
3313   else if (reorder->left_column || reorder->right_column)
3314     {
3315       GdkRectangle visible_rect;
3316       gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
3317       if (reorder->left_column)
3318         x = reorder->left_column->button->allocation.x + reorder->left_column->button->allocation.width;
3319       else
3320         x = reorder->right_column->button->allocation.x;
3321
3322       if (x < visible_rect.x)
3323         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT;
3324       else if (x > visible_rect.x + visible_rect.width)
3325         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT;
3326       else
3327         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW;
3328     }
3329
3330   /* We want to draw the rectangle over the initial location. */
3331   if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ORIGINAL)
3332     {
3333       GdkGC *gc;
3334       GdkColor col;
3335
3336       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ORIGINAL)
3337         {
3338           if (tree_view->priv->drag_highlight_window)
3339             {
3340               gdk_window_set_user_data (tree_view->priv->drag_highlight_window,
3341                                         NULL);
3342               gdk_window_destroy (tree_view->priv->drag_highlight_window);
3343             }
3344
3345           attributes.window_type = GDK_WINDOW_CHILD;
3346           attributes.wclass = GDK_INPUT_OUTPUT;
3347           attributes.x = tree_view->priv->drag_column_x;
3348           attributes.y = 0;
3349           width = attributes.width = tree_view->priv->drag_column->button->allocation.width;
3350           height = attributes.height = tree_view->priv->drag_column->button->allocation.height;
3351           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
3352           attributes.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
3353           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3354           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
3355           tree_view->priv->drag_highlight_window = gdk_window_new (tree_view->priv->header_window, &attributes, attributes_mask);
3356           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
3357
3358           mask = gdk_pixmap_new (tree_view->priv->drag_highlight_window, width, height, 1);
3359           gc = gdk_gc_new (mask);
3360           col.pixel = 1;
3361           gdk_gc_set_foreground (gc, &col);
3362           gdk_draw_rectangle (mask, gc, TRUE, 0, 0, width, height);
3363           col.pixel = 0;
3364           gdk_gc_set_foreground(gc, &col);
3365           gdk_draw_rectangle (mask, gc, TRUE, 2, 2, width - 4, height - 4);
3366           g_object_unref (gc);
3367
3368           gdk_window_shape_combine_mask (tree_view->priv->drag_highlight_window,
3369                                          mask, 0, 0);
3370           if (mask) g_object_unref (mask);
3371           tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_ORIGINAL;
3372         }
3373     }
3374   else if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW)
3375     {
3376       gint i, j = 1;
3377       GdkGC *gc;
3378       GdkColor col;
3379
3380       width = tree_view->priv->expander_size;
3381
3382       /* Get x, y, width, height of arrow */
3383       gdk_window_get_origin (tree_view->priv->header_window, &x, &y);
3384       if (reorder->left_column)
3385         {
3386           x += reorder->left_column->button->allocation.x + reorder->left_column->button->allocation.width - width/2;
3387           height = reorder->left_column->button->allocation.height;
3388         }
3389       else
3390         {
3391           x += reorder->right_column->button->allocation.x - width/2;
3392           height = reorder->right_column->button->allocation.height;
3393         }
3394       y -= tree_view->priv->expander_size/2; /* The arrow takes up only half the space */
3395       height += tree_view->priv->expander_size;
3396
3397       /* Create the new window */
3398       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW)
3399         {
3400           if (tree_view->priv->drag_highlight_window)
3401             {
3402               gdk_window_set_user_data (tree_view->priv->drag_highlight_window,
3403                                         NULL);
3404               gdk_window_destroy (tree_view->priv->drag_highlight_window);
3405             }
3406
3407           attributes.window_type = GDK_WINDOW_TEMP;
3408           attributes.wclass = GDK_INPUT_OUTPUT;
3409           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
3410           attributes.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
3411           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3412           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
3413           attributes.x = x;
3414           attributes.y = y;
3415           attributes.width = width;
3416           attributes.height = height;
3417           tree_view->priv->drag_highlight_window = gdk_window_new (gtk_widget_get_root_window (widget),
3418                                                                    &attributes, attributes_mask);
3419           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
3420
3421           mask = gdk_pixmap_new (tree_view->priv->drag_highlight_window, width, height, 1);
3422           gc = gdk_gc_new (mask);
3423           col.pixel = 1;
3424           gdk_gc_set_foreground (gc, &col);
3425           gdk_draw_rectangle (mask, gc, TRUE, 0, 0, width, height);
3426
3427           /* Draw the 2 arrows as per above */
3428           col.pixel = 0;
3429           gdk_gc_set_foreground (gc, &col);
3430           for (i = 0; i < width; i ++)
3431             {
3432               if (i == (width/2 - 1))
3433                 continue;
3434               gdk_draw_line (mask, gc, i, j, i, height - j);
3435               if (i < (width/2 - 1))
3436                 j++;
3437               else
3438                 j--;
3439             }
3440           g_object_unref (gc);
3441           gdk_window_shape_combine_mask (tree_view->priv->drag_highlight_window,
3442                                          mask, 0, 0);
3443           if (mask) g_object_unref (mask);
3444         }
3445
3446       tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_ARROW;
3447       gdk_window_move (tree_view->priv->drag_highlight_window, x, y);
3448     }
3449   else if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT ||
3450            arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
3451     {
3452       gint i, j = 1;
3453       GdkGC *gc;
3454       GdkColor col;
3455
3456       width = tree_view->priv->expander_size;
3457
3458       /* Get x, y, width, height of arrow */
3459       width = width/2; /* remember, the arrow only takes half the available width */
3460       gdk_window_get_origin (widget->window, &x, &y);
3461       if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
3462         x += widget->allocation.width - width;
3463
3464       if (reorder->left_column)
3465         height = reorder->left_column->button->allocation.height;
3466       else
3467         height = reorder->right_column->button->allocation.height;
3468
3469       y -= tree_view->priv->expander_size;
3470       height += 2*tree_view->priv->expander_size;
3471
3472       /* Create the new window */
3473       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT &&
3474           tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
3475         {
3476           if (tree_view->priv->drag_highlight_window)
3477             {
3478               gdk_window_set_user_data (tree_view->priv->drag_highlight_window,
3479                                         NULL);
3480               gdk_window_destroy (tree_view->priv->drag_highlight_window);
3481             }
3482
3483           attributes.window_type = GDK_WINDOW_TEMP;
3484           attributes.wclass = GDK_INPUT_OUTPUT;
3485           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
3486           attributes.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
3487           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3488           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
3489           attributes.x = x;
3490           attributes.y = y;
3491           attributes.width = width;
3492           attributes.height = height;
3493           tree_view->priv->drag_highlight_window = gdk_window_new (NULL, &attributes, attributes_mask);
3494           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
3495
3496           mask = gdk_pixmap_new (tree_view->priv->drag_highlight_window, width, height, 1);
3497           gc = gdk_gc_new (mask);
3498           col.pixel = 1;
3499           gdk_gc_set_foreground (gc, &col);
3500           gdk_draw_rectangle (mask, gc, TRUE, 0, 0, width, height);
3501
3502           /* Draw the 2 arrows as per above */
3503           col.pixel = 0;
3504           gdk_gc_set_foreground (gc, &col);
3505           j = tree_view->priv->expander_size;
3506           for (i = 0; i < width; i ++)
3507             {
3508               gint k;
3509               if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT)
3510                 k = width - i - 1;
3511               else
3512                 k = i;
3513               gdk_draw_line (mask, gc, k, j, k, height - j);
3514               gdk_draw_line (mask, gc, k, 0, k, tree_view->priv->expander_size - j);
3515               gdk_draw_line (mask, gc, k, height, k, height - tree_view->priv->expander_size + j);
3516               j--;
3517             }
3518           g_object_unref (gc);
3519           gdk_window_shape_combine_mask (tree_view->priv->drag_highlight_window,
3520                                          mask, 0, 0);
3521           if (mask) g_object_unref (mask);
3522         }
3523
3524       tree_view->priv->drag_column_window_state = arrow_type;
3525       gdk_window_move (tree_view->priv->drag_highlight_window, x, y);
3526    }
3527   else
3528     {
3529       g_warning (G_STRLOC"Invalid GtkTreeViewColumnReorder struct");
3530       gdk_window_hide (tree_view->priv->drag_highlight_window);
3531       return;
3532     }
3533
3534   gdk_window_show (tree_view->priv->drag_highlight_window);
3535   gdk_window_raise (tree_view->priv->drag_highlight_window);
3536 }
3537
3538 static gboolean
3539 gtk_tree_view_motion_resize_column (GtkWidget      *widget,
3540                                     GdkEventMotion *event)
3541 {
3542   gint x;
3543   gint new_width;
3544   GtkTreeViewColumn *column;
3545   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
3546
3547   column = gtk_tree_view_get_column (tree_view, tree_view->priv->drag_pos);
3548
3549   if (event->is_hint || event->window != widget->window)
3550     gtk_widget_get_pointer (widget, &x, NULL);
3551   else
3552     x = event->x;
3553
3554   if (tree_view->priv->hadjustment)
3555     x += tree_view->priv->hadjustment->value;
3556
3557   new_width = gtk_tree_view_new_column_width (tree_view,
3558                                               tree_view->priv->drag_pos, &x);
3559   if (x != tree_view->priv->x_drag &&
3560       (new_width != column->fixed_width))
3561     {
3562       column->use_resized_width = TRUE;
3563       column->resized_width = new_width;
3564       if (column->expand)
3565         column->resized_width -= tree_view->priv->last_extra_space_per_column;
3566       gtk_widget_queue_resize (widget);
3567     }
3568
3569   return FALSE;
3570 }
3571
3572
3573 static void
3574 gtk_tree_view_update_current_reorder (GtkTreeView *tree_view)
3575 {
3576   GtkTreeViewColumnReorder *reorder = NULL;
3577   GList *list;
3578   gint mouse_x;
3579
3580   gdk_window_get_pointer (tree_view->priv->header_window, &mouse_x, NULL, NULL);
3581   for (list = tree_view->priv->column_drag_info; list; list = list->next)
3582     {
3583       reorder = (GtkTreeViewColumnReorder *) list->data;
3584       if (mouse_x >= reorder->left_align && mouse_x < reorder->right_align)
3585         break;
3586       reorder = NULL;
3587     }
3588
3589   /*  if (reorder && reorder == tree_view->priv->cur_reorder)
3590       return;*/
3591
3592   tree_view->priv->cur_reorder = reorder;
3593   gtk_tree_view_motion_draw_column_motion_arrow (tree_view);
3594 }
3595
3596 static void
3597 gtk_tree_view_vertical_autoscroll (GtkTreeView *tree_view)
3598 {
3599   GdkRectangle visible_rect;
3600   gint y;
3601   gint offset;
3602   gfloat value;
3603
3604   gdk_window_get_pointer (tree_view->priv->bin_window, NULL, &y, NULL);
3605   y += tree_view->priv->dy;
3606
3607   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
3608
3609   /* see if we are near the edge. */
3610   offset = y - (visible_rect.y + 2 * SCROLL_EDGE_SIZE);
3611   if (offset > 0)
3612     {
3613       offset = y - (visible_rect.y + visible_rect.height - 2 * SCROLL_EDGE_SIZE);
3614       if (offset < 0)
3615         return;
3616     }
3617
3618   value = CLAMP (tree_view->priv->vadjustment->value + offset, 0.0,
3619                  tree_view->priv->vadjustment->upper - tree_view->priv->vadjustment->page_size);
3620   gtk_adjustment_set_value (tree_view->priv->vadjustment, value);
3621 }
3622
3623 static gboolean
3624 gtk_tree_view_horizontal_autoscroll (GtkTreeView *tree_view)
3625 {
3626   GdkRectangle visible_rect;
3627   gint x;
3628   gint offset;
3629   gfloat value;
3630
3631   gdk_window_get_pointer (tree_view->priv->bin_window, &x, NULL, NULL);
3632
3633   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
3634
3635   /* See if we are near the edge. */
3636   offset = x - (visible_rect.x + SCROLL_EDGE_SIZE);
3637   if (offset > 0)
3638     {
3639       offset = x - (visible_rect.x + visible_rect.width - SCROLL_EDGE_SIZE);
3640       if (offset < 0)
3641         return TRUE;
3642     }
3643   offset = offset/3;
3644
3645   value = CLAMP (tree_view->priv->hadjustment->value + offset,
3646                  0.0, tree_view->priv->hadjustment->upper - tree_view->priv->hadjustment->page_size);
3647   gtk_adjustment_set_value (tree_view->priv->hadjustment, value);
3648
3649   return TRUE;
3650
3651 }
3652
3653 static gboolean
3654 gtk_tree_view_motion_drag_column (GtkWidget      *widget,
3655                                   GdkEventMotion *event)
3656 {
3657   GtkTreeView *tree_view = (GtkTreeView *) widget;
3658   GtkTreeViewColumn *column = tree_view->priv->drag_column;
3659   gint x, y;
3660
3661   /* Sanity Check */
3662   if ((column == NULL) ||
3663       (event->window != tree_view->priv->drag_window))
3664     return FALSE;
3665
3666   /* Handle moving the header */
3667   gdk_window_get_position (tree_view->priv->drag_window, &x, &y);
3668   x = CLAMP (x + (gint)event->x - column->drag_x, 0,
3669              MAX (tree_view->priv->width, GTK_WIDGET (tree_view)->allocation.width) - column->button->allocation.width);
3670   gdk_window_move (tree_view->priv->drag_window, x, y);
3671   
3672   /* autoscroll, if needed */
3673   gtk_tree_view_horizontal_autoscroll (tree_view);
3674   /* Update the current reorder position and arrow; */
3675   gtk_tree_view_update_current_reorder (tree_view);
3676
3677   return TRUE;
3678 }
3679
3680 static void
3681 gtk_tree_view_stop_rubber_band (GtkTreeView *tree_view)
3682 {
3683   remove_scroll_timeout (tree_view);
3684   gtk_grab_remove (GTK_WIDGET (tree_view));
3685
3686   if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
3687     {
3688       GtkTreePath *tmp_path;
3689
3690       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
3691
3692       /* The anchor path should be set to the start path */
3693       tmp_path = _gtk_tree_view_find_path (tree_view,
3694                                            tree_view->priv->rubber_band_start_tree,
3695                                            tree_view->priv->rubber_band_start_node);
3696
3697       if (tree_view->priv->anchor)
3698         gtk_tree_row_reference_free (tree_view->priv->anchor);
3699
3700       tree_view->priv->anchor =
3701         gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
3702                                           tree_view->priv->model,
3703                                           tmp_path);
3704
3705       gtk_tree_path_free (tmp_path);
3706
3707       /* ... and the cursor to the end path */
3708       tmp_path = _gtk_tree_view_find_path (tree_view,
3709                                            tree_view->priv->rubber_band_end_tree,
3710                                            tree_view->priv->rubber_band_end_node);
3711       gtk_tree_view_real_set_cursor (GTK_TREE_VIEW (tree_view), tmp_path, FALSE, FALSE);
3712       gtk_tree_path_free (tmp_path);
3713
3714       _gtk_tree_selection_emit_changed (tree_view->priv->selection);
3715     }
3716
3717   /* Clear status variables */
3718   tree_view->priv->rubber_band_status = RUBBER_BAND_OFF;
3719   tree_view->priv->rubber_band_shift = 0;
3720   tree_view->priv->rubber_band_ctrl = 0;
3721
3722   tree_view->priv->rubber_band_start_node = NULL;
3723   tree_view->priv->rubber_band_start_tree = NULL;
3724   tree_view->priv->rubber_band_end_node = NULL;
3725   tree_view->priv->rubber_band_end_tree = NULL;
3726 }
3727
3728 static void
3729 gtk_tree_view_update_rubber_band_selection_range (GtkTreeView *tree_view,
3730                                                  GtkRBTree   *start_tree,
3731                                                  GtkRBNode   *start_node,
3732                                                  GtkRBTree   *end_tree,
3733                                                  GtkRBNode   *end_node,
3734                                                  gboolean     select,
3735                                                  gboolean     skip_start,
3736                                                  gboolean     skip_end)
3737 {
3738   if (start_node == end_node)
3739     return;
3740
3741   /* We skip the first node and jump inside the loop */
3742   if (skip_start)
3743     goto skip_first;
3744
3745   do
3746     {
3747       /* Small optimization by assuming insensitive nodes are never
3748        * selected.
3749        */
3750       if (!GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
3751         {
3752           GtkTreePath *path;
3753           gboolean selectable;
3754
3755           path = _gtk_tree_view_find_path (tree_view, start_tree, start_node);
3756           selectable = _gtk_tree_selection_row_is_selectable (tree_view->priv->selection, start_node, path);
3757           gtk_tree_path_free (path);
3758
3759           if (!selectable)
3760             goto node_not_selectable;
3761         }
3762
3763       if (select)
3764         {
3765           if (tree_view->priv->rubber_band_shift)
3766             GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3767           else if (tree_view->priv->rubber_band_ctrl)
3768             {
3769               /* Toggle the selection state */
3770               if (GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
3771                 GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3772               else
3773                 GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3774             }
3775           else
3776             GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3777         }
3778       else
3779         {
3780           /* Mirror the above */
3781           if (tree_view->priv->rubber_band_shift)
3782             GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3783           else if (tree_view->priv->rubber_band_ctrl)
3784             {
3785               /* Toggle the selection state */
3786               if (GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
3787                 GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3788               else
3789                 GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3790             }
3791           else
3792             GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
3793         }
3794
3795       _gtk_tree_view_queue_draw_node (tree_view, start_tree, start_node, NULL);
3796
3797 node_not_selectable:
3798       if (start_node == end_node)
3799         break;
3800
3801 skip_first:
3802
3803       if (start_node->children)
3804         {
3805           start_tree = start_node->children;
3806           start_node = start_tree->root;
3807           while (start_node->left != start_tree->nil)
3808             start_node = start_node->left;
3809         }
3810       else
3811         {
3812           _gtk_rbtree_next_full (start_tree, start_node, &start_tree, &start_node);
3813
3814           if (!start_tree)
3815             /* Ran out of tree */
3816             break;
3817         }
3818
3819       if (skip_end && start_node == end_node)
3820         break;
3821     }
3822   while (TRUE);
3823 }
3824
3825 static void
3826 gtk_tree_view_update_rubber_band_selection (GtkTreeView *tree_view)
3827 {
3828   GtkRBTree *start_tree, *end_tree;
3829   GtkRBNode *start_node, *end_node;
3830
3831   _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);
3832   _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);
3833
3834   /* Handle the start area first */
3835   if (!tree_view->priv->rubber_band_start_node)
3836     {
3837       gtk_tree_view_update_rubber_band_selection_range (tree_view,
3838                                                        start_tree,
3839                                                        start_node,
3840                                                        end_tree,
3841                                                        end_node,
3842                                                        TRUE,
3843                                                        FALSE,
3844                                                        FALSE);
3845     }
3846   else if (_gtk_rbtree_node_find_offset (start_tree, start_node) <
3847            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_start_tree, tree_view->priv->rubber_band_start_node))
3848     {
3849       /* New node is above the old one; selection became bigger */
3850       gtk_tree_view_update_rubber_band_selection_range (tree_view,
3851                                                        start_tree,
3852                                                        start_node,
3853                                                        tree_view->priv->rubber_band_start_tree,
3854                                                        tree_view->priv->rubber_band_start_node,
3855                                                        TRUE,
3856                                                        FALSE,
3857                                                        TRUE);
3858     }
3859   else if (_gtk_rbtree_node_find_offset (start_tree, start_node) >
3860            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_start_tree, tree_view->priv->rubber_band_start_node))
3861     {
3862       /* New node is below the old one; selection became smaller */
3863       gtk_tree_view_update_rubber_band_selection_range (tree_view,
3864                                                        tree_view->priv->rubber_band_start_tree,
3865                                                        tree_view->priv->rubber_band_start_node,
3866                                                        start_tree,
3867                                                        start_node,
3868                                                        FALSE,
3869                                                        FALSE,
3870                                                        TRUE);
3871     }
3872
3873   tree_view->priv->rubber_band_start_tree = start_tree;
3874   tree_view->priv->rubber_band_start_node = start_node;
3875
3876   /* Next, handle the end area */
3877   if (!tree_view->priv->rubber_band_end_node)
3878     {
3879       /* In the event this happens, start_node was also NULL; this case is
3880        * handled above.
3881        */
3882     }
3883   else if (!end_node)
3884     {
3885       /* Find the last node in the tree */
3886       _gtk_rbtree_find_offset (tree_view->priv->tree, tree_view->priv->height - 1,
3887                                &end_tree, &end_node);
3888
3889       /* Selection reached end of the tree */
3890       gtk_tree_view_update_rubber_band_selection_range (tree_view,
3891                                                        tree_view->priv->rubber_band_end_tree,
3892                                                        tree_view->priv->rubber_band_end_node,
3893                                                        end_tree,
3894                                                        end_node,
3895                                                        TRUE,
3896                                                        TRUE,
3897                                                        FALSE);
3898     }
3899   else if (_gtk_rbtree_node_find_offset (end_tree, end_node) >
3900            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_end_tree, tree_view->priv->rubber_band_end_node))
3901     {
3902       /* New node is below the old one; selection became bigger */
3903       gtk_tree_view_update_rubber_band_selection_range (tree_view,
3904                                                        tree_view->priv->rubber_band_end_tree,
3905                                                        tree_view->priv->rubber_band_end_node,
3906                                                        end_tree,
3907                                                        end_node,
3908                                                        TRUE,
3909                                                        TRUE,
3910                                                        FALSE);
3911     }
3912   else if (_gtk_rbtree_node_find_offset (end_tree, end_node) <
3913            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_end_tree, tree_view->priv->rubber_band_end_node))
3914     {
3915       /* New node is above the old one; selection became smaller */
3916       gtk_tree_view_update_rubber_band_selection_range (tree_view,
3917                                                        end_tree,
3918                                                        end_node,
3919                                                        tree_view->priv->rubber_band_end_tree,
3920                                                        tree_view->priv->rubber_band_end_node,
3921                                                        FALSE,
3922                                                        TRUE,
3923                                                        FALSE);
3924     }
3925
3926   tree_view->priv->rubber_band_end_tree = end_tree;
3927   tree_view->priv->rubber_band_end_node = end_node;
3928 }
3929
3930 static void
3931 gtk_tree_view_update_rubber_band (GtkTreeView *tree_view)
3932 {
3933   gint x, y;
3934   GdkRectangle old_area;
3935   GdkRectangle new_area;
3936   GdkRectangle common;
3937   GdkRegion *invalid_region;
3938
3939   old_area.x = MIN (tree_view->priv->press_start_x, tree_view->priv->rubber_band_x);
3940   old_area.y = MIN (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y) - tree_view->priv->dy;
3941   old_area.width = ABS (tree_view->priv->rubber_band_x - tree_view->priv->press_start_x) + 1;
3942   old_area.height = ABS (tree_view->priv->rubber_band_y - tree_view->priv->press_start_y) + 1;
3943
3944   gdk_window_get_pointer (tree_view->priv->bin_window, &x, &y, NULL);
3945
3946   x = MAX (x, 0);
3947   y = MAX (y, 0) + tree_view->priv->dy;
3948
3949   new_area.x = MIN (tree_view->priv->press_start_x, x);
3950   new_area.y = MIN (tree_view->priv->press_start_y, y) - tree_view->priv->dy;
3951   new_area.width = ABS (x - tree_view->priv->press_start_x) + 1;
3952   new_area.height = ABS (y - tree_view->priv->press_start_y) + 1;
3953
3954   invalid_region = gdk_region_rectangle (&old_area);
3955   gdk_region_union_with_rect (invalid_region, &new_area);
3956
3957   gdk_rectangle_intersect (&old_area, &new_area, &common);
3958   if (common.width > 2 && common.height > 2)
3959     {
3960       GdkRegion *common_region;
3961
3962       /* make sure the border is invalidated */
3963       common.x += 1;
3964       common.y += 1;
3965       common.width -= 2;
3966       common.height -= 2;
3967
3968       common_region = gdk_region_rectangle (&common);
3969
3970       gdk_region_subtract (invalid_region, common_region);
3971       gdk_region_destroy (common_region);
3972     }
3973
3974   gdk_window_invalidate_region (tree_view->priv->bin_window, invalid_region, TRUE);
3975
3976   gdk_region_destroy (invalid_region);
3977
3978   tree_view->priv->rubber_band_x = x;
3979   tree_view->priv->rubber_band_y = y;
3980
3981   gtk_tree_view_update_rubber_band_selection (tree_view);
3982 }
3983
3984 static void
3985 gtk_tree_view_paint_rubber_band (GtkTreeView  *tree_view,
3986                                 GdkRectangle *area)
3987 {
3988   cairo_t *cr;
3989   GdkRectangle rect;
3990   GdkRectangle rubber_rect;
3991
3992   rubber_rect.x = MIN (tree_view->priv->press_start_x, tree_view->priv->rubber_band_x);
3993   rubber_rect.y = MIN (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y) - tree_view->priv->dy;
3994   rubber_rect.width = ABS (tree_view->priv->press_start_x - tree_view->priv->rubber_band_x) + 1;
3995   rubber_rect.height = ABS (tree_view->priv->press_start_y - tree_view->priv->rubber_band_y) + 1;
3996
3997   if (!gdk_rectangle_intersect (&rubber_rect, area, &rect))
3998     return;
3999
4000   cr = gdk_cairo_create (tree_view->priv->bin_window);
4001   cairo_set_line_width (cr, 1.0);
4002
4003   cairo_set_source_rgba (cr,
4004                          GTK_WIDGET (tree_view)->style->fg[GTK_STATE_NORMAL].red / 65535.,
4005                          GTK_WIDGET (tree_view)->style->fg[GTK_STATE_NORMAL].green / 65535.,
4006                          GTK_WIDGET (tree_view)->style->fg[GTK_STATE_NORMAL].blue / 65535.,
4007                          .25);
4008
4009   gdk_cairo_rectangle (cr, &rect);
4010   cairo_clip (cr);
4011   cairo_paint (cr);
4012
4013   cairo_set_source_rgb (cr,
4014                         GTK_WIDGET (tree_view)->style->fg[GTK_STATE_NORMAL].red / 65535.,
4015                         GTK_WIDGET (tree_view)->style->fg[GTK_STATE_NORMAL].green / 65535.,
4016                         GTK_WIDGET (tree_view)->style->fg[GTK_STATE_NORMAL].blue / 65535.);
4017
4018   cairo_rectangle (cr,
4019                    rubber_rect.x + 0.5, rubber_rect.y + 0.5,
4020                    rubber_rect.width - 1, rubber_rect.height - 1);
4021   cairo_stroke (cr);
4022
4023   cairo_destroy (cr);
4024 }
4025
4026 static gboolean
4027 gtk_tree_view_motion_bin_window (GtkWidget      *widget,
4028                                  GdkEventMotion *event)
4029 {
4030   GtkTreeView *tree_view;
4031   GtkRBTree *tree;
4032   GtkRBNode *node;
4033   gint new_y;
4034
4035   tree_view = (GtkTreeView *) widget;
4036
4037   if (tree_view->priv->tree == NULL)
4038     return FALSE;
4039
4040   if (tree_view->priv->rubber_band_status == RUBBER_BAND_MAYBE_START)
4041     {
4042       gtk_grab_add (GTK_WIDGET (tree_view));
4043       gtk_tree_view_update_rubber_band (tree_view);
4044
4045       tree_view->priv->rubber_band_status = RUBBER_BAND_ACTIVE;
4046     }
4047   else if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
4048     {
4049       gtk_tree_view_update_rubber_band (tree_view);
4050
4051       add_scroll_timeout (tree_view);
4052     }
4053
4054   /* only check for an initiated drag when a button is pressed */
4055   if (tree_view->priv->pressed_button >= 0
4056       && !tree_view->priv->rubber_band_status)
4057     gtk_tree_view_maybe_begin_dragging_row (tree_view, event);
4058
4059   new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
4060   if (new_y < 0)
4061     new_y = 0;
4062
4063   _gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
4064
4065   /* If we are currently pressing down a button, we don't want to prelight anything else. */
4066   if ((tree_view->priv->button_pressed_node != NULL) &&
4067       (tree_view->priv->button_pressed_node != node))
4068     node = NULL;
4069
4070   prelight_or_select (tree_view, tree, node, event->x, event->y);
4071
4072   return TRUE;
4073 }
4074
4075 static gboolean
4076 gtk_tree_view_motion (GtkWidget      *widget,
4077                       GdkEventMotion *event)
4078 {
4079   GtkTreeView *tree_view;
4080
4081   tree_view = (GtkTreeView *) widget;
4082
4083   /* Resizing a column */
4084   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE))
4085     return gtk_tree_view_motion_resize_column (widget, event);
4086
4087   /* Drag column */
4088   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
4089     return gtk_tree_view_motion_drag_column (widget, event);
4090
4091   /* Sanity check it */
4092   if (event->window == tree_view->priv->bin_window)
4093     return gtk_tree_view_motion_bin_window (widget, event);
4094
4095   return FALSE;
4096 }
4097
4098 /* Invalidate the focus rectangle near the edge of the bin_window; used when
4099  * the tree is empty.
4100  */
4101 static void
4102 invalidate_empty_focus (GtkTreeView *tree_view)
4103 {
4104   GdkRectangle area;
4105
4106   if (!GTK_WIDGET_HAS_FOCUS (tree_view))
4107     return;
4108
4109   area.x = 0;
4110   area.y = 0;
4111   gdk_drawable_get_size (tree_view->priv->bin_window, &area.width, &area.height);
4112   gdk_window_invalidate_rect (tree_view->priv->bin_window, &area, FALSE);
4113 }
4114
4115 /* Draws a focus rectangle near the edge of the bin_window; used when the tree
4116  * is empty.
4117  */
4118 static void
4119 draw_empty_focus (GtkTreeView *tree_view, GdkRectangle *clip_area)
4120 {
4121   gint w, h;
4122
4123   if (!GTK_WIDGET_HAS_FOCUS (tree_view))
4124     return;
4125
4126   gdk_drawable_get_size (tree_view->priv->bin_window, &w, &h);
4127
4128   w -= 2;
4129   h -= 2;
4130
4131   if (w > 0 && h > 0)
4132     gtk_paint_focus (GTK_WIDGET (tree_view)->style,
4133                      tree_view->priv->bin_window,
4134                      GTK_WIDGET_STATE (tree_view),
4135                      clip_area,
4136                      GTK_WIDGET (tree_view),
4137                      NULL,
4138                      1, 1, w, h);
4139 }
4140
4141 static void
4142 gtk_tree_view_draw_grid_lines (GtkTreeView    *tree_view,
4143                                GdkEventExpose *event,
4144                                gint            n_visible_columns)
4145 {
4146   GList *list = tree_view->priv->columns;
4147   gint i = 0;
4148   gint current_x = 0;
4149
4150   if (tree_view->priv->grid_lines != GTK_TREE_VIEW_GRID_LINES_VERTICAL
4151       && tree_view->priv->grid_lines != GTK_TREE_VIEW_GRID_LINES_BOTH)
4152     return;
4153
4154   /* Only draw the lines for visible rows and columns */
4155   for (list = tree_view->priv->columns; list; list = list->next, i++)
4156     {
4157       GtkTreeViewColumn *column = list->data;
4158
4159       /* We don't want a line for the last column */
4160       if (i == n_visible_columns - 1)
4161         break;
4162
4163       if (! column->visible)
4164         continue;
4165
4166       current_x += column->width;
4167
4168       gdk_draw_line (event->window,
4169                      tree_view->priv->grid_line_gc,
4170                      current_x - 1, 0,
4171                      current_x - 1, tree_view->priv->height);
4172     }
4173 }
4174
4175 /* Warning: Very scary function.
4176  * Modify at your own risk
4177  *
4178  * KEEP IN SYNC WITH gtk_tree_view_create_row_drag_icon()!
4179  * FIXME: It's not...
4180  */
4181 static gboolean
4182 gtk_tree_view_bin_expose (GtkWidget      *widget,
4183                           GdkEventExpose *event)
4184 {
4185   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
4186   GtkTreePath *path;
4187   GtkRBTree *tree;
4188   GList *list;
4189   GtkRBNode *node;
4190   GtkRBNode *cursor = NULL;
4191   GtkRBTree *cursor_tree = NULL;
4192   GtkRBNode *drag_highlight = NULL;
4193   GtkRBTree *drag_highlight_tree = NULL;
4194   GtkTreeIter iter;
4195   gint new_y;
4196   gint y_offset, cell_offset;
4197   gint max_height;
4198   gint depth;
4199   GdkRectangle background_area;
4200   GdkRectangle cell_area;
4201   guint flags;
4202   gint highlight_x;
4203   gint expander_cell_width;
4204   gint bin_window_width;
4205   gint bin_window_height;
4206   GtkTreePath *cursor_path;
4207   GtkTreePath *drag_dest_path;
4208   GList *first_column, *last_column;
4209   gint vertical_separator;
4210   gint horizontal_separator;
4211   gint focus_line_width;
4212   gboolean allow_rules;
4213   gboolean has_special_cell;
4214   gboolean rtl;
4215   gint n_visible_columns;
4216   gint pointer_x, pointer_y;
4217   gint grid_line_width;
4218   gboolean got_pointer = FALSE;
4219   gboolean row_ending_details;
4220   gboolean draw_vgrid_lines, draw_hgrid_lines;
4221
4222   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
4223
4224   gtk_widget_style_get (widget,
4225                         "horizontal-separator", &horizontal_separator,
4226                         "vertical-separator", &vertical_separator,
4227                         "allow-rules", &allow_rules,
4228                         "focus-line-width", &focus_line_width,
4229                         "row-ending-details", &row_ending_details,
4230                         NULL);
4231
4232   if (tree_view->priv->tree == NULL)
4233     {
4234       draw_empty_focus (tree_view, &event->area);
4235       return TRUE;
4236     }
4237
4238   /* clip event->area to the visible area */
4239   if (event->area.height < 0)
4240     return TRUE;
4241
4242   validate_visible_area (tree_view);
4243
4244   new_y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, event->area.y);
4245
4246   if (new_y < 0)
4247     new_y = 0;
4248   y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
4249   gdk_drawable_get_size (tree_view->priv->bin_window,
4250                          &bin_window_width, &bin_window_height);
4251
4252   if (tree_view->priv->height < bin_window_height)
4253     {
4254       gtk_paint_flat_box (widget->style,
4255                           event->window,
4256                           widget->state,
4257                           GTK_SHADOW_NONE,
4258                           &event->area,
4259                           widget,
4260                           "cell_even",
4261                           0, tree_view->priv->height,
4262                           bin_window_width,
4263                           bin_window_height - tree_view->priv->height);
4264     }
4265
4266   if (node == NULL)
4267     return TRUE;
4268
4269   /* find the path for the node */
4270   path = _gtk_tree_view_find_path ((GtkTreeView *)widget,
4271                                    tree,
4272                                    node);
4273   gtk_tree_model_get_iter (tree_view->priv->model,
4274                            &iter,
4275                            path);
4276   depth = gtk_tree_path_get_depth (path);
4277   gtk_tree_path_free (path);
4278   
4279   cursor_path = NULL;
4280   drag_dest_path = NULL;
4281
4282   if (tree_view->priv->cursor)
4283     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
4284
4285   if (cursor_path)
4286     _gtk_tree_view_find_node (tree_view, cursor_path,
4287                               &cursor_tree, &cursor);
4288
4289   if (tree_view->priv->drag_dest_row)
4290     drag_dest_path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
4291
4292   if (drag_dest_path)
4293     _gtk_tree_view_find_node (tree_view, drag_dest_path,
4294                               &drag_highlight_tree, &drag_highlight);
4295
4296   draw_vgrid_lines =
4297     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_VERTICAL
4298     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
4299   draw_hgrid_lines =
4300     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_HORIZONTAL
4301     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
4302
4303   if (draw_vgrid_lines || draw_hgrid_lines)
4304     gtk_widget_style_get (widget, "grid-line-width", &grid_line_width, NULL);
4305   
4306   n_visible_columns = 0;
4307   for (list = tree_view->priv->columns; list; list = list->next)
4308     {
4309       if (! GTK_TREE_VIEW_COLUMN (list->data)->visible)
4310         continue;
4311       n_visible_columns ++;
4312     }
4313
4314   /* Find the last column */
4315   for (last_column = g_list_last (tree_view->priv->columns);
4316        last_column && !(GTK_TREE_VIEW_COLUMN (last_column->data)->visible);
4317        last_column = last_column->prev)
4318     ;
4319
4320   /* and the first */
4321   for (first_column = g_list_first (tree_view->priv->columns);
4322        first_column && !(GTK_TREE_VIEW_COLUMN (first_column->data)->visible);
4323        first_column = first_column->next)
4324     ;
4325
4326   /* Actually process the expose event.  To do this, we want to
4327    * start at the first node of the event, and walk the tree in
4328    * order, drawing each successive node.
4329    */
4330
4331   do
4332     {
4333       gboolean parity;
4334       gboolean is_separator = FALSE;
4335       gboolean is_first = FALSE;
4336       gboolean is_last = FALSE;
4337       
4338       is_separator = row_is_separator (tree_view, &iter, NULL);
4339
4340       max_height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
4341
4342       cell_offset = 0;
4343       highlight_x = 0; /* should match x coord of first cell */
4344       expander_cell_width = 0;
4345
4346       background_area.y = y_offset + event->area.y;
4347       background_area.height = max_height;
4348
4349       flags = 0;
4350
4351       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PRELIT))
4352         flags |= GTK_CELL_RENDERER_PRELIT;
4353
4354       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
4355         flags |= GTK_CELL_RENDERER_SELECTED;
4356
4357       parity = _gtk_rbtree_node_find_parity (tree, node);
4358
4359       /* we *need* to set cell data on all cells before the call
4360        * to _has_special_cell, else _has_special_cell() does not
4361        * return a correct value.
4362        */
4363       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
4364            list;
4365            list = (rtl ? list->prev : list->next))
4366         {
4367           GtkTreeViewColumn *column = list->data;
4368           gtk_tree_view_column_cell_set_cell_data (column,
4369                                                    tree_view->priv->model,
4370                                                    &iter,
4371                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
4372                                                    node->children?TRUE:FALSE);
4373         }
4374
4375       has_special_cell = gtk_tree_view_has_special_cell (tree_view);
4376
4377       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
4378            list;
4379            list = (rtl ? list->prev : list->next))
4380         {
4381           GtkTreeViewColumn *column = list->data;
4382           const gchar *detail = NULL;
4383           GtkStateType state;
4384
4385           if (!column->visible)
4386             continue;
4387
4388           if (cell_offset > event->area.x + event->area.width ||
4389               cell_offset + column->width < event->area.x)
4390             {
4391               cell_offset += column->width;
4392               continue;
4393             }
4394
4395           if (column->show_sort_indicator)
4396             flags |= GTK_CELL_RENDERER_SORTED;
4397           else
4398             flags &= ~GTK_CELL_RENDERER_SORTED;
4399
4400           if (cursor == node)
4401             flags |= GTK_CELL_RENDERER_FOCUSED;
4402           else
4403             flags &= ~GTK_CELL_RENDERER_FOCUSED;
4404
4405           background_area.x = cell_offset;
4406           background_area.width = column->width;
4407
4408           cell_area = background_area;
4409           cell_area.y += vertical_separator / 2;
4410           cell_area.x += horizontal_separator / 2;
4411           cell_area.height -= vertical_separator;
4412           cell_area.width -= horizontal_separator;
4413
4414           if (draw_vgrid_lines)
4415             {
4416               if (list == first_column)
4417                 {
4418                   cell_area.width -= grid_line_width / 2;
4419                 }
4420               else if (list == last_column)
4421                 {
4422                   cell_area.x += grid_line_width / 2;
4423                   cell_area.width -= grid_line_width / 2;
4424                 }
4425               else
4426                 {
4427                   cell_area.x += grid_line_width / 2;
4428                   cell_area.width -= grid_line_width;
4429                 }
4430             }
4431
4432           if (draw_hgrid_lines)
4433             {
4434               cell_area.y += grid_line_width / 2;
4435               cell_area.height -= grid_line_width;
4436             }
4437
4438           if (gdk_region_rect_in (event->region, &background_area) == GDK_OVERLAP_RECTANGLE_OUT)
4439             {
4440               cell_offset += column->width;
4441               continue;
4442             }
4443
4444           gtk_tree_view_column_cell_set_cell_data (column,
4445                                                    tree_view->priv->model,
4446                                                    &iter,
4447                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
4448                                                    node->children?TRUE:FALSE);
4449
4450           /* Select the detail for drawing the cell.  relevant
4451            * factors are parity, sortedness, and whether to
4452            * display rules.
4453            */
4454           if (allow_rules && tree_view->priv->has_rules)
4455             {
4456               if ((flags & GTK_CELL_RENDERER_SORTED) &&
4457                   n_visible_columns >= 3)
4458                 {
4459                   if (parity)
4460                     detail = "cell_odd_ruled_sorted";
4461                   else
4462                     detail = "cell_even_ruled_sorted";
4463                 }
4464               else
4465                 {
4466                   if (parity)
4467                     detail = "cell_odd_ruled";
4468                   else
4469                     detail = "cell_even_ruled";
4470                 }
4471             }
4472           else
4473             {
4474               if ((flags & GTK_CELL_RENDERER_SORTED) &&
4475                   n_visible_columns >= 3)
4476                 {
4477                   if (parity)
4478                     detail = "cell_odd_sorted";
4479                   else
4480                     detail = "cell_even_sorted";
4481                 }
4482               else
4483                 {
4484                   if (parity)
4485                     detail = "cell_odd";
4486                   else
4487                     detail = "cell_even";
4488                 }
4489             }
4490
4491           g_assert (detail);
4492
4493           if (widget->state == GTK_STATE_INSENSITIVE)
4494             state = GTK_STATE_INSENSITIVE;          
4495           else if (flags & GTK_CELL_RENDERER_SELECTED)
4496             state = GTK_STATE_SELECTED;
4497           else
4498             state = GTK_STATE_NORMAL;
4499
4500           /* Draw background */
4501           if (row_ending_details)
4502             {
4503               char new_detail[128];
4504
4505               is_first = (rtl ? !list->next : !list->prev);
4506               is_last = (rtl ? !list->prev : !list->next);
4507
4508               /* (I don't like the snprintfs either, but couldn't find a
4509                * less messy way).
4510                */
4511               if (is_first && is_last)
4512                 g_snprintf (new_detail, 127, "%s", detail);
4513               else if (is_first)
4514                 g_snprintf (new_detail, 127, "%s_start", detail);
4515               else if (is_last)
4516                 g_snprintf (new_detail, 127, "%s_end", detail);
4517               else
4518                 g_snprintf (new_detail, 128, "%s_middle", detail);
4519
4520               gtk_paint_flat_box (widget->style,
4521                                   event->window,
4522                                   state,
4523                                   GTK_SHADOW_NONE,
4524                                   &event->area,
4525                                   widget,
4526                                   new_detail,
4527                                   background_area.x,
4528                                   background_area.y,
4529                                   background_area.width,
4530                                   background_area.height);
4531             }
4532           else
4533             {
4534               gtk_paint_flat_box (widget->style,
4535                                   event->window,
4536                                   state,
4537                                   GTK_SHADOW_NONE,
4538                                   &event->area,
4539                                   widget,
4540                                   detail,
4541                                   background_area.x,
4542                                   background_area.y,
4543                                   background_area.width,
4544                                   background_area.height);
4545             }
4546
4547           if (draw_hgrid_lines)
4548             {
4549               if (background_area.y > 0)
4550                 gdk_draw_line (event->window,
4551                                tree_view->priv->grid_line_gc,
4552                                background_area.x, background_area.y,
4553                                background_area.x + background_area.width,
4554                                background_area.y);
4555
4556               if (y_offset + max_height >= event->area.height)
4557                 gdk_draw_line (event->window,
4558                                tree_view->priv->grid_line_gc,
4559                                background_area.x, background_area.y + max_height,
4560                                background_area.x + background_area.width,
4561                                background_area.y + max_height);
4562             }
4563
4564           if (gtk_tree_view_is_expander_column (tree_view, column))
4565             {
4566               if (!rtl)
4567                 cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
4568               cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
4569
4570               if (TREE_VIEW_DRAW_EXPANDERS(tree_view))
4571                 {
4572                   if (!rtl)
4573                     cell_area.x += depth * tree_view->priv->expander_size;
4574                   cell_area.width -= depth * tree_view->priv->expander_size;
4575                 }
4576
4577               /* If we have an expander column, the highlight underline
4578                * starts with that column, so that it indicates which
4579                * level of the tree we're dropping at.
4580                */
4581               highlight_x = cell_area.x;
4582               expander_cell_width = cell_area.width;
4583
4584               if (is_separator)
4585                 gtk_paint_hline (widget->style,
4586                                  event->window,
4587                                  state,
4588                                  &cell_area,
4589                                  widget,
4590                                  NULL,
4591                                  cell_area.x,
4592                                  cell_area.x + cell_area.width,
4593                                  cell_area.y + cell_area.height / 2);
4594               else
4595                 _gtk_tree_view_column_cell_render (column,
4596                                                    event->window,
4597                                                    &background_area,
4598                                                    &cell_area,
4599                                                    &event->area,
4600                                                    flags);
4601               if (TREE_VIEW_DRAW_EXPANDERS(tree_view)
4602                   && (node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT)
4603                 {
4604                   if (!got_pointer)
4605                     {
4606                       gdk_window_get_pointer (tree_view->priv->bin_window, 
4607                                               &pointer_x, &pointer_y, NULL);
4608                       got_pointer = TRUE;
4609                     }
4610
4611                   gtk_tree_view_draw_arrow (GTK_TREE_VIEW (widget),
4612                                             tree,
4613                                             node,
4614                                             pointer_x, pointer_y);
4615                 }
4616             }
4617           else
4618             {
4619               if (is_separator)
4620                 gtk_paint_hline (widget->style,
4621                                  event->window,
4622                                  state,
4623                                  &cell_area,
4624                                  widget,
4625                                  NULL,
4626                                  cell_area.x,
4627                                  cell_area.x + cell_area.width,
4628                                  cell_area.y + cell_area.height / 2);
4629               else
4630                 _gtk_tree_view_column_cell_render (column,
4631                                                    event->window,
4632                                                    &background_area,
4633                                                    &cell_area,
4634                                                    &event->area,
4635                                                    flags);
4636             }
4637
4638           if (gtk_tree_view_is_expander_column (tree_view, column) &&
4639               tree_view->priv->tree_lines_enabled)
4640             {
4641               gint x = background_area.x;
4642               gint mult = rtl ? -1 : 1;
4643               gint y0 = background_area.y;
4644               gint y1 = background_area.y + background_area.height/2;
4645               gint y2 = background_area.y + background_area.height;
4646
4647               if (rtl)
4648                 x += background_area.width - 1;
4649
4650               if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT
4651                   && depth > 1)
4652                 {
4653                   gdk_draw_line (event->window,
4654                                  tree_view->priv->tree_line_gc,
4655                                  x + tree_view->priv->expander_size * (depth - 1.5) * mult,
4656                                  y1,
4657                                  x + tree_view->priv->expander_size * (depth - 1.1) * mult,
4658                                  y1);
4659                 }
4660               else if (depth > 1)
4661                 {
4662                   gdk_draw_line (event->window,
4663                                  tree_view->priv->tree_line_gc,
4664                                  x + tree_view->priv->expander_size * (depth - 1.5) * mult,
4665                                  y1,
4666                                  x + tree_view->priv->expander_size * (depth - 0.5) * mult,
4667                                  y1);
4668                 }
4669
4670               if (depth > 1)
4671                 {
4672                   gint i;
4673                   GtkRBNode *tmp_node;
4674                   GtkRBTree *tmp_tree;
4675
4676                   if (!_gtk_rbtree_next (tree, node))
4677                     gdk_draw_line (event->window,
4678                                    tree_view->priv->tree_line_gc,
4679                                    x + tree_view->priv->expander_size * (depth - 1.5) * mult,
4680                                    y0,
4681                                    x + tree_view->priv->expander_size * (depth - 1.5) * mult,
4682                                    y1);
4683                   else
4684                     gdk_draw_line (event->window,
4685                                    tree_view->priv->tree_line_gc,
4686                                    x + tree_view->priv->expander_size * (depth - 1.5) * mult,
4687                                    y0,
4688                                    x + tree_view->priv->expander_size * (depth - 1.5) * mult,
4689                                    y2);
4690
4691                   tmp_node = tree->parent_node;
4692                   tmp_tree = tree->parent_tree;
4693
4694                   for (i = depth - 2; i > 0; i--)
4695                     {
4696                       if (_gtk_rbtree_next (tmp_tree, tmp_node))
4697                         gdk_draw_line (event->window,
4698                                        tree_view->priv->tree_line_gc,
4699                                        x + tree_view->priv->expander_size * (i - 0.5) * mult,
4700                                        y0,
4701                                        x + tree_view->priv->expander_size * (i - 0.5) * mult,
4702                                        y2);
4703
4704                       tmp_node = tmp_tree->parent_node;
4705                       tmp_tree = tmp_tree->parent_tree;
4706                     }
4707                 }
4708             }
4709
4710           if (node == cursor && has_special_cell &&
4711               ((column == tree_view->priv->focus_column &&
4712                 GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS) &&
4713                 GTK_WIDGET_HAS_FOCUS (widget)) ||
4714                (column == tree_view->priv->edited_column)))
4715             {
4716               _gtk_tree_view_column_cell_draw_focus (column,
4717                                                      event->window,
4718                                                      &background_area,
4719                                                      &cell_area,
4720                                                      &event->area,
4721                                                      flags);
4722             }
4723
4724           cell_offset += column->width;
4725         }
4726
4727       if (node == drag_highlight)
4728         {
4729           /* Draw indicator for the drop
4730            */
4731           gint highlight_y = -1;
4732           GtkRBTree *tree = NULL;
4733           GtkRBNode *node = NULL;
4734           gint width;
4735
4736           switch (tree_view->priv->drag_dest_pos)
4737             {
4738             case GTK_TREE_VIEW_DROP_BEFORE:
4739               highlight_y = background_area.y - 1;
4740               if (highlight_y < 0)
4741                       highlight_y = 0;
4742               break;
4743
4744             case GTK_TREE_VIEW_DROP_AFTER:
4745               highlight_y = background_area.y + background_area.height - 1;
4746               break;
4747
4748             case GTK_TREE_VIEW_DROP_INTO_OR_BEFORE:
4749             case GTK_TREE_VIEW_DROP_INTO_OR_AFTER:
4750               _gtk_tree_view_find_node (tree_view, drag_dest_path, &tree, &node);
4751
4752               if (tree == NULL)
4753                 break;
4754               gdk_drawable_get_size (tree_view->priv->bin_window,
4755                                      &width, NULL);
4756
4757               if (row_ending_details)
4758                 gtk_paint_focus (widget->style,
4759                                  tree_view->priv->bin_window,
4760                                  GTK_WIDGET_STATE (widget),
4761                                  &event->area,
4762                                  widget,
4763                                  (is_first
4764                                   ? (is_last ? "treeview-drop-indicator" : "treeview-drop-indicator-left" )
4765                                   : (is_last ? "treeview-drop-indicator-right" : "tree-view-drop-indicator-middle" )),
4766                                  0, BACKGROUND_FIRST_PIXEL (tree_view, tree, node)
4767                                  - focus_line_width / 2,
4768                                  width, ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node))
4769                                - focus_line_width + 1);
4770               else
4771                 gtk_paint_focus (widget->style,
4772                                  tree_view->priv->bin_window,
4773                                  GTK_WIDGET_STATE (widget),
4774                                  &event->area,
4775                                  widget,
4776                                  "treeview-drop-indicator",
4777                                  0, BACKGROUND_FIRST_PIXEL (tree_view, tree, node)
4778                                  - focus_line_width / 2,
4779                                  width, ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node))
4780                                  - focus_line_width + 1);
4781               break;
4782             }
4783
4784           if (highlight_y >= 0)
4785             {
4786               gdk_draw_line (event->window,
4787                              widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
4788                              rtl ? highlight_x + expander_cell_width : highlight_x,
4789                              highlight_y,
4790                              rtl ? 0 : bin_window_width,
4791                              highlight_y);
4792             }
4793         }
4794
4795       /* draw the big row-spanning focus rectangle, if needed */
4796       if (!has_special_cell && node == cursor &&
4797           GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS) &&
4798           GTK_WIDGET_HAS_FOCUS (widget))
4799         {
4800           gint tmp_y, tmp_height;
4801           gint width;
4802           GtkStateType focus_rect_state;
4803
4804           focus_rect_state =
4805             flags & GTK_CELL_RENDERER_SELECTED ? GTK_STATE_SELECTED :
4806             (flags & GTK_CELL_RENDERER_PRELIT ? GTK_STATE_PRELIGHT :
4807              (flags & GTK_CELL_RENDERER_INSENSITIVE ? GTK_STATE_INSENSITIVE :
4808               GTK_STATE_NORMAL));
4809
4810           gdk_drawable_get_size (tree_view->priv->bin_window,
4811                                  &width, NULL);
4812           
4813           if (draw_hgrid_lines)
4814             {
4815               tmp_y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node) + grid_line_width / 2;
4816               tmp_height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node)) - grid_line_width;
4817             }
4818           else
4819             {
4820               tmp_y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
4821               tmp_height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
4822             }
4823
4824           if (row_ending_details)
4825             gtk_paint_focus (widget->style,
4826                              tree_view->priv->bin_window,
4827                              focus_rect_state,
4828                              &event->area,
4829                              widget,
4830                              (is_first
4831                               ? (is_last ? "treeview" : "treeview-left" )
4832                               : (is_last ? "treeview-right" : "treeview-middle" )),
4833                              0, tmp_y,
4834                              width, tmp_height);
4835           else
4836             gtk_paint_focus (widget->style,
4837                              tree_view->priv->bin_window,
4838                              focus_rect_state,
4839                              &event->area,
4840                              widget,
4841                              "treeview",
4842                              0, tmp_y,
4843                              width, tmp_height);
4844         }
4845
4846       y_offset += max_height;
4847       if (node->children)
4848         {
4849           GtkTreeIter parent = iter;
4850           gboolean has_child;
4851
4852           tree = node->children;
4853           node = tree->root;
4854
4855           g_assert (node != tree->nil);
4856
4857           while (node->left != tree->nil)
4858             node = node->left;
4859           has_child = gtk_tree_model_iter_children (tree_view->priv->model,
4860                                                     &iter,
4861                                                     &parent);
4862           depth++;
4863
4864           /* Sanity Check! */
4865           TREE_VIEW_INTERNAL_ASSERT (has_child, FALSE);
4866         }
4867       else
4868         {
4869           gboolean done = FALSE;
4870
4871           do
4872             {
4873               node = _gtk_rbtree_next (tree, node);
4874               if (node != NULL)
4875                 {
4876                   gboolean has_next = gtk_tree_model_iter_next (tree_view->priv->model, &iter);
4877                   done = TRUE;
4878
4879                   /* Sanity Check! */
4880                   TREE_VIEW_INTERNAL_ASSERT (has_next, FALSE);
4881                 }
4882               else
4883                 {
4884                   GtkTreeIter parent_iter = iter;
4885                   gboolean has_parent;
4886
4887                   node = tree->parent_node;
4888                   tree = tree->parent_tree;
4889                   if (tree == NULL)
4890                     /* we should go to done to free some memory */
4891                     goto done;
4892                   has_parent = gtk_tree_model_iter_parent (tree_view->priv->model,
4893                                                            &iter,
4894                                                            &parent_iter);
4895                   depth--;
4896
4897                   /* Sanity check */
4898                   TREE_VIEW_INTERNAL_ASSERT (has_parent, FALSE);
4899                 }
4900             }
4901           while (!done);
4902         }
4903     }
4904   while (y_offset < event->area.height);
4905
4906 done:
4907   gtk_tree_view_draw_grid_lines (tree_view, event, n_visible_columns);
4908
4909  if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
4910    {
4911      GdkRectangle *rectangles;
4912      gint n_rectangles;
4913
4914      gdk_region_get_rectangles (event->region,
4915                                 &rectangles,
4916                                 &n_rectangles);
4917
4918      while (n_rectangles--)
4919        gtk_tree_view_paint_rubber_band (tree_view, &rectangles[n_rectangles]);
4920
4921      g_free (rectangles);
4922    }
4923
4924   if (cursor_path)
4925     gtk_tree_path_free (cursor_path);
4926
4927   if (drag_dest_path)
4928     gtk_tree_path_free (drag_dest_path);
4929
4930   return FALSE;
4931 }
4932
4933 static gboolean
4934 gtk_tree_view_expose (GtkWidget      *widget,
4935                       GdkEventExpose *event)
4936 {
4937   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
4938
4939   if (event->window == tree_view->priv->bin_window)
4940     {
4941       gboolean retval;
4942       GList *tmp_list;
4943
4944       retval = gtk_tree_view_bin_expose (widget, event);
4945
4946       /* We can't just chain up to Container::expose as it will try to send the
4947        * event to the headers, so we handle propagating it to our children
4948        * (eg. widgets being edited) ourselves.
4949        */
4950       tmp_list = tree_view->priv->children;
4951       while (tmp_list)
4952         {
4953           GtkTreeViewChild *child = tmp_list->data;
4954           tmp_list = tmp_list->next;
4955
4956           gtk_container_propagate_expose (GTK_CONTAINER (tree_view), child->widget, event);
4957         }
4958
4959       return retval;
4960     }
4961
4962   else if (event->window == tree_view->priv->header_window)
4963     {
4964       GList *list;
4965       
4966       for (list = tree_view->priv->columns; list != NULL; list = list->next)
4967         {
4968           GtkTreeViewColumn *column = list->data;
4969
4970           if (column == tree_view->priv->drag_column)
4971             continue;
4972
4973           if (column->visible)
4974             gtk_container_propagate_expose (GTK_CONTAINER (tree_view),
4975                                             column->button,
4976                                             event);
4977         }
4978     }
4979   else if (event->window == tree_view->priv->drag_window)
4980     {
4981       gtk_container_propagate_expose (GTK_CONTAINER (tree_view),
4982                                       tree_view->priv->drag_column->button,
4983                                       event);
4984     }
4985   return TRUE;
4986 }
4987
4988 enum
4989 {
4990   DROP_HOME,
4991   DROP_RIGHT,
4992   DROP_LEFT,
4993   DROP_END
4994 };
4995
4996 /* returns 0x1 when no column has been found -- yes it's hackish */
4997 static GtkTreeViewColumn *
4998 gtk_tree_view_get_drop_column (GtkTreeView       *tree_view,
4999                                GtkTreeViewColumn *column,
5000                                gint               drop_position)
5001 {
5002   GtkTreeViewColumn *left_column = NULL;
5003   GtkTreeViewColumn *cur_column = NULL;
5004   GList *tmp_list;
5005
5006   if (!column->reorderable)
5007     return (GtkTreeViewColumn *)0x1;
5008
5009   switch (drop_position)
5010     {
5011       case DROP_HOME:
5012         /* find first column where we can drop */
5013         tmp_list = tree_view->priv->columns;
5014         if (column == GTK_TREE_VIEW_COLUMN (tmp_list->data))
5015           return (GtkTreeViewColumn *)0x1;
5016
5017         while (tmp_list)
5018           {
5019             g_assert (tmp_list);
5020
5021             cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5022             tmp_list = tmp_list->next;
5023
5024             if (left_column && left_column->visible == FALSE)
5025               continue;
5026
5027             if (!tree_view->priv->column_drop_func)
5028               return left_column;
5029
5030             if (!tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5031               {
5032                 left_column = cur_column;
5033                 continue;
5034               }
5035
5036             return left_column;
5037           }
5038
5039         if (!tree_view->priv->column_drop_func)
5040           return left_column;
5041
5042         if (tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data))
5043           return left_column;
5044         else
5045           return (GtkTreeViewColumn *)0x1;
5046         break;
5047
5048       case DROP_RIGHT:
5049         /* find first column after column where we can drop */
5050         tmp_list = tree_view->priv->columns;
5051
5052         for (; tmp_list; tmp_list = tmp_list->next)
5053           if (GTK_TREE_VIEW_COLUMN (tmp_list->data) == column)
5054             break;
5055
5056         if (!tmp_list || !tmp_list->next)
5057           return (GtkTreeViewColumn *)0x1;
5058
5059         tmp_list = tmp_list->next;
5060         left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5061         tmp_list = tmp_list->next;
5062
5063         while (tmp_list)
5064           {
5065             g_assert (tmp_list);
5066
5067             cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5068             tmp_list = tmp_list->next;
5069
5070             if (left_column && left_column->visible == FALSE)
5071               {
5072                 left_column = cur_column;
5073                 if (tmp_list)
5074                   tmp_list = tmp_list->next;
5075                 continue;
5076               }
5077
5078             if (!tree_view->priv->column_drop_func)
5079               return left_column;
5080
5081             if (!tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5082               {
5083                 left_column = cur_column;
5084                 continue;
5085               }
5086
5087             return left_column;
5088           }
5089
5090         if (!tree_view->priv->column_drop_func)
5091           return left_column;
5092
5093         if (tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data))
5094           return left_column;
5095         else
5096           return (GtkTreeViewColumn *)0x1;
5097         break;
5098
5099       case DROP_LEFT:
5100         /* find first column before column where we can drop */
5101         tmp_list = tree_view->priv->columns;
5102
5103         for (; tmp_list; tmp_list = tmp_list->next)
5104           if (GTK_TREE_VIEW_COLUMN (tmp_list->data) == column)
5105             break;
5106
5107         if (!tmp_list || !tmp_list->prev)
5108           return (GtkTreeViewColumn *)0x1;
5109
5110         tmp_list = tmp_list->prev;
5111         cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5112         tmp_list = tmp_list->prev;
5113
5114         while (tmp_list)
5115           {
5116             g_assert (tmp_list);
5117
5118             left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5119
5120             if (left_column && !left_column->visible)
5121               {
5122                 /*if (!tmp_list->prev)
5123                   return (GtkTreeViewColumn *)0x1;
5124                   */
5125 /*
5126                 cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->prev->data);
5127                 tmp_list = tmp_list->prev->prev;
5128                 continue;*/
5129
5130                 cur_column = left_column;
5131                 if (tmp_list)
5132                   tmp_list = tmp_list->prev;
5133                 continue;
5134               }
5135
5136             if (!tree_view->priv->column_drop_func)
5137               return left_column;
5138
5139             if (tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5140               return left_column;
5141
5142             cur_column = left_column;
5143             tmp_list = tmp_list->prev;
5144           }
5145
5146         if (!tree_view->priv->column_drop_func)
5147           return NULL;
5148
5149         if (tree_view->priv->column_drop_func (tree_view, column, NULL, cur_column, tree_view->priv->column_drop_func_data))
5150           return NULL;
5151         else
5152           return (GtkTreeViewColumn *)0x1;
5153         break;
5154
5155       case DROP_END:
5156         /* same as DROP_HOME case, but doing it backwards */
5157         tmp_list = g_list_last (tree_view->priv->columns);
5158         cur_column = NULL;
5159
5160         if (column == GTK_TREE_VIEW_COLUMN (tmp_list->data))
5161           return (GtkTreeViewColumn *)0x1;
5162
5163         while (tmp_list)
5164           {
5165             g_assert (tmp_list);
5166
5167             left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5168
5169             if (left_column && !left_column->visible)
5170               {
5171                 cur_column = left_column;
5172                 tmp_list = tmp_list->prev;
5173               }
5174
5175             if (!tree_view->priv->column_drop_func)
5176               return left_column;
5177
5178             if (tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5179               return left_column;
5180
5181             cur_column = left_column;
5182             tmp_list = tmp_list->prev;
5183           }
5184
5185         if (!tree_view->priv->column_drop_func)
5186           return NULL;
5187
5188         if (tree_view->priv->column_drop_func (tree_view, column, NULL, cur_column, tree_view->priv->column_drop_func_data))
5189           return NULL;
5190         else
5191           return (GtkTreeViewColumn *)0x1;
5192         break;
5193     }
5194
5195   return (GtkTreeViewColumn *)0x1;
5196 }
5197
5198 static gboolean
5199 gtk_tree_view_key_press (GtkWidget   *widget,
5200                          GdkEventKey *event)
5201 {
5202   GtkTreeView *tree_view = (GtkTreeView *) widget;
5203
5204   if (tree_view->priv->rubber_band_status)
5205     {
5206       if (event->keyval == GDK_Escape)
5207         gtk_tree_view_stop_rubber_band (tree_view);
5208
5209       return TRUE;
5210     }
5211
5212   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
5213     {
5214       if (event->keyval == GDK_Escape)
5215         {
5216           tree_view->priv->cur_reorder = NULL;
5217           gtk_tree_view_button_release_drag_column (widget, NULL);
5218         }
5219       return TRUE;
5220     }
5221
5222   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
5223     {
5224       GList *focus_column;
5225       gboolean rtl;
5226
5227       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
5228
5229       for (focus_column = tree_view->priv->columns;
5230            focus_column;
5231            focus_column = focus_column->next)
5232         {
5233           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
5234
5235           if (GTK_WIDGET_HAS_FOCUS (column->button))
5236             break;
5237         }
5238
5239       if (focus_column &&
5240           (event->state & GDK_SHIFT_MASK) && (event->state & GDK_MOD1_MASK) &&
5241           (event->keyval == GDK_Left || event->keyval == GDK_KP_Left
5242            || event->keyval == GDK_Right || event->keyval == GDK_KP_Right))
5243         {
5244           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
5245
5246           if (!column->resizable)
5247             {
5248               gtk_widget_error_bell (widget);
5249               return TRUE;
5250             }
5251
5252           if (event->keyval == (rtl ? GDK_Right : GDK_Left)
5253               || event->keyval == (rtl ? GDK_KP_Right : GDK_KP_Left))
5254             {
5255               gint old_width = column->resized_width;
5256
5257               column->resized_width = MAX (column->resized_width,
5258                                            column->width);
5259               column->resized_width -= 2;
5260               if (column->resized_width < 0)
5261                 column->resized_width = 0;
5262
5263               if (column->min_width == -1)
5264                 column->resized_width = MAX (column->button->requisition.width,
5265                                              column->resized_width);
5266               else
5267                 column->resized_width = MAX (column->min_width,
5268                                              column->resized_width);
5269
5270               if (column->max_width != -1)
5271                 column->resized_width = MIN (column->resized_width,
5272                                              column->max_width);
5273
5274               column->use_resized_width = TRUE;
5275
5276               if (column->resized_width != old_width)
5277                 gtk_widget_queue_resize (widget);
5278               else
5279                 gtk_widget_error_bell (widget);
5280             }
5281           else if (event->keyval == (rtl ? GDK_Left : GDK_Right)
5282                    || event->keyval == (rtl ? GDK_KP_Left : GDK_KP_Right))
5283             {
5284               gint old_width = column->resized_width;
5285
5286               column->resized_width = MAX (column->resized_width,
5287                                            column->width);
5288               column->resized_width += 2;
5289
5290               if (column->max_width != -1)
5291                 column->resized_width = MIN (column->resized_width,
5292                                              column->max_width);
5293
5294               column->use_resized_width = TRUE;
5295
5296               if (column->resized_width != old_width)
5297                 gtk_widget_queue_resize (widget);
5298               else
5299                 gtk_widget_error_bell (widget);
5300             }
5301
5302           return TRUE;
5303         }
5304
5305       if (focus_column &&
5306           (event->state & GDK_MOD1_MASK) &&
5307           (event->keyval == GDK_Left || event->keyval == GDK_KP_Left
5308            || event->keyval == GDK_Right || event->keyval == GDK_KP_Right
5309            || event->keyval == GDK_Home || event->keyval == GDK_KP_Home
5310            || event->keyval == GDK_End || event->keyval == GDK_KP_End))
5311         {
5312           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
5313
5314           if (event->keyval == (rtl ? GDK_Right : GDK_Left)
5315               || event->keyval == (rtl ? GDK_KP_Right : GDK_KP_Left))
5316             {
5317               GtkTreeViewColumn *col;
5318               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_LEFT);
5319               if (col != (GtkTreeViewColumn *)0x1)
5320                 gtk_tree_view_move_column_after (tree_view, column, col);
5321               else
5322                 gtk_widget_error_bell (widget);
5323             }
5324           else if (event->keyval == (rtl ? GDK_Left : GDK_Right)
5325                    || event->keyval == (rtl ? GDK_KP_Left : GDK_KP_Right))
5326             {
5327               GtkTreeViewColumn *col;
5328               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_RIGHT);
5329               if (col != (GtkTreeViewColumn *)0x1)
5330                 gtk_tree_view_move_column_after (tree_view, column, col);
5331               else
5332                 gtk_widget_error_bell (widget);
5333             }
5334           else if (event->keyval == GDK_Home || event->keyval == GDK_KP_Home)
5335             {
5336               GtkTreeViewColumn *col;
5337               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_HOME);
5338               if (col != (GtkTreeViewColumn *)0x1)
5339                 gtk_tree_view_move_column_after (tree_view, column, col);
5340               else
5341                 gtk_widget_error_bell (widget);
5342             }
5343           else if (event->keyval == GDK_End || event->keyval == GDK_KP_End)
5344             {
5345               GtkTreeViewColumn *col;
5346               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_END);
5347               if (col != (GtkTreeViewColumn *)0x1)
5348                 gtk_tree_view_move_column_after (tree_view, column, col);
5349               else
5350                 gtk_widget_error_bell (widget);
5351             }
5352
5353           return TRUE;
5354         }
5355     }
5356
5357   /* Chain up to the parent class.  It handles the keybindings. */
5358   if (GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->key_press_event (widget, event))
5359     return TRUE;
5360
5361   if (tree_view->priv->search_entry_avoid_unhandled_binding)
5362     {
5363       tree_view->priv->search_entry_avoid_unhandled_binding = FALSE;
5364       return FALSE;
5365     }
5366
5367   /* We pass the event to the search_entry.  If its text changes, then we start
5368    * the typeahead find capabilities. */
5369   if (GTK_WIDGET_HAS_FOCUS (tree_view)
5370       && tree_view->priv->enable_search
5371       && !tree_view->priv->search_custom_entry_set)
5372     {
5373       GdkEvent *new_event;
5374       char *old_text;
5375       const char *new_text;
5376       gboolean retval;
5377       GdkScreen *screen;
5378       gboolean text_modified;
5379       gulong popup_menu_id;
5380
5381       gtk_tree_view_ensure_interactive_directory (tree_view);
5382
5383       /* Make a copy of the current text */
5384       old_text = g_strdup (gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry)));
5385       new_event = gdk_event_copy ((GdkEvent *) event);
5386       g_object_unref (((GdkEventKey *) new_event)->window);
5387       ((GdkEventKey *) new_event)->window = g_object_ref (tree_view->priv->search_window->window);
5388       gtk_widget_realize (tree_view->priv->search_window);
5389
5390       popup_menu_id = g_signal_connect (tree_view->priv->search_entry, 
5391                                         "popup-menu", G_CALLBACK (gtk_true),
5392                                         NULL);
5393
5394       /* Move the entry off screen */
5395       screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
5396       gtk_window_move (GTK_WINDOW (tree_view->priv->search_window),
5397                        gdk_screen_get_width (screen) + 1,
5398                        gdk_screen_get_height (screen) + 1);
5399       gtk_widget_show (tree_view->priv->search_window);
5400
5401       /* Send the event to the window.  If the preedit_changed signal is emitted
5402        * during this event, we will set priv->imcontext_changed  */
5403       tree_view->priv->imcontext_changed = FALSE;
5404       retval = gtk_widget_event (tree_view->priv->search_window, new_event);
5405       gdk_event_free (new_event);
5406       gtk_widget_hide (tree_view->priv->search_window);
5407
5408       g_signal_handler_disconnect (tree_view->priv->search_entry, 
5409                                    popup_menu_id);
5410
5411       /* We check to make sure that the entry tried to handle the text, and that
5412        * the text has changed.
5413        */
5414       new_text = gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry));
5415       text_modified = strcmp (old_text, new_text) != 0;
5416       g_free (old_text);
5417       if (tree_view->priv->imcontext_changed ||    /* we're in a preedit */
5418           (retval && text_modified))               /* ...or the text was modified */
5419         {
5420           if (gtk_tree_view_real_start_interactive_search (tree_view, FALSE))
5421             {
5422               gtk_widget_grab_focus (GTK_WIDGET (tree_view));
5423               return TRUE;
5424             }
5425           else
5426             {
5427               gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
5428               return FALSE;
5429             }
5430         }
5431     }
5432
5433   return FALSE;
5434 }
5435
5436 static gboolean
5437 gtk_tree_view_key_release (GtkWidget   *widget,
5438                            GdkEventKey *event)
5439 {
5440   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
5441
5442   if (tree_view->priv->rubber_band_status)
5443     return TRUE;
5444
5445   return GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->key_release_event (widget, event);
5446 }
5447
5448 /* FIXME Is this function necessary? Can I get an enter_notify event
5449  * w/o either an expose event or a mouse motion event?
5450  */
5451 static gboolean
5452 gtk_tree_view_enter_notify (GtkWidget        *widget,
5453                             GdkEventCrossing *event)
5454 {
5455   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
5456   GtkRBTree *tree;
5457   GtkRBNode *node;
5458   gint new_y;
5459
5460   /* Sanity check it */
5461   if (event->window != tree_view->priv->bin_window)
5462     return FALSE;
5463
5464   if (tree_view->priv->tree == NULL)
5465     return FALSE;
5466
5467   if (event->mode == GDK_CROSSING_GRAB ||
5468       event->mode == GDK_CROSSING_GTK_GRAB ||
5469       event->mode == GDK_CROSSING_GTK_UNGRAB ||
5470       event->mode == GDK_CROSSING_STATE_CHANGED)
5471     return TRUE;
5472
5473   /* find the node internally */
5474   new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
5475   if (new_y < 0)
5476     new_y = 0;
5477   _gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
5478
5479   if ((tree_view->priv->button_pressed_node == NULL) ||
5480       (tree_view->priv->button_pressed_node == node))
5481     prelight_or_select (tree_view, tree, node, event->x, event->y);
5482
5483   return TRUE;
5484 }
5485
5486 static gboolean
5487 gtk_tree_view_leave_notify (GtkWidget        *widget,
5488                             GdkEventCrossing *event)
5489 {
5490   GtkTreeView *tree_view;
5491
5492   if (event->mode == GDK_CROSSING_GRAB)
5493     return TRUE;
5494
5495   tree_view = GTK_TREE_VIEW (widget);
5496
5497   if (tree_view->priv->prelight_node)
5498     _gtk_tree_view_queue_draw_node (tree_view,
5499                                    tree_view->priv->prelight_tree,
5500                                    tree_view->priv->prelight_node,
5501                                    NULL);
5502
5503   prelight_or_select (tree_view,
5504                       NULL, NULL,
5505                       -1000, -1000); /* coords not possibly over an arrow */
5506
5507   return TRUE;
5508 }
5509
5510
5511 static gint
5512 gtk_tree_view_focus_out (GtkWidget     *widget,
5513                          GdkEventFocus *event)
5514 {
5515   GtkTreeView *tree_view;
5516
5517   tree_view = GTK_TREE_VIEW (widget);
5518
5519   gtk_widget_queue_draw (widget);
5520
5521   /* destroy interactive search dialog */
5522   if (tree_view->priv->search_window)
5523     gtk_tree_view_search_dialog_hide (tree_view->priv->search_window, tree_view);
5524
5525   return FALSE;
5526 }
5527
5528
5529 /* Incremental Reflow
5530  */
5531
5532 static void
5533 gtk_tree_view_node_queue_redraw (GtkTreeView *tree_view,
5534                                  GtkRBTree   *tree,
5535                                  GtkRBNode   *node)
5536 {
5537   gint y;
5538
5539   y = _gtk_rbtree_node_find_offset (tree, node)
5540     - tree_view->priv->vadjustment->value
5541     + TREE_VIEW_HEADER_HEIGHT (tree_view);
5542
5543   gtk_widget_queue_draw_area (GTK_WIDGET (tree_view),
5544                               0, y,
5545                               GTK_WIDGET (tree_view)->allocation.width,
5546                               GTK_RBNODE_GET_HEIGHT (node));
5547 }
5548
5549 static gboolean
5550 node_is_visible (GtkTreeView *tree_view,
5551                  GtkRBTree   *tree,
5552                  GtkRBNode   *node)
5553 {
5554   int y;
5555   int height;
5556
5557   y = _gtk_rbtree_node_find_offset (tree, node);
5558   height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
5559
5560   if (y >= tree_view->priv->vadjustment->value &&
5561       y + height <= (tree_view->priv->vadjustment->value
5562                      + tree_view->priv->vadjustment->page_size))
5563     return TRUE;
5564
5565   return FALSE;
5566 }
5567
5568 /* Returns TRUE if it updated the size
5569  */
5570 static gboolean
5571 validate_row (GtkTreeView *tree_view,
5572               GtkRBTree   *tree,
5573               GtkRBNode   *node,
5574               GtkTreeIter *iter,
5575               GtkTreePath *path)
5576 {
5577   GtkTreeViewColumn *column;
5578   GList *list, *first_column, *last_column;
5579   gint height = 0;
5580   gint horizontal_separator;
5581   gint vertical_separator;
5582   gint focus_line_width;
5583   gint depth = gtk_tree_path_get_depth (path);
5584   gboolean retval = FALSE;
5585   gboolean is_separator = FALSE;
5586   gboolean draw_vgrid_lines, draw_hgrid_lines;
5587   gint focus_pad;
5588   gint grid_line_width;
5589   gboolean wide_separators;
5590   gint separator_height;
5591
5592   /* double check the row needs validating */
5593   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) &&
5594       ! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
5595     return FALSE;
5596
5597   is_separator = row_is_separator (tree_view, iter, NULL);
5598
5599   gtk_widget_style_get (GTK_WIDGET (tree_view),
5600                         "focus-padding", &focus_pad,
5601                         "focus-line-width", &focus_line_width,
5602                         "horizontal-separator", &horizontal_separator,
5603                         "vertical-separator", &vertical_separator,
5604                         "grid-line-width", &grid_line_width,
5605                         "wide-separators",  &wide_separators,
5606                         "separator-height", &separator_height,
5607                         NULL);
5608   
5609   draw_vgrid_lines =
5610     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_VERTICAL
5611     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
5612   draw_hgrid_lines =
5613     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_HORIZONTAL
5614     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
5615
5616   for (last_column = g_list_last (tree_view->priv->columns);
5617        last_column && !(GTK_TREE_VIEW_COLUMN (last_column->data)->visible);
5618        last_column = last_column->prev)
5619     ;
5620
5621   for (first_column = g_list_first (tree_view->priv->columns);
5622        first_column && !(GTK_TREE_VIEW_COLUMN (first_column->data)->visible);
5623        first_column = first_column->next)
5624     ;
5625
5626   for (list = tree_view->priv->columns; list; list = list->next)
5627     {
5628       gint tmp_width;
5629       gint tmp_height;
5630
5631       column = list->data;
5632
5633       if (! column->visible)
5634         continue;
5635
5636       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID) && !column->dirty)
5637         continue;
5638
5639       gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, iter,
5640                                                GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
5641                                                node->children?TRUE:FALSE);
5642       gtk_tree_view_column_cell_get_size (column,
5643                                           NULL, NULL, NULL,
5644                                           &tmp_width, &tmp_height);
5645
5646       if (!is_separator)
5647         {
5648           tmp_height += vertical_separator;
5649           height = MAX (height, tmp_height);
5650           height = MAX (height, tree_view->priv->expander_size);
5651         }
5652       else
5653         {
5654           if (wide_separators)
5655             height = separator_height + 2 * focus_pad;
5656           else
5657             height = 2 + 2 * focus_pad;
5658         }
5659
5660       if (gtk_tree_view_is_expander_column (tree_view, column))
5661         {
5662           tmp_width = tmp_width + horizontal_separator + (depth - 1) * tree_view->priv->level_indentation;
5663
5664           if (TREE_VIEW_DRAW_EXPANDERS (tree_view))
5665             tmp_width += depth * tree_view->priv->expander_size;
5666         }
5667       else
5668         tmp_width = tmp_width + horizontal_separator;
5669
5670       if (draw_vgrid_lines)
5671         {
5672           if (list->data == first_column || list->data == last_column)
5673             tmp_width += grid_line_width / 2.0;
5674           else
5675             tmp_width += grid_line_width;
5676         }
5677
5678       if (tmp_width > column->requested_width)
5679         {
5680           retval = TRUE;
5681           column->requested_width = tmp_width;
5682         }
5683     }
5684
5685   if (draw_hgrid_lines)
5686     height += grid_line_width;
5687
5688   if (height != GTK_RBNODE_GET_HEIGHT (node))
5689     {
5690       retval = TRUE;
5691       _gtk_rbtree_node_set_height (tree, node, height);
5692     }
5693   _gtk_rbtree_node_mark_valid (tree, node);
5694   tree_view->priv->post_validation_flag = TRUE;
5695
5696   return retval;
5697 }
5698
5699
5700 static void
5701 validate_visible_area (GtkTreeView *tree_view)
5702 {
5703   GtkTreePath *path = NULL;
5704   GtkTreePath *above_path = NULL;
5705   GtkTreeIter iter;
5706   GtkRBTree *tree = NULL;
5707   GtkRBNode *node = NULL;
5708   gboolean need_redraw = FALSE;
5709   gboolean size_changed = FALSE;
5710   gint total_height;
5711   gint area_above = 0;
5712   gint area_below = 0;
5713
5714   if (tree_view->priv->tree == NULL)
5715     return;
5716
5717   if (! GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID) &&
5718       tree_view->priv->scroll_to_path == NULL)
5719     return;
5720
5721   total_height = GTK_WIDGET (tree_view)->allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view);
5722
5723   if (total_height == 0)
5724     return;
5725
5726   /* First, we check to see if we need to scroll anywhere
5727    */
5728   if (tree_view->priv->scroll_to_path)
5729     {
5730       path = gtk_tree_row_reference_get_path (tree_view->priv->scroll_to_path);
5731       if (path && !_gtk_tree_view_find_node (tree_view, path, &tree, &node))
5732         {
5733           /* we are going to scroll, and will update dy */
5734           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
5735           if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
5736               GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
5737             {
5738               _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
5739               if (validate_row (tree_view, tree, node, &iter, path))
5740                 size_changed = TRUE;
5741             }
5742
5743           if (tree_view->priv->scroll_to_use_align)
5744             {
5745               gint height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
5746               area_above = (total_height - height) *
5747                 tree_view->priv->scroll_to_row_align;
5748               area_below = total_height - area_above - height;
5749               area_above = MAX (area_above, 0);
5750               area_below = MAX (area_below, 0);
5751             }
5752           else
5753             {
5754               /* two cases:
5755                * 1) row not visible
5756                * 2) row visible
5757                */
5758               gint dy;
5759               gint height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
5760
5761               dy = _gtk_rbtree_node_find_offset (tree, node);
5762
5763               if (dy >= tree_view->priv->vadjustment->value &&
5764                   dy + height <= (tree_view->priv->vadjustment->value
5765                                   + tree_view->priv->vadjustment->page_size))
5766                 {
5767                   /* row visible: keep the row at the same position */
5768                   area_above = dy - tree_view->priv->vadjustment->value;
5769                   area_below = (tree_view->priv->vadjustment->value +
5770                                 tree_view->priv->vadjustment->page_size)
5771                                - dy - height;
5772                 }
5773               else
5774                 {
5775                   /* row not visible */
5776                   if (dy >= 0
5777                       && dy + height <= tree_view->priv->vadjustment->page_size)
5778                     {
5779                       /* row at the beginning -- fixed */
5780                       area_above = dy;
5781                       area_below = tree_view->priv->vadjustment->page_size
5782                                    - area_above - height;
5783                     }
5784                   else if (dy >= (tree_view->priv->vadjustment->upper -
5785                                   tree_view->priv->vadjustment->page_size))
5786                     {
5787                       /* row at the end -- fixed */
5788                       area_above = dy - (tree_view->priv->vadjustment->upper -
5789                                    tree_view->priv->vadjustment->page_size);
5790                       area_below = tree_view->priv->vadjustment->page_size -
5791                                    area_above - height;
5792
5793                       if (area_below < 0)
5794                         {
5795                           area_above = tree_view->priv->vadjustment->page_size - height;
5796                           area_below = 0;
5797                         }
5798                     }
5799                   else
5800                     {
5801                       /* row somewhere in the middle, bring it to the top
5802                        * of the view
5803                        */
5804                       area_above = 0;
5805                       area_below = total_height - height;
5806                     }
5807                 }
5808             }
5809         }
5810       else
5811         /* the scroll to isn't valid; ignore it.
5812          */
5813         {
5814           if (tree_view->priv->scroll_to_path && !path)
5815             {
5816               gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
5817               tree_view->priv->scroll_to_path = NULL;
5818             }
5819           if (path)
5820             gtk_tree_path_free (path);
5821           path = NULL;
5822         }      
5823     }
5824
5825   /* We didn't have a scroll_to set, so we just handle things normally
5826    */
5827   if (path == NULL)
5828     {
5829       gint offset;
5830
5831       offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
5832                                         TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, 0),
5833                                         &tree, &node);
5834       if (node == NULL)
5835         {
5836           /* In this case, nothing has been validated */
5837           path = gtk_tree_path_new_first ();
5838           _gtk_tree_view_find_node (tree_view, path, &tree, &node);
5839         }
5840       else
5841         {
5842           path = _gtk_tree_view_find_path (tree_view, tree, node);
5843           total_height += offset;
5844         }
5845
5846       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
5847
5848       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
5849           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
5850         {
5851           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
5852           if (validate_row (tree_view, tree, node, &iter, path))
5853             size_changed = TRUE;
5854         }
5855       area_above = 0;
5856       area_below = total_height - ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
5857     }
5858
5859   above_path = gtk_tree_path_copy (path);
5860
5861   /* if we do not validate any row above the new top_row, we will make sure
5862    * that the row immediately above top_row has been validated. (if we do not
5863    * do this, _gtk_rbtree_find_offset will find the row above top_row, because
5864    * when invalidated that row's height will be zero. and this will mess up
5865    * scrolling).
5866    */
5867   if (area_above == 0)
5868     {
5869       GtkRBTree *tmptree;
5870       GtkRBNode *tmpnode;
5871
5872       _gtk_tree_view_find_node (tree_view, above_path, &tmptree, &tmpnode);
5873       _gtk_rbtree_prev_full (tmptree, tmpnode, &tmptree, &tmpnode);
5874
5875       if (tmpnode)
5876         {
5877           GtkTreePath *tmppath;
5878           GtkTreeIter tmpiter;
5879
5880           tmppath = _gtk_tree_view_find_path (tree_view, tmptree, tmpnode);
5881           gtk_tree_model_get_iter (tree_view->priv->model, &tmpiter, tmppath);
5882
5883           if (GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_INVALID) ||
5884               GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_COLUMN_INVALID))
5885             {
5886               _gtk_tree_view_queue_draw_node (tree_view, tmptree, tmpnode, NULL);
5887               if (validate_row (tree_view, tmptree, tmpnode, &tmpiter, tmppath))
5888                 size_changed = TRUE;
5889             }
5890
5891           gtk_tree_path_free (tmppath);
5892         }
5893     }
5894
5895   /* Now, we walk forwards and backwards, measuring rows. Unfortunately,
5896    * backwards is much slower then forward, as there is no iter_prev function.
5897    * We go forwards first in case we run out of tree.  Then we go backwards to
5898    * fill out the top.
5899    */
5900   while (node && area_below > 0)
5901     {
5902       if (node->children)
5903         {
5904           GtkTreeIter parent = iter;
5905           gboolean has_child;
5906
5907           tree = node->children;
5908           node = tree->root;
5909
5910           g_assert (node != tree->nil);
5911
5912           while (node->left != tree->nil)
5913             node = node->left;
5914           has_child = gtk_tree_model_iter_children (tree_view->priv->model,
5915                                                     &iter,
5916                                                     &parent);
5917           TREE_VIEW_INTERNAL_ASSERT_VOID (has_child);
5918           gtk_tree_path_down (path);
5919         }
5920       else
5921         {
5922           gboolean done = FALSE;
5923           do
5924             {
5925               node = _gtk_rbtree_next (tree, node);
5926               if (node != NULL)
5927                 {
5928                   gboolean has_next = gtk_tree_model_iter_next (tree_view->priv->model, &iter);
5929                   done = TRUE;
5930                   gtk_tree_path_next (path);
5931
5932                   /* Sanity Check! */
5933                   TREE_VIEW_INTERNAL_ASSERT_VOID (has_next);
5934                 }
5935               else
5936                 {
5937                   GtkTreeIter parent_iter = iter;
5938                   gboolean has_parent;
5939
5940                   node = tree->parent_node;
5941                   tree = tree->parent_tree;
5942                   if (tree == NULL)
5943                     break;
5944                   has_parent = gtk_tree_model_iter_parent (tree_view->priv->model,
5945                                                            &iter,
5946                                                            &parent_iter);
5947                   gtk_tree_path_up (path);
5948
5949                   /* Sanity check */
5950                   TREE_VIEW_INTERNAL_ASSERT_VOID (has_parent);
5951                 }
5952             }
5953           while (!done);
5954         }
5955
5956       if (!node)
5957         break;
5958
5959       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
5960           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
5961         {
5962           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
5963           if (validate_row (tree_view, tree, node, &iter, path))
5964               size_changed = TRUE;
5965         }
5966
5967       area_below -= ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
5968     }
5969   gtk_tree_path_free (path);
5970
5971   /* If we ran out of tree, and have extra area_below left, we need to add it
5972    * to area_above */
5973   if (area_below > 0)
5974     area_above += area_below;
5975
5976   _gtk_tree_view_find_node (tree_view, above_path, &tree, &node);
5977
5978   /* We walk backwards */
5979   while (area_above > 0)
5980     {
5981       _gtk_rbtree_prev_full (tree, node, &tree, &node);
5982
5983       /* Always find the new path in the tree.  We cannot just assume
5984        * a gtk_tree_path_prev() is enough here, as there might be children
5985        * in between this node and the previous sibling node.  If this
5986        * appears to be a performance hotspot in profiles, we can look into
5987        * intrigate logic for keeping path, node and iter in sync like
5988        * we do for forward walks.  (Which will be hard because of the lacking
5989        * iter_prev).
5990        */
5991
5992       if (node == NULL)
5993         break;
5994
5995       gtk_tree_path_free (above_path);
5996       above_path = _gtk_tree_view_find_path (tree_view, tree, node);
5997
5998       gtk_tree_model_get_iter (tree_view->priv->model, &iter, above_path);
5999
6000       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6001           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6002         {
6003           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
6004           if (validate_row (tree_view, tree, node, &iter, above_path))
6005             size_changed = TRUE;
6006         }
6007       area_above -= ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
6008     }
6009
6010   /* if we scrolled to a path, we need to set the dy here,
6011    * and sync the top row accordingly
6012    */
6013   if (tree_view->priv->scroll_to_path)
6014     {
6015       gtk_tree_view_set_top_row (tree_view, above_path, -area_above);
6016       gtk_tree_view_top_row_to_dy (tree_view);
6017
6018       need_redraw = TRUE;
6019     }
6020   else if (tree_view->priv->height <= tree_view->priv->vadjustment->page_size)
6021     {
6022       /* when we are not scrolling, we should never set dy to something
6023        * else than zero. we update top_row to be in sync with dy = 0.
6024        */
6025       gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
6026       gtk_tree_view_dy_to_top_row (tree_view);
6027     }
6028   else if (tree_view->priv->vadjustment->value + tree_view->priv->vadjustment->page_size > tree_view->priv->height)
6029     {
6030       gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), tree_view->priv->height - tree_view->priv->vadjustment->page_size);
6031       gtk_tree_view_dy_to_top_row (tree_view);
6032     }
6033   else
6034     gtk_tree_view_top_row_to_dy (tree_view);
6035
6036   /* update width/height and queue a resize */
6037   if (size_changed)
6038     {
6039       GtkRequisition requisition;
6040
6041       /* We temporarily guess a size, under the assumption that it will be the
6042        * same when we get our next size_allocate.  If we don't do this, we'll be
6043        * in an inconsistent state if we call top_row_to_dy. */
6044
6045       gtk_widget_size_request (GTK_WIDGET (tree_view), &requisition);
6046       tree_view->priv->hadjustment->upper = MAX (tree_view->priv->hadjustment->upper, (gfloat)requisition.width);
6047       tree_view->priv->vadjustment->upper = MAX (tree_view->priv->vadjustment->upper, (gfloat)requisition.height);
6048       gtk_adjustment_changed (tree_view->priv->hadjustment);
6049       gtk_adjustment_changed (tree_view->priv->vadjustment);
6050       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6051     }
6052
6053   if (tree_view->priv->scroll_to_path)
6054     {
6055       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
6056       tree_view->priv->scroll_to_path = NULL;
6057     }
6058
6059   if (above_path)
6060     gtk_tree_path_free (above_path);
6061
6062   if (tree_view->priv->scroll_to_column)
6063     {
6064       tree_view->priv->scroll_to_column = NULL;
6065     }
6066   if (need_redraw)
6067     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
6068 }
6069
6070 static void
6071 initialize_fixed_height_mode (GtkTreeView *tree_view)
6072 {
6073   if (!tree_view->priv->tree)
6074     return;
6075
6076   if (tree_view->priv->fixed_height < 0)
6077     {
6078       GtkTreeIter iter;
6079       GtkTreePath *path;
6080
6081       GtkRBTree *tree = NULL;
6082       GtkRBNode *node = NULL;
6083
6084       tree = tree_view->priv->tree;
6085       node = tree->root;
6086
6087       path = _gtk_tree_view_find_path (tree_view, tree, node);
6088       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6089
6090       validate_row (tree_view, tree, node, &iter, path);
6091
6092       gtk_tree_path_free (path);
6093
6094       tree_view->priv->fixed_height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
6095     }
6096
6097    _gtk_rbtree_set_fixed_height (tree_view->priv->tree,
6098                                  tree_view->priv->fixed_height, TRUE);
6099 }
6100
6101 /* Our strategy for finding nodes to validate is a little convoluted.  We find
6102  * the left-most uninvalidated node.  We then try walking right, validating
6103  * nodes.  Once we find a valid node, we repeat the previous process of finding
6104  * the first invalid node.
6105  */
6106
6107 static gboolean
6108 do_validate_rows (GtkTreeView *tree_view, gboolean queue_resize)
6109 {
6110   GtkRBTree *tree = NULL;
6111   GtkRBNode *node = NULL;
6112   gboolean validated_area = FALSE;
6113   gint retval = TRUE;
6114   GtkTreePath *path = NULL;
6115   GtkTreeIter iter;
6116   GTimer *timer;
6117   gint i = 0;
6118
6119   gint prev_height = -1;
6120   gboolean fixed_height = TRUE;
6121
6122   g_assert (tree_view);
6123
6124   if (tree_view->priv->tree == NULL)
6125       return FALSE;
6126
6127   if (tree_view->priv->fixed_height_mode)
6128     {
6129       if (tree_view->priv->fixed_height < 0)
6130         initialize_fixed_height_mode (tree_view);
6131
6132       return FALSE;
6133     }
6134
6135   timer = g_timer_new ();
6136   g_timer_start (timer);
6137
6138   do
6139     {
6140       if (! GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID))
6141         {
6142           retval = FALSE;
6143           goto done;
6144         }
6145
6146       if (path != NULL)
6147         {
6148           node = _gtk_rbtree_next (tree, node);
6149           if (node != NULL)
6150             {
6151               TREE_VIEW_INTERNAL_ASSERT (gtk_tree_model_iter_next (tree_view->priv->model, &iter), FALSE);
6152               gtk_tree_path_next (path);
6153             }
6154           else
6155             {
6156               gtk_tree_path_free (path);
6157               path = NULL;
6158             }
6159         }
6160
6161       if (path == NULL)
6162         {
6163           tree = tree_view->priv->tree;
6164           node = tree_view->priv->tree->root;
6165
6166           g_assert (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_DESCENDANTS_INVALID));
6167
6168           do
6169             {
6170               if (node->left != tree->nil &&
6171                   GTK_RBNODE_FLAG_SET (node->left, GTK_RBNODE_DESCENDANTS_INVALID))
6172                 {
6173                   node = node->left;
6174                 }
6175               else if (node->right != tree->nil &&
6176                        GTK_RBNODE_FLAG_SET (node->right, GTK_RBNODE_DESCENDANTS_INVALID))
6177                 {
6178                   node = node->right;
6179                 }
6180               else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6181                        GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6182                 {
6183                   break;
6184                 }
6185               else if (node->children != NULL)
6186                 {
6187                   tree = node->children;
6188                   node = tree->root;
6189                 }
6190               else
6191                 /* RBTree corruption!  All bad */
6192                 g_assert_not_reached ();
6193             }
6194           while (TRUE);
6195           path = _gtk_tree_view_find_path (tree_view, tree, node);
6196           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6197         }
6198
6199       validated_area = validate_row (tree_view, tree, node, &iter, path) ||
6200                        validated_area;
6201
6202       if (!tree_view->priv->fixed_height_check)
6203         {
6204           gint height;
6205
6206           height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
6207           if (prev_height < 0)
6208             prev_height = height;
6209           else if (prev_height != height)
6210             fixed_height = FALSE;
6211         }
6212
6213       i++;
6214     }
6215   while (g_timer_elapsed (timer, NULL) < GTK_TREE_VIEW_TIME_MS_PER_IDLE / 1000.);
6216
6217   if (!tree_view->priv->fixed_height_check)
6218    {
6219      if (fixed_height)
6220        _gtk_rbtree_set_fixed_height (tree_view->priv->tree, prev_height, FALSE);
6221
6222      tree_view->priv->fixed_height_check = 1;
6223    }
6224   
6225  done:
6226   if (validated_area)
6227     {
6228       GtkRequisition requisition;
6229       /* We temporarily guess a size, under the assumption that it will be the
6230        * same when we get our next size_allocate.  If we don't do this, we'll be
6231        * in an inconsistent state when we call top_row_to_dy. */
6232
6233       gtk_widget_size_request (GTK_WIDGET (tree_view), &requisition);
6234       tree_view->priv->hadjustment->upper = MAX (tree_view->priv->hadjustment->upper, (gfloat)requisition.width);
6235       tree_view->priv->vadjustment->upper = MAX (tree_view->priv->vadjustment->upper, (gfloat)requisition.height);
6236       gtk_adjustment_changed (tree_view->priv->hadjustment);
6237       gtk_adjustment_changed (tree_view->priv->vadjustment);
6238
6239       if (queue_resize)
6240         gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6241     }
6242
6243   if (path) gtk_tree_path_free (path);
6244   g_timer_destroy (timer);
6245
6246   return retval;
6247 }
6248
6249 static gboolean
6250 validate_rows (GtkTreeView *tree_view)
6251 {
6252   gboolean retval;
6253   
6254   retval = do_validate_rows (tree_view, TRUE);
6255   
6256   if (! retval && tree_view->priv->validate_rows_timer)
6257     {
6258       g_source_remove (tree_view->priv->validate_rows_timer);
6259       tree_view->priv->validate_rows_timer = 0;
6260     }
6261
6262   return retval;
6263 }
6264
6265 static gboolean
6266 validate_rows_handler (GtkTreeView *tree_view)
6267 {
6268   gboolean retval;
6269
6270   retval = do_validate_rows (tree_view, TRUE);
6271   if (! retval && tree_view->priv->validate_rows_timer)
6272     {
6273       g_source_remove (tree_view->priv->validate_rows_timer);
6274       tree_view->priv->validate_rows_timer = 0;
6275     }
6276
6277   return retval;
6278 }
6279
6280 static gboolean
6281 do_presize_handler (GtkTreeView *tree_view)
6282 {
6283   if (tree_view->priv->mark_rows_col_dirty)
6284     {
6285       if (tree_view->priv->tree)
6286         _gtk_rbtree_column_invalid (tree_view->priv->tree);
6287       tree_view->priv->mark_rows_col_dirty = FALSE;
6288     }
6289   validate_visible_area (tree_view);
6290   tree_view->priv->presize_handler_timer = 0;
6291
6292   if (tree_view->priv->fixed_height_mode)
6293     {
6294       GtkRequisition requisition;
6295
6296       gtk_widget_size_request (GTK_WIDGET (tree_view), &requisition);
6297
6298       tree_view->priv->hadjustment->upper = MAX (tree_view->priv->hadjustment->upper, (gfloat)requisition.width);
6299       tree_view->priv->vadjustment->upper = MAX (tree_view->priv->vadjustment->upper, (gfloat)requisition.height);
6300       gtk_adjustment_changed (tree_view->priv->hadjustment);
6301       gtk_adjustment_changed (tree_view->priv->vadjustment);
6302       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6303     }
6304                    
6305   return FALSE;
6306 }
6307
6308 static gboolean
6309 presize_handler_callback (gpointer data)
6310 {
6311   do_presize_handler (GTK_TREE_VIEW (data));
6312                    
6313   return FALSE;
6314 }
6315
6316 static void
6317 install_presize_handler (GtkTreeView *tree_view)
6318 {
6319   if (! GTK_WIDGET_REALIZED (tree_view))
6320     return;
6321
6322   if (! tree_view->priv->presize_handler_timer)
6323     {
6324       tree_view->priv->presize_handler_timer =
6325         gdk_threads_add_idle_full (GTK_PRIORITY_RESIZE - 2, presize_handler_callback, tree_view, NULL);
6326     }
6327   if (! tree_view->priv->validate_rows_timer)
6328     {
6329       tree_view->priv->validate_rows_timer =
6330         gdk_threads_add_idle_full (GTK_TREE_VIEW_PRIORITY_VALIDATE, (GSourceFunc) validate_rows_handler, tree_view, NULL);
6331     }
6332 }
6333
6334 static gboolean
6335 scroll_sync_handler (GtkTreeView *tree_view)
6336 {
6337   if (tree_view->priv->height <= tree_view->priv->vadjustment->page_size)
6338     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
6339   else if (gtk_tree_row_reference_valid (tree_view->priv->top_row))
6340     gtk_tree_view_top_row_to_dy (tree_view);
6341   else
6342     gtk_tree_view_dy_to_top_row (tree_view);
6343
6344   tree_view->priv->scroll_sync_timer = 0;
6345
6346   return FALSE;
6347 }
6348
6349 static void
6350 install_scroll_sync_handler (GtkTreeView *tree_view)
6351 {
6352   if (! GTK_WIDGET_REALIZED (tree_view))
6353     return;
6354
6355   if (!tree_view->priv->scroll_sync_timer)
6356     {
6357       tree_view->priv->scroll_sync_timer =
6358         gdk_threads_add_idle_full (GTK_TREE_VIEW_PRIORITY_SCROLL_SYNC, (GSourceFunc) scroll_sync_handler, tree_view, NULL);
6359     }
6360 }
6361
6362 static void
6363 gtk_tree_view_set_top_row (GtkTreeView *tree_view,
6364                            GtkTreePath *path,
6365                            gint         offset)
6366 {
6367   gtk_tree_row_reference_free (tree_view->priv->top_row);
6368
6369   if (!path)
6370     {
6371       tree_view->priv->top_row = NULL;
6372       tree_view->priv->top_row_dy = 0;
6373     }
6374   else
6375     {
6376       tree_view->priv->top_row = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
6377       tree_view->priv->top_row_dy = offset;
6378     }
6379 }
6380
6381 /* Always call this iff dy is in the visible range.  If the tree is empty, then
6382  * it's set to be NULL, and top_row_dy is 0;
6383  */
6384 static void
6385 gtk_tree_view_dy_to_top_row (GtkTreeView *tree_view)
6386 {
6387   gint offset;
6388   GtkTreePath *path;
6389   GtkRBTree *tree;
6390   GtkRBNode *node;
6391
6392   if (tree_view->priv->tree == NULL)
6393     {
6394       gtk_tree_view_set_top_row (tree_view, NULL, 0);
6395     }
6396   else
6397     {
6398       offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
6399                                         tree_view->priv->dy,
6400                                         &tree, &node);
6401
6402       if (tree == NULL)
6403         {
6404           tree_view->priv->top_row = NULL;
6405           tree_view->priv->top_row_dy = 0;
6406         }
6407       else
6408         {
6409           path = _gtk_tree_view_find_path (tree_view, tree, node);
6410           gtk_tree_view_set_top_row (tree_view, path, offset);
6411           gtk_tree_path_free (path);
6412         }
6413     }
6414 }
6415
6416 static void
6417 gtk_tree_view_top_row_to_dy (GtkTreeView *tree_view)
6418 {
6419   GtkTreePath *path;
6420   GtkRBTree *tree;
6421   GtkRBNode *node;
6422   int new_dy;
6423
6424   /* Avoid recursive calls */
6425   if (tree_view->priv->in_top_row_to_dy)
6426     return;
6427
6428   if (tree_view->priv->top_row)
6429     path = gtk_tree_row_reference_get_path (tree_view->priv->top_row);
6430   else
6431     path = NULL;
6432
6433   if (!path)
6434     tree = NULL;
6435   else
6436     _gtk_tree_view_find_node (tree_view, path, &tree, &node);
6437
6438   if (path)
6439     gtk_tree_path_free (path);
6440
6441   if (tree == NULL)
6442     {
6443       /* keep dy and set new toprow */
6444       gtk_tree_row_reference_free (tree_view->priv->top_row);
6445       tree_view->priv->top_row = NULL;
6446       tree_view->priv->top_row_dy = 0;
6447       /* DO NOT install the idle handler */
6448       gtk_tree_view_dy_to_top_row (tree_view);
6449       return;
6450     }
6451
6452   if (ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node))
6453       < tree_view->priv->top_row_dy)
6454     {
6455       /* new top row -- do NOT install the idle handler */
6456       gtk_tree_view_dy_to_top_row (tree_view);
6457       return;
6458     }
6459
6460   new_dy = _gtk_rbtree_node_find_offset (tree, node);
6461   new_dy += tree_view->priv->top_row_dy;
6462
6463   if (new_dy + tree_view->priv->vadjustment->page_size > tree_view->priv->height)
6464     new_dy = tree_view->priv->height - tree_view->priv->vadjustment->page_size;
6465
6466   new_dy = MAX (0, new_dy);
6467
6468   tree_view->priv->in_top_row_to_dy = TRUE;
6469   gtk_adjustment_set_value (tree_view->priv->vadjustment, (gdouble)new_dy);
6470   tree_view->priv->in_top_row_to_dy = FALSE;
6471 }
6472
6473
6474 void
6475 _gtk_tree_view_install_mark_rows_col_dirty (GtkTreeView *tree_view)
6476 {
6477   tree_view->priv->mark_rows_col_dirty = TRUE;
6478
6479   install_presize_handler (tree_view);
6480 }
6481
6482 /*
6483  * This function works synchronously (due to the while (validate_rows...)
6484  * loop).
6485  *
6486  * There was a check for column_type != GTK_TREE_VIEW_COLUMN_AUTOSIZE
6487  * here. You now need to check that yourself.
6488  */
6489 void
6490 _gtk_tree_view_column_autosize (GtkTreeView *tree_view,
6491                                 GtkTreeViewColumn *column)
6492 {
6493   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
6494   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (column));
6495
6496   _gtk_tree_view_column_cell_set_dirty (column, FALSE);
6497
6498   do_presize_handler (tree_view);
6499   while (validate_rows (tree_view));
6500
6501   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6502 }
6503
6504 /* Drag-and-drop */
6505
6506 static void
6507 set_source_row (GdkDragContext *context,
6508                 GtkTreeModel   *model,
6509                 GtkTreePath    *source_row)
6510 {
6511   g_object_set_data_full (G_OBJECT (context),
6512                           I_("gtk-tree-view-source-row"),
6513                           source_row ? gtk_tree_row_reference_new (model, source_row) : NULL,
6514                           (GDestroyNotify) (source_row ? gtk_tree_row_reference_free : NULL));
6515 }
6516
6517 static GtkTreePath*
6518 get_source_row (GdkDragContext *context)
6519 {
6520   GtkTreeRowReference *ref =
6521     g_object_get_data (G_OBJECT (context), "gtk-tree-view-source-row");
6522
6523   if (ref)
6524     return gtk_tree_row_reference_get_path (ref);
6525   else
6526     return NULL;
6527 }
6528
6529 typedef struct
6530 {
6531   GtkTreeRowReference *dest_row;
6532   guint                path_down_mode   : 1;
6533   guint                empty_view_drop  : 1;
6534   guint                drop_append_mode : 1;
6535 }
6536 DestRow;
6537
6538 static void
6539 dest_row_free (gpointer data)
6540 {
6541   DestRow *dr = (DestRow *)data;
6542
6543   gtk_tree_row_reference_free (dr->dest_row);
6544   g_slice_free (DestRow, dr);
6545 }
6546
6547 static void
6548 set_dest_row (GdkDragContext *context,
6549               GtkTreeModel   *model,
6550               GtkTreePath    *dest_row,
6551               gboolean        path_down_mode,
6552               gboolean        empty_view_drop,
6553               gboolean        drop_append_mode)
6554 {
6555   DestRow *dr;
6556
6557   if (!dest_row)
6558     {
6559       g_object_set_data_full (G_OBJECT (context), I_("gtk-tree-view-dest-row"),
6560                               NULL, NULL);
6561       return;
6562     }
6563
6564   dr = g_slice_new (DestRow);
6565
6566   dr->dest_row = gtk_tree_row_reference_new (model, dest_row);
6567   dr->path_down_mode = path_down_mode != FALSE;
6568   dr->empty_view_drop = empty_view_drop != FALSE;
6569   dr->drop_append_mode = drop_append_mode != FALSE;
6570
6571   g_object_set_data_full (G_OBJECT (context), I_("gtk-tree-view-dest-row"),
6572                           dr, (GDestroyNotify) dest_row_free);
6573 }
6574
6575 static GtkTreePath*
6576 get_dest_row (GdkDragContext *context,
6577               gboolean       *path_down_mode)
6578 {
6579   DestRow *dr =
6580     g_object_get_data (G_OBJECT (context), "gtk-tree-view-dest-row");
6581
6582   if (dr)
6583     {
6584       GtkTreePath *path = NULL;
6585
6586       if (path_down_mode)
6587         *path_down_mode = dr->path_down_mode;
6588
6589       if (dr->dest_row)
6590         path = gtk_tree_row_reference_get_path (dr->dest_row);
6591       else if (dr->empty_view_drop)
6592         path = gtk_tree_path_new_from_indices (0, -1);
6593       else
6594         path = NULL;
6595
6596       if (path && dr->drop_append_mode)
6597         gtk_tree_path_next (path);
6598
6599       return path;
6600     }
6601   else
6602     return NULL;
6603 }
6604
6605 /* Get/set whether drag_motion requested the drag data and
6606  * drag_data_received should thus not actually insert the data,
6607  * since the data doesn't result from a drop.
6608  */
6609 static void
6610 set_status_pending (GdkDragContext *context,
6611                     GdkDragAction   suggested_action)
6612 {
6613   g_object_set_data (G_OBJECT (context),
6614                      I_("gtk-tree-view-status-pending"),
6615                      GINT_TO_POINTER (suggested_action));
6616 }
6617
6618 static GdkDragAction
6619 get_status_pending (GdkDragContext *context)
6620 {
6621   return GPOINTER_TO_INT (g_object_get_data (G_OBJECT (context),
6622                                              "gtk-tree-view-status-pending"));
6623 }
6624
6625 static TreeViewDragInfo*
6626 get_info (GtkTreeView *tree_view)
6627 {
6628   return g_object_get_data (G_OBJECT (tree_view), "gtk-tree-view-drag-info");
6629 }
6630
6631 static void
6632 destroy_info (TreeViewDragInfo *di)
6633 {
6634   g_slice_free (TreeViewDragInfo, di);
6635 }
6636
6637 static TreeViewDragInfo*
6638 ensure_info (GtkTreeView *tree_view)
6639 {
6640   TreeViewDragInfo *di;
6641
6642   di = get_info (tree_view);
6643
6644   if (di == NULL)
6645     {
6646       di = g_slice_new0 (TreeViewDragInfo);
6647
6648       g_object_set_data_full (G_OBJECT (tree_view),
6649                               I_("gtk-tree-view-drag-info"),
6650                               di,
6651                               (GDestroyNotify) destroy_info);
6652     }
6653
6654   return di;
6655 }
6656
6657 static void
6658 remove_info (GtkTreeView *tree_view)
6659 {
6660   g_object_set_data (G_OBJECT (tree_view), I_("gtk-tree-view-drag-info"), NULL);
6661 }
6662
6663 #if 0
6664 static gint
6665 drag_scan_timeout (gpointer data)
6666 {
6667   GtkTreeView *tree_view;
6668   gint x, y;
6669   GdkModifierType state;
6670   GtkTreePath *path = NULL;
6671   GtkTreeViewColumn *column = NULL;
6672   GdkRectangle visible_rect;
6673
6674   GDK_THREADS_ENTER ();
6675
6676   tree_view = GTK_TREE_VIEW (data);
6677
6678   gdk_window_get_pointer (tree_view->priv->bin_window,
6679                           &x, &y, &state);
6680
6681   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
6682
6683   /* See if we are near the edge. */
6684   if ((x - visible_rect.x) < SCROLL_EDGE_SIZE ||
6685       (visible_rect.x + visible_rect.width - x) < SCROLL_EDGE_SIZE ||
6686       (y - visible_rect.y) < SCROLL_EDGE_SIZE ||
6687       (visible_rect.y + visible_rect.height - y) < SCROLL_EDGE_SIZE)
6688     {
6689       gtk_tree_view_get_path_at_pos (tree_view,
6690                                      tree_view->priv->bin_window,
6691                                      x, y,
6692                                      &path,
6693                                      &column,
6694                                      NULL,
6695                                      NULL);
6696
6697       if (path != NULL)
6698         {
6699           gtk_tree_view_scroll_to_cell (tree_view,
6700                                         path,
6701                                         column,
6702                                         TRUE,
6703                                         0.5, 0.5);
6704
6705           gtk_tree_path_free (path);
6706         }
6707     }
6708
6709   GDK_THREADS_LEAVE ();
6710
6711   return TRUE;
6712 }
6713 #endif /* 0 */
6714
6715 static void
6716 add_scroll_timeout (GtkTreeView *tree_view)
6717 {
6718   if (tree_view->priv->scroll_timeout == 0)
6719     {
6720       tree_view->priv->scroll_timeout =
6721         gdk_threads_add_timeout (150, scroll_row_timeout, tree_view);
6722     }
6723 }
6724
6725 static void
6726 remove_scroll_timeout (GtkTreeView *tree_view)
6727 {
6728   if (tree_view->priv->scroll_timeout != 0)
6729     {
6730       g_source_remove (tree_view->priv->scroll_timeout);
6731       tree_view->priv->scroll_timeout = 0;
6732     }
6733 }
6734
6735 static gboolean
6736 check_model_dnd (GtkTreeModel *model,
6737                  GType         required_iface,
6738                  const gchar  *signal)
6739 {
6740   if (model == NULL || !G_TYPE_CHECK_INSTANCE_TYPE ((model), required_iface))
6741     {
6742       g_warning ("You must override the default '%s' handler "
6743                  "on GtkTreeView when using models that don't support "
6744                  "the %s interface and enabling drag-and-drop. The simplest way to do this "
6745                  "is to connect to '%s' and call "
6746                  "g_signal_stop_emission_by_name() in your signal handler to prevent "
6747                  "the default handler from running. Look at the source code "
6748                  "for the default handler in gtktreeview.c to get an idea what "
6749                  "your handler should do. (gtktreeview.c is in the GTK source "
6750                  "code.) If you're using GTK from a language other than C, "
6751                  "there may be a more natural way to override default handlers, e.g. via derivation.",
6752                  signal, g_type_name (required_iface), signal);
6753       return FALSE;
6754     }
6755   else
6756     return TRUE;
6757 }
6758
6759 static void
6760 remove_open_timeout (GtkTreeView *tree_view)
6761 {
6762   if (tree_view->priv->open_dest_timeout != 0)
6763     {
6764       g_source_remove (tree_view->priv->open_dest_timeout);
6765       tree_view->priv->open_dest_timeout = 0;
6766     }
6767 }
6768
6769
6770 static gint
6771 open_row_timeout (gpointer data)
6772 {
6773   GtkTreeView *tree_view = data;
6774   GtkTreePath *dest_path = NULL;
6775   GtkTreeViewDropPosition pos;
6776   gboolean result = FALSE;
6777
6778   gtk_tree_view_get_drag_dest_row (tree_view,
6779                                    &dest_path,
6780                                    &pos);
6781
6782   if (dest_path &&
6783       (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
6784        pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
6785     {
6786       gtk_tree_view_expand_row (tree_view, dest_path, FALSE);
6787       tree_view->priv->open_dest_timeout = 0;
6788
6789       gtk_tree_path_free (dest_path);
6790     }
6791   else
6792     {
6793       if (dest_path)
6794         gtk_tree_path_free (dest_path);
6795
6796       result = TRUE;
6797     }
6798
6799   return result;
6800 }
6801
6802 static gboolean
6803 scroll_row_timeout (gpointer data)
6804 {
6805   GtkTreeView *tree_view = data;
6806
6807   gtk_tree_view_vertical_autoscroll (tree_view);
6808
6809   if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
6810     gtk_tree_view_update_rubber_band (tree_view);
6811
6812   return TRUE;
6813 }
6814
6815 /* Returns TRUE if event should not be propagated to parent widgets */
6816 static gboolean
6817 set_destination_row (GtkTreeView    *tree_view,
6818                      GdkDragContext *context,
6819                      /* coordinates relative to the widget */
6820                      gint            x,
6821                      gint            y,
6822                      GdkDragAction  *suggested_action,
6823                      GdkAtom        *target)
6824 {
6825   GtkTreePath *path = NULL;
6826   GtkTreeViewDropPosition pos;
6827   GtkTreeViewDropPosition old_pos;
6828   TreeViewDragInfo *di;
6829   GtkWidget *widget;
6830   GtkTreePath *old_dest_path = NULL;
6831   gboolean can_drop = FALSE;
6832
6833   *suggested_action = 0;
6834   *target = GDK_NONE;
6835
6836   widget = GTK_WIDGET (tree_view);
6837
6838   di = get_info (tree_view);
6839
6840   if (di == NULL || y - TREE_VIEW_HEADER_HEIGHT (tree_view) < 0)
6841     {
6842       /* someone unset us as a drag dest, note that if
6843        * we return FALSE drag_leave isn't called
6844        */
6845
6846       gtk_tree_view_set_drag_dest_row (tree_view,
6847                                        NULL,
6848                                        GTK_TREE_VIEW_DROP_BEFORE);
6849
6850       remove_scroll_timeout (GTK_TREE_VIEW (widget));
6851       remove_open_timeout (GTK_TREE_VIEW (widget));
6852
6853       return FALSE; /* no longer a drop site */
6854     }
6855
6856   *target = gtk_drag_dest_find_target (widget, context,
6857                                        gtk_drag_dest_get_target_list (widget));
6858   if (*target == GDK_NONE)
6859     {
6860       return FALSE;
6861     }
6862
6863   if (!gtk_tree_view_get_dest_row_at_pos (tree_view,
6864                                           x, y,
6865                                           &path,
6866                                           &pos))
6867     {
6868       gint n_children;
6869       GtkTreeModel *model;
6870
6871       remove_open_timeout (tree_view);
6872
6873       /* the row got dropped on empty space, let's setup a special case
6874        */
6875
6876       if (path)
6877         gtk_tree_path_free (path);
6878
6879       model = gtk_tree_view_get_model (tree_view);
6880
6881       n_children = gtk_tree_model_iter_n_children (model, NULL);
6882       if (n_children)
6883         {
6884           pos = GTK_TREE_VIEW_DROP_AFTER;
6885           path = gtk_tree_path_new_from_indices (n_children - 1, -1);
6886         }
6887       else
6888         {
6889           pos = GTK_TREE_VIEW_DROP_BEFORE;
6890           path = gtk_tree_path_new_from_indices (0, -1);
6891         }
6892
6893       can_drop = TRUE;
6894
6895       goto out;
6896     }
6897
6898   g_assert (path);
6899
6900   /* If we left the current row's "open" zone, unset the timeout for
6901    * opening the row
6902    */
6903   gtk_tree_view_get_drag_dest_row (tree_view,
6904                                    &old_dest_path,
6905                                    &old_pos);
6906
6907   if (old_dest_path &&
6908       (gtk_tree_path_compare (path, old_dest_path) != 0 ||
6909        !(pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
6910          pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE)))
6911     remove_open_timeout (tree_view);
6912
6913   if (old_dest_path)
6914     gtk_tree_path_free (old_dest_path);
6915
6916   if (TRUE /* FIXME if the location droppable predicate */)
6917     {
6918       can_drop = TRUE;
6919     }
6920
6921 out:
6922   if (can_drop)
6923     {
6924       GtkWidget *source_widget;
6925
6926       *suggested_action = context->suggested_action;
6927       source_widget = gtk_drag_get_source_widget (context);
6928
6929       if (source_widget == widget)
6930         {
6931           /* Default to MOVE, unless the user has
6932            * pressed ctrl or shift to affect available actions
6933            */
6934           if ((context->actions & GDK_ACTION_MOVE) != 0)
6935             *suggested_action = GDK_ACTION_MOVE;
6936         }
6937
6938       gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
6939                                        path, pos);
6940     }
6941   else
6942     {
6943       /* can't drop here */
6944       remove_open_timeout (tree_view);
6945
6946       gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
6947                                        NULL,
6948                                        GTK_TREE_VIEW_DROP_BEFORE);
6949     }
6950
6951   if (path)
6952     gtk_tree_path_free (path);
6953
6954   return TRUE;
6955 }
6956
6957 static GtkTreePath*
6958 get_logical_dest_row (GtkTreeView *tree_view,
6959                       gboolean    *path_down_mode,
6960                       gboolean    *drop_append_mode)
6961 {
6962   /* adjust path to point to the row the drop goes in front of */
6963   GtkTreePath *path = NULL;
6964   GtkTreeViewDropPosition pos;
6965
6966   g_return_val_if_fail (path_down_mode != NULL, NULL);
6967   g_return_val_if_fail (drop_append_mode != NULL, NULL);
6968
6969   *path_down_mode = FALSE;
6970   *drop_append_mode = 0;
6971
6972   gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
6973
6974   if (path == NULL)
6975     return NULL;
6976
6977   if (pos == GTK_TREE_VIEW_DROP_BEFORE)
6978     ; /* do nothing */
6979   else if (pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE ||
6980            pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER)
6981     *path_down_mode = TRUE;
6982   else
6983     {
6984       GtkTreeIter iter;
6985       GtkTreeModel *model = gtk_tree_view_get_model (tree_view);
6986
6987       g_assert (pos == GTK_TREE_VIEW_DROP_AFTER);
6988
6989       if (!gtk_tree_model_get_iter (model, &iter, path) ||
6990           !gtk_tree_model_iter_next (model, &iter))
6991         *drop_append_mode = 1;
6992       else
6993         {
6994           *drop_append_mode = 0;
6995           gtk_tree_path_next (path);
6996         }
6997     }
6998
6999   return path;
7000 }
7001
7002 static gboolean
7003 gtk_tree_view_maybe_begin_dragging_row (GtkTreeView      *tree_view,
7004                                         GdkEventMotion   *event)
7005 {
7006   GtkWidget *widget = GTK_WIDGET (tree_view);
7007   GdkDragContext *context;
7008   TreeViewDragInfo *di;
7009   GtkTreePath *path = NULL;
7010   gint button;
7011   gint cell_x, cell_y;
7012   GtkTreeModel *model;
7013   gboolean retval = FALSE;
7014
7015   di = get_info (tree_view);
7016
7017   if (di == NULL || !di->source_set)
7018     goto out;
7019
7020   if (tree_view->priv->pressed_button < 0)
7021     goto out;
7022
7023   if (!gtk_drag_check_threshold (widget,
7024                                  tree_view->priv->press_start_x,
7025                                  tree_view->priv->press_start_y,
7026                                  event->x, event->y))
7027     goto out;
7028
7029   model = gtk_tree_view_get_model (tree_view);
7030
7031   if (model == NULL)
7032     goto out;
7033
7034   button = tree_view->priv->pressed_button;
7035   tree_view->priv->pressed_button = -1;
7036
7037   gtk_tree_view_get_path_at_pos (tree_view,
7038                                  tree_view->priv->press_start_x,
7039                                  tree_view->priv->press_start_y,
7040                                  &path,
7041                                  NULL,
7042                                  &cell_x,
7043                                  &cell_y);
7044
7045   if (path == NULL)
7046     goto out;
7047
7048   if (!GTK_IS_TREE_DRAG_SOURCE (model) ||
7049       !gtk_tree_drag_source_row_draggable (GTK_TREE_DRAG_SOURCE (model),
7050                                            path))
7051     goto out;
7052
7053   if (!(GDK_BUTTON1_MASK << (button - 1) & di->start_button_mask))
7054     goto out;
7055
7056   /* Now we can begin the drag */
7057
7058   retval = TRUE;
7059
7060   context = gtk_drag_begin (widget,
7061                             gtk_drag_source_get_target_list (widget),
7062                             di->source_actions,
7063                             button,
7064                             (GdkEvent*)event);
7065
7066   set_source_row (context, model, path);
7067
7068  out:
7069   if (path)
7070     gtk_tree_path_free (path);
7071
7072   return retval;
7073 }
7074
7075
7076 static void
7077 gtk_tree_view_drag_begin (GtkWidget      *widget,
7078                           GdkDragContext *context)
7079 {
7080   GtkTreeView *tree_view;
7081   GtkTreePath *path = NULL;
7082   gint cell_x, cell_y;
7083   GdkPixmap *row_pix;
7084   TreeViewDragInfo *di;
7085
7086   tree_view = GTK_TREE_VIEW (widget);
7087
7088   /* if the user uses a custom DND source impl, we don't set the icon here */
7089   di = get_info (tree_view);
7090
7091   if (di == NULL || !di->source_set)
7092     return;
7093
7094   gtk_tree_view_get_path_at_pos (tree_view,
7095                                  tree_view->priv->press_start_x,
7096                                  tree_view->priv->press_start_y,
7097                                  &path,
7098                                  NULL,
7099                                  &cell_x,
7100                                  &cell_y);
7101
7102   g_return_if_fail (path != NULL);
7103
7104   row_pix = gtk_tree_view_create_row_drag_icon (tree_view,
7105                                                 path);
7106
7107   gtk_drag_set_icon_pixmap (context,
7108                             gdk_drawable_get_colormap (row_pix),
7109                             row_pix,
7110                             NULL,
7111                             /* the + 1 is for the black border in the icon */
7112                             tree_view->priv->press_start_x + 1,
7113                             cell_y + 1);
7114
7115   g_object_unref (row_pix);
7116   gtk_tree_path_free (path);
7117 }
7118
7119 static void
7120 gtk_tree_view_drag_end (GtkWidget      *widget,
7121                         GdkDragContext *context)
7122 {
7123   /* do nothing */
7124 }
7125
7126 /* Default signal implementations for the drag signals */
7127 static void
7128 gtk_tree_view_drag_data_get (GtkWidget        *widget,
7129                              GdkDragContext   *context,
7130                              GtkSelectionData *selection_data,
7131                              guint             info,
7132                              guint             time)
7133 {
7134   GtkTreeView *tree_view;
7135   GtkTreeModel *model;
7136   TreeViewDragInfo *di;
7137   GtkTreePath *source_row;
7138
7139   tree_view = GTK_TREE_VIEW (widget);
7140
7141   model = gtk_tree_view_get_model (tree_view);
7142
7143   if (model == NULL)
7144     return;
7145
7146   di = get_info (GTK_TREE_VIEW (widget));
7147
7148   if (di == NULL)
7149     return;
7150
7151   source_row = get_source_row (context);
7152
7153   if (source_row == NULL)
7154     return;
7155
7156   /* We can implement the GTK_TREE_MODEL_ROW target generically for
7157    * any model; for DragSource models there are some other targets
7158    * we also support.
7159    */
7160
7161   if (GTK_IS_TREE_DRAG_SOURCE (model) &&
7162       gtk_tree_drag_source_drag_data_get (GTK_TREE_DRAG_SOURCE (model),
7163                                           source_row,
7164                                           selection_data))
7165     goto done;
7166
7167   /* If drag_data_get does nothing, try providing row data. */
7168   if (selection_data->target == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
7169     {
7170       gtk_tree_set_row_drag_data (selection_data,
7171                                   model,
7172                                   source_row);
7173     }
7174
7175  done:
7176   gtk_tree_path_free (source_row);
7177 }
7178
7179
7180 static void
7181 gtk_tree_view_drag_data_delete (GtkWidget      *widget,
7182                                 GdkDragContext *context)
7183 {
7184   TreeViewDragInfo *di;
7185   GtkTreeModel *model;
7186   GtkTreeView *tree_view;
7187   GtkTreePath *source_row;
7188
7189   tree_view = GTK_TREE_VIEW (widget);
7190   model = gtk_tree_view_get_model (tree_view);
7191
7192   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_SOURCE, "drag_data_delete"))
7193     return;
7194
7195   di = get_info (tree_view);
7196
7197   if (di == NULL)
7198     return;
7199
7200   source_row = get_source_row (context);
7201
7202   if (source_row == NULL)
7203     return;
7204
7205   gtk_tree_drag_source_drag_data_delete (GTK_TREE_DRAG_SOURCE (model),
7206                                          source_row);
7207
7208   gtk_tree_path_free (source_row);
7209
7210   set_source_row (context, NULL, NULL);
7211 }
7212
7213 static void
7214 gtk_tree_view_drag_leave (GtkWidget      *widget,
7215                           GdkDragContext *context,
7216                           guint             time)
7217 {
7218   /* unset any highlight row */
7219   gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7220                                    NULL,
7221                                    GTK_TREE_VIEW_DROP_BEFORE);
7222
7223   remove_scroll_timeout (GTK_TREE_VIEW (widget));
7224   remove_open_timeout (GTK_TREE_VIEW (widget));
7225 }
7226
7227
7228 static gboolean
7229 gtk_tree_view_drag_motion (GtkWidget        *widget,
7230                            GdkDragContext   *context,
7231                            /* coordinates relative to the widget */
7232                            gint              x,
7233                            gint              y,
7234                            guint             time)
7235 {
7236   gboolean empty;
7237   GtkTreePath *path = NULL;
7238   GtkTreeViewDropPosition pos;
7239   GtkTreeView *tree_view;
7240   GdkDragAction suggested_action = 0;
7241   GdkAtom target;
7242
7243   tree_view = GTK_TREE_VIEW (widget);
7244
7245   if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
7246     return FALSE;
7247
7248   gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
7249
7250   /* we only know this *after* set_desination_row */
7251   empty = tree_view->priv->empty_view_drop;
7252
7253   if (path == NULL && !empty)
7254     {
7255       /* Can't drop here. */
7256       gdk_drag_status (context, 0, time);
7257     }
7258   else
7259     {
7260       if (tree_view->priv->open_dest_timeout == 0 &&
7261           (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
7262            pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
7263         {
7264           tree_view->priv->open_dest_timeout =
7265             gdk_threads_add_timeout (AUTO_EXPAND_TIMEOUT, open_row_timeout, tree_view);
7266         }
7267       else
7268         {
7269           add_scroll_timeout (tree_view);
7270         }
7271
7272       if (target == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
7273         {
7274           /* Request data so we can use the source row when
7275            * determining whether to accept the drop
7276            */
7277           set_status_pending (context, suggested_action);
7278           gtk_drag_get_data (widget, context, target, time);
7279         }
7280       else
7281         {
7282           set_status_pending (context, 0);
7283           gdk_drag_status (context, suggested_action, time);
7284         }
7285     }
7286
7287   if (path)
7288     gtk_tree_path_free (path);
7289
7290   return TRUE;
7291 }
7292
7293
7294 static gboolean
7295 gtk_tree_view_drag_drop (GtkWidget        *widget,
7296                          GdkDragContext   *context,
7297                          /* coordinates relative to the widget */
7298                          gint              x,
7299                          gint              y,
7300                          guint             time)
7301 {
7302   GtkTreeView *tree_view;
7303   GtkTreePath *path;
7304   GdkDragAction suggested_action = 0;
7305   GdkAtom target = GDK_NONE;
7306   TreeViewDragInfo *di;
7307   GtkTreeModel *model;
7308   gboolean path_down_mode;
7309   gboolean drop_append_mode;
7310
7311   tree_view = GTK_TREE_VIEW (widget);
7312
7313   model = gtk_tree_view_get_model (tree_view);
7314
7315   remove_scroll_timeout (GTK_TREE_VIEW (widget));
7316   remove_open_timeout (GTK_TREE_VIEW (widget));
7317
7318   di = get_info (tree_view);
7319
7320   if (di == NULL)
7321     return FALSE;
7322
7323   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_drop"))
7324     return FALSE;
7325
7326   if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
7327     return FALSE;
7328
7329   path = get_logical_dest_row (tree_view, &path_down_mode, &drop_append_mode);
7330
7331   if (target != GDK_NONE && path != NULL)
7332     {
7333       /* in case a motion had requested drag data, change things so we
7334        * treat drag data receives as a drop.
7335        */
7336       set_status_pending (context, 0);
7337       set_dest_row (context, model, path,
7338                     path_down_mode, tree_view->priv->empty_view_drop,
7339                     drop_append_mode);
7340     }
7341
7342   if (path)
7343     gtk_tree_path_free (path);
7344
7345   /* Unset this thing */
7346   gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7347                                    NULL,
7348                                    GTK_TREE_VIEW_DROP_BEFORE);
7349
7350   if (target != GDK_NONE)
7351     {
7352       gtk_drag_get_data (widget, context, target, time);
7353       return TRUE;
7354     }
7355   else
7356     return FALSE;
7357 }
7358
7359 static void
7360 gtk_tree_view_drag_data_received (GtkWidget        *widget,
7361                                   GdkDragContext   *context,
7362                                   /* coordinates relative to the widget */
7363                                   gint              x,
7364                                   gint              y,
7365                                   GtkSelectionData *selection_data,
7366                                   guint             info,
7367                                   guint             time)
7368 {
7369   GtkTreePath *path;
7370   TreeViewDragInfo *di;
7371   gboolean accepted = FALSE;
7372   GtkTreeModel *model;
7373   GtkTreeView *tree_view;
7374   GtkTreePath *dest_row;
7375   GdkDragAction suggested_action;
7376   gboolean path_down_mode;
7377   gboolean drop_append_mode;
7378
7379   tree_view = GTK_TREE_VIEW (widget);
7380
7381   model = gtk_tree_view_get_model (tree_view);
7382
7383   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_data_received"))
7384     return;
7385
7386   di = get_info (tree_view);
7387
7388   if (di == NULL)
7389     return;
7390
7391   suggested_action = get_status_pending (context);
7392
7393   if (suggested_action)
7394     {
7395       /* We are getting this data due to a request in drag_motion,
7396        * rather than due to a request in drag_drop, so we are just
7397        * supposed to call drag_status, not actually paste in the
7398        * data.
7399        */
7400       path = get_logical_dest_row (tree_view, &path_down_mode,
7401                                    &drop_append_mode);
7402
7403       if (path == NULL)
7404         suggested_action = 0;
7405       else if (path_down_mode)
7406         gtk_tree_path_down (path);
7407
7408       if (suggested_action)
7409         {
7410           if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
7411                                                      path,
7412                                                      selection_data))
7413             {
7414               if (path_down_mode)
7415                 {
7416                   path_down_mode = FALSE;
7417                   gtk_tree_path_up (path);
7418
7419                   if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
7420                                                              path,
7421                                                              selection_data))
7422                     suggested_action = 0;
7423                 }
7424               else
7425                 suggested_action = 0;
7426             }
7427         }
7428
7429       gdk_drag_status (context, suggested_action, time);
7430
7431       if (path)
7432         gtk_tree_path_free (path);
7433
7434       /* If you can't drop, remove user drop indicator until the next motion */
7435       if (suggested_action == 0)
7436         gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7437                                          NULL,
7438                                          GTK_TREE_VIEW_DROP_BEFORE);
7439
7440       return;
7441     }
7442
7443   dest_row = get_dest_row (context, &path_down_mode);
7444
7445   if (dest_row == NULL)
7446     return;
7447
7448   if (selection_data->length >= 0)
7449     {
7450       if (path_down_mode)
7451         {
7452           gtk_tree_path_down (dest_row);
7453           if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
7454                                                      dest_row, selection_data))
7455             gtk_tree_path_up (dest_row);
7456         }
7457     }
7458
7459   if (selection_data->length >= 0)
7460     {
7461       if (gtk_tree_drag_dest_drag_data_received (GTK_TREE_DRAG_DEST (model),
7462                                                  dest_row,
7463                                                  selection_data))
7464         accepted = TRUE;
7465     }
7466
7467   gtk_drag_finish (context,
7468                    accepted,
7469                    (context->action == GDK_ACTION_MOVE),
7470                    time);
7471
7472   if (gtk_tree_path_get_depth (dest_row) == 1
7473       && gtk_tree_path_get_indices (dest_row)[0] == 0)
7474     {
7475       /* special special case drag to "0", scroll to first item */
7476       if (!tree_view->priv->scroll_to_path)
7477         gtk_tree_view_scroll_to_cell (tree_view, dest_row, NULL, FALSE, 0.0, 0.0);
7478     }
7479
7480   gtk_tree_path_free (dest_row);
7481
7482   /* drop dest_row */
7483   set_dest_row (context, NULL, NULL, FALSE, FALSE, FALSE);
7484 }
7485
7486
7487
7488 /* GtkContainer Methods
7489  */
7490
7491
7492 static void
7493 gtk_tree_view_remove (GtkContainer *container,
7494                       GtkWidget    *widget)
7495 {
7496   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
7497   GtkTreeViewChild *child = NULL;
7498   GList *tmp_list;
7499
7500   tmp_list = tree_view->priv->children;
7501   while (tmp_list)
7502     {
7503       child = tmp_list->data;
7504       if (child->widget == widget)
7505         {
7506           gtk_widget_unparent (widget);
7507
7508           tree_view->priv->children = g_list_remove_link (tree_view->priv->children, tmp_list);
7509           g_list_free_1 (tmp_list);
7510           g_slice_free (GtkTreeViewChild, child);
7511           return;
7512         }
7513
7514       tmp_list = tmp_list->next;
7515     }
7516
7517   tmp_list = tree_view->priv->columns;
7518
7519   while (tmp_list)
7520     {
7521       GtkTreeViewColumn *column;
7522       column = tmp_list->data;
7523       if (column->button == widget)
7524         {
7525           gtk_widget_unparent (widget);
7526           return;
7527         }
7528       tmp_list = tmp_list->next;
7529     }
7530 }
7531
7532 static void
7533 gtk_tree_view_forall (GtkContainer *container,
7534                       gboolean      include_internals,
7535                       GtkCallback   callback,
7536                       gpointer      callback_data)
7537 {
7538   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
7539   GtkTreeViewChild *child = NULL;
7540   GtkTreeViewColumn *column;
7541   GList *tmp_list;
7542
7543   tmp_list = tree_view->priv->children;
7544   while (tmp_list)
7545     {
7546       child = tmp_list->data;
7547       tmp_list = tmp_list->next;
7548
7549       (* callback) (child->widget, callback_data);
7550     }
7551   if (include_internals == FALSE)
7552     return;
7553
7554   for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
7555     {
7556       column = tmp_list->data;
7557
7558       if (column->button)
7559         (* callback) (column->button, callback_data);
7560     }
7561 }
7562
7563 /* Returns TRUE if the treeview contains no "special" (editable or activatable)
7564  * cells. If so we draw one big row-spanning focus rectangle.
7565  */
7566 static gboolean
7567 gtk_tree_view_has_special_cell (GtkTreeView *tree_view)
7568 {
7569   GList *list;
7570
7571   for (list = tree_view->priv->columns; list; list = list->next)
7572     {
7573       if (!((GtkTreeViewColumn *)list->data)->visible)
7574         continue;
7575       if (_gtk_tree_view_column_count_special_cells (list->data))
7576         return TRUE;
7577     }
7578
7579   return FALSE;
7580 }
7581
7582 static void
7583 column_sizing_notify (GObject    *object,
7584                       GParamSpec *pspec,
7585                       gpointer    data)
7586 {
7587   GtkTreeViewColumn *c = GTK_TREE_VIEW_COLUMN (object);
7588
7589   if (gtk_tree_view_column_get_sizing (c) != GTK_TREE_VIEW_COLUMN_FIXED)
7590     /* disable fixed height mode */
7591     g_object_set (data, "fixed-height-mode", FALSE, NULL);
7592 }
7593
7594 /**
7595  * gtk_tree_view_set_fixed_height_mode:
7596  * @tree_view: a #GtkTreeView 
7597  * @enable: %TRUE to enable fixed height mode
7598  * 
7599  * Enables or disables the fixed height mode of @tree_view. 
7600  * Fixed height mode speeds up #GtkTreeView by assuming that all 
7601  * rows have the same height. 
7602  * Only enable this option if all rows are the same height and all
7603  * columns are of type %GTK_TREE_VIEW_COLUMN_FIXED.
7604  *
7605  * Since: 2.6 
7606  **/
7607 void
7608 gtk_tree_view_set_fixed_height_mode (GtkTreeView *tree_view,
7609                                      gboolean     enable)
7610 {
7611   GList *l;
7612   
7613   enable = enable != FALSE;
7614
7615   if (enable == tree_view->priv->fixed_height_mode)
7616     return;
7617
7618   if (!enable)
7619     {
7620       tree_view->priv->fixed_height_mode = 0;
7621       tree_view->priv->fixed_height = -1;
7622
7623       /* force a revalidation */
7624       install_presize_handler (tree_view);
7625     }
7626   else 
7627     {
7628       /* make sure all columns are of type FIXED */
7629       for (l = tree_view->priv->columns; l; l = l->next)
7630         {
7631           GtkTreeViewColumn *c = l->data;
7632           
7633           g_return_if_fail (gtk_tree_view_column_get_sizing (c) == GTK_TREE_VIEW_COLUMN_FIXED);
7634         }
7635       
7636       /* yes, we really have to do this is in a separate loop */
7637       for (l = tree_view->priv->columns; l; l = l->next)
7638         g_signal_connect (l->data, "notify::sizing",
7639                           G_CALLBACK (column_sizing_notify), tree_view);
7640       
7641       tree_view->priv->fixed_height_mode = 1;
7642       tree_view->priv->fixed_height = -1;
7643       
7644       if (tree_view->priv->tree)
7645         initialize_fixed_height_mode (tree_view);
7646     }
7647
7648   g_object_notify (G_OBJECT (tree_view), "fixed-height-mode");
7649 }
7650
7651 /**
7652  * gtk_tree_view_get_fixed_height_mode:
7653  * @tree_view: a #GtkTreeView
7654  * 
7655  * Returns whether fixed height mode is turned on for @tree_view.
7656  * 
7657  * Return value: %TRUE if @tree_view is in fixed height mode
7658  * 
7659  * Since: 2.6
7660  **/
7661 gboolean
7662 gtk_tree_view_get_fixed_height_mode (GtkTreeView *tree_view)
7663 {
7664   return tree_view->priv->fixed_height_mode;
7665 }
7666
7667 /* Returns TRUE if the focus is within the headers, after the focus operation is
7668  * done
7669  */
7670 static gboolean
7671 gtk_tree_view_header_focus (GtkTreeView      *tree_view,
7672                             GtkDirectionType  dir,
7673                             gboolean          clamp_column_visible)
7674 {
7675   GtkWidget *focus_child;
7676
7677   GList *last_column, *first_column;
7678   GList *tmp_list;
7679   gboolean rtl;
7680
7681   if (! GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
7682     return FALSE;
7683
7684   focus_child = GTK_CONTAINER (tree_view)->focus_child;
7685
7686   first_column = tree_view->priv->columns;
7687   while (first_column)
7688     {
7689       if (GTK_WIDGET_CAN_FOCUS (GTK_TREE_VIEW_COLUMN (first_column->data)->button) &&
7690           GTK_TREE_VIEW_COLUMN (first_column->data)->visible &&
7691           (GTK_TREE_VIEW_COLUMN (first_column->data)->clickable ||
7692            GTK_TREE_VIEW_COLUMN (first_column->data)->reorderable))
7693         break;
7694       first_column = first_column->next;
7695     }
7696
7697   /* No headers are visible, or are focusable.  We can't focus in or out.
7698    */
7699   if (first_column == NULL)
7700     return FALSE;
7701
7702   last_column = g_list_last (tree_view->priv->columns);
7703   while (last_column)
7704     {
7705       if (GTK_WIDGET_CAN_FOCUS (GTK_TREE_VIEW_COLUMN (last_column->data)->button) &&
7706           GTK_TREE_VIEW_COLUMN (last_column->data)->visible &&
7707           (GTK_TREE_VIEW_COLUMN (last_column->data)->clickable ||
7708            GTK_TREE_VIEW_COLUMN (last_column->data)->reorderable))
7709         break;
7710       last_column = last_column->prev;
7711     }
7712
7713
7714   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
7715
7716   switch (dir)
7717     {
7718     case GTK_DIR_TAB_BACKWARD:
7719     case GTK_DIR_TAB_FORWARD:
7720     case GTK_DIR_UP:
7721     case GTK_DIR_DOWN:
7722       if (focus_child == NULL)
7723         {
7724           if (tree_view->priv->focus_column != NULL && GTK_WIDGET_CAN_FOCUS (tree_view->priv->focus_column->button))
7725             focus_child = tree_view->priv->focus_column->button;
7726           else
7727             focus_child = GTK_TREE_VIEW_COLUMN (first_column->data)->button;
7728           gtk_widget_grab_focus (focus_child);
7729           break;
7730         }
7731       return FALSE;
7732
7733     case GTK_DIR_LEFT:
7734     case GTK_DIR_RIGHT:
7735       if (focus_child == NULL)
7736         {
7737           if (tree_view->priv->focus_column != NULL)
7738             focus_child = tree_view->priv->focus_column->button;
7739           else if (dir == GTK_DIR_LEFT)
7740             focus_child = GTK_TREE_VIEW_COLUMN (last_column->data)->button;
7741           else
7742             focus_child = GTK_TREE_VIEW_COLUMN (first_column->data)->button;
7743           gtk_widget_grab_focus (focus_child);
7744           break;
7745         }
7746
7747       if (gtk_widget_child_focus (focus_child, dir))
7748         {
7749           /* The focus moves inside the button. */
7750           /* This is probably a great example of bad UI */
7751           break;
7752         }
7753
7754       /* We need to move the focus among the row of buttons. */
7755       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
7756         if (GTK_TREE_VIEW_COLUMN (tmp_list->data)->button == focus_child)
7757           break;
7758
7759       if ((tmp_list == first_column && dir == (rtl ? GTK_DIR_RIGHT : GTK_DIR_LEFT))
7760           || (tmp_list == last_column && dir == (rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT)))
7761         {
7762           gtk_widget_error_bell (GTK_WIDGET (tree_view));
7763           break;
7764         }
7765
7766       while (tmp_list)
7767         {
7768           GtkTreeViewColumn *column;
7769
7770           if (dir == (rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT))
7771             tmp_list = tmp_list->next;
7772           else
7773             tmp_list = tmp_list->prev;
7774
7775           if (tmp_list == NULL)
7776             {
7777               g_warning ("Internal button not found");
7778               break;
7779             }
7780           column = tmp_list->data;
7781           if (column->button &&
7782               column->visible &&
7783               GTK_WIDGET_CAN_FOCUS (column->button))
7784             {
7785               focus_child = column->button;
7786               gtk_widget_grab_focus (column->button);
7787               break;
7788             }
7789         }
7790       break;
7791     default:
7792       g_assert_not_reached ();
7793       break;
7794     }
7795
7796   /* if focus child is non-null, we assume it's been set to the current focus child
7797    */
7798   if (focus_child)
7799     {
7800       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
7801         if (GTK_TREE_VIEW_COLUMN (tmp_list->data)->button == focus_child)
7802           {
7803             tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
7804             break;
7805           }
7806
7807       if (clamp_column_visible)
7808         {
7809           gtk_tree_view_clamp_column_visible (tree_view,
7810                                               tree_view->priv->focus_column,
7811                                               FALSE);
7812         }
7813     }
7814
7815   return (focus_child != NULL);
7816 }
7817
7818 /* This function returns in 'path' the first focusable path, if the given path
7819  * is already focusable, it's the returned one.
7820  */
7821 static gboolean
7822 search_first_focusable_path (GtkTreeView  *tree_view,
7823                              GtkTreePath **path,
7824                              gboolean      search_forward,
7825                              GtkRBTree   **new_tree,
7826                              GtkRBNode   **new_node)
7827 {
7828   GtkRBTree *tree = NULL;
7829   GtkRBNode *node = NULL;
7830
7831   if (!path || !*path)
7832     return FALSE;
7833
7834   _gtk_tree_view_find_node (tree_view, *path, &tree, &node);
7835
7836   if (!tree || !node)
7837     return FALSE;
7838
7839   while (node && row_is_separator (tree_view, NULL, *path))
7840     {
7841       if (search_forward)
7842         _gtk_rbtree_next_full (tree, node, &tree, &node);
7843       else
7844         _gtk_rbtree_prev_full (tree, node, &tree, &node);
7845
7846       if (*path)
7847         gtk_tree_path_free (*path);
7848
7849       if (node)
7850         *path = _gtk_tree_view_find_path (tree_view, tree, node);
7851       else
7852         *path = NULL;
7853     }
7854
7855   if (new_tree)
7856     *new_tree = tree;
7857
7858   if (new_node)
7859     *new_node = node;
7860
7861   return (*path != NULL);
7862 }
7863
7864 static gint
7865 gtk_tree_view_focus (GtkWidget        *widget,
7866                      GtkDirectionType  direction)
7867 {
7868   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
7869   GtkContainer *container = GTK_CONTAINER (widget);
7870   GtkWidget *focus_child;
7871
7872   if (!GTK_WIDGET_IS_SENSITIVE (container) || !GTK_WIDGET_CAN_FOCUS (widget))
7873     return FALSE;
7874
7875   focus_child = container->focus_child;
7876
7877   gtk_tree_view_stop_editing (GTK_TREE_VIEW (widget), FALSE);
7878   /* Case 1.  Headers currently have focus. */
7879   if (focus_child)
7880     {
7881       switch (direction)
7882         {
7883         case GTK_DIR_LEFT:
7884         case GTK_DIR_RIGHT:
7885           gtk_tree_view_header_focus (tree_view, direction, TRUE);
7886           return TRUE;
7887         case GTK_DIR_TAB_BACKWARD:
7888         case GTK_DIR_UP:
7889           return FALSE;
7890         case GTK_DIR_TAB_FORWARD:
7891         case GTK_DIR_DOWN:
7892           gtk_widget_grab_focus (widget);
7893           return TRUE;
7894         default:
7895           g_assert_not_reached ();
7896           return FALSE;
7897         }
7898     }
7899
7900   /* Case 2. We don't have focus at all. */
7901   if (!GTK_WIDGET_HAS_FOCUS (container))
7902     {
7903       if (!gtk_tree_view_header_focus (tree_view, direction, FALSE))
7904         gtk_widget_grab_focus (widget);
7905       return TRUE;
7906     }
7907
7908   /* Case 3. We have focus already. */
7909   if (direction == GTK_DIR_TAB_BACKWARD)
7910     return (gtk_tree_view_header_focus (tree_view, direction, FALSE));
7911   else if (direction == GTK_DIR_TAB_FORWARD)
7912     return FALSE;
7913
7914   /* Other directions caught by the keybindings */
7915   gtk_widget_grab_focus (widget);
7916   return TRUE;
7917 }
7918
7919 static void
7920 gtk_tree_view_grab_focus (GtkWidget *widget)
7921 {
7922   GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->grab_focus (widget);
7923
7924   gtk_tree_view_focus_to_cursor (GTK_TREE_VIEW (widget));
7925 }
7926
7927 static void
7928 gtk_tree_view_style_set (GtkWidget *widget,
7929                          GtkStyle *previous_style)
7930 {
7931   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
7932   GList *list;
7933   GtkTreeViewColumn *column;
7934
7935   if (GTK_WIDGET_REALIZED (widget))
7936     {
7937       gdk_window_set_back_pixmap (widget->window, NULL, FALSE);
7938       gdk_window_set_background (tree_view->priv->bin_window, &widget->style->base[widget->state]);
7939       gtk_style_set_background (widget->style, tree_view->priv->header_window, GTK_STATE_NORMAL);
7940
7941       gtk_tree_view_set_grid_lines (tree_view, tree_view->priv->grid_lines);
7942       gtk_tree_view_set_enable_tree_lines (tree_view, tree_view->priv->tree_lines_enabled);
7943     }
7944
7945   gtk_widget_style_get (widget,
7946                         "expander-size", &tree_view->priv->expander_size,
7947                         NULL);
7948   tree_view->priv->expander_size += EXPANDER_EXTRA_PADDING;
7949
7950   for (list = tree_view->priv->columns; list; list = list->next)
7951     {
7952       column = list->data;
7953       _gtk_tree_view_column_cell_set_dirty (column, TRUE);
7954     }
7955
7956   tree_view->priv->fixed_height = -1;
7957   _gtk_rbtree_mark_invalid (tree_view->priv->tree);
7958
7959   gtk_widget_queue_resize (widget);
7960 }
7961
7962
7963 static void
7964 gtk_tree_view_set_focus_child (GtkContainer *container,
7965                                GtkWidget    *child)
7966 {
7967   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
7968   GList *list;
7969
7970   for (list = tree_view->priv->columns; list; list = list->next)
7971     {
7972       if (GTK_TREE_VIEW_COLUMN (list->data)->button == child)
7973         {
7974           tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (list->data);
7975           break;
7976         }
7977     }
7978
7979   GTK_CONTAINER_CLASS (gtk_tree_view_parent_class)->set_focus_child (container, child);
7980 }
7981
7982 static void
7983 gtk_tree_view_set_adjustments (GtkTreeView   *tree_view,
7984                                GtkAdjustment *hadj,
7985                                GtkAdjustment *vadj)
7986 {
7987   gboolean need_adjust = FALSE;
7988
7989   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7990
7991   if (hadj)
7992     g_return_if_fail (GTK_IS_ADJUSTMENT (hadj));
7993   else
7994     hadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
7995   if (vadj)
7996     g_return_if_fail (GTK_IS_ADJUSTMENT (vadj));
7997   else
7998     vadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
7999
8000   if (tree_view->priv->hadjustment && (tree_view->priv->hadjustment != hadj))
8001     {
8002       g_signal_handlers_disconnect_by_func (tree_view->priv->hadjustment,
8003                                             gtk_tree_view_adjustment_changed,
8004                                             tree_view);
8005       g_object_unref (tree_view->priv->hadjustment);
8006     }
8007
8008   if (tree_view->priv->vadjustment && (tree_view->priv->vadjustment != vadj))
8009     {
8010       g_signal_handlers_disconnect_by_func (tree_view->priv->vadjustment,
8011                                             gtk_tree_view_adjustment_changed,
8012                                             tree_view);
8013       g_object_unref (tree_view->priv->vadjustment);
8014     }
8015
8016   if (tree_view->priv->hadjustment != hadj)
8017     {
8018       tree_view->priv->hadjustment = hadj;
8019       g_object_ref_sink (tree_view->priv->hadjustment);
8020
8021       g_signal_connect (tree_view->priv->hadjustment, "value-changed",
8022                         G_CALLBACK (gtk_tree_view_adjustment_changed),
8023                         tree_view);
8024       need_adjust = TRUE;
8025     }
8026
8027   if (tree_view->priv->vadjustment != vadj)
8028     {
8029       tree_view->priv->vadjustment = vadj;
8030       g_object_ref_sink (tree_view->priv->vadjustment);
8031
8032       g_signal_connect (tree_view->priv->vadjustment, "value-changed",
8033                         G_CALLBACK (gtk_tree_view_adjustment_changed),
8034                         tree_view);
8035       need_adjust = TRUE;
8036     }
8037
8038   if (need_adjust)
8039     gtk_tree_view_adjustment_changed (NULL, tree_view);
8040 }
8041
8042
8043 static gboolean
8044 gtk_tree_view_real_move_cursor (GtkTreeView       *tree_view,
8045                                 GtkMovementStep    step,
8046                                 gint               count)
8047 {
8048   GdkModifierType state;
8049
8050   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
8051   g_return_val_if_fail (step == GTK_MOVEMENT_LOGICAL_POSITIONS ||
8052                         step == GTK_MOVEMENT_VISUAL_POSITIONS ||
8053                         step == GTK_MOVEMENT_DISPLAY_LINES ||
8054                         step == GTK_MOVEMENT_PAGES ||
8055                         step == GTK_MOVEMENT_BUFFER_ENDS, FALSE);
8056
8057   if (tree_view->priv->tree == NULL)
8058     return FALSE;
8059   if (!GTK_WIDGET_HAS_FOCUS (GTK_WIDGET (tree_view)))
8060     return FALSE;
8061
8062   gtk_tree_view_stop_editing (tree_view, FALSE);
8063   GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
8064   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
8065
8066   if (gtk_get_current_event_state (&state))
8067     {
8068       if ((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
8069         tree_view->priv->ctrl_pressed = TRUE;
8070       if ((state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
8071         tree_view->priv->shift_pressed = TRUE;
8072     }
8073   /* else we assume not pressed */
8074
8075   switch (step)
8076     {
8077       /* currently we make no distinction.  When we go bi-di, we need to */
8078     case GTK_MOVEMENT_LOGICAL_POSITIONS:
8079     case GTK_MOVEMENT_VISUAL_POSITIONS:
8080       gtk_tree_view_move_cursor_left_right (tree_view, count);
8081       break;
8082     case GTK_MOVEMENT_DISPLAY_LINES:
8083       gtk_tree_view_move_cursor_up_down (tree_view, count);
8084       break;
8085     case GTK_MOVEMENT_PAGES:
8086       gtk_tree_view_move_cursor_page_up_down (tree_view, count);
8087       break;
8088     case GTK_MOVEMENT_BUFFER_ENDS:
8089       gtk_tree_view_move_cursor_start_end (tree_view, count);
8090       break;
8091     default:
8092       g_assert_not_reached ();
8093     }
8094
8095   tree_view->priv->ctrl_pressed = FALSE;
8096   tree_view->priv->shift_pressed = FALSE;
8097
8098   return TRUE;
8099 }
8100
8101 static void
8102 gtk_tree_view_put (GtkTreeView *tree_view,
8103                    GtkWidget   *child_widget,
8104                    /* in bin_window coordinates */
8105                    gint         x,
8106                    gint         y,
8107                    gint         width,
8108                    gint         height)
8109 {
8110   GtkTreeViewChild *child;
8111   
8112   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8113   g_return_if_fail (GTK_IS_WIDGET (child_widget));
8114
8115   child = g_slice_new (GtkTreeViewChild);
8116
8117   child->widget = child_widget;
8118   child->x = x;
8119   child->y = y;
8120   child->width = width;
8121   child->height = height;
8122
8123   tree_view->priv->children = g_list_append (tree_view->priv->children, child);
8124
8125   if (GTK_WIDGET_REALIZED (tree_view))
8126     gtk_widget_set_parent_window (child->widget, tree_view->priv->bin_window);
8127   
8128   gtk_widget_set_parent (child_widget, GTK_WIDGET (tree_view));
8129 }
8130
8131 void
8132 _gtk_tree_view_child_move_resize (GtkTreeView *tree_view,
8133                                   GtkWidget   *widget,
8134                                   /* in tree coordinates */
8135                                   gint         x,
8136                                   gint         y,
8137                                   gint         width,
8138                                   gint         height)
8139 {
8140   GtkTreeViewChild *child = NULL;
8141   GList *list;
8142   GdkRectangle allocation;
8143
8144   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8145   g_return_if_fail (GTK_IS_WIDGET (widget));
8146
8147   for (list = tree_view->priv->children; list; list = list->next)
8148     {
8149       if (((GtkTreeViewChild *)list->data)->widget == widget)
8150         {
8151           child = list->data;
8152           break;
8153         }
8154     }
8155   if (child == NULL)
8156     return;
8157
8158   allocation.x = child->x = x;
8159   allocation.y = child->y = y;
8160   allocation.width = child->width = width;
8161   allocation.height = child->height = height;
8162
8163   if (GTK_WIDGET_REALIZED (widget))
8164     gtk_widget_size_allocate (widget, &allocation);
8165 }
8166
8167
8168 /* TreeModel Callbacks
8169  */
8170
8171 static void
8172 gtk_tree_view_row_changed (GtkTreeModel *model,
8173                            GtkTreePath  *path,
8174                            GtkTreeIter  *iter,
8175                            gpointer      data)
8176 {
8177   GtkTreeView *tree_view = (GtkTreeView *)data;
8178   GtkRBTree *tree;
8179   GtkRBNode *node;
8180   gboolean free_path = FALSE;
8181   GList *list;
8182   GtkTreePath *cursor_path;
8183
8184   g_return_if_fail (path != NULL || iter != NULL);
8185
8186   if (tree_view->priv->cursor != NULL)
8187     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
8188   else
8189     cursor_path = NULL;
8190
8191   if (tree_view->priv->edited_column &&
8192       (cursor_path == NULL || gtk_tree_path_compare (cursor_path, path) == 0))
8193     gtk_tree_view_stop_editing (tree_view, TRUE);
8194
8195   if (cursor_path != NULL)
8196     gtk_tree_path_free (cursor_path);
8197
8198   if (path == NULL)
8199     {
8200       path = gtk_tree_model_get_path (model, iter);
8201       free_path = TRUE;
8202     }
8203   else if (iter == NULL)
8204     gtk_tree_model_get_iter (model, iter, path);
8205
8206   if (_gtk_tree_view_find_node (tree_view,
8207                                 path,
8208                                 &tree,
8209                                 &node))
8210     /* We aren't actually showing the node */
8211     goto done;
8212
8213   if (tree == NULL)
8214     goto done;
8215
8216   if (tree_view->priv->fixed_height_mode
8217       && tree_view->priv->fixed_height >= 0)
8218     {
8219       _gtk_rbtree_node_set_height (tree, node, tree_view->priv->fixed_height);
8220       if (GTK_WIDGET_REALIZED (tree_view))
8221         gtk_tree_view_node_queue_redraw (tree_view, tree, node);
8222     }
8223   else
8224     {
8225       _gtk_rbtree_node_mark_invalid (tree, node);
8226       for (list = tree_view->priv->columns; list; list = list->next)
8227         {
8228           GtkTreeViewColumn *column;
8229
8230           column = list->data;
8231           if (! column->visible)
8232             continue;
8233
8234           if (column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
8235             {
8236               _gtk_tree_view_column_cell_set_dirty (column, TRUE);
8237             }
8238         }
8239     }
8240
8241  done:
8242   if (GTK_WIDGET_REALIZED (tree_view) && !tree_view->priv->fixed_height_mode)
8243     install_presize_handler (tree_view);
8244   if (free_path)
8245     gtk_tree_path_free (path);
8246 }
8247
8248 static void
8249 gtk_tree_view_row_inserted (GtkTreeModel *model,
8250                             GtkTreePath  *path,
8251                             GtkTreeIter  *iter,
8252                             gpointer      data)
8253 {
8254   GtkTreeView *tree_view = (GtkTreeView *) data;
8255   gint *indices;
8256   GtkRBTree *tmptree, *tree;
8257   GtkRBNode *tmpnode = NULL;
8258   gint depth;
8259   gint i = 0;
8260   gint height;
8261   gboolean free_path = FALSE;
8262   gboolean node_visible = TRUE;
8263
8264   g_return_if_fail (path != NULL || iter != NULL);
8265
8266   if (tree_view->priv->fixed_height_mode
8267       && tree_view->priv->fixed_height >= 0)
8268     height = tree_view->priv->fixed_height;
8269   else
8270     height = 0;
8271
8272   if (path == NULL)
8273     {
8274       path = gtk_tree_model_get_path (model, iter);
8275       free_path = TRUE;
8276     }
8277   else if (iter == NULL)
8278     gtk_tree_model_get_iter (model, iter, path);
8279
8280   if (tree_view->priv->tree == NULL)
8281     tree_view->priv->tree = _gtk_rbtree_new ();
8282
8283   tmptree = tree = tree_view->priv->tree;
8284
8285   /* Update all row-references */
8286   gtk_tree_row_reference_inserted (G_OBJECT (data), path);
8287   depth = gtk_tree_path_get_depth (path);
8288   indices = gtk_tree_path_get_indices (path);
8289
8290   /* First, find the parent tree */
8291   while (i < depth - 1)
8292     {
8293       if (tmptree == NULL)
8294         {
8295           /* We aren't showing the node */
8296           node_visible = FALSE;
8297           goto done;
8298         }
8299
8300       tmpnode = _gtk_rbtree_find_count (tmptree, indices[i] + 1);
8301       if (tmpnode == NULL)
8302         {
8303           g_warning ("A node was inserted with a parent that's not in the tree.\n" \
8304                      "This possibly means that a GtkTreeModel inserted a child node\n" \
8305                      "before the parent was inserted.");
8306           goto done;
8307         }
8308       else if (!GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_IS_PARENT))
8309         {
8310           /* FIXME enforce correct behavior on model, probably */
8311           /* In theory, the model should have emitted has_child_toggled here.  We
8312            * try to catch it anyway, just to be safe, in case the model hasn't.
8313            */
8314           GtkTreePath *tmppath = _gtk_tree_view_find_path (tree_view,
8315                                                            tree,
8316                                                            tmpnode);
8317           gtk_tree_view_row_has_child_toggled (model, tmppath, NULL, data);
8318           gtk_tree_path_free (tmppath);
8319           goto done;
8320         }
8321
8322       tmptree = tmpnode->children;
8323       tree = tmptree;
8324       i++;
8325     }
8326
8327   if (tree == NULL)
8328     {
8329       node_visible = FALSE;
8330       goto done;
8331     }
8332
8333   /* ref the node */
8334   gtk_tree_model_ref_node (tree_view->priv->model, iter);
8335   if (indices[depth - 1] == 0)
8336     {
8337       tmpnode = _gtk_rbtree_find_count (tree, 1);
8338       tmpnode = _gtk_rbtree_insert_before (tree, tmpnode, height, FALSE);
8339     }
8340   else
8341     {
8342       tmpnode = _gtk_rbtree_find_count (tree, indices[depth - 1]);
8343       tmpnode = _gtk_rbtree_insert_after (tree, tmpnode, height, FALSE);
8344     }
8345
8346  done:
8347   if (height > 0)
8348     {
8349       if (tree)
8350         _gtk_rbtree_node_mark_valid (tree, tmpnode);
8351
8352       if (node_visible && node_is_visible (tree_view, tree, tmpnode))
8353         gtk_widget_queue_resize (GTK_WIDGET (tree_view));
8354       else
8355         gtk_widget_queue_resize_no_redraw (GTK_WIDGET (tree_view));
8356     }
8357   else
8358     install_presize_handler (tree_view);
8359   if (free_path)
8360     gtk_tree_path_free (path);
8361 }
8362
8363 static void
8364 gtk_tree_view_row_has_child_toggled (GtkTreeModel *model,
8365                                      GtkTreePath  *path,
8366                                      GtkTreeIter  *iter,
8367                                      gpointer      data)
8368 {
8369   GtkTreeView *tree_view = (GtkTreeView *)data;
8370   GtkTreeIter real_iter;
8371   gboolean has_child;
8372   GtkRBTree *tree;
8373   GtkRBNode *node;
8374   gboolean free_path = FALSE;
8375
8376   g_return_if_fail (path != NULL || iter != NULL);
8377
8378   if (iter)
8379     real_iter = *iter;
8380
8381   if (path == NULL)
8382     {
8383       path = gtk_tree_model_get_path (model, iter);
8384       free_path = TRUE;
8385     }
8386   else if (iter == NULL)
8387     gtk_tree_model_get_iter (model, &real_iter, path);
8388
8389   if (_gtk_tree_view_find_node (tree_view,
8390                                 path,
8391                                 &tree,
8392                                 &node))
8393     /* We aren't actually showing the node */
8394     goto done;
8395
8396   if (tree == NULL)
8397     goto done;
8398
8399   has_child = gtk_tree_model_iter_has_child (model, &real_iter);
8400   /* Sanity check.
8401    */
8402   if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT) == has_child)
8403     goto done;
8404
8405   if (has_child)
8406     GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_PARENT);
8407   else
8408     GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_PARENT);
8409
8410   if (has_child && GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IS_LIST))
8411     {
8412       GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IS_LIST);
8413       if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS))
8414         {
8415           GList *list;
8416
8417           for (list = tree_view->priv->columns; list; list = list->next)
8418             if (GTK_TREE_VIEW_COLUMN (list->data)->visible)
8419               {
8420                 GTK_TREE_VIEW_COLUMN (list->data)->dirty = TRUE;
8421                 _gtk_tree_view_column_cell_set_dirty (GTK_TREE_VIEW_COLUMN (list->data), TRUE);
8422                 break;
8423               }
8424         }
8425       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
8426     }
8427   else
8428     {
8429       _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
8430     }
8431
8432  done:
8433   if (free_path)
8434     gtk_tree_path_free (path);
8435 }
8436
8437 static void
8438 count_children_helper (GtkRBTree *tree,
8439                        GtkRBNode *node,
8440                        gpointer   data)
8441 {
8442   if (node->children)
8443     _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, data);
8444   (*((gint *)data))++;
8445 }
8446
8447 static void
8448 check_selection_helper (GtkRBTree *tree,
8449                         GtkRBNode *node,
8450                         gpointer   data)
8451 {
8452   gint *value = (gint *)data;
8453
8454   *value = GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED);
8455
8456   if (node->children && !*value)
8457     _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, check_selection_helper, data);
8458 }
8459
8460 static void
8461 gtk_tree_view_row_deleted (GtkTreeModel *model,
8462                            GtkTreePath  *path,
8463                            gpointer      data)
8464 {
8465   GtkTreeView *tree_view = (GtkTreeView *)data;
8466   GtkRBTree *tree;
8467   GtkRBNode *node;
8468   GList *list;
8469   gint selection_changed = FALSE;
8470
8471   g_return_if_fail (path != NULL);
8472
8473   gtk_tree_row_reference_deleted (G_OBJECT (data), path);
8474
8475   if (_gtk_tree_view_find_node (tree_view, path, &tree, &node))
8476     return;
8477
8478   if (tree == NULL)
8479     return;
8480
8481   /* check if the selection has been changed */
8482   _gtk_rbtree_traverse (tree, node, G_POST_ORDER,
8483                         check_selection_helper, &selection_changed);
8484
8485   for (list = tree_view->priv->columns; list; list = list->next)
8486     if (((GtkTreeViewColumn *)list->data)->visible &&
8487         ((GtkTreeViewColumn *)list->data)->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
8488       _gtk_tree_view_column_cell_set_dirty ((GtkTreeViewColumn *)list->data, TRUE);
8489
8490   /* Ensure we don't have a dangling pointer to a dead node */
8491   ensure_unprelighted (tree_view);
8492
8493   /* Cancel editting if we've started */
8494   gtk_tree_view_stop_editing (tree_view, TRUE);
8495
8496   /* If we have a node expanded/collapsed timeout, remove it */
8497   remove_expand_collapse_timeout (tree_view);
8498
8499   if (tree_view->priv->destroy_count_func)
8500     {
8501       gint child_count = 0;
8502       if (node->children)
8503         _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, &child_count);
8504       tree_view->priv->destroy_count_func (tree_view, path, child_count, tree_view->priv->destroy_count_data);
8505     }
8506
8507   if (tree->root->count == 1)
8508     {
8509       if (tree_view->priv->tree == tree)
8510         tree_view->priv->tree = NULL;
8511
8512       _gtk_rbtree_remove (tree);
8513     }
8514   else
8515     {
8516       _gtk_rbtree_remove_node (tree, node);
8517     }
8518
8519   if (! gtk_tree_row_reference_valid (tree_view->priv->top_row))
8520     {
8521       gtk_tree_row_reference_free (tree_view->priv->top_row);
8522       tree_view->priv->top_row = NULL;
8523     }
8524
8525   install_scroll_sync_handler (tree_view);
8526
8527   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
8528
8529   if (selection_changed)
8530     g_signal_emit_by_name (tree_view->priv->selection, "changed");
8531 }
8532
8533 static void
8534 gtk_tree_view_rows_reordered (GtkTreeModel *model,
8535                               GtkTreePath  *parent,
8536                               GtkTreeIter  *iter,
8537                               gint         *new_order,
8538                               gpointer      data)
8539 {
8540   GtkTreeView *tree_view = GTK_TREE_VIEW (data);
8541   GtkRBTree *tree;
8542   GtkRBNode *node;
8543   gint len;
8544
8545   len = gtk_tree_model_iter_n_children (model, iter);
8546
8547   if (len < 2)
8548     return;
8549
8550   gtk_tree_row_reference_reordered (G_OBJECT (data),
8551                                     parent,
8552                                     iter,
8553                                     new_order);
8554
8555   if (_gtk_tree_view_find_node (tree_view,
8556                                 parent,
8557                                 &tree,
8558                                 &node))
8559     return;
8560
8561   /* We need to special case the parent path */
8562   if (tree == NULL)
8563     tree = tree_view->priv->tree;
8564   else
8565     tree = node->children;
8566
8567   if (tree == NULL)
8568     return;
8569
8570   if (tree_view->priv->edited_column)
8571     gtk_tree_view_stop_editing (tree_view, TRUE);
8572
8573   /* we need to be unprelighted */
8574   ensure_unprelighted (tree_view);
8575
8576   /* clear the timeout */
8577   cancel_arrow_animation (tree_view);
8578   
8579   _gtk_rbtree_reorder (tree, new_order, len);
8580
8581   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
8582
8583   gtk_tree_view_dy_to_top_row (tree_view);
8584 }
8585
8586
8587 /* Internal tree functions
8588  */
8589
8590
8591 static void
8592 gtk_tree_view_get_background_xrange (GtkTreeView       *tree_view,
8593                                      GtkRBTree         *tree,
8594                                      GtkTreeViewColumn *column,
8595                                      gint              *x1,
8596                                      gint              *x2)
8597 {
8598   GtkTreeViewColumn *tmp_column = NULL;
8599   gint total_width;
8600   GList *list;
8601   gboolean rtl;
8602
8603   if (x1)
8604     *x1 = 0;
8605
8606   if (x2)
8607     *x2 = 0;
8608
8609   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
8610
8611   total_width = 0;
8612   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
8613        list;
8614        list = (rtl ? list->prev : list->next))
8615     {
8616       tmp_column = list->data;
8617
8618       if (tmp_column == column)
8619         break;
8620
8621       if (tmp_column->visible)
8622         total_width += tmp_column->width;
8623     }
8624
8625   if (tmp_column != column)
8626     {
8627       g_warning (G_STRLOC": passed-in column isn't in the tree");
8628       return;
8629     }
8630
8631   if (x1)
8632     *x1 = total_width;
8633
8634   if (x2)
8635     {
8636       if (column->visible)
8637         *x2 = total_width + column->width;
8638       else
8639         *x2 = total_width; /* width of 0 */
8640     }
8641 }
8642 static void
8643 gtk_tree_view_get_arrow_xrange (GtkTreeView *tree_view,
8644                                 GtkRBTree   *tree,
8645                                 gint        *x1,
8646                                 gint        *x2)
8647 {
8648   gint x_offset = 0;
8649   GList *list;
8650   GtkTreeViewColumn *tmp_column = NULL;
8651   gint total_width;
8652   gboolean indent_expanders;
8653   gboolean rtl;
8654
8655   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
8656
8657   total_width = 0;
8658   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
8659        list;
8660        list = (rtl ? list->prev : list->next))
8661     {
8662       tmp_column = list->data;
8663
8664       if (gtk_tree_view_is_expander_column (tree_view, tmp_column))
8665         {
8666           if (rtl)
8667             x_offset = total_width + tmp_column->width - tree_view->priv->expander_size;
8668           else
8669             x_offset = total_width;
8670           break;
8671         }
8672
8673       if (tmp_column->visible)
8674         total_width += tmp_column->width;
8675     }
8676
8677   gtk_widget_style_get (GTK_WIDGET (tree_view),
8678                         "indent-expanders", &indent_expanders,
8679                         NULL);
8680
8681   if (indent_expanders)
8682     {
8683       if (rtl)
8684         x_offset -= tree_view->priv->expander_size * _gtk_rbtree_get_depth (tree);
8685       else
8686         x_offset += tree_view->priv->expander_size * _gtk_rbtree_get_depth (tree);
8687     }
8688
8689   *x1 = x_offset;
8690   
8691   if (tmp_column && tmp_column->visible)
8692     /* +1 because x2 isn't included in the range. */
8693     *x2 = *x1 + tree_view->priv->expander_size + 1;
8694   else
8695     *x2 = *x1;
8696 }
8697
8698 static void
8699 gtk_tree_view_build_tree (GtkTreeView *tree_view,
8700                           GtkRBTree   *tree,
8701                           GtkTreeIter *iter,
8702                           gint         depth,
8703                           gboolean     recurse)
8704 {
8705   GtkRBNode *temp = NULL;
8706   GtkTreePath *path = NULL;
8707   gboolean is_list = GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IS_LIST);
8708
8709   do
8710     {
8711       gtk_tree_model_ref_node (tree_view->priv->model, iter);
8712       temp = _gtk_rbtree_insert_after (tree, temp, 0, FALSE);
8713
8714       if (tree_view->priv->fixed_height > 0)
8715         {
8716           if (GTK_RBNODE_FLAG_SET (temp, GTK_RBNODE_INVALID))
8717             {
8718               _gtk_rbtree_node_set_height (tree, temp, tree_view->priv->fixed_height);
8719               _gtk_rbtree_node_mark_valid (tree, temp);
8720             }
8721         }
8722
8723       if (is_list)
8724         continue;
8725
8726       if (recurse)
8727         {
8728           GtkTreeIter child;
8729
8730           if (!path)
8731             path = gtk_tree_model_get_path (tree_view->priv->model, iter);
8732           else
8733             gtk_tree_path_next (path);
8734
8735           if (gtk_tree_model_iter_children (tree_view->priv->model, &child, iter))
8736             {
8737               gboolean expand;
8738
8739               g_signal_emit (tree_view, tree_view_signals[TEST_EXPAND_ROW], 0, iter, path, &expand);
8740
8741               if (gtk_tree_model_iter_has_child (tree_view->priv->model, iter)
8742                   && !expand)
8743                 {
8744                   temp->children = _gtk_rbtree_new ();
8745                   temp->children->parent_tree = tree;
8746                   temp->children->parent_node = temp;
8747                   gtk_tree_view_build_tree (tree_view, temp->children, &child, depth + 1, recurse);
8748                 }
8749             }
8750         }
8751
8752       if (gtk_tree_model_iter_has_child (tree_view->priv->model, iter))
8753         {
8754           if ((temp->flags&GTK_RBNODE_IS_PARENT) != GTK_RBNODE_IS_PARENT)
8755             temp->flags ^= GTK_RBNODE_IS_PARENT;
8756         }
8757     }
8758   while (gtk_tree_model_iter_next (tree_view->priv->model, iter));
8759
8760   if (path)
8761     gtk_tree_path_free (path);
8762 }
8763
8764 /* Make sure the node is visible vertically */
8765 static void
8766 gtk_tree_view_clamp_node_visible (GtkTreeView *tree_view,
8767                                   GtkRBTree   *tree,
8768                                   GtkRBNode   *node)
8769 {
8770   gint node_dy, height;
8771   GtkTreePath *path = NULL;
8772
8773   if (!GTK_WIDGET_REALIZED (tree_view))
8774     return;
8775
8776   /* just return if the node is visible, avoiding a costly expose */
8777   node_dy = _gtk_rbtree_node_find_offset (tree, node);
8778   height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
8779   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID)
8780       && node_dy >= tree_view->priv->vadjustment->value
8781       && node_dy + height <= (tree_view->priv->vadjustment->value
8782                               + tree_view->priv->vadjustment->page_size))
8783     return;
8784
8785   path = _gtk_tree_view_find_path (tree_view, tree, node);
8786   if (path)
8787     {
8788       /* We process updates because we want to clear old selected items when we scroll.
8789        * if this is removed, we get a "selection streak" at the bottom. */
8790       gdk_window_process_updates (tree_view->priv->bin_window, TRUE);
8791       gtk_tree_view_scroll_to_cell (tree_view, path, NULL, FALSE, 0.0, 0.0);
8792       gtk_tree_path_free (path);
8793     }
8794 }
8795
8796 static void
8797 gtk_tree_view_clamp_column_visible (GtkTreeView       *tree_view,
8798                                     GtkTreeViewColumn *column,
8799                                     gboolean           focus_to_cell)
8800 {
8801   gint x, width;
8802
8803   if (column == NULL)
8804     return;
8805
8806   x = column->button->allocation.x;
8807   width = column->button->allocation.width;
8808
8809   if (width > tree_view->priv->hadjustment->page_size)
8810     {
8811       /* The column is larger than the horizontal page size.  If the
8812        * column has cells which can be focussed individually, then we make
8813        * sure the cell which gets focus is fully visible (if even the
8814        * focus cell is bigger than the page size, we make sure the
8815        * left-hand side of the cell is visible).
8816        *
8817        * If the column does not have those so-called special cells, we
8818        * make sure the left-hand side of the column is visible.
8819        */
8820
8821       if (focus_to_cell && gtk_tree_view_has_special_cell (tree_view))
8822         {
8823           GtkTreePath *cursor_path;
8824           GdkRectangle background_area, cell_area, focus_area;
8825
8826           cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
8827
8828           gtk_tree_view_get_cell_area (tree_view,
8829                                        cursor_path, column, &cell_area);
8830           gtk_tree_view_get_background_area (tree_view,
8831                                              cursor_path, column,
8832                                              &background_area);
8833
8834           gtk_tree_path_free (cursor_path);
8835
8836           _gtk_tree_view_column_get_focus_area (column,
8837                                                 &background_area,
8838                                                 &cell_area,
8839                                                 &focus_area);
8840
8841           x = focus_area.x;
8842           width = focus_area.width;
8843
8844           if (width < tree_view->priv->hadjustment->page_size)
8845             {
8846               if ((tree_view->priv->hadjustment->value + tree_view->priv->hadjustment->page_size) < (x + width))
8847                 gtk_adjustment_set_value (tree_view->priv->hadjustment,
8848                                           x + width - tree_view->priv->hadjustment->page_size);
8849               else if (tree_view->priv->hadjustment->value > x)
8850                 gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
8851             }
8852         }
8853
8854       gtk_adjustment_set_value (tree_view->priv->hadjustment,
8855                                 CLAMP (x,
8856                                        tree_view->priv->hadjustment->lower,
8857                                        tree_view->priv->hadjustment->upper
8858                                        - tree_view->priv->hadjustment->page_size));
8859     }
8860   else
8861     {
8862       if ((tree_view->priv->hadjustment->value + tree_view->priv->hadjustment->page_size) < (x + width))
8863           gtk_adjustment_set_value (tree_view->priv->hadjustment,
8864                                     x + width - tree_view->priv->hadjustment->page_size);
8865       else if (tree_view->priv->hadjustment->value > x)
8866         gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
8867   }
8868 }
8869
8870 /* This function could be more efficient.  I'll optimize it if profiling seems
8871  * to imply that it is important */
8872 GtkTreePath *
8873 _gtk_tree_view_find_path (GtkTreeView *tree_view,
8874                           GtkRBTree   *tree,
8875                           GtkRBNode   *node)
8876 {
8877   GtkTreePath *path;
8878   GtkRBTree *tmp_tree;
8879   GtkRBNode *tmp_node, *last;
8880   gint count;
8881
8882   path = gtk_tree_path_new ();
8883
8884   g_return_val_if_fail (node != NULL, path);
8885   g_return_val_if_fail (node != tree->nil, path);
8886
8887   count = 1 + node->left->count;
8888
8889   last = node;
8890   tmp_node = node->parent;
8891   tmp_tree = tree;
8892   while (tmp_tree)
8893     {
8894       while (tmp_node != tmp_tree->nil)
8895         {
8896           if (tmp_node->right == last)
8897             count += 1 + tmp_node->left->count;
8898           last = tmp_node;
8899           tmp_node = tmp_node->parent;
8900         }
8901       gtk_tree_path_prepend_index (path, count - 1);
8902       last = tmp_tree->parent_node;
8903       tmp_tree = tmp_tree->parent_tree;
8904       if (last)
8905         {
8906           count = 1 + last->left->count;
8907           tmp_node = last->parent;
8908         }
8909     }
8910   return path;
8911 }
8912
8913 /* Returns TRUE if we ran out of tree before finding the path.  If the path is
8914  * invalid (ie. points to a node that's not in the tree), *tree and *node are
8915  * both set to NULL.
8916  */
8917 gboolean
8918 _gtk_tree_view_find_node (GtkTreeView  *tree_view,
8919                           GtkTreePath  *path,
8920                           GtkRBTree   **tree,
8921                           GtkRBNode   **node)
8922 {
8923   GtkRBNode *tmpnode = NULL;
8924   GtkRBTree *tmptree = tree_view->priv->tree;
8925   gint *indices = gtk_tree_path_get_indices (path);
8926   gint depth = gtk_tree_path_get_depth (path);
8927   gint i = 0;
8928
8929   *node = NULL;
8930   *tree = NULL;
8931
8932   if (depth == 0 || tmptree == NULL)
8933     return FALSE;
8934   do
8935     {
8936       tmpnode = _gtk_rbtree_find_count (tmptree, indices[i] + 1);
8937       ++i;
8938       if (tmpnode == NULL)
8939         {
8940           *tree = NULL;
8941           *node = NULL;
8942           return FALSE;
8943         }
8944       if (i >= depth)
8945         {
8946           *tree = tmptree;
8947           *node = tmpnode;
8948           return FALSE;
8949         }
8950       *tree = tmptree;
8951       *node = tmpnode;
8952       tmptree = tmpnode->children;
8953       if (tmptree == NULL)
8954         return TRUE;
8955     }
8956   while (1);
8957 }
8958
8959 static gboolean
8960 gtk_tree_view_is_expander_column (GtkTreeView       *tree_view,
8961                                   GtkTreeViewColumn *column)
8962 {
8963   GList *list;
8964
8965   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IS_LIST))
8966     return FALSE;
8967
8968   if (tree_view->priv->expander_column != NULL)
8969     {
8970       if (tree_view->priv->expander_column == column)
8971         return TRUE;
8972       return FALSE;
8973     }
8974   else
8975     {
8976       for (list = tree_view->priv->columns;
8977            list;
8978            list = list->next)
8979         if (((GtkTreeViewColumn *)list->data)->visible)
8980           break;
8981       if (list && list->data == column)
8982         return TRUE;
8983     }
8984   return FALSE;
8985 }
8986
8987 static void
8988 gtk_tree_view_add_move_binding (GtkBindingSet  *binding_set,
8989                                 guint           keyval,
8990                                 guint           modmask,
8991                                 gboolean        add_shifted_binding,
8992                                 GtkMovementStep step,
8993                                 gint            count)
8994 {
8995   
8996   gtk_binding_entry_add_signal (binding_set, keyval, modmask,
8997                                 "move-cursor", 2,
8998                                 G_TYPE_ENUM, step,
8999                                 G_TYPE_INT, count);
9000
9001   if (add_shifted_binding)
9002     gtk_binding_entry_add_signal (binding_set, keyval, GDK_SHIFT_MASK,
9003                                   "move-cursor", 2,
9004                                   G_TYPE_ENUM, step,
9005                                   G_TYPE_INT, count);
9006
9007   if ((modmask & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
9008    return;
9009
9010   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK | GDK_SHIFT_MASK,
9011                                 "move-cursor", 2,
9012                                 G_TYPE_ENUM, step,
9013                                 G_TYPE_INT, count);
9014
9015   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK,
9016                                 "move-cursor", 2,
9017                                 G_TYPE_ENUM, step,
9018                                 G_TYPE_INT, count);
9019 }
9020
9021 static gint
9022 gtk_tree_view_unref_tree_helper (GtkTreeModel *model,
9023                                  GtkTreeIter  *iter,
9024                                  GtkRBTree    *tree,
9025                                  GtkRBNode    *node)
9026 {
9027   gint retval = FALSE;
9028   do
9029     {
9030       g_return_val_if_fail (node != NULL, FALSE);
9031
9032       if (node->children)
9033         {
9034           GtkTreeIter child;
9035           GtkRBTree *new_tree;
9036           GtkRBNode *new_node;
9037
9038           new_tree = node->children;
9039           new_node = new_tree->root;
9040
9041           while (new_node && new_node->left != new_tree->nil)
9042             new_node = new_node->left;
9043
9044           if (!gtk_tree_model_iter_children (model, &child, iter))
9045             return FALSE;
9046
9047           retval = retval || gtk_tree_view_unref_tree_helper (model, &child, new_tree, new_node);
9048         }
9049
9050       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
9051         retval = TRUE;
9052       gtk_tree_model_unref_node (model, iter);
9053       node = _gtk_rbtree_next (tree, node);
9054     }
9055   while (gtk_tree_model_iter_next (model, iter));
9056
9057   return retval;
9058 }
9059
9060 static gint
9061 gtk_tree_view_unref_and_check_selection_tree (GtkTreeView *tree_view,
9062                                               GtkRBTree   *tree)
9063 {
9064   GtkTreeIter iter;
9065   GtkTreePath *path;
9066   GtkRBNode *node;
9067   gint retval;
9068
9069   if (!tree)
9070     return FALSE;
9071
9072   node = tree->root;
9073   while (node && node->left != tree->nil)
9074     node = node->left;
9075
9076   g_return_val_if_fail (node != NULL, FALSE);
9077   path = _gtk_tree_view_find_path (tree_view, tree, node);
9078   gtk_tree_model_get_iter (GTK_TREE_MODEL (tree_view->priv->model),
9079                            &iter, path);
9080   retval = gtk_tree_view_unref_tree_helper (GTK_TREE_MODEL (tree_view->priv->model), &iter, tree, node);
9081   gtk_tree_path_free (path);
9082
9083   return retval;
9084 }
9085
9086 static void
9087 gtk_tree_view_set_column_drag_info (GtkTreeView       *tree_view,
9088                                     GtkTreeViewColumn *column)
9089 {
9090   GtkTreeViewColumn *left_column;
9091   GtkTreeViewColumn *cur_column = NULL;
9092   GtkTreeViewColumnReorder *reorder;
9093   gboolean rtl;
9094   GList *tmp_list;
9095   gint left;
9096
9097   /* We want to precalculate the motion list such that we know what column slots
9098    * are available.
9099    */
9100   left_column = NULL;
9101   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
9102
9103   /* First, identify all possible drop spots */
9104   if (rtl)
9105     tmp_list = g_list_last (tree_view->priv->columns);
9106   else
9107     tmp_list = g_list_first (tree_view->priv->columns);
9108
9109   while (tmp_list)
9110     {
9111       cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
9112       tmp_list = rtl?g_list_previous (tmp_list):g_list_next (tmp_list);
9113
9114       if (cur_column->visible == FALSE)
9115         continue;
9116
9117       /* If it's not the column moving and func tells us to skip over the column, we continue. */
9118       if (left_column != column && cur_column != column &&
9119           tree_view->priv->column_drop_func &&
9120           ! tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
9121         {
9122           left_column = cur_column;
9123           continue;
9124         }
9125       reorder = g_slice_new0 (GtkTreeViewColumnReorder);
9126       reorder->left_column = left_column;
9127       left_column = reorder->right_column = cur_column;
9128
9129       tree_view->priv->column_drag_info = g_list_append (tree_view->priv->column_drag_info, reorder);
9130     }
9131
9132   /* Add the last one */
9133   if (tree_view->priv->column_drop_func == NULL ||
9134       ((left_column != column) &&
9135        tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data)))
9136     {
9137       reorder = g_slice_new0 (GtkTreeViewColumnReorder);
9138       reorder->left_column = left_column;
9139       reorder->right_column = NULL;
9140       tree_view->priv->column_drag_info = g_list_append (tree_view->priv->column_drag_info, reorder);
9141     }
9142
9143   /* We quickly check to see if it even makes sense to reorder columns. */
9144   /* If there is nothing that can be moved, then we return */
9145
9146   if (tree_view->priv->column_drag_info == NULL)
9147     return;
9148
9149   /* We know there are always 2 slots possbile, as you can always return column. */
9150   /* If that's all there is, return */
9151   if (tree_view->priv->column_drag_info->next == NULL || 
9152       (tree_view->priv->column_drag_info->next->next == NULL &&
9153        ((GtkTreeViewColumnReorder *)tree_view->priv->column_drag_info->data)->right_column == column &&
9154        ((GtkTreeViewColumnReorder *)tree_view->priv->column_drag_info->next->data)->left_column == column))
9155     {
9156       for (tmp_list = tree_view->priv->column_drag_info; tmp_list; tmp_list = tmp_list->next)
9157         g_slice_free (GtkTreeViewColumnReorder, tmp_list->data);
9158       g_list_free (tree_view->priv->column_drag_info);
9159       tree_view->priv->column_drag_info = NULL;
9160       return;
9161     }
9162   /* We fill in the ranges for the columns, now that we've isolated them */
9163   left = - TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER (tree_view);
9164
9165   for (tmp_list = tree_view->priv->column_drag_info; tmp_list; tmp_list = tmp_list->next)
9166     {
9167       reorder = (GtkTreeViewColumnReorder *) tmp_list->data;
9168
9169       reorder->left_align = left;
9170       if (tmp_list->next != NULL)
9171         {
9172           g_assert (tmp_list->next->data);
9173           left = reorder->right_align = (reorder->right_column->button->allocation.x +
9174                                          reorder->right_column->button->allocation.width +
9175                                          ((GtkTreeViewColumnReorder *)tmp_list->next->data)->left_column->button->allocation.x)/2;
9176         }
9177       else
9178         {
9179           gint width;
9180
9181           gdk_drawable_get_size (tree_view->priv->header_window, &width, NULL);
9182           reorder->right_align = width + TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER (tree_view);
9183         }
9184     }
9185 }
9186
9187 void
9188 _gtk_tree_view_column_start_drag (GtkTreeView       *tree_view,
9189                                   GtkTreeViewColumn *column)
9190 {
9191   GdkEvent *send_event;
9192   GtkAllocation allocation;
9193   gint x, y, width, height;
9194   GdkScreen *screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
9195   GdkDisplay *display = gdk_screen_get_display (screen);
9196
9197   g_return_if_fail (tree_view->priv->column_drag_info == NULL);
9198   g_return_if_fail (tree_view->priv->cur_reorder == NULL);
9199
9200   gtk_tree_view_set_column_drag_info (tree_view, column);
9201
9202   if (tree_view->priv->column_drag_info == NULL)
9203     return;
9204
9205   if (tree_view->priv->drag_window == NULL)
9206     {
9207       GdkWindowAttr attributes;
9208       guint attributes_mask;
9209
9210       attributes.window_type = GDK_WINDOW_CHILD;
9211       attributes.wclass = GDK_INPUT_OUTPUT;
9212       attributes.x = column->button->allocation.x;
9213       attributes.y = 0;
9214       attributes.width = column->button->allocation.width;
9215       attributes.height = column->button->allocation.height;
9216       attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
9217       attributes.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
9218       attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
9219       attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
9220
9221       tree_view->priv->drag_window = gdk_window_new (tree_view->priv->bin_window,
9222                                                      &attributes,
9223                                                      attributes_mask);
9224       gdk_window_set_user_data (tree_view->priv->drag_window, GTK_WIDGET (tree_view));
9225     }
9226
9227   gdk_display_pointer_ungrab (display, GDK_CURRENT_TIME);
9228   gdk_display_keyboard_ungrab (display, GDK_CURRENT_TIME);
9229
9230   gtk_grab_remove (column->button);
9231
9232   send_event = gdk_event_new (GDK_LEAVE_NOTIFY);
9233   send_event->crossing.send_event = TRUE;
9234   send_event->crossing.window = g_object_ref (GTK_BUTTON (column->button)->event_window);
9235   send_event->crossing.subwindow = NULL;
9236   send_event->crossing.detail = GDK_NOTIFY_ANCESTOR;
9237   send_event->crossing.time = GDK_CURRENT_TIME;
9238
9239   gtk_propagate_event (column->button, send_event);
9240   gdk_event_free (send_event);
9241
9242   send_event = gdk_event_new (GDK_BUTTON_RELEASE);
9243   send_event->button.window = g_object_ref (gdk_screen_get_root_window (screen));
9244   send_event->button.send_event = TRUE;
9245   send_event->button.time = GDK_CURRENT_TIME;
9246   send_event->button.x = -1;
9247   send_event->button.y = -1;
9248   send_event->button.axes = NULL;
9249   send_event->button.state = 0;
9250   send_event->button.button = 1;
9251   send_event->button.device = gdk_display_get_core_pointer (display);
9252   send_event->button.x_root = 0;
9253   send_event->button.y_root = 0;
9254
9255   gtk_propagate_event (column->button, send_event);
9256   gdk_event_free (send_event);
9257
9258   /* Kids, don't try this at home */
9259   g_object_ref (column->button);
9260   gtk_container_remove (GTK_CONTAINER (tree_view), column->button);
9261   gtk_widget_set_parent_window (column->button, tree_view->priv->drag_window);
9262   gtk_widget_set_parent (column->button, GTK_WIDGET (tree_view));
9263   g_object_unref (column->button);
9264
9265   tree_view->priv->drag_column_x = column->button->allocation.x;
9266   allocation = column->button->allocation;
9267   allocation.x = 0;
9268   gtk_widget_size_allocate (column->button, &allocation);
9269   gtk_widget_set_parent_window (column->button, tree_view->priv->drag_window);
9270
9271   tree_view->priv->drag_column = column;
9272   gdk_window_show (tree_view->priv->drag_window);
9273
9274   gdk_window_get_origin (tree_view->priv->header_window, &x, &y);
9275   gdk_drawable_get_size (tree_view->priv->header_window, &width, &height);
9276
9277   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
9278   while (gtk_events_pending ())
9279     gtk_main_iteration ();
9280
9281   GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG);
9282   gdk_pointer_grab (tree_view->priv->drag_window,
9283                     FALSE,
9284                     GDK_POINTER_MOTION_MASK|GDK_BUTTON_RELEASE_MASK,
9285                     NULL, NULL, GDK_CURRENT_TIME);
9286   gdk_keyboard_grab (tree_view->priv->drag_window,
9287                      FALSE,
9288                      GDK_CURRENT_TIME);
9289 }
9290
9291 static void
9292 gtk_tree_view_queue_draw_arrow (GtkTreeView        *tree_view,
9293                                 GtkRBTree          *tree,
9294                                 GtkRBNode          *node,
9295                                 const GdkRectangle *clip_rect)
9296 {
9297   GdkRectangle rect;
9298
9299   if (!GTK_WIDGET_REALIZED (tree_view))
9300     return;
9301
9302   rect.x = 0;
9303   rect.width = MAX (tree_view->priv->expander_size, MAX (tree_view->priv->width, GTK_WIDGET (tree_view)->allocation.width));
9304
9305   rect.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
9306   rect.height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
9307
9308   if (clip_rect)
9309     {
9310       GdkRectangle new_rect;
9311
9312       gdk_rectangle_intersect (clip_rect, &rect, &new_rect);
9313
9314       gdk_window_invalidate_rect (tree_view->priv->bin_window, &new_rect, TRUE);
9315     }
9316   else
9317     {
9318       gdk_window_invalidate_rect (tree_view->priv->bin_window, &rect, TRUE);
9319     }
9320 }
9321
9322 void
9323 _gtk_tree_view_queue_draw_node (GtkTreeView        *tree_view,
9324                                 GtkRBTree          *tree,
9325                                 GtkRBNode          *node,
9326                                 const GdkRectangle *clip_rect)
9327 {
9328   GdkRectangle rect;
9329
9330   if (!GTK_WIDGET_REALIZED (tree_view))
9331     return;
9332
9333   rect.x = 0;
9334   rect.width = MAX (tree_view->priv->width, GTK_WIDGET (tree_view)->allocation.width);
9335
9336   rect.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
9337   rect.height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
9338
9339   if (clip_rect)
9340     {
9341       GdkRectangle new_rect;
9342
9343       gdk_rectangle_intersect (clip_rect, &rect, &new_rect);
9344
9345       gdk_window_invalidate_rect (tree_view->priv->bin_window, &new_rect, TRUE);
9346     }
9347   else
9348     {
9349       gdk_window_invalidate_rect (tree_view->priv->bin_window, &rect, TRUE);
9350     }
9351 }
9352
9353 static void
9354 gtk_tree_view_queue_draw_path (GtkTreeView        *tree_view,
9355                                GtkTreePath        *path,
9356                                const GdkRectangle *clip_rect)
9357 {
9358   GtkRBTree *tree = NULL;
9359   GtkRBNode *node = NULL;
9360
9361   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
9362
9363   if (tree)
9364     _gtk_tree_view_queue_draw_node (tree_view, tree, node, clip_rect);
9365 }
9366
9367 /* x and y are the mouse position
9368  */
9369 static void
9370 gtk_tree_view_draw_arrow (GtkTreeView *tree_view,
9371                           GtkRBTree   *tree,
9372                           GtkRBNode   *node,
9373                           /* in bin_window coordinates */
9374                           gint         x,
9375                           gint         y)
9376 {
9377   GdkRectangle area;
9378   GtkStateType state;
9379   GtkWidget *widget;
9380   gint x_offset = 0;
9381   gint x2;
9382   gint vertical_separator;
9383   gint expander_size;
9384   GtkExpanderStyle expander_style;
9385
9386   gtk_widget_style_get (GTK_WIDGET (tree_view),
9387                         "vertical-separator", &vertical_separator,
9388                         NULL);
9389   expander_size = tree_view->priv->expander_size - EXPANDER_EXTRA_PADDING;
9390
9391   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
9392     return;
9393
9394   widget = GTK_WIDGET (tree_view);
9395
9396   gtk_tree_view_get_arrow_xrange (tree_view, tree, &x_offset, &x2);
9397
9398   area.x = x_offset;
9399   area.y = CELL_FIRST_PIXEL (tree_view, tree, node, vertical_separator);
9400   area.width = expander_size + 2;
9401   area.height = MAX (CELL_HEIGHT (node, vertical_separator), (expander_size - vertical_separator));
9402
9403   if (GTK_WIDGET_STATE (tree_view) == GTK_STATE_INSENSITIVE)
9404     {
9405       state = GTK_STATE_INSENSITIVE;
9406     }
9407   else if (node == tree_view->priv->button_pressed_node)
9408     {
9409       if (x >= area.x && x <= (area.x + area.width) &&
9410           y >= area.y && y <= (area.y + area.height))
9411         state = GTK_STATE_ACTIVE;
9412       else
9413         state = GTK_STATE_NORMAL;
9414     }
9415   else
9416     {
9417       if (node == tree_view->priv->prelight_node &&
9418           GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT))
9419         state = GTK_STATE_PRELIGHT;
9420       else
9421         state = GTK_STATE_NORMAL;
9422     }
9423
9424   if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_EXPANDED))
9425     expander_style = GTK_EXPANDER_SEMI_EXPANDED;
9426   else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_COLLAPSED))
9427     expander_style = GTK_EXPANDER_SEMI_COLLAPSED;
9428   else if (node->children != NULL)
9429     expander_style = GTK_EXPANDER_EXPANDED;
9430   else
9431     expander_style = GTK_EXPANDER_COLLAPSED;
9432
9433   gtk_paint_expander (widget->style,
9434                       tree_view->priv->bin_window,
9435                       state,
9436                       &area,
9437                       widget,
9438                       "treeview",
9439                       area.x + area.width / 2,
9440                       area.y + area.height / 2,
9441                       expander_style);
9442 }
9443
9444 static void
9445 gtk_tree_view_focus_to_cursor (GtkTreeView *tree_view)
9446
9447 {
9448   GtkTreePath *cursor_path;
9449
9450   if ((tree_view->priv->tree == NULL) ||
9451       (! GTK_WIDGET_REALIZED (tree_view)))
9452     return;
9453
9454   cursor_path = NULL;
9455   if (tree_view->priv->cursor)
9456     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
9457
9458   if (cursor_path == NULL)
9459     {
9460       /* Consult the selection before defaulting to the
9461        * first focusable element
9462        */
9463       GList *selected_rows;
9464       GtkTreeModel *model;
9465       GtkTreeSelection *selection;
9466
9467       selection = gtk_tree_view_get_selection (tree_view);
9468       selected_rows = gtk_tree_selection_get_selected_rows (selection, &model);
9469
9470       if (selected_rows)
9471         {
9472           cursor_path = gtk_tree_path_copy((const GtkTreePath *)(selected_rows->data));
9473           g_list_foreach (selected_rows, (GFunc)gtk_tree_path_free, NULL);
9474           g_list_free (selected_rows);
9475         }
9476       else
9477         {
9478           cursor_path = gtk_tree_path_new_first ();
9479           search_first_focusable_path (tree_view, &cursor_path,
9480                                        TRUE, NULL, NULL);
9481         }
9482
9483       gtk_tree_row_reference_free (tree_view->priv->cursor);
9484       tree_view->priv->cursor = NULL;
9485
9486       if (cursor_path)
9487         {
9488           if (tree_view->priv->selection->type == GTK_SELECTION_MULTIPLE)
9489             gtk_tree_view_real_set_cursor (tree_view, cursor_path, FALSE, FALSE);
9490           else
9491             gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE);
9492         }
9493     }
9494
9495   if (cursor_path)
9496     {
9497       GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
9498
9499       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
9500       gtk_tree_path_free (cursor_path);
9501
9502       if (tree_view->priv->focus_column == NULL)
9503         {
9504           GList *list;
9505           for (list = tree_view->priv->columns; list; list = list->next)
9506             {
9507               if (GTK_TREE_VIEW_COLUMN (list->data)->visible)
9508                 {
9509                   tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (list->data);
9510                   break;
9511                 }
9512             }
9513         }
9514     }
9515 }
9516
9517 static void
9518 gtk_tree_view_move_cursor_up_down (GtkTreeView *tree_view,
9519                                    gint         count)
9520 {
9521   gint selection_count;
9522   GtkRBTree *cursor_tree = NULL;
9523   GtkRBNode *cursor_node = NULL;
9524   GtkRBTree *new_cursor_tree = NULL;
9525   GtkRBNode *new_cursor_node = NULL;
9526   GtkTreePath *cursor_path = NULL;
9527   gboolean grab_focus = TRUE;
9528   gboolean selectable;
9529
9530   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
9531     return;
9532
9533   cursor_path = NULL;
9534   if (!gtk_tree_row_reference_valid (tree_view->priv->cursor))
9535     /* FIXME: we lost the cursor; should we get the first? */
9536     return;
9537
9538   cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
9539   _gtk_tree_view_find_node (tree_view, cursor_path,
9540                             &cursor_tree, &cursor_node);
9541
9542   if (cursor_tree == NULL)
9543     /* FIXME: we lost the cursor; should we get the first? */
9544     return;
9545
9546   selection_count = gtk_tree_selection_count_selected_rows (tree_view->priv->selection);
9547   selectable = _gtk_tree_selection_row_is_selectable (tree_view->priv->selection,
9548                                                       cursor_node,
9549                                                       cursor_path);
9550
9551   if (selection_count == 0
9552       && tree_view->priv->selection->type != GTK_SELECTION_NONE
9553       && !tree_view->priv->ctrl_pressed
9554       && selectable)
9555     {
9556       /* Don't move the cursor, but just select the current node */
9557       new_cursor_tree = cursor_tree;
9558       new_cursor_node = cursor_node;
9559     }
9560   else
9561     {
9562       if (count == -1)
9563         _gtk_rbtree_prev_full (cursor_tree, cursor_node,
9564                                &new_cursor_tree, &new_cursor_node);
9565       else
9566         _gtk_rbtree_next_full (cursor_tree, cursor_node,
9567                                &new_cursor_tree, &new_cursor_node);
9568     }
9569
9570   gtk_tree_path_free (cursor_path);
9571
9572   if (new_cursor_node)
9573     {
9574       cursor_path = _gtk_tree_view_find_path (tree_view,
9575                                               new_cursor_tree, new_cursor_node);
9576
9577       search_first_focusable_path (tree_view, &cursor_path,
9578                                    (count != -1),
9579                                    &new_cursor_tree,
9580                                    &new_cursor_node);
9581
9582       if (cursor_path)
9583         gtk_tree_path_free (cursor_path);
9584     }
9585
9586   /*
9587    * If the list has only one item and multi-selection is set then select
9588    * the row (if not yet selected).
9589    */
9590   if (tree_view->priv->selection->type == GTK_SELECTION_MULTIPLE &&
9591       new_cursor_node == NULL)
9592     {
9593       if (count == -1)
9594         _gtk_rbtree_next_full (cursor_tree, cursor_node,
9595                                &new_cursor_tree, &new_cursor_node);
9596       else
9597         _gtk_rbtree_prev_full (cursor_tree, cursor_node,
9598                                &new_cursor_tree, &new_cursor_node);
9599
9600       if (new_cursor_node == NULL
9601           && !GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_SELECTED))
9602         {
9603           new_cursor_node = cursor_node;
9604           new_cursor_tree = cursor_tree;
9605         }
9606       else
9607         {
9608           new_cursor_node = NULL;
9609         }
9610     }
9611
9612   if (new_cursor_node)
9613     {
9614       cursor_path = _gtk_tree_view_find_path (tree_view, new_cursor_tree, new_cursor_node);
9615       gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, TRUE);
9616       gtk_tree_path_free (cursor_path);
9617     }
9618   else
9619     {
9620       gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
9621
9622       if (!tree_view->priv->shift_pressed)
9623         {
9624           if (! gtk_widget_keynav_failed (GTK_WIDGET (tree_view),
9625                                           count < 0 ?
9626                                           GTK_DIR_UP : GTK_DIR_DOWN))
9627             {
9628               GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (tree_view));
9629
9630               if (toplevel)
9631                 gtk_widget_child_focus (toplevel,
9632                                         count < 0 ?
9633                                         GTK_DIR_TAB_BACKWARD :
9634                                         GTK_DIR_TAB_FORWARD);
9635
9636               grab_focus = FALSE;
9637             }
9638         }
9639       else
9640         {
9641           gtk_widget_error_bell (GTK_WIDGET (tree_view));
9642         }
9643     }
9644
9645   if (grab_focus)
9646     gtk_widget_grab_focus (GTK_WIDGET (tree_view));
9647 }
9648
9649 static void
9650 gtk_tree_view_move_cursor_page_up_down (GtkTreeView *tree_view,
9651                                         gint         count)
9652 {
9653   GtkRBTree *cursor_tree = NULL;
9654   GtkRBNode *cursor_node = NULL;
9655   GtkTreePath *old_cursor_path = NULL;
9656   GtkTreePath *cursor_path = NULL;
9657   GtkRBTree *start_cursor_tree = NULL;
9658   GtkRBNode *start_cursor_node = NULL;
9659   gint y;
9660   gint window_y;
9661   gint vertical_separator;
9662
9663   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
9664     return;
9665
9666   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
9667     old_cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
9668   else
9669     /* This is sorta weird.  Focus in should give us a cursor */
9670     return;
9671
9672   gtk_widget_style_get (GTK_WIDGET (tree_view), "vertical-separator", &vertical_separator, NULL);
9673   _gtk_tree_view_find_node (tree_view, old_cursor_path,
9674                             &cursor_tree, &cursor_node);
9675
9676   if (cursor_tree == NULL)
9677     {
9678       /* FIXME: we lost the cursor.  Should we try to get one? */
9679       gtk_tree_path_free (old_cursor_path);
9680       return;
9681     }
9682   g_return_if_fail (cursor_node != NULL);
9683
9684   y = _gtk_rbtree_node_find_offset (cursor_tree, cursor_node);
9685   window_y = RBTREE_Y_TO_TREE_WINDOW_Y (tree_view, y);
9686   y += tree_view->priv->cursor_offset;
9687   y += count * (int)tree_view->priv->vadjustment->page_increment;
9688   y = CLAMP (y, (gint)tree_view->priv->vadjustment->lower,  (gint)tree_view->priv->vadjustment->upper - vertical_separator);
9689
9690   if (y >= tree_view->priv->height)
9691     y = tree_view->priv->height - 1;
9692
9693   tree_view->priv->cursor_offset =
9694     _gtk_rbtree_find_offset (tree_view->priv->tree, y,
9695                              &cursor_tree, &cursor_node);
9696
9697   if (tree_view->priv->cursor_offset > BACKGROUND_HEIGHT (cursor_node))
9698     {
9699       _gtk_rbtree_next_full (cursor_tree, cursor_node,
9700                              &cursor_tree, &cursor_node);
9701       tree_view->priv->cursor_offset -= BACKGROUND_HEIGHT (cursor_node);
9702     }
9703
9704   y -= tree_view->priv->cursor_offset;
9705   cursor_path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
9706
9707   start_cursor_tree = cursor_tree;
9708   start_cursor_node = cursor_node;
9709
9710   if (! search_first_focusable_path (tree_view, &cursor_path,
9711                                      (count != -1),
9712                                      &cursor_tree, &cursor_node))
9713     {
9714       /* It looks like we reached the end of the view without finding
9715        * a focusable row.  We will step backwards to find the last
9716        * focusable row.
9717        */
9718       cursor_tree = start_cursor_tree;
9719       cursor_node = start_cursor_node;
9720       cursor_path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
9721
9722       search_first_focusable_path (tree_view, &cursor_path,
9723                                    (count == -1),
9724                                    &cursor_tree, &cursor_node);
9725     }
9726
9727   if (!cursor_path)
9728     goto cleanup;
9729
9730   /* update y */
9731   y = _gtk_rbtree_node_find_offset (cursor_tree, cursor_node);
9732
9733   gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE);
9734
9735   y -= window_y;
9736   gtk_tree_view_scroll_to_point (tree_view, -1, y);
9737   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
9738   _gtk_tree_view_queue_draw_node (tree_view, cursor_tree, cursor_node, NULL);
9739
9740   if (!gtk_tree_path_compare (old_cursor_path, cursor_path))
9741     gtk_widget_error_bell (GTK_WIDGET (tree_view));
9742
9743   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
9744
9745 cleanup:
9746   gtk_tree_path_free (old_cursor_path);
9747   gtk_tree_path_free (cursor_path);
9748 }
9749
9750 static void
9751 gtk_tree_view_move_cursor_left_right (GtkTreeView *tree_view,
9752                                       gint         count)
9753 {
9754   GtkRBTree *cursor_tree = NULL;
9755   GtkRBNode *cursor_node = NULL;
9756   GtkTreePath *cursor_path = NULL;
9757   GtkTreeViewColumn *column;
9758   GtkTreeIter iter;
9759   GList *list;
9760   gboolean found_column = FALSE;
9761   gboolean rtl;
9762
9763   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
9764
9765   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
9766     return;
9767
9768   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
9769     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
9770   else
9771     return;
9772
9773   _gtk_tree_view_find_node (tree_view, cursor_path, &cursor_tree, &cursor_node);
9774   if (cursor_tree == NULL)
9775     return;
9776   if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path) == FALSE)
9777     {
9778       gtk_tree_path_free (cursor_path);
9779       return;
9780     }
9781   gtk_tree_path_free (cursor_path);
9782
9783   list = rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns);
9784   if (tree_view->priv->focus_column)
9785     {
9786       for (; list; list = (rtl ? list->prev : list->next))
9787         {
9788           if (list->data == tree_view->priv->focus_column)
9789             break;
9790         }
9791     }
9792
9793   while (list)
9794     {
9795       gboolean left, right;
9796
9797       column = list->data;
9798       if (column->visible == FALSE)
9799         goto loop_end;
9800
9801       gtk_tree_view_column_cell_set_cell_data (column,
9802                                                tree_view->priv->model,
9803                                                &iter,
9804                                                GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_PARENT),
9805                                                cursor_node->children?TRUE:FALSE);
9806
9807       if (rtl)
9808         {
9809           right = list->prev ? TRUE : FALSE;
9810           left = list->next ? TRUE : FALSE;
9811         }
9812       else
9813         {
9814           left = list->prev ? TRUE : FALSE;
9815           right = list->next ? TRUE : FALSE;
9816         }
9817
9818       if (_gtk_tree_view_column_cell_focus (column, count, left, right))
9819         {
9820           tree_view->priv->focus_column = column;
9821           found_column = TRUE;
9822           break;
9823         }
9824     loop_end:
9825       if (count == 1)
9826         list = rtl ? list->prev : list->next;
9827       else
9828         list = rtl ? list->next : list->prev;
9829     }
9830
9831   if (found_column)
9832     {
9833       if (!gtk_tree_view_has_special_cell (tree_view))
9834         _gtk_tree_view_queue_draw_node (tree_view,
9835                                         cursor_tree,
9836                                         cursor_node,
9837                                         NULL);
9838       g_signal_emit (tree_view, tree_view_signals[CURSOR_CHANGED], 0);
9839       gtk_widget_grab_focus (GTK_WIDGET (tree_view));
9840     }
9841   else
9842     {
9843       gtk_widget_error_bell (GTK_WIDGET (tree_view));
9844     }
9845
9846   gtk_tree_view_clamp_column_visible (tree_view,
9847                                       tree_view->priv->focus_column, TRUE);
9848 }
9849
9850 static void
9851 gtk_tree_view_move_cursor_start_end (GtkTreeView *tree_view,
9852                                      gint         count)
9853 {
9854   GtkRBTree *cursor_tree;
9855   GtkRBNode *cursor_node;
9856   GtkTreePath *path;
9857   GtkTreePath *old_path;
9858
9859   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
9860     return;
9861
9862   g_return_if_fail (tree_view->priv->tree != NULL);
9863
9864   gtk_tree_view_get_cursor (tree_view, &old_path, NULL);
9865
9866   cursor_tree = tree_view->priv->tree;
9867   cursor_node = cursor_tree->root;
9868
9869   if (count == -1)
9870     {
9871       while (cursor_node && cursor_node->left != cursor_tree->nil)
9872         cursor_node = cursor_node->left;
9873
9874       /* Now go forward to find the first focusable row. */
9875       path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
9876       search_first_focusable_path (tree_view, &path,
9877                                    TRUE, &cursor_tree, &cursor_node);
9878     }
9879   else
9880     {
9881       do
9882         {
9883           while (cursor_node && cursor_node->right != cursor_tree->nil)
9884             cursor_node = cursor_node->right;
9885           if (cursor_node->children == NULL)
9886             break;
9887
9888           cursor_tree = cursor_node->children;
9889           cursor_node = cursor_tree->root;
9890         }
9891       while (1);
9892
9893       /* Now go backwards to find last focusable row. */
9894       path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
9895       search_first_focusable_path (tree_view, &path,
9896                                    FALSE, &cursor_tree, &cursor_node);
9897     }
9898
9899   if (!path)
9900     goto cleanup;
9901
9902   if (gtk_tree_path_compare (old_path, path))
9903     {
9904       gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
9905       gtk_widget_grab_focus (GTK_WIDGET (tree_view));
9906     }
9907   else
9908     {
9909       gtk_widget_error_bell (GTK_WIDGET (tree_view));
9910     }
9911
9912 cleanup:
9913   gtk_tree_path_free (old_path);
9914   gtk_tree_path_free (path);
9915 }
9916
9917 static gboolean
9918 gtk_tree_view_real_select_all (GtkTreeView *tree_view)
9919 {
9920   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
9921     return FALSE;
9922
9923   if (tree_view->priv->selection->type != GTK_SELECTION_MULTIPLE)
9924     return FALSE;
9925
9926   gtk_tree_selection_select_all (tree_view->priv->selection);
9927
9928   return TRUE;
9929 }
9930
9931 static gboolean
9932 gtk_tree_view_real_unselect_all (GtkTreeView *tree_view)
9933 {
9934   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
9935     return FALSE;
9936
9937   if (tree_view->priv->selection->type != GTK_SELECTION_MULTIPLE)
9938     return FALSE;
9939
9940   gtk_tree_selection_unselect_all (tree_view->priv->selection);
9941
9942   return TRUE;
9943 }
9944
9945 static gboolean
9946 gtk_tree_view_real_select_cursor_row (GtkTreeView *tree_view,
9947                                       gboolean     start_editing)
9948 {
9949   GtkRBTree *new_tree = NULL;
9950   GtkRBNode *new_node = NULL;
9951   GtkRBTree *cursor_tree = NULL;
9952   GtkRBNode *cursor_node = NULL;
9953   GtkTreePath *cursor_path = NULL;
9954   GtkTreeSelectMode mode = 0;
9955
9956   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
9957     return FALSE;
9958
9959   if (tree_view->priv->cursor)
9960     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
9961
9962   if (cursor_path == NULL)
9963     return FALSE;
9964
9965   _gtk_tree_view_find_node (tree_view, cursor_path,
9966                             &cursor_tree, &cursor_node);
9967
9968   if (cursor_tree == NULL)
9969     {
9970       gtk_tree_path_free (cursor_path);
9971       return FALSE;
9972     }
9973
9974   if (!tree_view->priv->shift_pressed && start_editing &&
9975       tree_view->priv->focus_column)
9976     {
9977       if (gtk_tree_view_start_editing (tree_view, cursor_path))
9978         {
9979           gtk_tree_path_free (cursor_path);
9980           return TRUE;
9981         }
9982     }
9983
9984   if (tree_view->priv->ctrl_pressed)
9985     mode |= GTK_TREE_SELECT_MODE_TOGGLE;
9986   if (tree_view->priv->shift_pressed)
9987     mode |= GTK_TREE_SELECT_MODE_EXTEND;
9988
9989   _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
9990                                             cursor_node,
9991                                             cursor_tree,
9992                                             cursor_path,
9993                                             mode,
9994                                             FALSE);
9995
9996   /* We bail out if the original (tree, node) don't exist anymore after
9997    * handling the selection-changed callback.  We do return TRUE because
9998    * the key press has been handled at this point.
9999    */
10000   _gtk_tree_view_find_node (tree_view, cursor_path, &new_tree, &new_node);
10001
10002   if (cursor_tree != new_tree || cursor_node != new_node)
10003     return FALSE;
10004
10005   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10006
10007   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10008   _gtk_tree_view_queue_draw_node (tree_view, cursor_tree, cursor_node, NULL);
10009
10010   if (!tree_view->priv->shift_pressed)
10011     gtk_tree_view_row_activated (tree_view, cursor_path,
10012                                  tree_view->priv->focus_column);
10013     
10014   gtk_tree_path_free (cursor_path);
10015
10016   return TRUE;
10017 }
10018
10019 static gboolean
10020 gtk_tree_view_real_toggle_cursor_row (GtkTreeView *tree_view)
10021 {
10022   GtkRBTree *new_tree = NULL;
10023   GtkRBNode *new_node = NULL;
10024   GtkRBTree *cursor_tree = NULL;
10025   GtkRBNode *cursor_node = NULL;
10026   GtkTreePath *cursor_path = NULL;
10027
10028   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
10029     return FALSE;
10030
10031   cursor_path = NULL;
10032   if (tree_view->priv->cursor)
10033     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10034
10035   if (cursor_path == NULL)
10036     return FALSE;
10037
10038   _gtk_tree_view_find_node (tree_view, cursor_path,
10039                             &cursor_tree, &cursor_node);
10040   if (cursor_tree == NULL)
10041     {
10042       gtk_tree_path_free (cursor_path);
10043       return FALSE;
10044     }
10045
10046   _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
10047                                             cursor_node,
10048                                             cursor_tree,
10049                                             cursor_path,
10050                                             GTK_TREE_SELECT_MODE_TOGGLE,
10051                                             FALSE);
10052
10053   /* We bail out if the original (tree, node) don't exist anymore after
10054    * handling the selection-changed callback.  We do return TRUE because
10055    * the key press has been handled at this point.
10056    */
10057   _gtk_tree_view_find_node (tree_view, cursor_path, &new_tree, &new_node);
10058
10059   if (cursor_tree != new_tree || cursor_node != new_node)
10060     return FALSE;
10061
10062   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10063
10064   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10065   gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10066   gtk_tree_path_free (cursor_path);
10067
10068   return TRUE;
10069 }
10070
10071 static gboolean
10072 gtk_tree_view_real_expand_collapse_cursor_row (GtkTreeView *tree_view,
10073                                                gboolean     logical,
10074                                                gboolean     expand,
10075                                                gboolean     open_all)
10076 {
10077   GtkTreePath *cursor_path = NULL;
10078   GtkRBTree *tree;
10079   GtkRBNode *node;
10080
10081   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
10082     return FALSE;
10083
10084   cursor_path = NULL;
10085   if (tree_view->priv->cursor)
10086     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10087
10088   if (cursor_path == NULL)
10089     return FALSE;
10090
10091   if (_gtk_tree_view_find_node (tree_view, cursor_path, &tree, &node))
10092     return FALSE;
10093
10094   /* Don't handle the event if we aren't an expander */
10095   if (!((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT))
10096     return FALSE;
10097
10098   if (!logical
10099       && gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL)
10100     expand = !expand;
10101
10102   if (expand)
10103     gtk_tree_view_real_expand_row (tree_view, cursor_path, tree, node, open_all, TRUE);
10104   else
10105     gtk_tree_view_real_collapse_row (tree_view, cursor_path, tree, node, TRUE);
10106
10107   gtk_tree_path_free (cursor_path);
10108
10109   return TRUE;
10110 }
10111
10112 static gboolean
10113 gtk_tree_view_real_select_cursor_parent (GtkTreeView *tree_view)
10114 {
10115   GtkRBTree *cursor_tree = NULL;
10116   GtkRBNode *cursor_node = NULL;
10117   GtkTreePath *cursor_path = NULL;
10118   GdkModifierType state;
10119
10120   if (! GTK_WIDGET_HAS_FOCUS (tree_view))
10121     goto out;
10122
10123   cursor_path = NULL;
10124   if (tree_view->priv->cursor)
10125     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10126
10127   if (cursor_path == NULL)
10128     goto out;
10129
10130   _gtk_tree_view_find_node (tree_view, cursor_path,
10131                             &cursor_tree, &cursor_node);
10132   if (cursor_tree == NULL)
10133     {
10134       gtk_tree_path_free (cursor_path);
10135       goto out;
10136     }
10137
10138   if (cursor_tree->parent_node)
10139     {
10140       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10141       cursor_node = cursor_tree->parent_node;
10142       cursor_tree = cursor_tree->parent_tree;
10143
10144       gtk_tree_path_up (cursor_path);
10145
10146       if (gtk_get_current_event_state (&state))
10147         {
10148           if ((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
10149             tree_view->priv->ctrl_pressed = TRUE;
10150         }
10151
10152       gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE);
10153       gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10154
10155       gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10156       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10157       gtk_tree_path_free (cursor_path);
10158
10159       tree_view->priv->ctrl_pressed = FALSE;
10160
10161       return TRUE;
10162     }
10163
10164  out:
10165
10166   tree_view->priv->search_entry_avoid_unhandled_binding = TRUE;
10167   return FALSE;
10168 }
10169
10170 static gboolean
10171 gtk_tree_view_search_entry_flush_timeout (GtkTreeView *tree_view)
10172 {
10173   gtk_tree_view_search_dialog_hide (tree_view->priv->search_window, tree_view);
10174   tree_view->priv->typeselect_flush_timeout = 0;
10175
10176   return FALSE;
10177 }
10178
10179 /* Cut and paste from gtkwindow.c */
10180 static void
10181 send_focus_change (GtkWidget *widget,
10182                    gboolean   in)
10183 {
10184   GdkEvent *fevent = gdk_event_new (GDK_FOCUS_CHANGE);
10185
10186   g_object_ref (widget);
10187    
10188  if (in)
10189     GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
10190   else
10191     GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
10192
10193   fevent->focus_change.type = GDK_FOCUS_CHANGE;
10194   fevent->focus_change.window = g_object_ref (widget->window);
10195   fevent->focus_change.in = in;
10196   
10197   gtk_widget_event (widget, fevent);
10198   
10199   g_object_notify (G_OBJECT (widget), "has-focus");
10200
10201   g_object_unref (widget);
10202   gdk_event_free (fevent);
10203 }
10204
10205 static void
10206 gtk_tree_view_ensure_interactive_directory (GtkTreeView *tree_view)
10207 {
10208   GtkWidget *frame, *vbox, *toplevel;
10209   GdkScreen *screen;
10210
10211   if (tree_view->priv->search_custom_entry_set)
10212     return;
10213
10214   toplevel = gtk_widget_get_toplevel (GTK_WIDGET (tree_view));
10215   screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
10216
10217    if (tree_view->priv->search_window != NULL)
10218      {
10219        if (GTK_WINDOW (toplevel)->group)
10220          gtk_window_group_add_window (GTK_WINDOW (toplevel)->group,
10221                                       GTK_WINDOW (tree_view->priv->search_window));
10222        else if (GTK_WINDOW (tree_view->priv->search_window)->group)
10223          gtk_window_group_remove_window (GTK_WINDOW (tree_view->priv->search_window)->group,
10224                                          GTK_WINDOW (tree_view->priv->search_window));
10225        gtk_window_set_screen (GTK_WINDOW (tree_view->priv->search_window), screen);
10226        return;
10227      }
10228    
10229   tree_view->priv->search_window = gtk_window_new (GTK_WINDOW_POPUP);
10230   gtk_window_set_screen (GTK_WINDOW (tree_view->priv->search_window), screen);
10231
10232   if (GTK_WINDOW (toplevel)->group)
10233     gtk_window_group_add_window (GTK_WINDOW (toplevel)->group,
10234                                  GTK_WINDOW (tree_view->priv->search_window));
10235
10236   gtk_window_set_type_hint (GTK_WINDOW (tree_view->priv->search_window),
10237                             GDK_WINDOW_TYPE_HINT_UTILITY);
10238   gtk_window_set_modal (GTK_WINDOW (tree_view->priv->search_window), TRUE);
10239   g_signal_connect (tree_view->priv->search_window, "delete-event",
10240                     G_CALLBACK (gtk_tree_view_search_delete_event),
10241                     tree_view);
10242   g_signal_connect (tree_view->priv->search_window, "key-press-event",
10243                     G_CALLBACK (gtk_tree_view_search_key_press_event),
10244                     tree_view);
10245   g_signal_connect (tree_view->priv->search_window, "button-press-event",
10246                     G_CALLBACK (gtk_tree_view_search_button_press_event),
10247                     tree_view);
10248   g_signal_connect (tree_view->priv->search_window, "scroll-event",
10249                     G_CALLBACK (gtk_tree_view_search_scroll_event),
10250                     tree_view);
10251
10252   frame = gtk_frame_new (NULL);
10253   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
10254   gtk_widget_show (frame);
10255   gtk_container_add (GTK_CONTAINER (tree_view->priv->search_window), frame);
10256
10257   vbox = gtk_vbox_new (FALSE, 0);
10258   gtk_widget_show (vbox);
10259   gtk_container_add (GTK_CONTAINER (frame), vbox);
10260   gtk_container_set_border_width (GTK_CONTAINER (vbox), 3);
10261
10262   /* add entry */
10263   tree_view->priv->search_entry = gtk_entry_new ();
10264   gtk_widget_show (tree_view->priv->search_entry);
10265   g_signal_connect (tree_view->priv->search_entry, "populate-popup",
10266                     G_CALLBACK (gtk_tree_view_search_disable_popdown),
10267                     tree_view);
10268   g_signal_connect (tree_view->priv->search_entry,
10269                     "activate", G_CALLBACK (gtk_tree_view_search_activate),
10270                     tree_view);
10271   g_signal_connect (GTK_ENTRY (tree_view->priv->search_entry)->im_context,
10272                     "preedit-changed",
10273                     G_CALLBACK (gtk_tree_view_search_preedit_changed),
10274                     tree_view);
10275   gtk_container_add (GTK_CONTAINER (vbox),
10276                      tree_view->priv->search_entry);
10277
10278   gtk_widget_realize (tree_view->priv->search_entry);
10279 }
10280
10281 /* Pops up the interactive search entry.  If keybinding is TRUE then the user
10282  * started this by typing the start_interactive_search keybinding.  Otherwise, it came from 
10283  */
10284 static gboolean
10285 gtk_tree_view_real_start_interactive_search (GtkTreeView *tree_view,
10286                                              gboolean     keybinding)
10287 {
10288   /* We only start interactive search if we have focus or the columns
10289    * have focus.  If one of our children have focus, we don't want to
10290    * start the search.
10291    */
10292   GList *list;
10293   gboolean found_focus = FALSE;
10294   GtkWidgetClass *entry_parent_class;
10295   
10296   if (!tree_view->priv->enable_search && !keybinding)
10297     return FALSE;
10298
10299   if (tree_view->priv->search_custom_entry_set)
10300     return FALSE;
10301
10302   if (tree_view->priv->search_window != NULL &&
10303       GTK_WIDGET_VISIBLE (tree_view->priv->search_window))
10304     return TRUE;
10305
10306   for (list = tree_view->priv->columns; list; list = list->next)
10307     {
10308       GtkTreeViewColumn *column;
10309
10310       column = list->data;
10311       if (! column->visible)
10312         continue;
10313
10314       if (GTK_WIDGET_HAS_FOCUS (column->button))
10315         {
10316           found_focus = TRUE;
10317           break;
10318         }
10319     }
10320   
10321   if (GTK_WIDGET_HAS_FOCUS (tree_view))
10322     found_focus = TRUE;
10323
10324   if (!found_focus)
10325     return FALSE;
10326
10327   if (tree_view->priv->search_column < 0)
10328     return FALSE;
10329
10330   gtk_tree_view_ensure_interactive_directory (tree_view);
10331
10332   if (keybinding)
10333     gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
10334
10335   /* done, show it */
10336   tree_view->priv->search_position_func (tree_view, tree_view->priv->search_window, tree_view->priv->search_position_user_data);
10337   gtk_widget_show (tree_view->priv->search_window);
10338   if (tree_view->priv->search_entry_changed_id == 0)
10339     {
10340       tree_view->priv->search_entry_changed_id =
10341         g_signal_connect (tree_view->priv->search_entry, "changed",
10342                           G_CALLBACK (gtk_tree_view_search_init),
10343                           tree_view);
10344     }
10345
10346   tree_view->priv->typeselect_flush_timeout =
10347     gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
10348                    (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
10349                    tree_view);
10350
10351   /* Grab focus will select all the text.  We don't want that to happen, so we
10352    * call the parent instance and bypass the selection change.  This is probably
10353    * really non-kosher. */
10354   entry_parent_class = g_type_class_peek_parent (GTK_ENTRY_GET_CLASS (tree_view->priv->search_entry));
10355   (entry_parent_class->grab_focus) (tree_view->priv->search_entry);
10356
10357   /* send focus-in event */
10358   send_focus_change (tree_view->priv->search_entry, TRUE);
10359
10360   /* search first matching iter */
10361   gtk_tree_view_search_init (tree_view->priv->search_entry, tree_view);
10362
10363   return TRUE;
10364 }
10365
10366 static gboolean
10367 gtk_tree_view_start_interactive_search (GtkTreeView *tree_view)
10368 {
10369   return gtk_tree_view_real_start_interactive_search (tree_view, TRUE);
10370 }
10371
10372 /* this function returns the new width of the column being resized given
10373  * the column and x position of the cursor; the x cursor position is passed
10374  * in as a pointer and automagicly corrected if it's beyond min/max limits
10375  */
10376 static gint
10377 gtk_tree_view_new_column_width (GtkTreeView *tree_view,
10378                                 gint       i,
10379                                 gint      *x)
10380 {
10381   GtkTreeViewColumn *column;
10382   gint width;
10383   gboolean rtl;
10384
10385   /* first translate the x position from widget->window
10386    * to clist->clist_window
10387    */
10388   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
10389   column = g_list_nth (tree_view->priv->columns, i)->data;
10390   width = rtl ? (column->button->allocation.x + column->button->allocation.width - *x) : (*x - column->button->allocation.x);
10391  
10392   /* Clamp down the value */
10393   if (column->min_width == -1)
10394     width = MAX (column->button->requisition.width,
10395                  width);
10396   else
10397     width = MAX (column->min_width,
10398                  width);
10399   if (column->max_width != -1)
10400     width = MIN (width, column->max_width);
10401
10402   *x = rtl ? (column->button->allocation.x + column->button->allocation.width - width) : (column->button->allocation.x + width);
10403  
10404   return width;
10405 }
10406
10407
10408 /* FIXME this adjust_allocation is a big cut-and-paste from
10409  * GtkCList, needs to be some "official" way to do this
10410  * factored out.
10411  */
10412 typedef struct
10413 {
10414   GdkWindow *window;
10415   int dx;
10416   int dy;
10417 } ScrollData;
10418
10419 /* The window to which widget->window is relative */
10420 #define ALLOCATION_WINDOW(widget)               \
10421    (GTK_WIDGET_NO_WINDOW (widget) ?             \
10422     (widget)->window :                          \
10423      gdk_window_get_parent ((widget)->window))
10424
10425 static void
10426 adjust_allocation_recurse (GtkWidget *widget,
10427                            gpointer   data)
10428 {
10429   ScrollData *scroll_data = data;
10430
10431   /* Need to really size allocate instead of just poking
10432    * into widget->allocation if the widget is not realized.
10433    * FIXME someone figure out why this was.
10434    */
10435   if (!GTK_WIDGET_REALIZED (widget))
10436     {
10437       if (GTK_WIDGET_VISIBLE (widget))
10438         {
10439           GdkRectangle tmp_rectangle = widget->allocation;
10440           tmp_rectangle.x += scroll_data->dx;
10441           tmp_rectangle.y += scroll_data->dy;
10442           
10443           gtk_widget_size_allocate (widget, &tmp_rectangle);
10444         }
10445     }
10446   else
10447     {
10448       if (ALLOCATION_WINDOW (widget) == scroll_data->window)
10449         {
10450           widget->allocation.x += scroll_data->dx;
10451           widget->allocation.y += scroll_data->dy;
10452           
10453           if (GTK_IS_CONTAINER (widget))
10454             gtk_container_forall (GTK_CONTAINER (widget),
10455                                   adjust_allocation_recurse,
10456                                   data);
10457         }
10458     }
10459 }
10460
10461 static void
10462 adjust_allocation (GtkWidget *widget,
10463                    int        dx,
10464                    int        dy)
10465 {
10466   ScrollData scroll_data;
10467
10468   if (GTK_WIDGET_REALIZED (widget))
10469     scroll_data.window = ALLOCATION_WINDOW (widget);
10470   else
10471     scroll_data.window = NULL;
10472     
10473   scroll_data.dx = dx;
10474   scroll_data.dy = dy;
10475   
10476   adjust_allocation_recurse (widget, &scroll_data);
10477 }
10478
10479 /* Callbacks */
10480 static void
10481 gtk_tree_view_adjustment_changed (GtkAdjustment *adjustment,
10482                                   GtkTreeView   *tree_view)
10483 {
10484   if (GTK_WIDGET_REALIZED (tree_view))
10485     {
10486       gint dy;
10487         
10488       gdk_window_move (tree_view->priv->bin_window,
10489                        - tree_view->priv->hadjustment->value,
10490                        TREE_VIEW_HEADER_HEIGHT (tree_view));
10491       gdk_window_move (tree_view->priv->header_window,
10492                        - tree_view->priv->hadjustment->value,
10493                        0);
10494       dy = tree_view->priv->dy - (int) tree_view->priv->vadjustment->value;
10495       if (dy && tree_view->priv->edited_column)
10496         {
10497           if (GTK_IS_WIDGET (tree_view->priv->edited_column->editable_widget))
10498             {
10499               GList *list;
10500               GtkWidget *widget;
10501               GtkTreeViewChild *child = NULL;
10502
10503               widget = GTK_WIDGET (tree_view->priv->edited_column->editable_widget);
10504               adjust_allocation (widget, 0, dy); 
10505               
10506               for (list = tree_view->priv->children; list; list = list->next)
10507                 {
10508                   child = (GtkTreeViewChild *)list->data;
10509                   if (child->widget == widget)
10510                     {
10511                       child->y += dy;
10512                       break;
10513                     }
10514                 }
10515             }
10516         }
10517       gdk_window_scroll (tree_view->priv->bin_window, 0, dy);
10518
10519       if (tree_view->priv->dy != (int) tree_view->priv->vadjustment->value)
10520         {
10521           /* update our dy and top_row */
10522           tree_view->priv->dy = (int) tree_view->priv->vadjustment->value;
10523
10524           if (!tree_view->priv->in_top_row_to_dy)
10525             gtk_tree_view_dy_to_top_row (tree_view);
10526         }
10527
10528       gdk_window_process_updates (tree_view->priv->header_window, TRUE);
10529       gdk_window_process_updates (tree_view->priv->bin_window, TRUE);
10530     }
10531 }
10532
10533 \f
10534
10535 /* Public methods
10536  */
10537
10538 /**
10539  * gtk_tree_view_new:
10540  *
10541  * Creates a new #GtkTreeView widget.
10542  *
10543  * Return value: A newly created #GtkTreeView widget.
10544  **/
10545 GtkWidget *
10546 gtk_tree_view_new (void)
10547 {
10548   return g_object_new (GTK_TYPE_TREE_VIEW, NULL);
10549 }
10550
10551 /**
10552  * gtk_tree_view_new_with_model:
10553  * @model: the model.
10554  *
10555  * Creates a new #GtkTreeView widget with the model initialized to @model.
10556  *
10557  * Return value: A newly created #GtkTreeView widget.
10558  **/
10559 GtkWidget *
10560 gtk_tree_view_new_with_model (GtkTreeModel *model)
10561 {
10562   return g_object_new (GTK_TYPE_TREE_VIEW, "model", model, NULL);
10563 }
10564
10565 /* Public Accessors
10566  */
10567
10568 /**
10569  * gtk_tree_view_get_model:
10570  * @tree_view: a #GtkTreeView
10571  *
10572  * Returns the model the #GtkTreeView is based on.  Returns %NULL if the
10573  * model is unset.
10574  *
10575  * Return value: A #GtkTreeModel, or %NULL if none is currently being used.
10576  **/
10577 GtkTreeModel *
10578 gtk_tree_view_get_model (GtkTreeView *tree_view)
10579 {
10580   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
10581
10582   return tree_view->priv->model;
10583 }
10584
10585 /**
10586  * gtk_tree_view_set_model:
10587  * @tree_view: A #GtkTreeNode.
10588  * @model: The model.
10589  *
10590  * Sets the model for a #GtkTreeView.  If the @tree_view already has a model
10591  * set, it will remove it before setting the new model.  If @model is %NULL, 
10592  * then it will unset the old model.
10593  **/
10594 void
10595 gtk_tree_view_set_model (GtkTreeView  *tree_view,
10596                          GtkTreeModel *model)
10597 {
10598   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
10599   g_return_if_fail (model == NULL || GTK_IS_TREE_MODEL (model));
10600
10601   if (model == tree_view->priv->model)
10602     return;
10603
10604   if (tree_view->priv->scroll_to_path)
10605     {
10606       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
10607       tree_view->priv->scroll_to_path = NULL;
10608     }
10609
10610   if (tree_view->priv->model)
10611     {
10612       GList *tmplist = tree_view->priv->columns;
10613
10614       gtk_tree_view_unref_and_check_selection_tree (tree_view, tree_view->priv->tree);
10615       gtk_tree_view_stop_editing (tree_view, TRUE);
10616
10617       remove_expand_collapse_timeout (tree_view);
10618
10619       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
10620                                             gtk_tree_view_row_changed,
10621                                             tree_view);
10622       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
10623                                             gtk_tree_view_row_inserted,
10624                                             tree_view);
10625       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
10626                                             gtk_tree_view_row_has_child_toggled,
10627                                             tree_view);
10628       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
10629                                             gtk_tree_view_row_deleted,
10630                                             tree_view);
10631       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
10632                                             gtk_tree_view_rows_reordered,
10633                                             tree_view);
10634
10635       for (; tmplist; tmplist = tmplist->next)
10636         _gtk_tree_view_column_unset_model (tmplist->data,
10637                                            tree_view->priv->model);
10638
10639       if (tree_view->priv->tree)
10640         gtk_tree_view_free_rbtree (tree_view);
10641
10642       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
10643       tree_view->priv->drag_dest_row = NULL;
10644       gtk_tree_row_reference_free (tree_view->priv->cursor);
10645       tree_view->priv->cursor = NULL;
10646       gtk_tree_row_reference_free (tree_view->priv->anchor);
10647       tree_view->priv->anchor = NULL;
10648       gtk_tree_row_reference_free (tree_view->priv->top_row);
10649       tree_view->priv->top_row = NULL;
10650       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
10651       tree_view->priv->scroll_to_path = NULL;
10652
10653       tree_view->priv->scroll_to_column = NULL;
10654
10655       g_object_unref (tree_view->priv->model);
10656
10657       tree_view->priv->search_column = -1;
10658       tree_view->priv->fixed_height_check = 0;
10659       tree_view->priv->fixed_height = -1;
10660       tree_view->priv->dy = tree_view->priv->top_row_dy = 0;
10661       tree_view->priv->last_button_x = -1;
10662       tree_view->priv->last_button_y = -1;
10663     }
10664
10665   tree_view->priv->model = model;
10666
10667   if (tree_view->priv->model)
10668     {
10669       gint i;
10670       GtkTreePath *path;
10671       GtkTreeIter iter;
10672       GtkTreeModelFlags flags;
10673
10674       if (tree_view->priv->search_column == -1)
10675         {
10676           for (i = 0; i < gtk_tree_model_get_n_columns (model); i++)
10677             {
10678               GType type = gtk_tree_model_get_column_type (model, i);
10679
10680               if (g_value_type_transformable (type, G_TYPE_STRING))
10681                 {
10682                   tree_view->priv->search_column = i;
10683                   break;
10684                 }
10685             }
10686         }
10687
10688       g_object_ref (tree_view->priv->model);
10689       g_signal_connect (tree_view->priv->model,
10690                         "row-changed",
10691                         G_CALLBACK (gtk_tree_view_row_changed),
10692                         tree_view);
10693       g_signal_connect (tree_view->priv->model,
10694                         "row-inserted",
10695                         G_CALLBACK (gtk_tree_view_row_inserted),
10696                         tree_view);
10697       g_signal_connect (tree_view->priv->model,
10698                         "row-has-child-toggled",
10699                         G_CALLBACK (gtk_tree_view_row_has_child_toggled),
10700                         tree_view);
10701       g_signal_connect (tree_view->priv->model,
10702                         "row-deleted",
10703                         G_CALLBACK (gtk_tree_view_row_deleted),
10704                         tree_view);
10705       g_signal_connect (tree_view->priv->model,
10706                         "rows-reordered",
10707                         G_CALLBACK (gtk_tree_view_rows_reordered),
10708                         tree_view);
10709
10710       flags = gtk_tree_model_get_flags (tree_view->priv->model);
10711       if ((flags & GTK_TREE_MODEL_LIST_ONLY) == GTK_TREE_MODEL_LIST_ONLY)
10712         GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_IS_LIST);
10713       else
10714         GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IS_LIST);
10715
10716       path = gtk_tree_path_new_first ();
10717       if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, path))
10718         {
10719           tree_view->priv->tree = _gtk_rbtree_new ();
10720           gtk_tree_view_build_tree (tree_view, tree_view->priv->tree, &iter, 1, FALSE);
10721         }
10722       gtk_tree_path_free (path);
10723
10724       /*  FIXME: do I need to do this? gtk_tree_view_create_buttons (tree_view); */
10725       install_presize_handler (tree_view);
10726     }
10727
10728   g_object_notify (G_OBJECT (tree_view), "model");
10729
10730   if (tree_view->priv->selection)
10731   _gtk_tree_selection_emit_changed (tree_view->priv->selection);
10732
10733   if (GTK_WIDGET_REALIZED (tree_view))
10734     gtk_widget_queue_resize (GTK_WIDGET (tree_view));
10735 }
10736
10737 /**
10738  * gtk_tree_view_get_selection:
10739  * @tree_view: A #GtkTreeView.
10740  *
10741  * Gets the #GtkTreeSelection associated with @tree_view.
10742  *
10743  * Return value: A #GtkTreeSelection object.
10744  **/
10745 GtkTreeSelection *
10746 gtk_tree_view_get_selection (GtkTreeView *tree_view)
10747 {
10748   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
10749
10750   return tree_view->priv->selection;
10751 }
10752
10753 /**
10754  * gtk_tree_view_get_hadjustment:
10755  * @tree_view: A #GtkTreeView
10756  *
10757  * Gets the #GtkAdjustment currently being used for the horizontal aspect.
10758  *
10759  * Return value: A #GtkAdjustment object, or %NULL if none is currently being
10760  * used.
10761  **/
10762 GtkAdjustment *
10763 gtk_tree_view_get_hadjustment (GtkTreeView *tree_view)
10764 {
10765   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
10766
10767   if (tree_view->priv->hadjustment == NULL)
10768     gtk_tree_view_set_hadjustment (tree_view, NULL);
10769
10770   return tree_view->priv->hadjustment;
10771 }
10772
10773 /**
10774  * gtk_tree_view_set_hadjustment:
10775  * @tree_view: A #GtkTreeView
10776  * @adjustment: The #GtkAdjustment to set, or %NULL
10777  *
10778  * Sets the #GtkAdjustment for the current horizontal aspect.
10779  **/
10780 void
10781 gtk_tree_view_set_hadjustment (GtkTreeView   *tree_view,
10782                                GtkAdjustment *adjustment)
10783 {
10784   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
10785
10786   gtk_tree_view_set_adjustments (tree_view,
10787                                  adjustment,
10788                                  tree_view->priv->vadjustment);
10789
10790   g_object_notify (G_OBJECT (tree_view), "hadjustment");
10791 }
10792
10793 /**
10794  * gtk_tree_view_get_vadjustment:
10795  * @tree_view: A #GtkTreeView
10796  *
10797  * Gets the #GtkAdjustment currently being used for the vertical aspect.
10798  *
10799  * Return value: A #GtkAdjustment object, or %NULL if none is currently being
10800  * used.
10801  **/
10802 GtkAdjustment *
10803 gtk_tree_view_get_vadjustment (GtkTreeView *tree_view)
10804 {
10805   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
10806
10807   if (tree_view->priv->vadjustment == NULL)
10808     gtk_tree_view_set_vadjustment (tree_view, NULL);
10809
10810   return tree_view->priv->vadjustment;
10811 }
10812
10813 /**
10814  * gtk_tree_view_set_vadjustment:
10815  * @tree_view: A #GtkTreeView
10816  * @adjustment: The #GtkAdjustment to set, or %NULL
10817  *
10818  * Sets the #GtkAdjustment for the current vertical aspect.
10819  **/
10820 void
10821 gtk_tree_view_set_vadjustment (GtkTreeView   *tree_view,
10822                                GtkAdjustment *adjustment)
10823 {
10824   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
10825
10826   gtk_tree_view_set_adjustments (tree_view,
10827                                  tree_view->priv->hadjustment,
10828                                  adjustment);
10829
10830   g_object_notify (G_OBJECT (tree_view), "vadjustment");
10831 }
10832
10833 /* Column and header operations */
10834
10835 /**
10836  * gtk_tree_view_get_headers_visible:
10837  * @tree_view: A #GtkTreeView.
10838  *
10839  * Returns %TRUE if the headers on the @tree_view are visible.
10840  *
10841  * Return value: Whether the headers are visible or not.
10842  **/
10843 gboolean
10844 gtk_tree_view_get_headers_visible (GtkTreeView *tree_view)
10845 {
10846   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
10847
10848   return GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE);
10849 }
10850
10851 /**
10852  * gtk_tree_view_set_headers_visible:
10853  * @tree_view: A #GtkTreeView.
10854  * @headers_visible: %TRUE if the headers are visible
10855  *
10856  * Sets the visibility state of the headers.
10857  **/
10858 void
10859 gtk_tree_view_set_headers_visible (GtkTreeView *tree_view,
10860                                    gboolean     headers_visible)
10861 {
10862   gint x, y;
10863   GList *list;
10864   GtkTreeViewColumn *column;
10865
10866   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
10867
10868   headers_visible = !! headers_visible;
10869
10870   if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE) == headers_visible)
10871     return;
10872
10873   if (headers_visible)
10874     GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE);
10875   else
10876     GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE);
10877
10878   if (GTK_WIDGET_REALIZED (tree_view))
10879     {
10880       gdk_window_get_position (tree_view->priv->bin_window, &x, &y);
10881       if (headers_visible)
10882         {
10883           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));
10884
10885           if (GTK_WIDGET_MAPPED (tree_view))
10886             gtk_tree_view_map_buttons (tree_view);
10887         }
10888       else
10889         {
10890           gdk_window_move_resize (tree_view->priv->bin_window, x, y, tree_view->priv->width, tree_view->priv->height);
10891
10892           for (list = tree_view->priv->columns; list; list = list->next)
10893             {
10894               column = list->data;
10895               gtk_widget_unmap (column->button);
10896             }
10897           gdk_window_hide (tree_view->priv->header_window);
10898         }
10899     }
10900
10901   tree_view->priv->vadjustment->page_size = GTK_WIDGET (tree_view)->allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view);
10902   tree_view->priv->vadjustment->page_increment = (GTK_WIDGET (tree_view)->allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view)) / 2;
10903   tree_view->priv->vadjustment->lower = 0;
10904   tree_view->priv->vadjustment->upper = tree_view->priv->height;
10905   gtk_adjustment_changed (tree_view->priv->vadjustment);
10906
10907   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
10908
10909   g_object_notify (G_OBJECT (tree_view), "headers-visible");
10910 }
10911
10912 /**
10913  * gtk_tree_view_columns_autosize:
10914  * @tree_view: A #GtkTreeView.
10915  *
10916  * Resizes all columns to their optimal width. Only works after the
10917  * treeview has been realized.
10918  **/
10919 void
10920 gtk_tree_view_columns_autosize (GtkTreeView *tree_view)
10921 {
10922   gboolean dirty = FALSE;
10923   GList *list;
10924   GtkTreeViewColumn *column;
10925
10926   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
10927
10928   for (list = tree_view->priv->columns; list; list = list->next)
10929     {
10930       column = list->data;
10931       if (column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
10932         continue;
10933       _gtk_tree_view_column_cell_set_dirty (column, TRUE);
10934       dirty = TRUE;
10935     }
10936
10937   if (dirty)
10938     gtk_widget_queue_resize (GTK_WIDGET (tree_view));
10939 }
10940
10941 /**
10942  * gtk_tree_view_set_headers_clickable:
10943  * @tree_view: A #GtkTreeView.
10944  * @setting: %TRUE if the columns are clickable.
10945  *
10946  * Allow the column title buttons to be clicked.
10947  **/
10948 void
10949 gtk_tree_view_set_headers_clickable (GtkTreeView *tree_view,
10950                                      gboolean   setting)
10951 {
10952   GList *list;
10953
10954   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
10955
10956   for (list = tree_view->priv->columns; list; list = list->next)
10957     gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (list->data), setting);
10958
10959   g_object_notify (G_OBJECT (tree_view), "headers-clickable");
10960 }
10961
10962
10963 /**
10964  * gtk_tree_view_get_headers_clickable:
10965  * @tree_view: A #GtkTreeView.
10966  *
10967  * Returns whether all header columns are clickable.
10968  *
10969  * Return value: %TRUE if all header columns are clickable, otherwise %FALSE
10970  *
10971  * Since: 2.10
10972  **/
10973 gboolean 
10974 gtk_tree_view_get_headers_clickable (GtkTreeView *tree_view)
10975 {
10976   GList *list;
10977   
10978   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
10979
10980   for (list = tree_view->priv->columns; list; list = list->next)
10981     if (!GTK_TREE_VIEW_COLUMN (list->data)->clickable)
10982       return FALSE;
10983
10984   return TRUE;
10985 }
10986
10987 /**
10988  * gtk_tree_view_set_rules_hint
10989  * @tree_view: a #GtkTreeView
10990  * @setting: %TRUE if the tree requires reading across rows
10991  *
10992  * This function tells GTK+ that the user interface for your
10993  * application requires users to read across tree rows and associate
10994  * cells with one another. By default, GTK+ will then render the tree
10995  * with alternating row colors. Do <emphasis>not</emphasis> use it
10996  * just because you prefer the appearance of the ruled tree; that's a
10997  * question for the theme. Some themes will draw tree rows in
10998  * alternating colors even when rules are turned off, and users who
10999  * prefer that appearance all the time can choose those themes. You
11000  * should call this function only as a <emphasis>semantic</emphasis>
11001  * hint to the theme engine that your tree makes alternating colors
11002  * useful from a functional standpoint (since it has lots of columns,
11003  * generally).
11004  *
11005  **/
11006 void
11007 gtk_tree_view_set_rules_hint (GtkTreeView  *tree_view,
11008                               gboolean      setting)
11009 {
11010   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11011
11012   setting = setting != FALSE;
11013
11014   if (tree_view->priv->has_rules != setting)
11015     {
11016       tree_view->priv->has_rules = setting;
11017       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
11018     }
11019
11020   g_object_notify (G_OBJECT (tree_view), "rules-hint");
11021 }
11022
11023 /**
11024  * gtk_tree_view_get_rules_hint
11025  * @tree_view: a #GtkTreeView
11026  *
11027  * Gets the setting set by gtk_tree_view_set_rules_hint().
11028  *
11029  * Return value: %TRUE if rules are useful for the user of this tree
11030  **/
11031 gboolean
11032 gtk_tree_view_get_rules_hint (GtkTreeView  *tree_view)
11033 {
11034   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
11035
11036   return tree_view->priv->has_rules;
11037 }
11038
11039 /* Public Column functions
11040  */
11041
11042 /**
11043  * gtk_tree_view_append_column:
11044  * @tree_view: A #GtkTreeView.
11045  * @column: The #GtkTreeViewColumn to add.
11046  *
11047  * Appends @column to the list of columns. If @tree_view has "fixed_height"
11048  * mode enabled, then @column must have its "sizing" property set to be
11049  * GTK_TREE_VIEW_COLUMN_FIXED.
11050  *
11051  * Return value: The number of columns in @tree_view after appending.
11052  **/
11053 gint
11054 gtk_tree_view_append_column (GtkTreeView       *tree_view,
11055                              GtkTreeViewColumn *column)
11056 {
11057   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11058   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
11059   g_return_val_if_fail (column->tree_view == NULL, -1);
11060
11061   return gtk_tree_view_insert_column (tree_view, column, -1);
11062 }
11063
11064
11065 /**
11066  * gtk_tree_view_remove_column:
11067  * @tree_view: A #GtkTreeView.
11068  * @column: The #GtkTreeViewColumn to remove.
11069  *
11070  * Removes @column from @tree_view.
11071  *
11072  * Return value: The number of columns in @tree_view after removing.
11073  **/
11074 gint
11075 gtk_tree_view_remove_column (GtkTreeView       *tree_view,
11076                              GtkTreeViewColumn *column)
11077 {
11078   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11079   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
11080   g_return_val_if_fail (column->tree_view == GTK_WIDGET (tree_view), -1);
11081
11082   if (tree_view->priv->focus_column == column)
11083     tree_view->priv->focus_column = NULL;
11084
11085   if (tree_view->priv->edited_column == column)
11086     {
11087       gtk_tree_view_stop_editing (tree_view, TRUE);
11088
11089       /* no need to, but just to be sure ... */
11090       tree_view->priv->edited_column = NULL;
11091     }
11092
11093   g_signal_handlers_disconnect_by_func (column,
11094                                         G_CALLBACK (column_sizing_notify),
11095                                         tree_view);
11096
11097   _gtk_tree_view_column_unset_tree_view (column);
11098
11099   tree_view->priv->columns = g_list_remove (tree_view->priv->columns, column);
11100   tree_view->priv->n_columns--;
11101
11102   if (GTK_WIDGET_REALIZED (tree_view))
11103     {
11104       GList *list;
11105
11106       _gtk_tree_view_column_unrealize_button (column);
11107       for (list = tree_view->priv->columns; list; list = list->next)
11108         {
11109           GtkTreeViewColumn *tmp_column;
11110
11111           tmp_column = GTK_TREE_VIEW_COLUMN (list->data);
11112           if (tmp_column->visible)
11113             _gtk_tree_view_column_cell_set_dirty (tmp_column, TRUE);
11114         }
11115
11116       if (tree_view->priv->n_columns == 0 &&
11117           gtk_tree_view_get_headers_visible (tree_view))
11118         gdk_window_hide (tree_view->priv->header_window);
11119
11120       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11121     }
11122
11123   g_object_unref (column);
11124   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
11125
11126   return tree_view->priv->n_columns;
11127 }
11128
11129 /**
11130  * gtk_tree_view_insert_column:
11131  * @tree_view: A #GtkTreeView.
11132  * @column: The #GtkTreeViewColumn to be inserted.
11133  * @position: The position to insert @column in.
11134  *
11135  * This inserts the @column into the @tree_view at @position.  If @position is
11136  * -1, then the column is inserted at the end. If @tree_view has
11137  * "fixed_height" mode enabled, then @column must have its "sizing" property
11138  * set to be GTK_TREE_VIEW_COLUMN_FIXED.
11139  *
11140  * Return value: The number of columns in @tree_view after insertion.
11141  **/
11142 gint
11143 gtk_tree_view_insert_column (GtkTreeView       *tree_view,
11144                              GtkTreeViewColumn *column,
11145                              gint               position)
11146 {
11147   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11148   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
11149   g_return_val_if_fail (column->tree_view == NULL, -1);
11150
11151   if (tree_view->priv->fixed_height_mode)
11152     g_return_val_if_fail (gtk_tree_view_column_get_sizing (column)
11153                           == GTK_TREE_VIEW_COLUMN_FIXED, -1);
11154
11155   g_object_ref_sink (column);
11156
11157   if (tree_view->priv->n_columns == 0 &&
11158       GTK_WIDGET_REALIZED (tree_view) &&
11159       gtk_tree_view_get_headers_visible (tree_view))
11160     {
11161       gdk_window_show (tree_view->priv->header_window);
11162     }
11163
11164   g_signal_connect (column, "notify::sizing",
11165                     G_CALLBACK (column_sizing_notify), tree_view);
11166
11167   tree_view->priv->columns = g_list_insert (tree_view->priv->columns,
11168                                             column, position);
11169   tree_view->priv->n_columns++;
11170
11171   _gtk_tree_view_column_set_tree_view (column, tree_view);
11172
11173   if (GTK_WIDGET_REALIZED (tree_view))
11174     {
11175       GList *list;
11176
11177       _gtk_tree_view_column_realize_button (column);
11178
11179       for (list = tree_view->priv->columns; list; list = list->next)
11180         {
11181           column = GTK_TREE_VIEW_COLUMN (list->data);
11182           if (column->visible)
11183             _gtk_tree_view_column_cell_set_dirty (column, TRUE);
11184         }
11185       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11186     }
11187
11188   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
11189
11190   return tree_view->priv->n_columns;
11191 }
11192
11193 /**
11194  * gtk_tree_view_insert_column_with_attributes:
11195  * @tree_view: A #GtkTreeView
11196  * @position: The position to insert the new column in.
11197  * @title: The title to set the header to.
11198  * @cell: The #GtkCellRenderer.
11199  * @Varargs: A %NULL-terminated list of attributes.
11200  *
11201  * Creates a new #GtkTreeViewColumn and inserts it into the @tree_view at
11202  * @position.  If @position is -1, then the newly created column is inserted at
11203  * the end.  The column is initialized with the attributes given. If @tree_view
11204  * has "fixed_height" mode enabled, then the new column will have its sizing
11205  * property set to be GTK_TREE_VIEW_COLUMN_FIXED.
11206  *
11207  * Return value: The number of columns in @tree_view after insertion.
11208  **/
11209 gint
11210 gtk_tree_view_insert_column_with_attributes (GtkTreeView     *tree_view,
11211                                              gint             position,
11212                                              const gchar     *title,
11213                                              GtkCellRenderer *cell,
11214                                              ...)
11215 {
11216   GtkTreeViewColumn *column;
11217   gchar *attribute;
11218   va_list args;
11219   gint column_id;
11220
11221   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11222
11223   column = gtk_tree_view_column_new ();
11224   if (tree_view->priv->fixed_height_mode)
11225     gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
11226
11227   gtk_tree_view_column_set_title (column, title);
11228   gtk_tree_view_column_pack_start (column, cell, TRUE);
11229
11230   va_start (args, cell);
11231
11232   attribute = va_arg (args, gchar *);
11233
11234   while (attribute != NULL)
11235     {
11236       column_id = va_arg (args, gint);
11237       gtk_tree_view_column_add_attribute (column, cell, attribute, column_id);
11238       attribute = va_arg (args, gchar *);
11239     }
11240
11241   va_end (args);
11242
11243   gtk_tree_view_insert_column (tree_view, column, position);
11244
11245   return tree_view->priv->n_columns;
11246 }
11247
11248 /**
11249  * gtk_tree_view_insert_column_with_data_func:
11250  * @tree_view: a #GtkTreeView
11251  * @position: Position to insert, -1 for append
11252  * @title: column title
11253  * @cell: cell renderer for column
11254  * @func: function to set attributes of cell renderer
11255  * @data: data for @func
11256  * @dnotify: destroy notifier for @data
11257  *
11258  * Convenience function that inserts a new column into the #GtkTreeView
11259  * with the given cell renderer and a #GtkCellDataFunc to set cell renderer
11260  * attributes (normally using data from the model). See also
11261  * gtk_tree_view_column_set_cell_data_func(), gtk_tree_view_column_pack_start().
11262  * If @tree_view has "fixed_height" mode enabled, then the new column will have its
11263  * "sizing" property set to be GTK_TREE_VIEW_COLUMN_FIXED.
11264  *
11265  * Return value: number of columns in the tree view post-insert
11266  **/
11267 gint
11268 gtk_tree_view_insert_column_with_data_func  (GtkTreeView               *tree_view,
11269                                              gint                       position,
11270                                              const gchar               *title,
11271                                              GtkCellRenderer           *cell,
11272                                              GtkTreeCellDataFunc        func,
11273                                              gpointer                   data,
11274                                              GDestroyNotify             dnotify)
11275 {
11276   GtkTreeViewColumn *column;
11277
11278   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11279
11280   column = gtk_tree_view_column_new ();
11281   if (tree_view->priv->fixed_height_mode)
11282     gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
11283
11284   gtk_tree_view_column_set_title (column, title);
11285   gtk_tree_view_column_pack_start (column, cell, TRUE);
11286   gtk_tree_view_column_set_cell_data_func (column, cell, func, data, dnotify);
11287
11288   gtk_tree_view_insert_column (tree_view, column, position);
11289
11290   return tree_view->priv->n_columns;
11291 }
11292
11293 /**
11294  * gtk_tree_view_get_column:
11295  * @tree_view: A #GtkTreeView.
11296  * @n: The position of the column, counting from 0.
11297  *
11298  * Gets the #GtkTreeViewColumn at the given position in the #tree_view.
11299  *
11300  * Return value: The #GtkTreeViewColumn, or %NULL if the position is outside the
11301  * range of columns.
11302  **/
11303 GtkTreeViewColumn *
11304 gtk_tree_view_get_column (GtkTreeView *tree_view,
11305                           gint         n)
11306 {
11307   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11308
11309   if (n < 0 || n >= tree_view->priv->n_columns)
11310     return NULL;
11311
11312   if (tree_view->priv->columns == NULL)
11313     return NULL;
11314
11315   return GTK_TREE_VIEW_COLUMN (g_list_nth (tree_view->priv->columns, n)->data);
11316 }
11317
11318 /**
11319  * gtk_tree_view_get_columns:
11320  * @tree_view: A #GtkTreeView
11321  *
11322  * Returns a #GList of all the #GtkTreeViewColumn s currently in @tree_view.
11323  * The returned list must be freed with g_list_free ().
11324  *
11325  * Return value: A list of #GtkTreeViewColumn s
11326  **/
11327 GList *
11328 gtk_tree_view_get_columns (GtkTreeView *tree_view)
11329 {
11330   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11331
11332   return g_list_copy (tree_view->priv->columns);
11333 }
11334
11335 /**
11336  * gtk_tree_view_move_column_after:
11337  * @tree_view: A #GtkTreeView
11338  * @column: The #GtkTreeViewColumn to be moved.
11339  * @base_column: The #GtkTreeViewColumn to be moved relative to, or %NULL.
11340  *
11341  * Moves @column to be after to @base_column.  If @base_column is %NULL, then
11342  * @column is placed in the first position.
11343  **/
11344 void
11345 gtk_tree_view_move_column_after (GtkTreeView       *tree_view,
11346                                  GtkTreeViewColumn *column,
11347                                  GtkTreeViewColumn *base_column)
11348 {
11349   GList *column_list_el, *base_el = NULL;
11350
11351   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11352
11353   column_list_el = g_list_find (tree_view->priv->columns, column);
11354   g_return_if_fail (column_list_el != NULL);
11355
11356   if (base_column)
11357     {
11358       base_el = g_list_find (tree_view->priv->columns, base_column);
11359       g_return_if_fail (base_el != NULL);
11360     }
11361
11362   if (column_list_el->prev == base_el)
11363     return;
11364
11365   tree_view->priv->columns = g_list_remove_link (tree_view->priv->columns, column_list_el);
11366   if (base_el == NULL)
11367     {
11368       column_list_el->prev = NULL;
11369       column_list_el->next = tree_view->priv->columns;
11370       if (column_list_el->next)
11371         column_list_el->next->prev = column_list_el;
11372       tree_view->priv->columns = column_list_el;
11373     }
11374   else
11375     {
11376       column_list_el->prev = base_el;
11377       column_list_el->next = base_el->next;
11378       if (column_list_el->next)
11379         column_list_el->next->prev = column_list_el;
11380       base_el->next = column_list_el;
11381     }
11382
11383   if (GTK_WIDGET_REALIZED (tree_view))
11384     {
11385       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11386       gtk_tree_view_size_allocate_columns (GTK_WIDGET (tree_view), NULL);
11387     }
11388
11389   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
11390 }
11391
11392 /**
11393  * gtk_tree_view_set_expander_column:
11394  * @tree_view: A #GtkTreeView
11395  * @column: %NULL, or the column to draw the expander arrow at.
11396  *
11397  * Sets the column to draw the expander arrow at. It must be in @tree_view.  
11398  * If @column is %NULL, then the expander arrow is always at the first 
11399  * visible column.
11400  *
11401  * If you do not want expander arrow to appear in your tree, set the 
11402  * expander column to a hidden column.
11403  **/
11404 void
11405 gtk_tree_view_set_expander_column (GtkTreeView       *tree_view,
11406                                    GtkTreeViewColumn *column)
11407 {
11408   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11409   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
11410
11411   if (tree_view->priv->expander_column != column)
11412     {
11413       GList *list;
11414
11415       if (column)
11416         {
11417           /* Confirm that column is in tree_view */
11418           for (list = tree_view->priv->columns; list; list = list->next)
11419             if (list->data == column)
11420               break;
11421           g_return_if_fail (list != NULL);
11422         }
11423
11424       tree_view->priv->expander_column = column;
11425       g_object_notify (G_OBJECT (tree_view), "expander-column");
11426     }
11427 }
11428
11429 /**
11430  * gtk_tree_view_get_expander_column:
11431  * @tree_view: A #GtkTreeView
11432  *
11433  * Returns the column that is the current expander column.  This
11434  * column has the expander arrow drawn next to it.
11435  *
11436  * Return value: The expander column.
11437  **/
11438 GtkTreeViewColumn *
11439 gtk_tree_view_get_expander_column (GtkTreeView *tree_view)
11440 {
11441   GList *list;
11442
11443   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11444
11445   for (list = tree_view->priv->columns; list; list = list->next)
11446     if (gtk_tree_view_is_expander_column (tree_view, GTK_TREE_VIEW_COLUMN (list->data)))
11447       return (GtkTreeViewColumn *) list->data;
11448   return NULL;
11449 }
11450
11451
11452 /**
11453  * gtk_tree_view_set_column_drag_function:
11454  * @tree_view: A #GtkTreeView.
11455  * @func: A function to determine which columns are reorderable, or %NULL.
11456  * @user_data: User data to be passed to @func, or %NULL
11457  * @destroy: Destroy notifier for @user_data, or %NULL
11458  *
11459  * Sets a user function for determining where a column may be dropped when
11460  * dragged.  This function is called on every column pair in turn at the
11461  * beginning of a column drag to determine where a drop can take place.  The
11462  * arguments passed to @func are: the @tree_view, the #GtkTreeViewColumn being
11463  * dragged, the two #GtkTreeViewColumn s determining the drop spot, and
11464  * @user_data.  If either of the #GtkTreeViewColumn arguments for the drop spot
11465  * are %NULL, then they indicate an edge.  If @func is set to be %NULL, then
11466  * @tree_view reverts to the default behavior of allowing all columns to be
11467  * dropped everywhere.
11468  **/
11469 void
11470 gtk_tree_view_set_column_drag_function (GtkTreeView               *tree_view,
11471                                         GtkTreeViewColumnDropFunc  func,
11472                                         gpointer                   user_data,
11473                                         GDestroyNotify             destroy)
11474 {
11475   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11476
11477   if (tree_view->priv->column_drop_func_data_destroy)
11478     tree_view->priv->column_drop_func_data_destroy (tree_view->priv->column_drop_func_data);
11479
11480   tree_view->priv->column_drop_func = func;
11481   tree_view->priv->column_drop_func_data = user_data;
11482   tree_view->priv->column_drop_func_data_destroy = destroy;
11483 }
11484
11485 /**
11486  * gtk_tree_view_scroll_to_point:
11487  * @tree_view: a #GtkTreeView
11488  * @tree_x: X coordinate of new top-left pixel of visible area, or -1
11489  * @tree_y: Y coordinate of new top-left pixel of visible area, or -1
11490  *
11491  * Scrolls the tree view such that the top-left corner of the visible
11492  * area is @tree_x, @tree_y, where @tree_x and @tree_y are specified
11493  * in tree coordinates.  The @tree_view must be realized before
11494  * this function is called.  If it isn't, you probably want to be
11495  * using gtk_tree_view_scroll_to_cell().
11496  *
11497  * If either @tree_x or @tree_y are -1, then that direction isn't scrolled.
11498  **/
11499 void
11500 gtk_tree_view_scroll_to_point (GtkTreeView *tree_view,
11501                                gint         tree_x,
11502                                gint         tree_y)
11503 {
11504   GtkAdjustment *hadj;
11505   GtkAdjustment *vadj;
11506
11507   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11508   g_return_if_fail (GTK_WIDGET_REALIZED (tree_view));
11509
11510   hadj = tree_view->priv->hadjustment;
11511   vadj = tree_view->priv->vadjustment;
11512
11513   if (tree_x != -1)
11514     gtk_adjustment_set_value (hadj, CLAMP (tree_x, hadj->lower, hadj->upper - hadj->page_size));
11515   if (tree_y != -1)
11516     gtk_adjustment_set_value (vadj, CLAMP (tree_y, vadj->lower, vadj->upper - vadj->page_size));
11517 }
11518
11519 /**
11520  * gtk_tree_view_scroll_to_cell:
11521  * @tree_view: A #GtkTreeView.
11522  * @path: The path of the row to move to, or %NULL.
11523  * @column: The #GtkTreeViewColumn to move horizontally to, or %NULL.
11524  * @use_align: whether to use alignment arguments, or %FALSE.
11525  * @row_align: The vertical alignment of the row specified by @path.
11526  * @col_align: The horizontal alignment of the column specified by @column.
11527  *
11528  * Moves the alignments of @tree_view to the position specified by @column and
11529  * @path.  If @column is %NULL, then no horizontal scrolling occurs.  Likewise,
11530  * if @path is %NULL no vertical scrolling occurs.  At a minimum, one of @column
11531  * or @path need to be non-%NULL.  @row_align determines where the row is
11532  * placed, and @col_align determines where @column is placed.  Both are expected
11533  * to be between 0.0 and 1.0. 0.0 means left/top alignment, 1.0 means
11534  * right/bottom alignment, 0.5 means center.
11535  *
11536  * If @use_align is %FALSE, then the alignment arguments are ignored, and the
11537  * tree does the minimum amount of work to scroll the cell onto the screen.
11538  * This means that the cell will be scrolled to the edge closest to its current
11539  * position.  If the cell is currently visible on the screen, nothing is done.
11540  *
11541  * This function only works if the model is set, and @path is a valid row on the
11542  * model.  If the model changes before the @tree_view is realized, the centered
11543  * path will be modified to reflect this change.
11544  **/
11545 void
11546 gtk_tree_view_scroll_to_cell (GtkTreeView       *tree_view,
11547                               GtkTreePath       *path,
11548                               GtkTreeViewColumn *column,
11549                               gboolean           use_align,
11550                               gfloat             row_align,
11551                               gfloat             col_align)
11552 {
11553   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11554   g_return_if_fail (tree_view->priv->model != NULL);
11555   g_return_if_fail (tree_view->priv->tree != NULL);
11556   g_return_if_fail (row_align >= 0.0 && row_align <= 1.0);
11557   g_return_if_fail (col_align >= 0.0 && col_align <= 1.0);
11558   g_return_if_fail (path != NULL || column != NULL);
11559
11560 #if 0
11561   g_print ("gtk_tree_view_scroll_to_cell:\npath: %s\ncolumn: %s\nuse_align: %d\nrow_align: %f\ncol_align: %f\n",
11562            gtk_tree_path_to_string (path), column?"non-null":"null", use_align, row_align, col_align);
11563 #endif
11564   row_align = CLAMP (row_align, 0.0, 1.0);
11565   col_align = CLAMP (col_align, 0.0, 1.0);
11566
11567
11568   /* Note: Despite the benefits that come from having one code path for the
11569    * scrolling code, we short-circuit validate_visible_area's immplementation as
11570    * it is much slower than just going to the point.
11571    */
11572   if (! GTK_WIDGET_VISIBLE (tree_view) ||
11573       ! GTK_WIDGET_REALIZED (tree_view) ||
11574       GTK_WIDGET_ALLOC_NEEDED (tree_view) || 
11575       GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID))
11576     {
11577       if (tree_view->priv->scroll_to_path)
11578         gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
11579
11580       tree_view->priv->scroll_to_path = NULL;
11581       tree_view->priv->scroll_to_column = NULL;
11582
11583       if (path)
11584         tree_view->priv->scroll_to_path = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
11585       if (column)
11586         tree_view->priv->scroll_to_column = column;
11587       tree_view->priv->scroll_to_use_align = use_align;
11588       tree_view->priv->scroll_to_row_align = row_align;
11589       tree_view->priv->scroll_to_col_align = col_align;
11590
11591       install_presize_handler (tree_view);
11592     }
11593   else
11594     {
11595       GdkRectangle cell_rect;
11596       GdkRectangle vis_rect;
11597       gint dest_x, dest_y;
11598
11599       gtk_tree_view_get_background_area (tree_view, path, column, &cell_rect);
11600       gtk_tree_view_get_visible_rect (tree_view, &vis_rect);
11601
11602       cell_rect.y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, cell_rect.y);
11603
11604       dest_x = vis_rect.x;
11605       dest_y = vis_rect.y;
11606
11607       if (column)
11608         {
11609           if (use_align)
11610             {
11611               dest_x = cell_rect.x - ((vis_rect.width - cell_rect.width) * col_align);
11612             }
11613           else
11614             {
11615               if (cell_rect.x < vis_rect.x)
11616                 dest_x = cell_rect.x;
11617               if (cell_rect.x + cell_rect.width > vis_rect.x + vis_rect.width)
11618                 dest_x = cell_rect.x + cell_rect.width - vis_rect.width;
11619             }
11620         }
11621
11622       if (path)
11623         {
11624           if (use_align)
11625             {
11626               dest_y = cell_rect.y - ((vis_rect.height - cell_rect.height) * row_align);
11627               dest_y = MAX (dest_y, 0);
11628             }
11629           else
11630             {
11631               if (cell_rect.y < vis_rect.y)
11632                 dest_y = cell_rect.y;
11633               if (cell_rect.y + cell_rect.height > vis_rect.y + vis_rect.height)
11634                 dest_y = cell_rect.y + cell_rect.height - vis_rect.height;
11635             }
11636         }
11637
11638       gtk_tree_view_scroll_to_point (tree_view, dest_x, dest_y);
11639     }
11640 }
11641
11642 /**
11643  * gtk_tree_view_row_activated:
11644  * @tree_view: A #GtkTreeView
11645  * @path: The #GtkTreePath to be activated.
11646  * @column: The #GtkTreeViewColumn to be activated.
11647  *
11648  * Activates the cell determined by @path and @column.
11649  **/
11650 void
11651 gtk_tree_view_row_activated (GtkTreeView       *tree_view,
11652                              GtkTreePath       *path,
11653                              GtkTreeViewColumn *column)
11654 {
11655   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11656
11657   g_signal_emit (tree_view, tree_view_signals[ROW_ACTIVATED], 0, path, column);
11658 }
11659
11660
11661 static void
11662 gtk_tree_view_expand_all_emission_helper (GtkRBTree *tree,
11663                                           GtkRBNode *node,
11664                                           gpointer   data)
11665 {
11666   GtkTreeView *tree_view = data;
11667
11668   if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT &&
11669       node->children)
11670     {
11671       GtkTreePath *path;
11672       GtkTreeIter iter;
11673
11674       path = _gtk_tree_view_find_path (tree_view, tree, node);
11675       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
11676
11677       g_signal_emit (tree_view, tree_view_signals[ROW_EXPANDED], 0, &iter, path);
11678
11679       gtk_tree_path_free (path);
11680     }
11681
11682   if (node->children)
11683     _gtk_rbtree_traverse (node->children,
11684                           node->children->root,
11685                           G_PRE_ORDER,
11686                           gtk_tree_view_expand_all_emission_helper,
11687                           tree_view);
11688 }
11689
11690 /**
11691  * gtk_tree_view_expand_all:
11692  * @tree_view: A #GtkTreeView.
11693  *
11694  * Recursively expands all nodes in the @tree_view.
11695  **/
11696 void
11697 gtk_tree_view_expand_all (GtkTreeView *tree_view)
11698 {
11699   GtkTreePath *path;
11700   GtkRBTree *tree;
11701   GtkRBNode *node;
11702
11703   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11704
11705   if (tree_view->priv->tree == NULL)
11706     return;
11707
11708   path = gtk_tree_path_new_first ();
11709   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
11710
11711   while (node)
11712     {
11713       gtk_tree_view_real_expand_row (tree_view, path, tree, node, TRUE, FALSE);
11714       node = _gtk_rbtree_next (tree, node);
11715       gtk_tree_path_next (path);
11716   }
11717
11718   gtk_tree_path_free (path);
11719 }
11720
11721 /* Timeout to animate the expander during expands and collapses */
11722 static gboolean
11723 expand_collapse_timeout (gpointer data)
11724 {
11725   return do_expand_collapse (data);
11726 }
11727
11728 static void
11729 add_expand_collapse_timeout (GtkTreeView *tree_view,
11730                              GtkRBTree   *tree,
11731                              GtkRBNode   *node,
11732                              gboolean     expand)
11733 {
11734   if (tree_view->priv->expand_collapse_timeout != 0)
11735     return;
11736
11737   tree_view->priv->expand_collapse_timeout =
11738       gdk_threads_add_timeout (50, expand_collapse_timeout, tree_view);
11739   tree_view->priv->expanded_collapsed_tree = tree;
11740   tree_view->priv->expanded_collapsed_node = node;
11741
11742   if (expand)
11743     GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
11744   else
11745     GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
11746 }
11747
11748 static void
11749 remove_expand_collapse_timeout (GtkTreeView *tree_view)
11750 {
11751   if (tree_view->priv->expand_collapse_timeout)
11752     {
11753       g_source_remove (tree_view->priv->expand_collapse_timeout);
11754       tree_view->priv->expand_collapse_timeout = 0;
11755     }
11756
11757   if (tree_view->priv->expanded_collapsed_node != NULL)
11758     {
11759       GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_EXPANDED);
11760       GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_COLLAPSED);
11761
11762       tree_view->priv->expanded_collapsed_node = NULL;
11763     }
11764 }
11765
11766 static void
11767 cancel_arrow_animation (GtkTreeView *tree_view)
11768 {
11769   if (tree_view->priv->expand_collapse_timeout)
11770     {
11771       while (do_expand_collapse (tree_view));
11772
11773       remove_expand_collapse_timeout (tree_view);
11774     }
11775 }
11776
11777 static gboolean
11778 do_expand_collapse (GtkTreeView *tree_view)
11779 {
11780   GtkRBNode *node;
11781   GtkRBTree *tree;
11782   gboolean expanding;
11783   gboolean redraw;
11784
11785   redraw = FALSE;
11786   expanding = TRUE;
11787
11788   node = tree_view->priv->expanded_collapsed_node;
11789   tree = tree_view->priv->expanded_collapsed_tree;
11790
11791   if (node->children == NULL)
11792     expanding = FALSE;
11793
11794   if (expanding)
11795     {
11796       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_COLLAPSED))
11797         {
11798           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
11799           GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
11800
11801           redraw = TRUE;
11802
11803         }
11804       else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_EXPANDED))
11805         {
11806           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
11807
11808           redraw = TRUE;
11809         }
11810     }
11811   else
11812     {
11813       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_EXPANDED))
11814         {
11815           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
11816           GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
11817
11818           redraw = TRUE;
11819         }
11820       else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_COLLAPSED))
11821         {
11822           GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
11823
11824           redraw = TRUE;
11825
11826         }
11827     }
11828
11829   if (redraw)
11830     {
11831       gtk_tree_view_queue_draw_arrow (tree_view, tree, node, NULL);
11832
11833       return TRUE;
11834     }
11835
11836   return FALSE;
11837 }
11838
11839 /**
11840  * gtk_tree_view_collapse_all:
11841  * @tree_view: A #GtkTreeView.
11842  *
11843  * Recursively collapses all visible, expanded nodes in @tree_view.
11844  **/
11845 void
11846 gtk_tree_view_collapse_all (GtkTreeView *tree_view)
11847 {
11848   GtkRBTree *tree;
11849   GtkRBNode *node;
11850   GtkTreePath *path;
11851   gint *indices;
11852
11853   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11854
11855   if (tree_view->priv->tree == NULL)
11856     return;
11857
11858   path = gtk_tree_path_new ();
11859   gtk_tree_path_down (path);
11860   indices = gtk_tree_path_get_indices (path);
11861
11862   tree = tree_view->priv->tree;
11863   node = tree->root;
11864   while (node && node->left != tree->nil)
11865     node = node->left;
11866
11867   while (node)
11868     {
11869       if (node->children)
11870         gtk_tree_view_real_collapse_row (tree_view, path, tree, node, FALSE);
11871       indices[0]++;
11872       node = _gtk_rbtree_next (tree, node);
11873     }
11874
11875   gtk_tree_path_free (path);
11876 }
11877
11878 /**
11879  * gtk_tree_view_expand_to_path:
11880  * @tree_view: A #GtkTreeView.
11881  * @path: path to a row.
11882  *
11883  * Expands the row at @path. This will also expand all parent rows of
11884  * @path as necessary.
11885  *
11886  * Since: 2.2
11887  **/
11888 void
11889 gtk_tree_view_expand_to_path (GtkTreeView *tree_view,
11890                               GtkTreePath *path)
11891 {
11892   gint i, depth;
11893   gint *indices;
11894   GtkTreePath *tmp;
11895
11896   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11897   g_return_if_fail (path != NULL);
11898
11899   depth = gtk_tree_path_get_depth (path);
11900   indices = gtk_tree_path_get_indices (path);
11901
11902   tmp = gtk_tree_path_new ();
11903   g_return_if_fail (tmp != NULL);
11904
11905   for (i = 0; i < depth; i++)
11906     {
11907       gtk_tree_path_append_index (tmp, indices[i]);
11908       gtk_tree_view_expand_row (tree_view, tmp, FALSE);
11909     }
11910
11911   gtk_tree_path_free (tmp);
11912 }
11913
11914 /* FIXME the bool return values for expand_row and collapse_row are
11915  * not analagous; they should be TRUE if the row had children and
11916  * was not already in the requested state.
11917  */
11918
11919
11920 static gboolean
11921 gtk_tree_view_real_expand_row (GtkTreeView *tree_view,
11922                                GtkTreePath *path,
11923                                GtkRBTree   *tree,
11924                                GtkRBNode   *node,
11925                                gboolean     open_all,
11926                                gboolean     animate)
11927 {
11928   GtkTreeIter iter;
11929   GtkTreeIter temp;
11930   gboolean expand;
11931
11932   if (animate)
11933     g_object_get (gtk_widget_get_settings (GTK_WIDGET (tree_view)),
11934                   "gtk-enable-animations", &animate,
11935                   NULL);
11936
11937   remove_auto_expand_timeout (tree_view);
11938
11939   if (node->children && !open_all)
11940     return FALSE;
11941
11942   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
11943     return FALSE;
11944
11945   gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
11946   if (! gtk_tree_model_iter_has_child (tree_view->priv->model, &iter))
11947     return FALSE;
11948
11949
11950    if (node->children && open_all)
11951     {
11952       gboolean retval = FALSE;
11953       GtkTreePath *tmp_path = gtk_tree_path_copy (path);
11954
11955       gtk_tree_path_append_index (tmp_path, 0);
11956       tree = node->children;
11957       node = tree->root;
11958       while (node->left != tree->nil)
11959         node = node->left;
11960       /* try to expand the children */
11961       do
11962         {
11963          gboolean t;
11964          t = gtk_tree_view_real_expand_row (tree_view, tmp_path, tree, node,
11965                                             TRUE, animate);
11966          if (t)
11967            retval = TRUE;
11968
11969          gtk_tree_path_next (tmp_path);
11970          node = _gtk_rbtree_next (tree, node);
11971        }
11972       while (node != NULL);
11973
11974       gtk_tree_path_free (tmp_path);
11975
11976       return retval;
11977     }
11978
11979   g_signal_emit (tree_view, tree_view_signals[TEST_EXPAND_ROW], 0, &iter, path, &expand);
11980
11981   if (!gtk_tree_model_iter_has_child (tree_view->priv->model, &iter))
11982     return FALSE;
11983
11984   if (expand)
11985     return FALSE;
11986
11987   node->children = _gtk_rbtree_new ();
11988   node->children->parent_tree = tree;
11989   node->children->parent_node = node;
11990
11991   gtk_tree_model_iter_children (tree_view->priv->model, &temp, &iter);
11992
11993   gtk_tree_view_build_tree (tree_view,
11994                             node->children,
11995                             &temp,
11996                             gtk_tree_path_get_depth (path) + 1,
11997                             open_all);
11998
11999   remove_expand_collapse_timeout (tree_view);
12000
12001   if (animate)
12002     add_expand_collapse_timeout (tree_view, tree, node, TRUE);
12003
12004   install_presize_handler (tree_view);
12005
12006   g_signal_emit (tree_view, tree_view_signals[ROW_EXPANDED], 0, &iter, path);
12007   if (open_all && node->children)
12008     {
12009       _gtk_rbtree_traverse (node->children,
12010                             node->children->root,
12011                             G_PRE_ORDER,
12012                             gtk_tree_view_expand_all_emission_helper,
12013                             tree_view);
12014     }
12015   return TRUE;
12016 }
12017
12018
12019 /**
12020  * gtk_tree_view_expand_row:
12021  * @tree_view: a #GtkTreeView
12022  * @path: path to a row
12023  * @open_all: whether to recursively expand, or just expand immediate children
12024  *
12025  * Opens the row so its children are visible.
12026  *
12027  * Return value: %TRUE if the row existed and had children
12028  **/
12029 gboolean
12030 gtk_tree_view_expand_row (GtkTreeView *tree_view,
12031                           GtkTreePath *path,
12032                           gboolean     open_all)
12033 {
12034   GtkRBTree *tree;
12035   GtkRBNode *node;
12036
12037   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12038   g_return_val_if_fail (tree_view->priv->model != NULL, FALSE);
12039   g_return_val_if_fail (path != NULL, FALSE);
12040
12041   if (_gtk_tree_view_find_node (tree_view,
12042                                 path,
12043                                 &tree,
12044                                 &node))
12045     return FALSE;
12046
12047   if (tree != NULL)
12048     return gtk_tree_view_real_expand_row (tree_view, path, tree, node, open_all, FALSE);
12049   else
12050     return FALSE;
12051 }
12052
12053 static gboolean
12054 gtk_tree_view_real_collapse_row (GtkTreeView *tree_view,
12055                                  GtkTreePath *path,
12056                                  GtkRBTree   *tree,
12057                                  GtkRBNode   *node,
12058                                  gboolean     animate)
12059 {
12060   GtkTreeIter iter;
12061   GtkTreeIter children;
12062   gboolean collapse;
12063   gint x, y;
12064   GList *list;
12065   GdkWindow *child, *parent;
12066
12067   if (animate)
12068     g_object_get (gtk_widget_get_settings (GTK_WIDGET (tree_view)),
12069                   "gtk-enable-animations", &animate,
12070                   NULL);
12071
12072   remove_auto_expand_timeout (tree_view);
12073
12074   if (node->children == NULL)
12075     return FALSE;
12076
12077   gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
12078
12079   g_signal_emit (tree_view, tree_view_signals[TEST_COLLAPSE_ROW], 0, &iter, path, &collapse);
12080
12081   if (collapse)
12082     return FALSE;
12083
12084   /* if the prelighted node is a child of us, we want to unprelight it.  We have
12085    * a chance to prelight the correct node below */
12086
12087   if (tree_view->priv->prelight_tree)
12088     {
12089       GtkRBTree *parent_tree;
12090       GtkRBNode *parent_node;
12091
12092       parent_tree = tree_view->priv->prelight_tree->parent_tree;
12093       parent_node = tree_view->priv->prelight_tree->parent_node;
12094       while (parent_tree)
12095         {
12096           if (parent_tree == tree && parent_node == node)
12097             {
12098               ensure_unprelighted (tree_view);
12099               break;
12100             }
12101           parent_node = parent_tree->parent_node;
12102           parent_tree = parent_tree->parent_tree;
12103         }
12104     }
12105
12106   TREE_VIEW_INTERNAL_ASSERT (gtk_tree_model_iter_children (tree_view->priv->model, &children, &iter), FALSE);
12107
12108   for (list = tree_view->priv->columns; list; list = list->next)
12109     {
12110       GtkTreeViewColumn *column = list->data;
12111
12112       if (column->visible == FALSE)
12113         continue;
12114       if (gtk_tree_view_column_get_sizing (column) == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
12115         _gtk_tree_view_column_cell_set_dirty (column, TRUE);
12116     }
12117
12118   if (tree_view->priv->destroy_count_func)
12119     {
12120       GtkTreePath *child_path;
12121       gint child_count = 0;
12122       child_path = gtk_tree_path_copy (path);
12123       gtk_tree_path_down (child_path);
12124       if (node->children)
12125         _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, &child_count);
12126       tree_view->priv->destroy_count_func (tree_view, child_path, child_count, tree_view->priv->destroy_count_data);
12127       gtk_tree_path_free (child_path);
12128     }
12129
12130   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
12131     {
12132       GtkTreePath *cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
12133
12134       if (gtk_tree_path_is_ancestor (path, cursor_path))
12135         {
12136           gtk_tree_row_reference_free (tree_view->priv->cursor);
12137           tree_view->priv->cursor = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
12138                                                                       tree_view->priv->model,
12139                                                                       path);
12140         }
12141       gtk_tree_path_free (cursor_path);
12142     }
12143
12144   if (gtk_tree_row_reference_valid (tree_view->priv->anchor))
12145     {
12146       GtkTreePath *anchor_path = gtk_tree_row_reference_get_path (tree_view->priv->anchor);
12147       if (gtk_tree_path_is_ancestor (path, anchor_path))
12148         {
12149           gtk_tree_row_reference_free (tree_view->priv->anchor);
12150           tree_view->priv->anchor = NULL;
12151         }
12152       gtk_tree_path_free (anchor_path);
12153     }
12154
12155   /* Stop a pending double click */
12156   tree_view->priv->last_button_x = -1;
12157   tree_view->priv->last_button_y = -1;
12158
12159   remove_expand_collapse_timeout (tree_view);
12160
12161   if (gtk_tree_view_unref_and_check_selection_tree (tree_view, node->children))
12162     {
12163       _gtk_rbtree_remove (node->children);
12164       g_signal_emit_by_name (tree_view->priv->selection, "changed");
12165     }
12166   else
12167     _gtk_rbtree_remove (node->children);
12168   
12169   if (animate)
12170     add_expand_collapse_timeout (tree_view, tree, node, FALSE);
12171   
12172   if (GTK_WIDGET_MAPPED (tree_view))
12173     {
12174       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
12175     }
12176
12177   g_signal_emit (tree_view, tree_view_signals[ROW_COLLAPSED], 0, &iter, path);
12178
12179   if (GTK_WIDGET_MAPPED (tree_view))
12180     {
12181       /* now that we've collapsed all rows, we want to try to set the prelight
12182        * again. To do this, we fake a motion event and send it to ourselves. */
12183
12184       child = tree_view->priv->bin_window;
12185       parent = gdk_window_get_parent (child);
12186
12187       if (gdk_window_get_pointer (parent, &x, &y, NULL) == child)
12188         {
12189           GdkEventMotion event;
12190           gint child_x, child_y;
12191
12192           gdk_window_get_position (child, &child_x, &child_y);
12193
12194           event.window = tree_view->priv->bin_window;
12195           event.x = x - child_x;
12196           event.y = y - child_y;
12197
12198           /* despite the fact this isn't a real event, I'm almost positive it will
12199            * never trigger a drag event.  maybe_drag is the only function that uses
12200            * more than just event.x and event.y. */
12201           gtk_tree_view_motion_bin_window (GTK_WIDGET (tree_view), &event);
12202         }
12203     }
12204
12205   return TRUE;
12206 }
12207
12208 /**
12209  * gtk_tree_view_collapse_row:
12210  * @tree_view: a #GtkTreeView
12211  * @path: path to a row in the @tree_view
12212  *
12213  * Collapses a row (hides its child rows, if they exist).
12214  *
12215  * Return value: %TRUE if the row was collapsed.
12216  **/
12217 gboolean
12218 gtk_tree_view_collapse_row (GtkTreeView *tree_view,
12219                             GtkTreePath *path)
12220 {
12221   GtkRBTree *tree;
12222   GtkRBNode *node;
12223
12224   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12225   g_return_val_if_fail (tree_view->priv->tree != NULL, FALSE);
12226   g_return_val_if_fail (path != NULL, FALSE);
12227
12228   if (_gtk_tree_view_find_node (tree_view,
12229                                 path,
12230                                 &tree,
12231                                 &node))
12232     return FALSE;
12233
12234   if (tree == NULL || node->children == NULL)
12235     return FALSE;
12236
12237   return gtk_tree_view_real_collapse_row (tree_view, path, tree, node, FALSE);
12238 }
12239
12240 static void
12241 gtk_tree_view_map_expanded_rows_helper (GtkTreeView            *tree_view,
12242                                         GtkRBTree              *tree,
12243                                         GtkTreePath            *path,
12244                                         GtkTreeViewMappingFunc  func,
12245                                         gpointer                user_data)
12246 {
12247   GtkRBNode *node;
12248
12249   if (tree == NULL || tree->root == NULL)
12250     return;
12251
12252   node = tree->root;
12253
12254   while (node && node->left != tree->nil)
12255     node = node->left;
12256
12257   while (node)
12258     {
12259       if (node->children)
12260         {
12261           (* func) (tree_view, path, user_data);
12262           gtk_tree_path_down (path);
12263           gtk_tree_view_map_expanded_rows_helper (tree_view, node->children, path, func, user_data);
12264           gtk_tree_path_up (path);
12265         }
12266       gtk_tree_path_next (path);
12267       node = _gtk_rbtree_next (tree, node);
12268     }
12269 }
12270
12271 /**
12272  * gtk_tree_view_map_expanded_rows:
12273  * @tree_view: A #GtkTreeView
12274  * @func: A function to be called
12275  * @data: User data to be passed to the function.
12276  *
12277  * Calls @func on all expanded rows.
12278  **/
12279 void
12280 gtk_tree_view_map_expanded_rows (GtkTreeView            *tree_view,
12281                                  GtkTreeViewMappingFunc  func,
12282                                  gpointer                user_data)
12283 {
12284   GtkTreePath *path;
12285
12286   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12287   g_return_if_fail (func != NULL);
12288
12289   path = gtk_tree_path_new_first ();
12290
12291   gtk_tree_view_map_expanded_rows_helper (tree_view,
12292                                           tree_view->priv->tree,
12293                                           path, func, user_data);
12294
12295   gtk_tree_path_free (path);
12296 }
12297
12298 /**
12299  * gtk_tree_view_row_expanded:
12300  * @tree_view: A #GtkTreeView.
12301  * @path: A #GtkTreePath to test expansion state.
12302  *
12303  * Returns %TRUE if the node pointed to by @path is expanded in @tree_view.
12304  *
12305  * Return value: %TRUE if #path is expanded.
12306  **/
12307 gboolean
12308 gtk_tree_view_row_expanded (GtkTreeView *tree_view,
12309                             GtkTreePath *path)
12310 {
12311   GtkRBTree *tree;
12312   GtkRBNode *node;
12313
12314   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12315   g_return_val_if_fail (path != NULL, FALSE);
12316
12317   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
12318
12319   if (node == NULL)
12320     return FALSE;
12321
12322   return (node->children != NULL);
12323 }
12324
12325 /**
12326  * gtk_tree_view_get_reorderable:
12327  * @tree_view: a #GtkTreeView
12328  *
12329  * Retrieves whether the user can reorder the tree via drag-and-drop. See
12330  * gtk_tree_view_set_reorderable().
12331  *
12332  * Return value: %TRUE if the tree can be reordered.
12333  **/
12334 gboolean
12335 gtk_tree_view_get_reorderable (GtkTreeView *tree_view)
12336 {
12337   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12338
12339   return tree_view->priv->reorderable;
12340 }
12341
12342 /**
12343  * gtk_tree_view_set_reorderable:
12344  * @tree_view: A #GtkTreeView.
12345  * @reorderable: %TRUE, if the tree can be reordered.
12346  *
12347  * This function is a convenience function to allow you to reorder
12348  * models that support the #GtkDragSourceIface and the
12349  * #GtkDragDestIface.  Both #GtkTreeStore and #GtkListStore support
12350  * these.  If @reorderable is %TRUE, then the user can reorder the
12351  * model by dragging and dropping rows. The developer can listen to
12352  * these changes by connecting to the model's row_inserted and
12353  * row_deleted signals. The reordering is implemented by setting up
12354  * the tree view as a drag source and destination. Therefore, drag and
12355  * drop can not be used in a reorderable view for any other purpose.
12356  *
12357  * This function does not give you any degree of control over the order -- any
12358  * reordering is allowed.  If more control is needed, you should probably
12359  * handle drag and drop manually.
12360  **/
12361 void
12362 gtk_tree_view_set_reorderable (GtkTreeView *tree_view,
12363                                gboolean     reorderable)
12364 {
12365   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12366
12367   reorderable = reorderable != FALSE;
12368
12369   if (tree_view->priv->reorderable == reorderable)
12370     return;
12371
12372   if (reorderable)
12373     {
12374       const GtkTargetEntry row_targets[] = {
12375         { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, 0 }
12376       };
12377
12378       gtk_tree_view_enable_model_drag_source (tree_view,
12379                                               GDK_BUTTON1_MASK,
12380                                               row_targets,
12381                                               G_N_ELEMENTS (row_targets),
12382                                               GDK_ACTION_MOVE);
12383       gtk_tree_view_enable_model_drag_dest (tree_view,
12384                                             row_targets,
12385                                             G_N_ELEMENTS (row_targets),
12386                                             GDK_ACTION_MOVE);
12387     }
12388   else
12389     {
12390       gtk_tree_view_unset_rows_drag_source (tree_view);
12391       gtk_tree_view_unset_rows_drag_dest (tree_view);
12392     }
12393
12394   tree_view->priv->reorderable = reorderable;
12395
12396   g_object_notify (G_OBJECT (tree_view), "reorderable");
12397 }
12398
12399 static void
12400 gtk_tree_view_real_set_cursor (GtkTreeView     *tree_view,
12401                                GtkTreePath     *path,
12402                                gboolean         clear_and_select,
12403                                gboolean         clamp_node)
12404 {
12405   GtkRBTree *tree = NULL;
12406   GtkRBNode *node = NULL;
12407
12408   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
12409     {
12410       GtkTreePath *cursor_path;
12411       cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
12412       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
12413       gtk_tree_path_free (cursor_path);
12414     }
12415
12416   gtk_tree_row_reference_free (tree_view->priv->cursor);
12417   tree_view->priv->cursor = NULL;
12418
12419   /* One cannot set the cursor on a separator.   Also, if
12420    * _gtk_tree_view_find_node returns TRUE, it ran out of tree
12421    * before finding the tree and node belonging to path.  The
12422    * path maps to a non-existing path and we will silently bail out.
12423    * We unset tree and node to avoid further processing.
12424    */
12425   if (!row_is_separator (tree_view, NULL, path)
12426       && _gtk_tree_view_find_node (tree_view, path, &tree, &node) == FALSE)
12427     {
12428       tree_view->priv->cursor =
12429           gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
12430                                             tree_view->priv->model,
12431                                             path);
12432     }
12433   else
12434     {
12435       tree = NULL;
12436       node = NULL;
12437     }
12438
12439   if (tree != NULL)
12440     {
12441       GtkRBTree *new_tree = NULL;
12442       GtkRBNode *new_node = NULL;
12443
12444       if (clear_and_select && !tree_view->priv->ctrl_pressed)
12445         {
12446           GtkTreeSelectMode mode = 0;
12447
12448           if (tree_view->priv->ctrl_pressed)
12449             mode |= GTK_TREE_SELECT_MODE_TOGGLE;
12450           if (tree_view->priv->shift_pressed)
12451             mode |= GTK_TREE_SELECT_MODE_EXTEND;
12452
12453           _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
12454                                                     node, tree, path, mode,
12455                                                     FALSE);
12456         }
12457
12458       /* We have to re-find tree and node here again, somebody might have
12459        * cleared the node or the whole tree in the GtkTreeSelection::changed
12460        * callback. If the nodes differ we bail out here.
12461        */
12462       _gtk_tree_view_find_node (tree_view, path, &new_tree, &new_node);
12463
12464       if (tree != new_tree || node != new_node)
12465         return;
12466
12467       if (clamp_node)
12468         {
12469           gtk_tree_view_clamp_node_visible (tree_view, tree, node);
12470           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
12471         }
12472     }
12473
12474   g_signal_emit (tree_view, tree_view_signals[CURSOR_CHANGED], 0);
12475 }
12476
12477 /**
12478  * gtk_tree_view_get_cursor:
12479  * @tree_view: A #GtkTreeView
12480  * @path: A pointer to be filled with the current cursor path, or %NULL
12481  * @focus_column: A pointer to be filled with the current focus column, or %NULL
12482  *
12483  * Fills in @path and @focus_column with the current path and focus column.  If
12484  * the cursor isn't currently set, then *@path will be %NULL.  If no column
12485  * currently has focus, then *@focus_column will be %NULL.
12486  *
12487  * The returned #GtkTreePath must be freed with gtk_tree_path_free() when
12488  * you are done with it.
12489  **/
12490 void
12491 gtk_tree_view_get_cursor (GtkTreeView        *tree_view,
12492                           GtkTreePath       **path,
12493                           GtkTreeViewColumn **focus_column)
12494 {
12495   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12496
12497   if (path)
12498     {
12499       if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
12500         *path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
12501       else
12502         *path = NULL;
12503     }
12504
12505   if (focus_column)
12506     {
12507       *focus_column = tree_view->priv->focus_column;
12508     }
12509 }
12510
12511 /**
12512  * gtk_tree_view_set_cursor:
12513  * @tree_view: A #GtkTreeView
12514  * @path: A #GtkTreePath
12515  * @focus_column: A #GtkTreeViewColumn, or %NULL
12516  * @start_editing: %TRUE if the specified cell should start being edited.
12517  *
12518  * Sets the current keyboard focus to be at @path, and selects it.  This is
12519  * useful when you want to focus the user's attention on a particular row.  If
12520  * @focus_column is not %NULL, then focus is given to the column specified by 
12521  * it. Additionally, if @focus_column is specified, and @start_editing is 
12522  * %TRUE, then editing should be started in the specified cell.  
12523  * This function is often followed by @gtk_widget_grab_focus (@tree_view) 
12524  * in order to give keyboard focus to the widget.  Please note that editing 
12525  * can only happen when the widget is realized.
12526  *
12527  * If @path is invalid for @model, the current cursor (if any) will be unset
12528  * and the function will return without failing.
12529  **/
12530 void
12531 gtk_tree_view_set_cursor (GtkTreeView       *tree_view,
12532                           GtkTreePath       *path,
12533                           GtkTreeViewColumn *focus_column,
12534                           gboolean           start_editing)
12535 {
12536   gtk_tree_view_set_cursor_on_cell (tree_view, path, focus_column,
12537                                     NULL, start_editing);
12538 }
12539
12540 /**
12541  * gtk_tree_view_set_cursor_on_cell:
12542  * @tree_view: A #GtkTreeView
12543  * @path: A #GtkTreePath
12544  * @focus_column: A #GtkTreeViewColumn, or %NULL
12545  * @focus_cell: A #GtkCellRenderer, or %NULL
12546  * @start_editing: %TRUE if the specified cell should start being edited.
12547  *
12548  * Sets the current keyboard focus to be at @path, and selects it.  This is
12549  * useful when you want to focus the user's attention on a particular row.  If
12550  * @focus_column is not %NULL, then focus is given to the column specified by
12551  * it. If @focus_column and @focus_cell are not %NULL, and @focus_column
12552  * contains 2 or more editable or activatable cells, then focus is given to
12553  * the cell specified by @focus_cell. Additionally, if @focus_column is
12554  * specified, and @start_editing is %TRUE, then editing should be started in
12555  * the specified cell.  This function is often followed by
12556  * @gtk_widget_grab_focus (@tree_view) in order to give keyboard focus to the
12557  * widget.  Please note that editing can only happen when the widget is
12558  * realized.
12559  *
12560  * If @path is invalid for @model, the current cursor (if any) will be unset
12561  * and the function will return without failing.
12562  *
12563  * Since: 2.2
12564  **/
12565 void
12566 gtk_tree_view_set_cursor_on_cell (GtkTreeView       *tree_view,
12567                                   GtkTreePath       *path,
12568                                   GtkTreeViewColumn *focus_column,
12569                                   GtkCellRenderer   *focus_cell,
12570                                   gboolean           start_editing)
12571 {
12572   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12573   g_return_if_fail (path != NULL);
12574   g_return_if_fail (focus_column == NULL || GTK_IS_TREE_VIEW_COLUMN (focus_column));
12575
12576   if (!tree_view->priv->model)
12577     return;
12578
12579   if (focus_cell)
12580     {
12581       g_return_if_fail (focus_column);
12582       g_return_if_fail (GTK_IS_CELL_RENDERER (focus_cell));
12583     }
12584
12585   /* cancel the current editing, if it exists */
12586   if (tree_view->priv->edited_column &&
12587       tree_view->priv->edited_column->editable_widget)
12588     gtk_tree_view_stop_editing (tree_view, TRUE);
12589
12590   gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
12591
12592   if (focus_column && focus_column->visible)
12593     {
12594       GList *list;
12595       gboolean column_in_tree = FALSE;
12596
12597       for (list = tree_view->priv->columns; list; list = list->next)
12598         if (list->data == focus_column)
12599           {
12600             column_in_tree = TRUE;
12601             break;
12602           }
12603       g_return_if_fail (column_in_tree);
12604       tree_view->priv->focus_column = focus_column;
12605       if (focus_cell)
12606         gtk_tree_view_column_focus_cell (focus_column, focus_cell);
12607       if (start_editing)
12608         gtk_tree_view_start_editing (tree_view, path);
12609     }
12610 }
12611
12612 /**
12613  * gtk_tree_view_get_bin_window:
12614  * @tree_view: A #GtkTreeView
12615  * 
12616  * Returns the window that @tree_view renders to.  This is used primarily to
12617  * compare to <literal>event->window</literal> to confirm that the event on
12618  * @tree_view is on the right window.
12619  * 
12620  * Return value: A #GdkWindow, or %NULL when @tree_view hasn't been realized yet
12621  **/
12622 GdkWindow *
12623 gtk_tree_view_get_bin_window (GtkTreeView *tree_view)
12624 {
12625   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
12626
12627   return tree_view->priv->bin_window;
12628 }
12629
12630 /**
12631  * gtk_tree_view_get_path_at_pos:
12632  * @tree_view: A #GtkTreeView.
12633  * @x: The x position to be identified (relative to bin_window).
12634  * @y: The y position to be identified (relative to bin_window).
12635  * @path: A pointer to a #GtkTreePath pointer to be filled in, or %NULL
12636  * @column: A pointer to a #GtkTreeViewColumn pointer to be filled in, or %NULL
12637  * @cell_x: A pointer where the X coordinate relative to the cell can be placed, or %NULL
12638  * @cell_y: A pointer where the Y coordinate relative to the cell can be placed, or %NULL
12639  *
12640  * Finds the path at the point (@x, @y), relative to bin_window coordinates
12641  * (please see gtk_tree_view_get_bin_window()).
12642  * That is, @x and @y are relative to an events coordinates. @x and @y must
12643  * come from an event on the @tree_view only where <literal>event->window ==
12644  * gtk_tree_view_get_bin_window (<!-- -->)</literal>. It is primarily for
12645  * things like popup menus. If @path is non-%NULL, then it will be filled
12646  * with the #GtkTreePath at that point.  This path should be freed with
12647  * gtk_tree_path_free().  If @column is non-%NULL, then it will be filled
12648  * with the column at that point.  @cell_x and @cell_y return the coordinates
12649  * relative to the cell background (i.e. the @background_area passed to
12650  * gtk_cell_renderer_render()).  This function is only meaningful if
12651  * @tree_view is realized.  Therefore this function will always return %FALSE
12652  * if @tree_view is not realized or does not have a model.
12653  *
12654  * For converting widget coordinates (eg. the ones you get from
12655  * GtkWidget::query-tooltip), please see
12656  * gtk_tree_view_convert_widget_to_bin_window_coords().
12657  *
12658  * Return value: %TRUE if a row exists at that coordinate.
12659  **/
12660 gboolean
12661 gtk_tree_view_get_path_at_pos (GtkTreeView        *tree_view,
12662                                gint                x,
12663                                gint                y,
12664                                GtkTreePath       **path,
12665                                GtkTreeViewColumn **column,
12666                                gint               *cell_x,
12667                                gint               *cell_y)
12668 {
12669   GtkRBTree *tree;
12670   GtkRBNode *node;
12671   gint y_offset;
12672
12673   g_return_val_if_fail (tree_view != NULL, FALSE);
12674
12675   if (path)
12676     *path = NULL;
12677   if (column)
12678     *column = NULL;
12679
12680   if (tree_view->priv->bin_window == NULL)
12681     return FALSE;
12682
12683   if (tree_view->priv->tree == NULL)
12684     return FALSE;
12685
12686   if (x > tree_view->priv->hadjustment->upper)
12687     return FALSE;
12688
12689   if (x < 0 || y < 0)
12690     return FALSE;
12691
12692   if (column || cell_x)
12693     {
12694       GtkTreeViewColumn *tmp_column;
12695       GtkTreeViewColumn *last_column = NULL;
12696       GList *list;
12697       gint remaining_x = x;
12698       gboolean found = FALSE;
12699       gboolean rtl;
12700
12701       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
12702       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
12703            list;
12704            list = (rtl ? list->prev : list->next))
12705         {
12706           tmp_column = list->data;
12707
12708           if (tmp_column->visible == FALSE)
12709             continue;
12710
12711           last_column = tmp_column;
12712           if (remaining_x <= tmp_column->width)
12713             {
12714               found = TRUE;
12715
12716               if (column)
12717                 *column = tmp_column;
12718
12719               if (cell_x)
12720                 *cell_x = remaining_x;
12721
12722               break;
12723             }
12724           remaining_x -= tmp_column->width;
12725         }
12726
12727       /* If found is FALSE and there is a last_column, then it the remainder
12728        * space is in that area
12729        */
12730       if (!found)
12731         {
12732           if (last_column)
12733             {
12734               if (column)
12735                 *column = last_column;
12736               
12737               if (cell_x)
12738                 *cell_x = last_column->width + remaining_x;
12739             }
12740           else
12741             {
12742               return FALSE;
12743             }
12744         }
12745     }
12746
12747   y_offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
12748                                       TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, y),
12749                                       &tree, &node);
12750
12751   if (tree == NULL)
12752     return FALSE;
12753
12754   if (cell_y)
12755     *cell_y = y_offset;
12756
12757   if (path)
12758     *path = _gtk_tree_view_find_path (tree_view, tree, node);
12759
12760   return TRUE;
12761 }
12762
12763
12764 /**
12765  * gtk_tree_view_get_cell_area:
12766  * @tree_view: a #GtkTreeView
12767  * @path: a #GtkTreePath for the row, or %NULL to get only horizontal coordinates
12768  * @column: a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordinates
12769  * @rect: rectangle to fill with cell rect
12770  *
12771  * Fills the bounding rectangle in bin_window coordinates for the cell at the
12772  * row specified by @path and the column specified by @column.  If @path is
12773  * %NULL, or points to a path not currently displayed, the @y and @height fields
12774  * of the rectangle will be filled with 0. If @column is %NULL, the @x and @width
12775  * fields will be filled with 0.  The sum of all cell rects does not cover the
12776  * entire tree; there are extra pixels in between rows, for example. The
12777  * returned rectangle is equivalent to the @cell_area passed to
12778  * gtk_cell_renderer_render().  This function is only valid if @tree_view is
12779  * realized.
12780  **/
12781 void
12782 gtk_tree_view_get_cell_area (GtkTreeView        *tree_view,
12783                              GtkTreePath        *path,
12784                              GtkTreeViewColumn  *column,
12785                              GdkRectangle       *rect)
12786 {
12787   GtkRBTree *tree = NULL;
12788   GtkRBNode *node = NULL;
12789   gint vertical_separator;
12790   gint horizontal_separator;
12791
12792   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12793   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
12794   g_return_if_fail (rect != NULL);
12795   g_return_if_fail (!column || column->tree_view == (GtkWidget *) tree_view);
12796   g_return_if_fail (GTK_WIDGET_REALIZED (tree_view));
12797
12798   gtk_widget_style_get (GTK_WIDGET (tree_view),
12799                         "vertical-separator", &vertical_separator,
12800                         "horizontal-separator", &horizontal_separator,
12801                         NULL);
12802
12803   rect->x = 0;
12804   rect->y = 0;
12805   rect->width = 0;
12806   rect->height = 0;
12807
12808   if (column)
12809     {
12810       rect->x = column->button->allocation.x + horizontal_separator/2;
12811       rect->width = column->button->allocation.width - horizontal_separator;
12812     }
12813
12814   if (path)
12815     {
12816       gboolean ret = _gtk_tree_view_find_node (tree_view, path, &tree, &node);
12817
12818       /* Get vertical coords */
12819       if ((!ret && tree == NULL) || ret)
12820         return;
12821
12822       rect->y = CELL_FIRST_PIXEL (tree_view, tree, node, vertical_separator);
12823       rect->height = MAX (CELL_HEIGHT (node, vertical_separator), tree_view->priv->expander_size - vertical_separator);
12824
12825       if (column &&
12826           gtk_tree_view_is_expander_column (tree_view, column))
12827         {
12828           gint depth = gtk_tree_path_get_depth (path);
12829           gboolean rtl;
12830
12831           rtl = gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL;
12832
12833           if (!rtl)
12834             rect->x += (depth - 1) * tree_view->priv->level_indentation;
12835           rect->width -= (depth - 1) * tree_view->priv->level_indentation;
12836
12837           if (TREE_VIEW_DRAW_EXPANDERS (tree_view))
12838             {
12839               if (!rtl)
12840                 rect->x += depth * tree_view->priv->expander_size;
12841               rect->width -= depth * tree_view->priv->expander_size;
12842             }
12843
12844           rect->width = MAX (rect->width, 0);
12845         }
12846     }
12847 }
12848
12849 /**
12850  * gtk_tree_view_get_background_area:
12851  * @tree_view: a #GtkTreeView
12852  * @path: a #GtkTreePath for the row, or %NULL to get only horizontal coordinates
12853  * @column: a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordiantes
12854  * @rect: rectangle to fill with cell background rect
12855  *
12856  * Fills the bounding rectangle in bin_window coordinates for the cell at the
12857  * row specified by @path and the column specified by @column.  If @path is
12858  * %NULL, or points to a node not found in the tree, the @y and @height fields of
12859  * the rectangle will be filled with 0. If @column is %NULL, the @x and @width
12860  * fields will be filled with 0.  The returned rectangle is equivalent to the
12861  * @background_area passed to gtk_cell_renderer_render().  These background
12862  * areas tile to cover the entire bin window.  Contrast with the @cell_area,
12863  * returned by gtk_tree_view_get_cell_area(), which returns only the cell
12864  * itself, excluding surrounding borders and the tree expander area.
12865  *
12866  **/
12867 void
12868 gtk_tree_view_get_background_area (GtkTreeView        *tree_view,
12869                                    GtkTreePath        *path,
12870                                    GtkTreeViewColumn  *column,
12871                                    GdkRectangle       *rect)
12872 {
12873   GtkRBTree *tree = NULL;
12874   GtkRBNode *node = NULL;
12875
12876   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12877   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
12878   g_return_if_fail (rect != NULL);
12879
12880   rect->x = 0;
12881   rect->y = 0;
12882   rect->width = 0;
12883   rect->height = 0;
12884
12885   if (path)
12886     {
12887       /* Get vertical coords */
12888
12889       if (!_gtk_tree_view_find_node (tree_view, path, &tree, &node) &&
12890           tree == NULL)
12891         return;
12892
12893       rect->y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
12894
12895       rect->height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
12896     }
12897
12898   if (column)
12899     {
12900       gint x2 = 0;
12901
12902       gtk_tree_view_get_background_xrange (tree_view, tree, column, &rect->x, &x2);
12903       rect->width = x2 - rect->x;
12904     }
12905 }
12906
12907 /**
12908  * gtk_tree_view_get_visible_rect:
12909  * @tree_view: a #GtkTreeView
12910  * @visible_rect: rectangle to fill
12911  *
12912  * Fills @visible_rect with the currently-visible region of the
12913  * buffer, in tree coordinates. Convert to bin_window coordinates with
12914  * gtk_tree_view_convert_tree_to_bin_window_coords().
12915  * Tree coordinates start at 0,0 for row 0 of the tree, and cover the entire
12916  * scrollable area of the tree.
12917  **/
12918 void
12919 gtk_tree_view_get_visible_rect (GtkTreeView  *tree_view,
12920                                 GdkRectangle *visible_rect)
12921 {
12922   GtkWidget *widget;
12923
12924   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12925
12926   widget = GTK_WIDGET (tree_view);
12927
12928   if (visible_rect)
12929     {
12930       visible_rect->x = tree_view->priv->hadjustment->value;
12931       visible_rect->y = tree_view->priv->vadjustment->value;
12932       visible_rect->width = widget->allocation.width;
12933       visible_rect->height = widget->allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view);
12934     }
12935 }
12936
12937 /**
12938  * gtk_tree_view_widget_to_tree_coords:
12939  * @tree_view: a #GtkTreeView
12940  * @wx: X coordinate relative to bin_window
12941  * @wy: Y coordinate relative to bin_window
12942  * @tx: return location for tree X coordinate
12943  * @ty: return location for tree Y coordinate
12944  *
12945  * Converts bin_window coordinates to coordinates for the
12946  * tree (the full scrollable area of the tree).
12947  *
12948  * Deprecated: 2.12: Due to historial reasons the name of this function is
12949  * incorrect.  For converting coordinates relative to the widget to
12950  * bin_window coordinates, please see
12951  * gtk_tree_view_convert_widget_to_bin_window_coords().
12952  *
12953  **/
12954 void
12955 gtk_tree_view_widget_to_tree_coords (GtkTreeView *tree_view,
12956                                       gint         wx,
12957                                       gint         wy,
12958                                       gint        *tx,
12959                                       gint        *ty)
12960 {
12961   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12962
12963   if (tx)
12964     *tx = wx + tree_view->priv->hadjustment->value;
12965   if (ty)
12966     *ty = wy + tree_view->priv->dy;
12967 }
12968
12969 /**
12970  * gtk_tree_view_tree_to_widget_coords:
12971  * @tree_view: a #GtkTreeView
12972  * @tx: tree X coordinate
12973  * @ty: tree Y coordinate
12974  * @wx: return location for X coordinate relative to bin_window
12975  * @wy: return location for Y coordinate relative to bin_window
12976  *
12977  * Converts tree coordinates (coordinates in full scrollable area of the tree)
12978  * to bin_window coordinates.
12979  *
12980  * Deprecated: 2.12: Due to historial reasons the name of this function is
12981  * incorrect.  For converting bin_window coordinates to coordinates relative
12982  * to bin_window, please see
12983  * gtk_tree_view_convert_bin_window_to_widget_coords().
12984  *
12985  **/
12986 void
12987 gtk_tree_view_tree_to_widget_coords (GtkTreeView *tree_view,
12988                                      gint         tx,
12989                                      gint         ty,
12990                                      gint        *wx,
12991                                      gint        *wy)
12992 {
12993   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12994
12995   if (wx)
12996     *wx = tx - tree_view->priv->hadjustment->value;
12997   if (wy)
12998     *wy = ty - tree_view->priv->dy;
12999 }
13000
13001
13002 /**
13003  * gtk_tree_view_convert_widget_to_tree_coords:
13004  * @tree_view: a #GtkTreeView
13005  * @wx: X coordinate relative to the widget
13006  * @wy: Y coordinate relative to the widget
13007  * @tx: return location for tree X coordinate
13008  * @ty: return location for tree Y coordinate
13009  *
13010  * Converts widget coordinates to coordinates for the
13011  * tree (the full scrollable area of the tree).
13012  *
13013  * Since: 2.12
13014  **/
13015 void
13016 gtk_tree_view_convert_widget_to_tree_coords (GtkTreeView *tree_view,
13017                                              gint         wx,
13018                                              gint         wy,
13019                                              gint        *tx,
13020                                              gint        *ty)
13021 {
13022   gint x, y;
13023
13024   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13025
13026   gtk_tree_view_convert_widget_to_bin_window_coords (tree_view,
13027                                                      wx, wy,
13028                                                      &x, &y);
13029   gtk_tree_view_convert_bin_window_to_tree_coords (tree_view,
13030                                                    x, y,
13031                                                    tx, ty);
13032 }
13033
13034 /**
13035  * gtk_tree_view_convert_tree_to_widget_coords:
13036  * @tree_view: a #GtkTreeView
13037  * @tx: X coordinate relative to the tree
13038  * @ty: Y coordinate relative to the tree
13039  * @wx: return location for widget X coordinate
13040  * @wy: return location for widget Y coordinate
13041  *
13042  * Converts tree coordinates (coordinates in full scrollable area of the tree)
13043  * to widget coordinates.
13044  *
13045  * Since: 2.12
13046  **/
13047 void
13048 gtk_tree_view_convert_tree_to_widget_coords (GtkTreeView *tree_view,
13049                                              gint         tx,
13050                                              gint         ty,
13051                                              gint        *wx,
13052                                              gint        *wy)
13053 {
13054   gint x, y;
13055
13056   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13057
13058   gtk_tree_view_convert_tree_to_bin_window_coords (tree_view,
13059                                                    tx, ty,
13060                                                    &x, &y);
13061   gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
13062                                                      x, y,
13063                                                      wx, wy);
13064 }
13065
13066 /**
13067  * gtk_tree_view_convert_widget_to_bin_window_coords:
13068  * @tree_view: a #GtkTreeView
13069  * @wx: X coordinate relative to the widget
13070  * @wy: Y coordinate relative to the widget
13071  * @bx: return location for bin_window X coordinate
13072  * @by: return location for bin_window Y coordinate
13073  *
13074  * Converts widget coordinates to coordinates for the bin_window
13075  * (see gtk_tree_view_get_bin_window()).
13076  *
13077  * Since: 2.12
13078  **/
13079 void
13080 gtk_tree_view_convert_widget_to_bin_window_coords (GtkTreeView *tree_view,
13081                                                    gint         wx,
13082                                                    gint         wy,
13083                                                    gint        *bx,
13084                                                    gint        *by)
13085 {
13086   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13087
13088   if (bx)
13089     *bx = wx + tree_view->priv->hadjustment->value;
13090   if (by)
13091     *by = wy - TREE_VIEW_HEADER_HEIGHT (tree_view);
13092 }
13093
13094 /**
13095  * gtk_tree_view_convert_bin_window_to_widget_coords:
13096  * @tree_view: a #GtkTreeView
13097  * @bx: bin_window X coordinate
13098  * @by: bin_window Y coordinate
13099  * @wx: return location for widget X coordinate
13100  * @wy: return location for widget Y coordinate
13101  *
13102  * Converts bin_window coordinates (see gtk_tree_view_get_bin_window())
13103  * to widget relative coordinates.
13104  *
13105  * Since: 2.12
13106  **/
13107 void
13108 gtk_tree_view_convert_bin_window_to_widget_coords (GtkTreeView *tree_view,
13109                                                    gint         bx,
13110                                                    gint         by,
13111                                                    gint        *wx,
13112                                                    gint        *wy)
13113 {
13114   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13115
13116   if (wx)
13117     *wx = bx - tree_view->priv->hadjustment->value;
13118   if (wy)
13119     *wy = by + TREE_VIEW_HEADER_HEIGHT (tree_view);
13120 }
13121
13122 /**
13123  * gtk_tree_view_convert_tree_to_bin_window_coords:
13124  * @tree_view: a #GtkTreeView
13125  * @tx: tree X coordinate
13126  * @ty: tree Y coordinate
13127  * @bx: return location for X coordinate relative to bin_window
13128  * @by: return location for Y coordinate relative to bin_window
13129  *
13130  * Converts tree coordinates (coordinates in full scrollable area of the tree)
13131  * to bin_window coordinates.
13132  *
13133  * Since: 2.12
13134  **/
13135 void
13136 gtk_tree_view_convert_tree_to_bin_window_coords (GtkTreeView *tree_view,
13137                                                  gint         tx,
13138                                                  gint         ty,
13139                                                  gint        *bx,
13140                                                  gint        *by)
13141 {
13142   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13143
13144   if (bx)
13145     *bx = tx;
13146   if (by)
13147     *by = ty - tree_view->priv->dy;
13148 }
13149
13150 /**
13151  * gtk_tree_view_convert_bin_window_to_tree_coords:
13152  * @tree_view: a #GtkTreeView
13153  * @bx: X coordinate relative to bin_window
13154  * @by: Y coordinate relative to bin_window
13155  * @tx: return location for tree X coordinate
13156  * @ty: return location for tree Y coordinate
13157  *
13158  * Converts bin_window coordinates to coordinates for the
13159  * tree (the full scrollable area of the tree).
13160  *
13161  * Since: 2.12
13162  **/
13163 void
13164 gtk_tree_view_convert_bin_window_to_tree_coords (GtkTreeView *tree_view,
13165                                                  gint         bx,
13166                                                  gint         by,
13167                                                  gint        *tx,
13168                                                  gint        *ty)
13169 {
13170   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13171
13172   if (tx)
13173     *tx = bx;
13174   if (ty)
13175     *ty = by + tree_view->priv->dy;
13176 }
13177
13178
13179
13180 /**
13181  * gtk_tree_view_get_visible_range:
13182  * @tree_view: A #GtkTreeView
13183  * @start_path: Return location for start of region, or %NULL.
13184  * @end_path: Return location for end of region, or %NULL.
13185  *
13186  * Sets @start_path and @end_path to be the first and last visible path.
13187  * Note that there may be invisible paths in between.
13188  *
13189  * The paths should be freed with gtk_tree_path_free() after use.
13190  *
13191  * Returns: %TRUE, if valid paths were placed in @start_path and @end_path.
13192  *
13193  * Since: 2.8
13194  **/
13195 gboolean
13196 gtk_tree_view_get_visible_range (GtkTreeView  *tree_view,
13197                                  GtkTreePath **start_path,
13198                                  GtkTreePath **end_path)
13199 {
13200   GtkRBTree *tree;
13201   GtkRBNode *node;
13202   gboolean retval;
13203   
13204   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
13205
13206   if (!tree_view->priv->tree)
13207     return FALSE;
13208
13209   retval = TRUE;
13210
13211   if (start_path)
13212     {
13213       _gtk_rbtree_find_offset (tree_view->priv->tree,
13214                                TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, 0),
13215                                &tree, &node);
13216       if (node)
13217         *start_path = _gtk_tree_view_find_path (tree_view, tree, node);
13218       else
13219         retval = FALSE;
13220     }
13221
13222   if (end_path)
13223     {
13224       gint y;
13225
13226       if (tree_view->priv->height < tree_view->priv->vadjustment->page_size)
13227         y = tree_view->priv->height - 1;
13228       else
13229         y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, tree_view->priv->vadjustment->page_size) - 1;
13230
13231       _gtk_rbtree_find_offset (tree_view->priv->tree, y, &tree, &node);
13232       if (node)
13233         *end_path = _gtk_tree_view_find_path (tree_view, tree, node);
13234       else
13235         retval = FALSE;
13236     }
13237
13238   return retval;
13239 }
13240
13241 static void
13242 unset_reorderable (GtkTreeView *tree_view)
13243 {
13244   if (tree_view->priv->reorderable)
13245     {
13246       tree_view->priv->reorderable = FALSE;
13247       g_object_notify (G_OBJECT (tree_view), "reorderable");
13248     }
13249 }
13250
13251 /**
13252  * gtk_tree_view_enable_model_drag_source:
13253  * @tree_view: a #GtkTreeView
13254  * @start_button_mask: Mask of allowed buttons to start drag
13255  * @targets: the table of targets that the drag will support
13256  * @n_targets: the number of items in @targets
13257  * @actions: the bitmask of possible actions for a drag from this
13258  *    widget
13259  *
13260  * Turns @tree_view into a drag source for automatic DND. Calling this
13261  * method sets #GtkTreeView:reorderable to %FALSE.
13262  **/
13263 void
13264 gtk_tree_view_enable_model_drag_source (GtkTreeView              *tree_view,
13265                                         GdkModifierType           start_button_mask,
13266                                         const GtkTargetEntry     *targets,
13267                                         gint                      n_targets,
13268                                         GdkDragAction             actions)
13269 {
13270   TreeViewDragInfo *di;
13271
13272   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13273
13274   gtk_drag_source_set (GTK_WIDGET (tree_view),
13275                        0,
13276                        targets,
13277                        n_targets,
13278                        actions);
13279
13280   di = ensure_info (tree_view);
13281
13282   di->start_button_mask = start_button_mask;
13283   di->source_actions = actions;
13284   di->source_set = TRUE;
13285
13286   unset_reorderable (tree_view);
13287 }
13288
13289 /**
13290  * gtk_tree_view_enable_model_drag_dest:
13291  * @tree_view: a #GtkTreeView
13292  * @targets: the table of targets that the drag will support
13293  * @n_targets: the number of items in @targets
13294  * @actions: the bitmask of possible actions for a drag from this
13295  *    widget
13296  * 
13297  * Turns @tree_view into a drop destination for automatic DND. Calling
13298  * this method sets #GtkTreeView:reorderable to %FALSE.
13299  **/
13300 void
13301 gtk_tree_view_enable_model_drag_dest (GtkTreeView              *tree_view,
13302                                       const GtkTargetEntry     *targets,
13303                                       gint                      n_targets,
13304                                       GdkDragAction             actions)
13305 {
13306   TreeViewDragInfo *di;
13307
13308   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13309
13310   gtk_drag_dest_set (GTK_WIDGET (tree_view),
13311                      0,
13312                      targets,
13313                      n_targets,
13314                      actions);
13315
13316   di = ensure_info (tree_view);
13317   di->dest_set = TRUE;
13318
13319   unset_reorderable (tree_view);
13320 }
13321
13322 /**
13323  * gtk_tree_view_unset_rows_drag_source:
13324  * @tree_view: a #GtkTreeView
13325  *
13326  * Undoes the effect of
13327  * gtk_tree_view_enable_model_drag_source(). Calling this method sets
13328  * #GtkTreeView:reorderable to %FALSE.
13329  **/
13330 void
13331 gtk_tree_view_unset_rows_drag_source (GtkTreeView *tree_view)
13332 {
13333   TreeViewDragInfo *di;
13334
13335   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13336
13337   di = get_info (tree_view);
13338
13339   if (di)
13340     {
13341       if (di->source_set)
13342         {
13343           gtk_drag_source_unset (GTK_WIDGET (tree_view));
13344           di->source_set = FALSE;
13345         }
13346
13347       if (!di->dest_set && !di->source_set)
13348         remove_info (tree_view);
13349     }
13350   
13351   unset_reorderable (tree_view);
13352 }
13353
13354 /**
13355  * gtk_tree_view_unset_rows_drag_dest:
13356  * @tree_view: a #GtkTreeView
13357  *
13358  * Undoes the effect of
13359  * gtk_tree_view_enable_model_drag_dest(). Calling this method sets
13360  * #GtkTreeView:reorderable to %FALSE.
13361  **/
13362 void
13363 gtk_tree_view_unset_rows_drag_dest (GtkTreeView *tree_view)
13364 {
13365   TreeViewDragInfo *di;
13366
13367   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13368
13369   di = get_info (tree_view);
13370
13371   if (di)
13372     {
13373       if (di->dest_set)
13374         {
13375           gtk_drag_dest_unset (GTK_WIDGET (tree_view));
13376           di->dest_set = FALSE;
13377         }
13378
13379       if (!di->dest_set && !di->source_set)
13380         remove_info (tree_view);
13381     }
13382
13383   unset_reorderable (tree_view);
13384 }
13385
13386 /**
13387  * gtk_tree_view_set_drag_dest_row:
13388  * @tree_view: a #GtkTreeView
13389  * @path: The path of the row to highlight, or %NULL.
13390  * @pos: Specifies whether to drop before, after or into the row
13391  * 
13392  * Sets the row that is highlighted for feedback.
13393  **/
13394 void
13395 gtk_tree_view_set_drag_dest_row (GtkTreeView            *tree_view,
13396                                  GtkTreePath            *path,
13397                                  GtkTreeViewDropPosition pos)
13398 {
13399   GtkTreePath *current_dest;
13400
13401   /* Note; this function is exported to allow a custom DND
13402    * implementation, so it can't touch TreeViewDragInfo
13403    */
13404
13405   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13406
13407   current_dest = NULL;
13408
13409   if (tree_view->priv->drag_dest_row)
13410     {
13411       current_dest = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
13412       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
13413     }
13414
13415   /* special case a drop on an empty model */
13416   tree_view->priv->empty_view_drop = 0;
13417
13418   if (pos == GTK_TREE_VIEW_DROP_BEFORE && path
13419       && gtk_tree_path_get_depth (path) == 1
13420       && gtk_tree_path_get_indices (path)[0] == 0)
13421     {
13422       gint n_children;
13423
13424       n_children = gtk_tree_model_iter_n_children (tree_view->priv->model,
13425                                                    NULL);
13426
13427       if (!n_children)
13428         tree_view->priv->empty_view_drop = 1;
13429     }
13430
13431   tree_view->priv->drag_dest_pos = pos;
13432
13433   if (path)
13434     {
13435       tree_view->priv->drag_dest_row =
13436         gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
13437       gtk_tree_view_queue_draw_path (tree_view, path, NULL);
13438     }
13439   else
13440     tree_view->priv->drag_dest_row = NULL;
13441
13442   if (current_dest)
13443     {
13444       GtkRBTree *tree, *new_tree;
13445       GtkRBNode *node, *new_node;
13446
13447       _gtk_tree_view_find_node (tree_view, current_dest, &tree, &node);
13448       _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
13449
13450       if (tree && node)
13451         {
13452           _gtk_rbtree_next_full (tree, node, &new_tree, &new_node);
13453           if (new_tree && new_node)
13454             _gtk_tree_view_queue_draw_node (tree_view, new_tree, new_node, NULL);
13455
13456           _gtk_rbtree_prev_full (tree, node, &new_tree, &new_node);
13457           if (new_tree && new_node)
13458             _gtk_tree_view_queue_draw_node (tree_view, new_tree, new_node, NULL);
13459         }
13460       gtk_tree_path_free (current_dest);
13461     }
13462 }
13463
13464 /**
13465  * gtk_tree_view_get_drag_dest_row:
13466  * @tree_view: a #GtkTreeView
13467  * @path: Return location for the path of the highlighted row, or %NULL.
13468  * @pos: Return location for the drop position, or %NULL
13469  * 
13470  * Gets information about the row that is highlighted for feedback.
13471  **/
13472 void
13473 gtk_tree_view_get_drag_dest_row (GtkTreeView              *tree_view,
13474                                  GtkTreePath             **path,
13475                                  GtkTreeViewDropPosition  *pos)
13476 {
13477   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13478
13479   if (path)
13480     {
13481       if (tree_view->priv->drag_dest_row)
13482         *path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
13483       else
13484         {
13485           if (tree_view->priv->empty_view_drop)
13486             *path = gtk_tree_path_new_from_indices (0, -1);
13487           else
13488             *path = NULL;
13489         }
13490     }
13491
13492   if (pos)
13493     *pos = tree_view->priv->drag_dest_pos;
13494 }
13495
13496 /**
13497  * gtk_tree_view_get_dest_row_at_pos:
13498  * @tree_view: a #GtkTreeView
13499  * @drag_x: the position to determine the destination row for
13500  * @drag_y: the position to determine the destination row for
13501  * @path: Return location for the path of the highlighted row, or %NULL.
13502  * @pos: Return location for the drop position, or %NULL
13503  * 
13504  * Determines the destination row for a given position.  @drag_x and
13505  * @drag_y are expected to be in widget coordinates.  This function is only
13506  * meaningful if @tree_view is realized.  Therefore this function will always
13507  * return %FALSE if @tree_view is not realized or does not have a model.
13508  * 
13509  * Return value: whether there is a row at the given position, %TRUE if this
13510  * is indeed the case.
13511  **/
13512 gboolean
13513 gtk_tree_view_get_dest_row_at_pos (GtkTreeView             *tree_view,
13514                                    gint                     drag_x,
13515                                    gint                     drag_y,
13516                                    GtkTreePath            **path,
13517                                    GtkTreeViewDropPosition *pos)
13518 {
13519   gint cell_y;
13520   gint bin_x, bin_y;
13521   gdouble offset_into_row;
13522   gdouble third;
13523   GdkRectangle cell;
13524   GtkTreeViewColumn *column = NULL;
13525   GtkTreePath *tmp_path = NULL;
13526
13527   /* Note; this function is exported to allow a custom DND
13528    * implementation, so it can't touch TreeViewDragInfo
13529    */
13530
13531   g_return_val_if_fail (tree_view != NULL, FALSE);
13532   g_return_val_if_fail (drag_x >= 0, FALSE);
13533   g_return_val_if_fail (drag_y >= 0, FALSE);
13534
13535   if (path)
13536     *path = NULL;
13537
13538   if (tree_view->priv->bin_window == NULL)
13539     return FALSE;
13540
13541   if (tree_view->priv->tree == NULL)
13542     return FALSE;
13543
13544   /* If in the top third of a row, we drop before that row; if
13545    * in the bottom third, drop after that row; if in the middle,
13546    * and the row has children, drop into the row.
13547    */
13548   gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, drag_x, drag_y,
13549                                                      &bin_x, &bin_y);
13550
13551   if (!gtk_tree_view_get_path_at_pos (tree_view,
13552                                       bin_x,
13553                                       bin_y,
13554                                       &tmp_path,
13555                                       &column,
13556                                       NULL,
13557                                       &cell_y))
13558     return FALSE;
13559
13560   gtk_tree_view_get_background_area (tree_view, tmp_path, column,
13561                                      &cell);
13562
13563   offset_into_row = cell_y;
13564
13565   if (path)
13566     *path = tmp_path;
13567   else
13568     gtk_tree_path_free (tmp_path);
13569
13570   tmp_path = NULL;
13571
13572   third = cell.height / 3.0;
13573
13574   if (pos)
13575     {
13576       if (offset_into_row < third)
13577         {
13578           *pos = GTK_TREE_VIEW_DROP_BEFORE;
13579         }
13580       else if (offset_into_row < (cell.height / 2.0))
13581         {
13582           *pos = GTK_TREE_VIEW_DROP_INTO_OR_BEFORE;
13583         }
13584       else if (offset_into_row < third * 2.0)
13585         {
13586           *pos = GTK_TREE_VIEW_DROP_INTO_OR_AFTER;
13587         }
13588       else
13589         {
13590           *pos = GTK_TREE_VIEW_DROP_AFTER;
13591         }
13592     }
13593
13594   return TRUE;
13595 }
13596
13597
13598
13599 /* KEEP IN SYNC WITH GTK_TREE_VIEW_BIN_EXPOSE */
13600 /**
13601  * gtk_tree_view_create_row_drag_icon:
13602  * @tree_view: a #GtkTreeView
13603  * @path: a #GtkTreePath in @tree_view
13604  *
13605  * Creates a #GdkPixmap representation of the row at @path.  
13606  * This image is used for a drag icon.
13607  *
13608  * Return value: a newly-allocated pixmap of the drag icon.
13609  **/
13610 GdkPixmap *
13611 gtk_tree_view_create_row_drag_icon (GtkTreeView  *tree_view,
13612                                     GtkTreePath  *path)
13613 {
13614   GtkTreeIter   iter;
13615   GtkRBTree    *tree;
13616   GtkRBNode    *node;
13617   gint cell_offset;
13618   GList *list;
13619   GdkRectangle background_area;
13620   GdkRectangle expose_area;
13621   GtkWidget *widget;
13622   gint depth;
13623   /* start drawing inside the black outline */
13624   gint x = 1, y = 1;
13625   GdkDrawable *drawable;
13626   gint bin_window_width;
13627   gboolean is_separator = FALSE;
13628   gboolean rtl;
13629
13630   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
13631   g_return_val_if_fail (path != NULL, NULL);
13632
13633   widget = GTK_WIDGET (tree_view);
13634
13635   if (!GTK_WIDGET_REALIZED (tree_view))
13636     return NULL;
13637
13638   depth = gtk_tree_path_get_depth (path);
13639
13640   _gtk_tree_view_find_node (tree_view,
13641                             path,
13642                             &tree,
13643                             &node);
13644
13645   if (tree == NULL)
13646     return NULL;
13647
13648   if (!gtk_tree_model_get_iter (tree_view->priv->model,
13649                                 &iter,
13650                                 path))
13651     return NULL;
13652   
13653   is_separator = row_is_separator (tree_view, &iter, NULL);
13654
13655   cell_offset = x;
13656
13657   background_area.y = y;
13658   background_area.height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
13659
13660   gdk_drawable_get_size (tree_view->priv->bin_window,
13661                          &bin_window_width, NULL);
13662
13663   drawable = gdk_pixmap_new (tree_view->priv->bin_window,
13664                              bin_window_width + 2,
13665                              background_area.height + 2,
13666                              -1);
13667
13668   expose_area.x = 0;
13669   expose_area.y = 0;
13670   expose_area.width = bin_window_width + 2;
13671   expose_area.height = background_area.height + 2;
13672
13673   gdk_draw_rectangle (drawable,
13674                       widget->style->base_gc [GTK_WIDGET_STATE (widget)],
13675                       TRUE,
13676                       0, 0,
13677                       bin_window_width + 2,
13678                       background_area.height + 2);
13679
13680   rtl = gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL;
13681
13682   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
13683       list;
13684       list = (rtl ? list->prev : list->next))
13685     {
13686       GtkTreeViewColumn *column = list->data;
13687       GdkRectangle cell_area;
13688       gint vertical_separator;
13689
13690       if (!column->visible)
13691         continue;
13692
13693       gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, &iter,
13694                                                GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
13695                                                node->children?TRUE:FALSE);
13696
13697       background_area.x = cell_offset;
13698       background_area.width = column->width;
13699
13700       gtk_widget_style_get (widget,
13701                             "vertical-separator", &vertical_separator,
13702                             NULL);
13703
13704       cell_area = background_area;
13705
13706       cell_area.y += vertical_separator / 2;
13707       cell_area.height -= vertical_separator;
13708
13709       if (gtk_tree_view_is_expander_column (tree_view, column))
13710         {
13711           if (!rtl)
13712             cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
13713           cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
13714
13715           if (TREE_VIEW_DRAW_EXPANDERS(tree_view))
13716             {
13717               if (!rtl)
13718                 cell_area.x += depth * tree_view->priv->expander_size;
13719               cell_area.width -= depth * tree_view->priv->expander_size;
13720             }
13721         }
13722
13723       if (gtk_tree_view_column_cell_is_visible (column))
13724         {
13725           if (is_separator)
13726             gtk_paint_hline (widget->style,
13727                              drawable,
13728                              GTK_STATE_NORMAL,
13729                              &cell_area,
13730                              widget,
13731                              NULL,
13732                              cell_area.x,
13733                              cell_area.x + cell_area.width,
13734                              cell_area.y + cell_area.height / 2);
13735           else
13736             _gtk_tree_view_column_cell_render (column,
13737                                                drawable,
13738                                                &background_area,
13739                                                &cell_area,
13740                                                &expose_area,
13741                                                0);
13742         }
13743       cell_offset += column->width;
13744     }
13745
13746   gdk_draw_rectangle (drawable,
13747                       widget->style->black_gc,
13748                       FALSE,
13749                       0, 0,
13750                       bin_window_width + 1,
13751                       background_area.height + 1);
13752
13753   return drawable;
13754 }
13755
13756
13757 /**
13758  * gtk_tree_view_set_destroy_count_func:
13759  * @tree_view: A #GtkTreeView
13760  * @func: Function to be called when a view row is destroyed, or %NULL
13761  * @data: User data to be passed to @func, or %NULL
13762  * @destroy: Destroy notifier for @data, or %NULL
13763  *
13764  * This function should almost never be used.  It is meant for private use by
13765  * ATK for determining the number of visible children that are removed when the
13766  * user collapses a row, or a row is deleted.
13767  **/
13768 void
13769 gtk_tree_view_set_destroy_count_func (GtkTreeView             *tree_view,
13770                                       GtkTreeDestroyCountFunc  func,
13771                                       gpointer                 data,
13772                                       GDestroyNotify           destroy)
13773 {
13774   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13775
13776   if (tree_view->priv->destroy_count_destroy)
13777     tree_view->priv->destroy_count_destroy (tree_view->priv->destroy_count_data);
13778
13779   tree_view->priv->destroy_count_func = func;
13780   tree_view->priv->destroy_count_data = data;
13781   tree_view->priv->destroy_count_destroy = destroy;
13782 }
13783
13784
13785 /*
13786  * Interactive search
13787  */
13788
13789 /**
13790  * gtk_tree_view_set_enable_search:
13791  * @tree_view: A #GtkTreeView
13792  * @enable_search: %TRUE, if the user can search interactively
13793  *
13794  * If @enable_search is set, then the user can type in text to search through
13795  * the tree interactively (this is sometimes called "typeahead find").
13796  * 
13797  * Note that even if this is %FALSE, the user can still initiate a search 
13798  * using the "start-interactive-search" key binding.
13799  */
13800 void
13801 gtk_tree_view_set_enable_search (GtkTreeView *tree_view,
13802                                  gboolean     enable_search)
13803 {
13804   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13805
13806   enable_search = !!enable_search;
13807   
13808   if (tree_view->priv->enable_search != enable_search)
13809     {
13810        tree_view->priv->enable_search = enable_search;
13811        g_object_notify (G_OBJECT (tree_view), "enable-search");
13812     }
13813 }
13814
13815 /**
13816  * gtk_tree_view_get_enable_search:
13817  * @tree_view: A #GtkTreeView
13818  *
13819  * Returns whether or not the tree allows to start interactive searching 
13820  * by typing in text.
13821  *
13822  * Return value: whether or not to let the user search interactively
13823  */
13824 gboolean
13825 gtk_tree_view_get_enable_search (GtkTreeView *tree_view)
13826 {
13827   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
13828
13829   return tree_view->priv->enable_search;
13830 }
13831
13832
13833 /**
13834  * gtk_tree_view_get_search_column:
13835  * @tree_view: A #GtkTreeView
13836  *
13837  * Gets the column searched on by the interactive search code.
13838  *
13839  * Return value: the column the interactive search code searches in.
13840  */
13841 gint
13842 gtk_tree_view_get_search_column (GtkTreeView *tree_view)
13843 {
13844   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
13845
13846   return (tree_view->priv->search_column);
13847 }
13848
13849 /**
13850  * gtk_tree_view_set_search_column:
13851  * @tree_view: A #GtkTreeView
13852  * @column: the column of the model to search in, or -1 to disable searching
13853  *
13854  * Sets @column as the column where the interactive search code should
13855  * search in for the current model. 
13856  * 
13857  * If the search column is set, users can use the "start-interactive-search"
13858  * key binding to bring up search popup. The enable-search property controls
13859  * whether simply typing text will also start an interactive search.
13860  *
13861  * Note that @column refers to a column of the current model. The search 
13862  * column is reset to -1 when the model is changed.
13863  */
13864 void
13865 gtk_tree_view_set_search_column (GtkTreeView *tree_view,
13866                                  gint         column)
13867 {
13868   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13869   g_return_if_fail (column >= -1);
13870
13871   if (tree_view->priv->search_column == column)
13872     return;
13873
13874   tree_view->priv->search_column = column;
13875   g_object_notify (G_OBJECT (tree_view), "search-column");
13876 }
13877
13878 /**
13879  * gtk_tree_view_get_search_equal_func:
13880  * @tree_view: A #GtkTreeView
13881  *
13882  * Returns the compare function currently in use.
13883  *
13884  * Return value: the currently used compare function for the search code.
13885  */
13886
13887 GtkTreeViewSearchEqualFunc
13888 gtk_tree_view_get_search_equal_func (GtkTreeView *tree_view)
13889 {
13890   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
13891
13892   return tree_view->priv->search_equal_func;
13893 }
13894
13895 /**
13896  * gtk_tree_view_set_search_equal_func:
13897  * @tree_view: A #GtkTreeView
13898  * @search_equal_func: the compare function to use during the search
13899  * @search_user_data: user data to pass to @search_equal_func, or %NULL
13900  * @search_destroy: Destroy notifier for @search_user_data, or %NULL
13901  *
13902  * Sets the compare function for the interactive search capabilities; note
13903  * that somewhat like strcmp() returning 0 for equality
13904  * #GtkTreeViewSearchEqualFunc returns %FALSE on matches.
13905  **/
13906 void
13907 gtk_tree_view_set_search_equal_func (GtkTreeView                *tree_view,
13908                                      GtkTreeViewSearchEqualFunc  search_equal_func,
13909                                      gpointer                    search_user_data,
13910                                      GDestroyNotify              search_destroy)
13911 {
13912   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13913   g_return_if_fail (search_equal_func != NULL);
13914
13915   if (tree_view->priv->search_destroy)
13916     tree_view->priv->search_destroy (tree_view->priv->search_user_data);
13917
13918   tree_view->priv->search_equal_func = search_equal_func;
13919   tree_view->priv->search_user_data = search_user_data;
13920   tree_view->priv->search_destroy = search_destroy;
13921   if (tree_view->priv->search_equal_func == NULL)
13922     tree_view->priv->search_equal_func = gtk_tree_view_search_equal_func;
13923 }
13924
13925 /**
13926  * gtk_tree_view_get_search_entry:
13927  * @tree_view: A #GtkTreeView
13928  *
13929  * Returns the #GtkEntry which is currently in use as interactive search
13930  * entry for @tree_view.  In case the built-in entry is being used, %NULL
13931  * will be returned.
13932  *
13933  * Return value: the entry currently in use as search entry.
13934  *
13935  * Since: 2.10
13936  */
13937 GtkEntry *
13938 gtk_tree_view_get_search_entry (GtkTreeView *tree_view)
13939 {
13940   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
13941
13942   if (tree_view->priv->search_custom_entry_set)
13943     return GTK_ENTRY (tree_view->priv->search_entry);
13944
13945   return NULL;
13946 }
13947
13948 /**
13949  * gtk_tree_view_set_search_entry:
13950  * @tree_view: A #GtkTreeView
13951  * @entry: the entry the interactive search code of @tree_view should use or %NULL
13952  *
13953  * Sets the entry which the interactive search code will use for this
13954  * @tree_view.  This is useful when you want to provide a search entry
13955  * in our interface at all time at a fixed position.  Passing %NULL for
13956  * @entry will make the interactive search code use the built-in popup
13957  * entry again.
13958  *
13959  * Since: 2.10
13960  */
13961 void
13962 gtk_tree_view_set_search_entry (GtkTreeView *tree_view,
13963                                 GtkEntry    *entry)
13964 {
13965   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13966   g_return_if_fail (entry == NULL || GTK_IS_ENTRY (entry));
13967
13968   if (tree_view->priv->search_custom_entry_set)
13969     {
13970       if (tree_view->priv->search_entry_changed_id)
13971         {
13972           g_signal_handler_disconnect (tree_view->priv->search_entry,
13973                                        tree_view->priv->search_entry_changed_id);
13974           tree_view->priv->search_entry_changed_id = 0;
13975         }
13976       g_signal_handlers_disconnect_by_func (tree_view->priv->search_entry,
13977                                             G_CALLBACK (gtk_tree_view_search_key_press_event),
13978                                             tree_view);
13979
13980       g_object_unref (tree_view->priv->search_entry);
13981     }
13982   else if (tree_view->priv->search_window)
13983     {
13984       gtk_widget_destroy (tree_view->priv->search_window);
13985
13986       tree_view->priv->search_window = NULL;
13987     }
13988
13989   if (entry)
13990     {
13991       tree_view->priv->search_entry = g_object_ref (entry);
13992       tree_view->priv->search_custom_entry_set = TRUE;
13993
13994       if (tree_view->priv->search_entry_changed_id == 0)
13995         {
13996           tree_view->priv->search_entry_changed_id =
13997             g_signal_connect (tree_view->priv->search_entry, "changed",
13998                               G_CALLBACK (gtk_tree_view_search_init),
13999                               tree_view);
14000         }
14001       
14002         g_signal_connect (tree_view->priv->search_entry, "key-press-event",
14003                           G_CALLBACK (gtk_tree_view_search_key_press_event),
14004                           tree_view);
14005
14006         gtk_tree_view_search_init (tree_view->priv->search_entry, tree_view);
14007     }
14008   else
14009     {
14010       tree_view->priv->search_entry = NULL;
14011       tree_view->priv->search_custom_entry_set = FALSE;
14012     }
14013 }
14014
14015 /**
14016  * gtk_tree_view_set_search_position_func:
14017  * @tree_view: A #GtkTreeView
14018  * @func: the function to use to position the search dialog, or %NULL
14019  *    to use the default search position function
14020  * @data: user data to pass to @func, or %NULL
14021  * @destroy: Destroy notifier for @data, or %NULL
14022  *
14023  * Sets the function to use when positioning the search dialog.
14024  *
14025  * Since: 2.10
14026  **/
14027 void
14028 gtk_tree_view_set_search_position_func (GtkTreeView                   *tree_view,
14029                                         GtkTreeViewSearchPositionFunc  func,
14030                                         gpointer                       user_data,
14031                                         GDestroyNotify                 destroy)
14032 {
14033   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14034
14035   if (tree_view->priv->search_position_destroy)
14036     tree_view->priv->search_position_destroy (tree_view->priv->search_position_user_data);
14037
14038   tree_view->priv->search_position_func = func;
14039   tree_view->priv->search_position_user_data = user_data;
14040   tree_view->priv->search_position_destroy = destroy;
14041   if (tree_view->priv->search_position_func == NULL)
14042     tree_view->priv->search_position_func = gtk_tree_view_search_position_func;
14043 }
14044
14045 /**
14046  * gtk_tree_view_get_search_position_func:
14047  * @tree_view: A #GtkTreeView
14048  *
14049  * Returns the positioning function currently in use.
14050  *
14051  * Return value: the currently used function for positioning the search dialog.
14052  *
14053  * Since: 2.10
14054  */
14055 GtkTreeViewSearchPositionFunc
14056 gtk_tree_view_get_search_position_func (GtkTreeView *tree_view)
14057 {
14058   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14059
14060   return tree_view->priv->search_position_func;
14061 }
14062
14063
14064 static void
14065 gtk_tree_view_search_dialog_hide (GtkWidget   *search_dialog,
14066                                   GtkTreeView *tree_view)
14067 {
14068   if (tree_view->priv->disable_popdown)
14069     return;
14070
14071   if (tree_view->priv->search_entry_changed_id)
14072     {
14073       g_signal_handler_disconnect (tree_view->priv->search_entry,
14074                                    tree_view->priv->search_entry_changed_id);
14075       tree_view->priv->search_entry_changed_id = 0;
14076     }
14077   if (tree_view->priv->typeselect_flush_timeout)
14078     {
14079       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14080       tree_view->priv->typeselect_flush_timeout = 0;
14081     }
14082         
14083   if (GTK_WIDGET_VISIBLE (search_dialog))
14084     {
14085       /* send focus-in event */
14086       send_focus_change (GTK_WIDGET (tree_view->priv->search_entry), FALSE);
14087       gtk_widget_hide (search_dialog);
14088       gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
14089       send_focus_change (GTK_WIDGET (tree_view), TRUE);
14090     }
14091 }
14092
14093 static void
14094 gtk_tree_view_search_position_func (GtkTreeView *tree_view,
14095                                     GtkWidget   *search_dialog,
14096                                     gpointer     user_data)
14097 {
14098   gint x, y;
14099   gint tree_x, tree_y;
14100   gint tree_width, tree_height;
14101   GdkWindow *tree_window = GTK_WIDGET (tree_view)->window;
14102   GdkScreen *screen = gdk_drawable_get_screen (tree_window);
14103   GtkRequisition requisition;
14104   gint monitor_num;
14105   GdkRectangle monitor;
14106
14107   monitor_num = gdk_screen_get_monitor_at_window (screen, tree_window);
14108   gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
14109
14110   gtk_widget_realize (search_dialog);
14111
14112   gdk_window_get_origin (tree_window, &tree_x, &tree_y);
14113   gdk_drawable_get_size (tree_window,
14114                          &tree_width,
14115                          &tree_height);
14116   gtk_widget_size_request (search_dialog, &requisition);
14117
14118   if (tree_x + tree_width > gdk_screen_get_width (screen))
14119     x = gdk_screen_get_width (screen) - requisition.width;
14120   else if (tree_x + tree_width - requisition.width < 0)
14121     x = 0;
14122   else
14123     x = tree_x + tree_width - requisition.width;
14124
14125   if (tree_y + tree_height + requisition.height > gdk_screen_get_height (screen))
14126     y = gdk_screen_get_height (screen) - requisition.height;
14127   else if (tree_y + tree_height < 0) /* isn't really possible ... */
14128     y = 0;
14129   else
14130     y = tree_y + tree_height;
14131
14132   gtk_window_move (GTK_WINDOW (search_dialog), x, y);
14133 }
14134
14135 static void
14136 gtk_tree_view_search_disable_popdown (GtkEntry *entry,
14137                                       GtkMenu  *menu,
14138                                       gpointer  data)
14139 {
14140   GtkTreeView *tree_view = (GtkTreeView *)data;
14141
14142   tree_view->priv->disable_popdown = 1;
14143   g_signal_connect (menu, "hide",
14144                     G_CALLBACK (gtk_tree_view_search_enable_popdown), data);
14145 }
14146
14147 /* Because we're visible but offscreen, we just set a flag in the preedit
14148  * callback.
14149  */
14150 static void
14151 gtk_tree_view_search_preedit_changed (GtkIMContext *im_context,
14152                                       GtkTreeView  *tree_view)
14153 {
14154   tree_view->priv->imcontext_changed = 1;
14155   if (tree_view->priv->typeselect_flush_timeout)
14156     {
14157       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14158       tree_view->priv->typeselect_flush_timeout =
14159         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
14160                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
14161                        tree_view);
14162     }
14163
14164 }
14165
14166 static void
14167 gtk_tree_view_search_activate (GtkEntry    *entry,
14168                                GtkTreeView *tree_view)
14169 {
14170   GtkTreePath *path;
14171   GtkRBNode *node;
14172   GtkRBTree *tree;
14173
14174   gtk_tree_view_search_dialog_hide (tree_view->priv->search_window,
14175                                     tree_view);
14176
14177   /* If we have a row selected and it's the cursor row, we activate
14178    * the row XXX */
14179   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
14180     {
14181       path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
14182       
14183       _gtk_tree_view_find_node (tree_view, path, &tree, &node);
14184       
14185       if (node && GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
14186         gtk_tree_view_row_activated (tree_view, path, tree_view->priv->focus_column);
14187       
14188       gtk_tree_path_free (path);
14189     }
14190 }
14191
14192 static gboolean
14193 gtk_tree_view_real_search_enable_popdown (gpointer data)
14194 {
14195   GtkTreeView *tree_view = (GtkTreeView *)data;
14196
14197   tree_view->priv->disable_popdown = 0;
14198
14199   return FALSE;
14200 }
14201
14202 static void
14203 gtk_tree_view_search_enable_popdown (GtkWidget *widget,
14204                                      gpointer   data)
14205 {
14206   gdk_threads_add_timeout_full (G_PRIORITY_HIGH, 200, gtk_tree_view_real_search_enable_popdown, g_object_ref (data), g_object_unref);
14207 }
14208
14209 static gboolean
14210 gtk_tree_view_search_delete_event (GtkWidget *widget,
14211                                    GdkEventAny *event,
14212                                    GtkTreeView *tree_view)
14213 {
14214   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
14215
14216   gtk_tree_view_search_dialog_hide (widget, tree_view);
14217
14218   return TRUE;
14219 }
14220
14221 static gboolean
14222 gtk_tree_view_search_button_press_event (GtkWidget *widget,
14223                                          GdkEventButton *event,
14224                                          GtkTreeView *tree_view)
14225 {
14226   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
14227
14228   gtk_tree_view_search_dialog_hide (widget, tree_view);
14229
14230   if (event->window == tree_view->priv->bin_window)
14231     gtk_tree_view_button_press (GTK_WIDGET (tree_view), event);
14232
14233   return TRUE;
14234 }
14235
14236 static gboolean
14237 gtk_tree_view_search_scroll_event (GtkWidget *widget,
14238                                    GdkEventScroll *event,
14239                                    GtkTreeView *tree_view)
14240 {
14241   gboolean retval = FALSE;
14242
14243   if (event->direction == GDK_SCROLL_UP)
14244     {
14245       gtk_tree_view_search_move (widget, tree_view, TRUE);
14246       retval = TRUE;
14247     }
14248   else if (event->direction == GDK_SCROLL_DOWN)
14249     {
14250       gtk_tree_view_search_move (widget, tree_view, FALSE);
14251       retval = TRUE;
14252     }
14253
14254   /* renew the flush timeout */
14255   if (retval && tree_view->priv->typeselect_flush_timeout
14256       && !tree_view->priv->search_custom_entry_set)
14257     {
14258       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14259       tree_view->priv->typeselect_flush_timeout =
14260         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
14261                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
14262                        tree_view);
14263     }
14264
14265   return retval;
14266 }
14267
14268 static gboolean
14269 gtk_tree_view_search_key_press_event (GtkWidget *widget,
14270                                       GdkEventKey *event,
14271                                       GtkTreeView *tree_view)
14272 {
14273   gboolean retval = FALSE;
14274
14275   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
14276   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
14277
14278   /* close window and cancel the search */
14279   if (!tree_view->priv->search_custom_entry_set
14280       && (event->keyval == GDK_Escape ||
14281           event->keyval == GDK_Tab ||
14282             event->keyval == GDK_KP_Tab ||
14283             event->keyval == GDK_ISO_Left_Tab))
14284     {
14285       gtk_tree_view_search_dialog_hide (widget, tree_view);
14286       return TRUE;
14287     }
14288
14289   /* select previous matching iter */
14290   if (event->keyval == GDK_Up || event->keyval == GDK_KP_Up)
14291     {
14292       if (!gtk_tree_view_search_move (widget, tree_view, TRUE))
14293         gtk_widget_error_bell (widget);
14294
14295       retval = TRUE;
14296     }
14297
14298   if (((event->state & (GTK_DEFAULT_ACCEL_MOD_MASK | GDK_SHIFT_MASK)) == (GTK_DEFAULT_ACCEL_MOD_MASK | GDK_SHIFT_MASK))
14299       && (event->keyval == GDK_g || event->keyval == GDK_G))
14300     {
14301       if (!gtk_tree_view_search_move (widget, tree_view, TRUE))
14302         gtk_widget_error_bell (widget);
14303
14304       retval = TRUE;
14305     }
14306
14307   /* select next matching iter */
14308   if (event->keyval == GDK_Down || event->keyval == GDK_KP_Down)
14309     {
14310       if (!gtk_tree_view_search_move (widget, tree_view, FALSE))
14311         gtk_widget_error_bell (widget);
14312
14313       retval = TRUE;
14314     }
14315
14316   if (((event->state & (GTK_DEFAULT_ACCEL_MOD_MASK | GDK_SHIFT_MASK)) == GTK_DEFAULT_ACCEL_MOD_MASK)
14317       && (event->keyval == GDK_g || event->keyval == GDK_G))
14318     {
14319       if (!gtk_tree_view_search_move (widget, tree_view, FALSE))
14320         gtk_widget_error_bell (widget);
14321
14322       retval = TRUE;
14323     }
14324
14325   /* renew the flush timeout */
14326   if (retval && tree_view->priv->typeselect_flush_timeout
14327       && !tree_view->priv->search_custom_entry_set)
14328     {
14329       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14330       tree_view->priv->typeselect_flush_timeout =
14331         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
14332                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
14333                        tree_view);
14334     }
14335
14336   return retval;
14337 }
14338
14339 /*  this function returns FALSE if there is a search string but
14340  *  nothing was found, and TRUE otherwise.
14341  */
14342 static gboolean
14343 gtk_tree_view_search_move (GtkWidget   *window,
14344                            GtkTreeView *tree_view,
14345                            gboolean     up)
14346 {
14347   gboolean ret;
14348   gint len;
14349   gint count = 0;
14350   const gchar *text;
14351   GtkTreeIter iter;
14352   GtkTreeModel *model;
14353   GtkTreeSelection *selection;
14354
14355   text = gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry));
14356
14357   g_return_val_if_fail (text != NULL, FALSE);
14358
14359   len = strlen (text);
14360
14361   if (up && tree_view->priv->selected_iter == 1)
14362     return strlen (text) < 1;
14363
14364   len = strlen (text);
14365
14366   if (len < 1)
14367     return TRUE;
14368
14369   model = gtk_tree_view_get_model (tree_view);
14370   selection = gtk_tree_view_get_selection (tree_view);
14371
14372   /* search */
14373   gtk_tree_selection_unselect_all (selection);
14374   if (!gtk_tree_model_get_iter_first (model, &iter))
14375     return TRUE;
14376
14377   ret = gtk_tree_view_search_iter (model, selection, &iter, text,
14378                                    &count, up?((tree_view->priv->selected_iter) - 1):((tree_view->priv->selected_iter + 1)));
14379
14380   if (ret)
14381     {
14382       /* found */
14383       tree_view->priv->selected_iter += up?(-1):(1);
14384       return TRUE;
14385     }
14386   else
14387     {
14388       /* return to old iter */
14389       count = 0;
14390       gtk_tree_model_get_iter_first (model, &iter);
14391       gtk_tree_view_search_iter (model, selection,
14392                                  &iter, text,
14393                                  &count, tree_view->priv->selected_iter);
14394       return FALSE;
14395     }
14396 }
14397
14398 static gboolean
14399 gtk_tree_view_search_equal_func (GtkTreeModel *model,
14400                                  gint          column,
14401                                  const gchar  *key,
14402                                  GtkTreeIter  *iter,
14403                                  gpointer      search_data)
14404 {
14405   gboolean retval = TRUE;
14406   const gchar *str;
14407   gchar *normalized_string;
14408   gchar *normalized_key;
14409   gchar *case_normalized_string = NULL;
14410   gchar *case_normalized_key = NULL;
14411   GValue value = {0,};
14412   GValue transformed = {0,};
14413
14414   gtk_tree_model_get_value (model, iter, column, &value);
14415
14416   g_value_init (&transformed, G_TYPE_STRING);
14417
14418   if (!g_value_transform (&value, &transformed))
14419     {
14420       g_value_unset (&value);
14421       return TRUE;
14422     }
14423
14424   g_value_unset (&value);
14425
14426   str = g_value_get_string (&transformed);
14427   if (!str)
14428     {
14429       g_value_unset (&transformed);
14430       return TRUE;
14431     }
14432
14433   normalized_string = g_utf8_normalize (str, -1, G_NORMALIZE_ALL);
14434   normalized_key = g_utf8_normalize (key, -1, G_NORMALIZE_ALL);
14435
14436   if (normalized_string && normalized_key)
14437     {
14438       case_normalized_string = g_utf8_casefold (normalized_string, -1);
14439       case_normalized_key = g_utf8_casefold (normalized_key, -1);
14440
14441       if (strncmp (case_normalized_key, case_normalized_string, strlen (case_normalized_key)) == 0)
14442         retval = FALSE;
14443     }
14444
14445   g_value_unset (&transformed);
14446   g_free (normalized_key);
14447   g_free (normalized_string);
14448   g_free (case_normalized_key);
14449   g_free (case_normalized_string);
14450
14451   return retval;
14452 }
14453
14454 static gboolean
14455 gtk_tree_view_search_iter (GtkTreeModel     *model,
14456                            GtkTreeSelection *selection,
14457                            GtkTreeIter      *iter,
14458                            const gchar      *text,
14459                            gint             *count,
14460                            gint              n)
14461 {
14462   GtkRBTree *tree = NULL;
14463   GtkRBNode *node = NULL;
14464   GtkTreePath *path;
14465
14466   GtkTreeView *tree_view = gtk_tree_selection_get_tree_view (selection);
14467
14468   path = gtk_tree_model_get_path (model, iter);
14469   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
14470
14471   do
14472     {
14473       if (! tree_view->priv->search_equal_func (model, tree_view->priv->search_column, text, iter, tree_view->priv->search_user_data))
14474         {
14475           (*count)++;
14476           if (*count == n)
14477             {
14478               gtk_tree_view_scroll_to_cell (tree_view, path, NULL,
14479                                             TRUE, 0.5, 0.0);
14480               gtk_tree_selection_select_iter (selection, iter);
14481               gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
14482
14483               if (path)
14484                 gtk_tree_path_free (path);
14485
14486               return TRUE;
14487             }
14488         }
14489
14490       if (node->children)
14491         {
14492           gboolean has_child;
14493           GtkTreeIter tmp;
14494
14495           tree = node->children;
14496           node = tree->root;
14497
14498           while (node->left != tree->nil)
14499             node = node->left;
14500
14501           tmp = *iter;
14502           has_child = gtk_tree_model_iter_children (model, iter, &tmp);
14503           gtk_tree_path_down (path);
14504
14505           /* sanity check */
14506           TREE_VIEW_INTERNAL_ASSERT (has_child, FALSE);
14507         }
14508       else
14509         {
14510           gboolean done = FALSE;
14511
14512           do
14513             {
14514               node = _gtk_rbtree_next (tree, node);
14515
14516               if (node)
14517                 {
14518                   gboolean has_next;
14519
14520                   has_next = gtk_tree_model_iter_next (model, iter);
14521
14522                   done = TRUE;
14523                   gtk_tree_path_next (path);
14524
14525                   /* sanity check */
14526                   TREE_VIEW_INTERNAL_ASSERT (has_next, FALSE);
14527                 }
14528               else
14529                 {
14530                   gboolean has_parent;
14531                   GtkTreeIter tmp_iter = *iter;
14532
14533                   node = tree->parent_node;
14534                   tree = tree->parent_tree;
14535
14536                   if (!tree)
14537                     {
14538                       if (path)
14539                         gtk_tree_path_free (path);
14540
14541                       /* we've run out of tree, done with this func */
14542                       return FALSE;
14543                     }
14544
14545                   has_parent = gtk_tree_model_iter_parent (model,
14546                                                            iter,
14547                                                            &tmp_iter);
14548                   gtk_tree_path_up (path);
14549
14550                   /* sanity check */
14551                   TREE_VIEW_INTERNAL_ASSERT (has_parent, FALSE);
14552                 }
14553             }
14554           while (!done);
14555         }
14556     }
14557   while (1);
14558
14559   return FALSE;
14560 }
14561
14562 static void
14563 gtk_tree_view_search_init (GtkWidget   *entry,
14564                            GtkTreeView *tree_view)
14565 {
14566   gint ret;
14567   gint count = 0;
14568   const gchar *text;
14569   GtkTreeIter iter;
14570   GtkTreeModel *model;
14571   GtkTreeSelection *selection;
14572
14573   g_return_if_fail (GTK_IS_ENTRY (entry));
14574   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14575
14576   text = gtk_entry_get_text (GTK_ENTRY (entry));
14577
14578   model = gtk_tree_view_get_model (tree_view);
14579   selection = gtk_tree_view_get_selection (tree_view);
14580
14581   /* search */
14582   gtk_tree_selection_unselect_all (selection);
14583   if (tree_view->priv->typeselect_flush_timeout
14584       && !tree_view->priv->search_custom_entry_set)
14585     {
14586       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14587       tree_view->priv->typeselect_flush_timeout =
14588         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
14589                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
14590                        tree_view);
14591     }
14592
14593   if (*text == '\0')
14594     return;
14595
14596   if (!gtk_tree_model_get_iter_first (model, &iter))
14597     return;
14598
14599   ret = gtk_tree_view_search_iter (model, selection,
14600                                    &iter, text,
14601                                    &count, 1);
14602
14603   if (ret)
14604     tree_view->priv->selected_iter = 1;
14605 }
14606
14607 static void
14608 gtk_tree_view_remove_widget (GtkCellEditable *cell_editable,
14609                              GtkTreeView     *tree_view)
14610 {
14611   if (tree_view->priv->edited_column == NULL)
14612     return;
14613
14614   _gtk_tree_view_column_stop_editing (tree_view->priv->edited_column);
14615   tree_view->priv->edited_column = NULL;
14616
14617   if (GTK_WIDGET_HAS_FOCUS (cell_editable))
14618     gtk_widget_grab_focus (GTK_WIDGET (tree_view));
14619
14620   g_signal_handlers_disconnect_by_func (cell_editable,
14621                                         gtk_tree_view_remove_widget,
14622                                         tree_view);
14623
14624   gtk_container_remove (GTK_CONTAINER (tree_view),
14625                         GTK_WIDGET (cell_editable));  
14626
14627   /* FIXME should only redraw a single node */
14628   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
14629 }
14630
14631 static gboolean
14632 gtk_tree_view_start_editing (GtkTreeView *tree_view,
14633                              GtkTreePath *cursor_path)
14634 {
14635   GtkTreeIter iter;
14636   GdkRectangle background_area;
14637   GdkRectangle cell_area;
14638   GtkCellEditable *editable_widget = NULL;
14639   gchar *path_string;
14640   guint flags = 0; /* can be 0, as the flags are primarily for rendering */
14641   gint retval = FALSE;
14642   GtkRBTree *cursor_tree;
14643   GtkRBNode *cursor_node;
14644
14645   g_assert (tree_view->priv->focus_column);
14646
14647   if (! GTK_WIDGET_REALIZED (tree_view))
14648     return FALSE;
14649
14650   if (_gtk_tree_view_find_node (tree_view, cursor_path, &cursor_tree, &cursor_node) ||
14651       cursor_node == NULL)
14652     return FALSE;
14653
14654   path_string = gtk_tree_path_to_string (cursor_path);
14655   gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path);
14656
14657   validate_row (tree_view, cursor_tree, cursor_node, &iter, cursor_path);
14658
14659   gtk_tree_view_column_cell_set_cell_data (tree_view->priv->focus_column,
14660                                            tree_view->priv->model,
14661                                            &iter,
14662                                            GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_PARENT),
14663                                            cursor_node->children?TRUE:FALSE);
14664   gtk_tree_view_get_background_area (tree_view,
14665                                      cursor_path,
14666                                      tree_view->priv->focus_column,
14667                                      &background_area);
14668   gtk_tree_view_get_cell_area (tree_view,
14669                                cursor_path,
14670                                tree_view->priv->focus_column,
14671                                &cell_area);
14672
14673   if (_gtk_tree_view_column_cell_event (tree_view->priv->focus_column,
14674                                         &editable_widget,
14675                                         NULL,
14676                                         path_string,
14677                                         &background_area,
14678                                         &cell_area,
14679                                         flags))
14680     {
14681       retval = TRUE;
14682       if (editable_widget != NULL)
14683         {
14684           gint left, right;
14685           GdkRectangle area;
14686           GtkCellRenderer *cell;
14687
14688           area = cell_area;
14689           cell = _gtk_tree_view_column_get_edited_cell (tree_view->priv->focus_column);
14690
14691           _gtk_tree_view_column_get_neighbor_sizes (tree_view->priv->focus_column, cell, &left, &right);
14692
14693           area.x += left;
14694           area.width -= right + left;
14695
14696           gtk_tree_view_real_start_editing (tree_view,
14697                                             tree_view->priv->focus_column,
14698                                             cursor_path,
14699                                             editable_widget,
14700                                             &area,
14701                                             NULL,
14702                                             flags);
14703         }
14704
14705     }
14706   g_free (path_string);
14707   return retval;
14708 }
14709
14710 static void
14711 gtk_tree_view_real_start_editing (GtkTreeView       *tree_view,
14712                                   GtkTreeViewColumn *column,
14713                                   GtkTreePath       *path,
14714                                   GtkCellEditable   *cell_editable,
14715                                   GdkRectangle      *cell_area,
14716                                   GdkEvent          *event,
14717                                   guint              flags)
14718 {
14719   gint pre_val = tree_view->priv->vadjustment->value;
14720   GtkRequisition requisition;
14721
14722   tree_view->priv->edited_column = column;
14723   _gtk_tree_view_column_start_editing (column, GTK_CELL_EDITABLE (cell_editable));
14724
14725   gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
14726   cell_area->y += pre_val - (int)tree_view->priv->vadjustment->value;
14727
14728   gtk_widget_size_request (GTK_WIDGET (cell_editable), &requisition);
14729
14730   GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
14731
14732   if (requisition.height < cell_area->height)
14733     {
14734       gint diff = cell_area->height - requisition.height;
14735       gtk_tree_view_put (tree_view,
14736                          GTK_WIDGET (cell_editable),
14737                          cell_area->x, cell_area->y + diff/2,
14738                          cell_area->width, requisition.height);
14739     }
14740   else
14741     {
14742       gtk_tree_view_put (tree_view,
14743                          GTK_WIDGET (cell_editable),
14744                          cell_area->x, cell_area->y,
14745                          cell_area->width, cell_area->height);
14746     }
14747
14748   gtk_cell_editable_start_editing (GTK_CELL_EDITABLE (cell_editable),
14749                                    (GdkEvent *)event);
14750
14751   gtk_widget_grab_focus (GTK_WIDGET (cell_editable));
14752   g_signal_connect (cell_editable, "remove-widget",
14753                     G_CALLBACK (gtk_tree_view_remove_widget), tree_view);
14754 }
14755
14756 static void
14757 gtk_tree_view_stop_editing (GtkTreeView *tree_view,
14758                             gboolean     cancel_editing)
14759 {
14760   GtkTreeViewColumn *column;
14761   GtkCellRenderer *cell;
14762
14763   if (tree_view->priv->edited_column == NULL)
14764     return;
14765
14766   /*
14767    * This is very evil. We need to do this, because
14768    * gtk_cell_editable_editing_done may trigger gtk_tree_view_row_changed
14769    * later on. If gtk_tree_view_row_changed notices
14770    * tree_view->priv->edited_column != NULL, it'll call
14771    * gtk_tree_view_stop_editing again. Bad things will happen then.
14772    *
14773    * Please read that again if you intend to modify anything here.
14774    */
14775
14776   column = tree_view->priv->edited_column;
14777   tree_view->priv->edited_column = NULL;
14778
14779   cell = _gtk_tree_view_column_get_edited_cell (column);
14780   gtk_cell_renderer_stop_editing (cell, cancel_editing);
14781
14782   if (!cancel_editing)
14783     gtk_cell_editable_editing_done (column->editable_widget);
14784
14785   tree_view->priv->edited_column = column;
14786
14787   gtk_cell_editable_remove_widget (column->editable_widget);
14788 }
14789
14790
14791 /**
14792  * gtk_tree_view_set_hover_selection:
14793  * @tree_view: a #GtkTreeView
14794  * @hover: %TRUE to enable hover selection mode
14795  *
14796  * Enables of disables the hover selection mode of @tree_view.
14797  * Hover selection makes the selected row follow the pointer.
14798  * Currently, this works only for the selection modes 
14799  * %GTK_SELECTION_SINGLE and %GTK_SELECTION_BROWSE.
14800  * 
14801  * Since: 2.6
14802  **/
14803 void     
14804 gtk_tree_view_set_hover_selection (GtkTreeView *tree_view,
14805                                    gboolean     hover)
14806 {
14807   hover = hover != FALSE;
14808
14809   if (hover != tree_view->priv->hover_selection)
14810     {
14811       tree_view->priv->hover_selection = hover;
14812
14813       g_object_notify (G_OBJECT (tree_view), "hover-selection");
14814     }
14815 }
14816
14817 /**
14818  * gtk_tree_view_get_hover_selection:
14819  * @tree_view: a #GtkTreeView
14820  * 
14821  * Returns whether hover selection mode is turned on for @tree_view.
14822  * 
14823  * Return value: %TRUE if @tree_view is in hover selection mode
14824  *
14825  * Since: 2.6 
14826  **/
14827 gboolean 
14828 gtk_tree_view_get_hover_selection (GtkTreeView *tree_view)
14829 {
14830   return tree_view->priv->hover_selection;
14831 }
14832
14833 /**
14834  * gtk_tree_view_set_hover_expand:
14835  * @tree_view: a #GtkTreeView
14836  * @expand: %TRUE to enable hover selection mode
14837  *
14838  * Enables of disables the hover expansion mode of @tree_view.
14839  * Hover expansion makes rows expand or collapse if the pointer 
14840  * moves over them.
14841  * 
14842  * Since: 2.6
14843  **/
14844 void     
14845 gtk_tree_view_set_hover_expand (GtkTreeView *tree_view,
14846                                 gboolean     expand)
14847 {
14848   expand = expand != FALSE;
14849
14850   if (expand != tree_view->priv->hover_expand)
14851     {
14852       tree_view->priv->hover_expand = expand;
14853
14854       g_object_notify (G_OBJECT (tree_view), "hover-expand");
14855     }
14856 }
14857
14858 /**
14859  * gtk_tree_view_get_hover_expand:
14860  * @tree_view: a #GtkTreeView
14861  * 
14862  * Returns whether hover expansion mode is turned on for @tree_view.
14863  * 
14864  * Return value: %TRUE if @tree_view is in hover expansion mode
14865  *
14866  * Since: 2.6 
14867  **/
14868 gboolean 
14869 gtk_tree_view_get_hover_expand (GtkTreeView *tree_view)
14870 {
14871   return tree_view->priv->hover_expand;
14872 }
14873
14874 /**
14875  * gtk_tree_view_set_rubber_banding:
14876  * @tree_view: a #GtkTreeView
14877  * @enable: %TRUE to enable rubber banding
14878  *
14879  * Enables or disables rubber banding in @tree_view.  If the selection mode
14880  * is #GTK_SELECTION_MULTIPLE, rubber banding will allow the user to select
14881  * multiple rows by dragging the mouse.
14882  * 
14883  * Since: 2.10
14884  **/
14885 void
14886 gtk_tree_view_set_rubber_banding (GtkTreeView *tree_view,
14887                                   gboolean     enable)
14888 {
14889   enable = enable != FALSE;
14890
14891   if (enable != tree_view->priv->rubber_banding_enable)
14892     {
14893       tree_view->priv->rubber_banding_enable = enable;
14894
14895       g_object_notify (G_OBJECT (tree_view), "rubber-banding");
14896     }
14897 }
14898
14899 /**
14900  * gtk_tree_view_get_rubber_banding:
14901  * @tree_view: a #GtkTreeView
14902  * 
14903  * Returns whether rubber banding is turned on for @tree_view.  If the
14904  * selection mode is #GTK_SELECTION_MULTIPLE, rubber banding will allow the
14905  * user to select multiple rows by dragging the mouse.
14906  * 
14907  * Return value: %TRUE if rubber banding in @tree_view is enabled.
14908  *
14909  * Since: 2.10
14910  **/
14911 gboolean
14912 gtk_tree_view_get_rubber_banding (GtkTreeView *tree_view)
14913 {
14914   return tree_view->priv->rubber_banding_enable;
14915 }
14916
14917 /**
14918  * gtk_tree_view_is_rubber_banding_active:
14919  * @tree_view: a #GtkTreeView
14920  * 
14921  * Returns whether a rubber banding operation is currently being done
14922  * in @tree_view.
14923  *
14924  * Return value: %TRUE if a rubber banding operation is currently being
14925  * done in @tree_view.
14926  *
14927  * Since: 2.12
14928  **/
14929 gboolean
14930 gtk_tree_view_is_rubber_banding_active (GtkTreeView *tree_view)
14931 {
14932   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
14933
14934   if (tree_view->priv->rubber_banding_enable
14935       && tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
14936     return TRUE;
14937
14938   return FALSE;
14939 }
14940
14941 /**
14942  * gtk_tree_view_get_row_separator_func:
14943  * @tree_view: a #GtkTreeView
14944  * 
14945  * Returns the current row separator function.
14946  * 
14947  * Return value: the current row separator function.
14948  *
14949  * Since: 2.6
14950  **/
14951 GtkTreeViewRowSeparatorFunc 
14952 gtk_tree_view_get_row_separator_func (GtkTreeView *tree_view)
14953 {
14954   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14955
14956   return tree_view->priv->row_separator_func;
14957 }
14958
14959 /**
14960  * gtk_tree_view_set_row_separator_func:
14961  * @tree_view: a #GtkTreeView
14962  * @func: a #GtkTreeViewRowSeparatorFunc
14963  * @data: user data to pass to @func, or %NULL
14964  * @destroy: destroy notifier for @data, or %NULL
14965  * 
14966  * Sets the row separator function, which is used to determine
14967  * whether a row should be drawn as a separator. If the row separator
14968  * function is %NULL, no separators are drawn. This is the default value.
14969  *
14970  * Since: 2.6
14971  **/
14972 void
14973 gtk_tree_view_set_row_separator_func (GtkTreeView                 *tree_view,
14974                                       GtkTreeViewRowSeparatorFunc  func,
14975                                       gpointer                     data,
14976                                       GDestroyNotify               destroy)
14977 {
14978   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14979
14980   if (tree_view->priv->row_separator_destroy)
14981     tree_view->priv->row_separator_destroy (tree_view->priv->row_separator_data);
14982
14983   tree_view->priv->row_separator_func = func;
14984   tree_view->priv->row_separator_data = data;
14985   tree_view->priv->row_separator_destroy = destroy;
14986
14987   /* Have the tree recalculate heights */
14988   _gtk_rbtree_mark_invalid (tree_view->priv->tree);
14989   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
14990 }
14991
14992   
14993 static void
14994 gtk_tree_view_grab_notify (GtkWidget *widget,
14995                            gboolean   was_grabbed)
14996 {
14997   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
14998
14999   tree_view->priv->in_grab = !was_grabbed;
15000
15001   if (!was_grabbed)
15002     {
15003       tree_view->priv->pressed_button = -1;
15004
15005       if (tree_view->priv->rubber_band_status)
15006         gtk_tree_view_stop_rubber_band (tree_view);
15007     }
15008 }
15009
15010 static void
15011 gtk_tree_view_state_changed (GtkWidget      *widget,
15012                              GtkStateType    previous_state)
15013 {
15014   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
15015
15016   if (GTK_WIDGET_REALIZED (widget))
15017     {
15018       gdk_window_set_back_pixmap (widget->window, NULL, FALSE);
15019       gdk_window_set_background (tree_view->priv->bin_window, &widget->style->base[widget->state]);
15020     }
15021
15022   gtk_widget_queue_draw (widget);
15023 }
15024
15025 /**
15026  * gtk_tree_view_get_grid_lines:
15027  * @tree_view: a #GtkTreeView
15028  *
15029  * Returns which grid lines are enabled in @tree_view.
15030  *
15031  * Return value: a #GtkTreeViewGridLines value indicating which grid lines
15032  * are enabled.
15033  *
15034  * Since: 2.10
15035  */
15036 GtkTreeViewGridLines
15037 gtk_tree_view_get_grid_lines (GtkTreeView *tree_view)
15038 {
15039   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
15040
15041   return tree_view->priv->grid_lines;
15042 }
15043
15044 /**
15045  * gtk_tree_view_set_grid_lines:
15046  * @tree_view: a #GtkTreeView
15047  * @grid_lines: a #GtkTreeViewGridLines value indicating which grid lines to
15048  * enable.
15049  *
15050  * Sets which grid lines to draw in @tree_view.
15051  *
15052  * Since: 2.10
15053  */
15054 void
15055 gtk_tree_view_set_grid_lines (GtkTreeView           *tree_view,
15056                               GtkTreeViewGridLines   grid_lines)
15057 {
15058   GtkTreeViewPrivate *priv;
15059   GtkWidget *widget;
15060   GtkTreeViewGridLines old_grid_lines;
15061
15062   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15063
15064   priv = tree_view->priv;
15065   widget = GTK_WIDGET (tree_view);
15066
15067   old_grid_lines = priv->grid_lines;
15068   priv->grid_lines = grid_lines;
15069   
15070   if (GTK_WIDGET_REALIZED (widget))
15071     {
15072       if (grid_lines == GTK_TREE_VIEW_GRID_LINES_NONE &&
15073           priv->grid_line_gc)
15074         {
15075           g_object_unref (priv->grid_line_gc);
15076           priv->grid_line_gc = NULL;
15077         }
15078       
15079       if (grid_lines != GTK_TREE_VIEW_GRID_LINES_NONE && 
15080           !priv->grid_line_gc)
15081         {
15082           gint line_width;
15083           gint8 *dash_list;
15084
15085           gtk_widget_style_get (widget,
15086                                 "grid-line-width", &line_width,
15087                                 "grid-line-pattern", (gchar *)&dash_list,
15088                                 NULL);
15089       
15090           priv->grid_line_gc = gdk_gc_new (widget->window);
15091           gdk_gc_copy (priv->grid_line_gc, widget->style->black_gc);
15092           
15093           gdk_gc_set_line_attributes (priv->grid_line_gc, line_width,
15094                                       GDK_LINE_ON_OFF_DASH,
15095                                       GDK_CAP_BUTT, GDK_JOIN_MITER);
15096           gdk_gc_set_dashes (priv->grid_line_gc, 0, dash_list, 2);
15097
15098           g_free (dash_list);
15099         }      
15100     }
15101
15102   if (old_grid_lines != grid_lines)
15103     {
15104       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15105       
15106       g_object_notify (G_OBJECT (tree_view), "enable-grid-lines");
15107     }
15108 }
15109
15110 /**
15111  * gtk_tree_view_get_enable_tree_lines:
15112  * @tree_view: a #GtkTreeView.
15113  *
15114  * Returns whether or not tree lines are drawn in @tree_view.
15115  *
15116  * Return value: %TRUE if tree lines are drawn in @tree_view, %FALSE
15117  * otherwise.
15118  *
15119  * Since: 2.10
15120  */
15121 gboolean
15122 gtk_tree_view_get_enable_tree_lines (GtkTreeView *tree_view)
15123 {
15124   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15125
15126   return tree_view->priv->tree_lines_enabled;
15127 }
15128
15129 /**
15130  * gtk_tree_view_set_enable_tree_lines:
15131  * @tree_view: a #GtkTreeView
15132  * @enabled: %TRUE to enable tree line drawing, %FALSE otherwise.
15133  *
15134  * Sets whether to draw lines interconnecting the expanders in @tree_view.
15135  * This does not have any visible effects for lists.
15136  *
15137  * Since: 2.10
15138  */
15139 void
15140 gtk_tree_view_set_enable_tree_lines (GtkTreeView *tree_view,
15141                                      gboolean     enabled)
15142 {
15143   GtkTreeViewPrivate *priv;
15144   GtkWidget *widget;
15145   gboolean was_enabled;
15146
15147   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15148
15149   enabled = enabled != FALSE;
15150
15151   priv = tree_view->priv;
15152   widget = GTK_WIDGET (tree_view);
15153
15154   was_enabled = priv->tree_lines_enabled;
15155
15156   priv->tree_lines_enabled = enabled;
15157
15158   if (GTK_WIDGET_REALIZED (widget))
15159     {
15160       if (!enabled && priv->tree_line_gc)
15161         {
15162           g_object_unref (priv->tree_line_gc);
15163           priv->tree_line_gc = NULL;
15164         }
15165       
15166       if (enabled && !priv->tree_line_gc)
15167         {
15168           gint line_width;
15169           gint8 *dash_list;
15170           gtk_widget_style_get (widget,
15171                                 "tree-line-width", &line_width,
15172                                 "tree-line-pattern", (gchar *)&dash_list,
15173                                 NULL);
15174           
15175           priv->tree_line_gc = gdk_gc_new (widget->window);
15176           gdk_gc_copy (priv->tree_line_gc, widget->style->black_gc);
15177           
15178           gdk_gc_set_line_attributes (priv->tree_line_gc, line_width,
15179                                       GDK_LINE_ON_OFF_DASH,
15180                                       GDK_CAP_BUTT, GDK_JOIN_MITER);
15181           gdk_gc_set_dashes (priv->tree_line_gc, 0, dash_list, 2);
15182
15183           g_free (dash_list);
15184         }
15185     }
15186
15187   if (was_enabled != enabled)
15188     {
15189       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15190
15191       g_object_notify (G_OBJECT (tree_view), "enable-tree-lines");
15192     }
15193 }
15194
15195
15196 /**
15197  * gtk_tree_view_set_show_expanders:
15198  * @tree_view: a #GtkTreeView
15199  * @enabled: %TRUE to enable expander drawing, %FALSE otherwise.
15200  *
15201  * Sets whether to draw and enable expanders and indent child rows in
15202  * @tree_view.  When disabled there will be no expanders visible in trees
15203  * and there will be no way to expand and collapse rows by default.  Also
15204  * note that hiding the expanders will disable the default indentation.  You
15205  * can set a custom indentation in this case using
15206  * gtk_tree_view_set_level_indentation().
15207  * This does not have any visible effects for lists.
15208  *
15209  * Since: 2.12
15210  */
15211 void
15212 gtk_tree_view_set_show_expanders (GtkTreeView *tree_view,
15213                                   gboolean     enabled)
15214 {
15215   gboolean was_enabled;
15216
15217   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15218
15219   enabled = enabled != FALSE;
15220   was_enabled = GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS);
15221
15222   if (enabled)
15223     GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS);
15224   else
15225     GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS);
15226
15227   if (enabled != was_enabled)
15228     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15229 }
15230
15231 /**
15232  * gtk_tree_view_get_show_expanders:
15233  * @tree_view: a #GtkTreeView.
15234  *
15235  * Returns whether or not expanders are drawn in @tree_view.
15236  *
15237  * Return value: %TRUE if expanders are drawn in @tree_view, %FALSE
15238  * otherwise.
15239  *
15240  * Since: 2.12
15241  */
15242 gboolean
15243 gtk_tree_view_get_show_expanders (GtkTreeView *tree_view)
15244 {
15245   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15246
15247   return GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS);
15248 }
15249
15250 /**
15251  * gtk_tree_view_set_level_indentation:
15252  * @tree_view: a #GtkTreeView
15253  * @indentation: the amount, in pixels, of extra indentation in @tree_view.
15254  *
15255  * Sets the amount of extra indentation for child levels to use in @tree_view
15256  * in addition to the default indentation.  The value should be specified in
15257  * pixels, a value of 0 disables this feature and in this case only the default
15258  * indentation will be used.
15259  * This does not have any visible effects for lists.
15260  *
15261  * Since: 2.12
15262  */
15263 void
15264 gtk_tree_view_set_level_indentation (GtkTreeView *tree_view,
15265                                      gint         indentation)
15266 {
15267   tree_view->priv->level_indentation = indentation;
15268
15269   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15270 }
15271
15272 /**
15273  * gtk_tree_view_get_level_indentation:
15274  * @tree_view: a #GtkTreeView.
15275  *
15276  * Returns the amount, in pixels, of extra indentation for child levels
15277  * in @tree_view.
15278  *
15279  * Return value: the amount of extra indentation for child levels in
15280  * @tree_view.  A return value of 0 means that this feature is disabled.
15281  *
15282  * Since: 2.12
15283  */
15284 gint
15285 gtk_tree_view_get_level_indentation (GtkTreeView *tree_view)
15286 {
15287   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
15288
15289   return tree_view->priv->level_indentation;
15290 }
15291
15292 /**
15293  * gtk_tree_view_set_tooltip_row:
15294  * @tree_view: a #GtkTreeView
15295  * @tooltip: a #GtkTooltip
15296  * @path: a #GtkTreePath
15297  *
15298  * Sets the tip area of @tooltip to be the area covered by the row at @path.
15299  * See also gtk_tree_view_set_tooltip_column() for a simpler alternative.
15300  * See also gtk_tooltip_set_tip_area().
15301  *
15302  * Since: 2.12
15303  */
15304 void
15305 gtk_tree_view_set_tooltip_row (GtkTreeView *tree_view,
15306                                GtkTooltip  *tooltip,
15307                                GtkTreePath *path)
15308 {
15309   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15310   g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
15311
15312   gtk_tree_view_set_tooltip_cell (tree_view, tooltip, path, NULL, NULL);
15313 }
15314
15315 /**
15316  * gtk_tree_view_set_tooltip_cell:
15317  * @tree_view: a #GtkTreeView
15318  * @tooltip: a #GtkTooltip
15319  * @path: a #GtkTreePath or %NULL
15320  * @column: a #GtkTreeViewColumn or %NULL
15321  * @cell: a #GtkCellRenderer or %NULL
15322  *
15323  * Sets the tip area of @tooltip to the area @path, @column and @cell have
15324  * in common.  For example if @path is %NULL and @column is set, the tip
15325  * area will be set to the full area covered by @column.  See also
15326  * gtk_tooltip_set_tip_area().
15327  *
15328  * Note that if @path is not specified and @cell is set and part of a column
15329  * containing the expander, the tooltip might not show and hide at the correct
15330  * position.  In such cases @path must be set to the current node under the
15331  * mouse cursor for this function to operate correctly.
15332  *
15333  * See also gtk_tree_view_set_tooltip_column() for a simpler alternative.
15334  *
15335  * Since: 2.12
15336  */
15337 void
15338 gtk_tree_view_set_tooltip_cell (GtkTreeView       *tree_view,
15339                                 GtkTooltip        *tooltip,
15340                                 GtkTreePath       *path,
15341                                 GtkTreeViewColumn *column,
15342                                 GtkCellRenderer   *cell)
15343 {
15344   GdkRectangle rect;
15345
15346   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15347   g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
15348   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
15349   g_return_if_fail (cell == NULL || GTK_IS_CELL_RENDERER (cell));
15350
15351   /* Determine x values. */
15352   if (column && cell)
15353     {
15354       GdkRectangle tmp;
15355       gint start, width;
15356
15357       /* We always pass in path here, whether it is NULL or not.
15358        * For cells in expander columns path must be specified so that
15359        * we can correctly account for the indentation.  This also means
15360        * that the tooltip is constrained vertically by the "Determine y
15361        * values" code below; this is not a real problem since cells actually
15362        * don't stretch vertically in constrast to columns.
15363        */
15364       gtk_tree_view_get_cell_area (tree_view, path, column, &tmp);
15365       gtk_tree_view_column_cell_get_position (column, cell, &start, &width);
15366
15367       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
15368                                                          tmp.x + start, 0,
15369                                                          &rect.x, NULL);
15370       rect.width = width;
15371     }
15372   else if (column)
15373     {
15374       GdkRectangle tmp;
15375
15376       gtk_tree_view_get_background_area (tree_view, NULL, column, &tmp);
15377       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
15378                                                          tmp.x, 0,
15379                                                          &rect.x, NULL);
15380       rect.width = tmp.width;
15381     }
15382   else
15383     {
15384       rect.x = 0;
15385       rect.width = GTK_WIDGET (tree_view)->allocation.width;
15386     }
15387
15388   /* Determine y values. */
15389   if (path)
15390     {
15391       GdkRectangle tmp;
15392
15393       gtk_tree_view_get_background_area (tree_view, path, NULL, &tmp);
15394       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
15395                                                          0, tmp.y,
15396                                                          NULL, &rect.y);
15397       rect.height = tmp.height;
15398     }
15399   else
15400     {
15401       rect.y = 0;
15402       rect.height = tree_view->priv->vadjustment->page_size;
15403     }
15404
15405   gtk_tooltip_set_tip_area (tooltip, &rect);
15406 }
15407
15408 /**
15409  * gtk_tree_view_get_tooltip_context:
15410  * @tree_view: a #GtkTreeView
15411  * @x: the x coordinate (relative to widget coordinates)
15412  * @y: the y coordinate (relative to widget coordinates)
15413  * @keyboard_tip: whether this is a keyboard tooltip or not
15414  * @model: a pointer to receive a #GtkTreeModel or %NULL
15415  * @path: a pointer to receive a #GtkTreePath or %NULL
15416  * @iter: a pointer to receive a #GtkTreeIter or %NULL
15417  *
15418  * This function is supposed to be used in a #GtkWidget::query-tooltip
15419  * signal handler for #GtkTreeView.  The @x, @y and @keyboard_tip values
15420  * which are received in the signal handler, should be passed to this
15421  * function without modification.
15422  *
15423  * The return value indicates whether there is a tree view row at the given
15424  * coordinates (%TRUE) or not (%FALSE) for mouse tooltips.  For keyboard
15425  * tooltips the row returned will be the cursor row.  When %TRUE, then any of
15426  * @model, @path and @iter which have been provided will be set to point to
15427  * that row and the corresponding model.  @x and @y will always be converted
15428  * to be relative to @tree_view's bin_window if @keyboard_tooltip is %FALSE.
15429  *
15430  * Return value: whether or not the given tooltip context points to a row.
15431  *
15432  * Since: 2.12
15433  */
15434 gboolean
15435 gtk_tree_view_get_tooltip_context (GtkTreeView   *tree_view,
15436                                    gint          *x,
15437                                    gint          *y,
15438                                    gboolean       keyboard_tip,
15439                                    GtkTreeModel **model,
15440                                    GtkTreePath  **path,
15441                                    GtkTreeIter   *iter)
15442 {
15443   GtkTreePath *tmppath = NULL;
15444
15445   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15446   g_return_val_if_fail (x != NULL, FALSE);
15447   g_return_val_if_fail (y != NULL, FALSE);
15448
15449   if (keyboard_tip)
15450     {
15451       gtk_tree_view_get_cursor (tree_view, &tmppath, NULL);
15452
15453       if (!tmppath)
15454         return FALSE;
15455     }
15456   else
15457     {
15458       gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, *x, *y,
15459                                                          x, y);
15460
15461       if (!gtk_tree_view_get_path_at_pos (tree_view, *x, *y,
15462                                           &tmppath, NULL, NULL, NULL))
15463         return FALSE;
15464     }
15465
15466   if (model)
15467     *model = gtk_tree_view_get_model (tree_view);
15468
15469   if (iter)
15470     gtk_tree_model_get_iter (gtk_tree_view_get_model (tree_view),
15471                              iter, tmppath);
15472
15473   if (path)
15474     *path = tmppath;
15475   else
15476     gtk_tree_path_free (tmppath);
15477
15478   return TRUE;
15479 }
15480
15481 static gboolean
15482 gtk_tree_view_set_tooltip_query_cb (GtkWidget  *widget,
15483                                     gint        x,
15484                                     gint        y,
15485                                     gboolean    keyboard_tip,
15486                                     GtkTooltip *tooltip,
15487                                     gpointer    data)
15488 {
15489   GValue value = { 0, };
15490   GValue transformed = { 0, };
15491   GtkTreeIter iter;
15492   GtkTreePath *path;
15493   GtkTreeModel *model;
15494   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
15495
15496   if (!gtk_tree_view_get_tooltip_context (GTK_TREE_VIEW (widget),
15497                                           &x, &y,
15498                                           keyboard_tip,
15499                                           &model, &path, &iter))
15500     return FALSE;
15501
15502   gtk_tree_model_get_value (model, &iter,
15503                             tree_view->priv->tooltip_column, &value);
15504
15505   g_value_init (&transformed, G_TYPE_STRING);
15506
15507   if (!g_value_transform (&value, &transformed))
15508     {
15509       g_value_unset (&value);
15510       gtk_tree_path_free (path);
15511
15512       return FALSE;
15513     }
15514
15515   g_value_unset (&value);
15516
15517   if (!g_value_get_string (&transformed))
15518     {
15519       g_value_unset (&transformed);
15520       gtk_tree_path_free (path);
15521
15522       return FALSE;
15523     }
15524
15525   gtk_tooltip_set_markup (tooltip, g_value_get_string (&transformed));
15526   gtk_tree_view_set_tooltip_row (tree_view, tooltip, path);
15527
15528   gtk_tree_path_free (path);
15529   g_value_unset (&transformed);
15530
15531   return TRUE;
15532 }
15533
15534 /**
15535  * gtk_tree_view_set_tooltip_column:
15536  * @tree_view: a #GtkTreeView
15537  * @column: an integer, which is a valid column number for @tree_view's model
15538  *
15539  * If you only plan to have simple (text-only) tooltips on full rows, you
15540  * can use this function to have #GtkTreeView handle these automatically
15541  * for you. @column should be set to the column in @tree_view's model
15542  * containing the tooltip texts, or -1 to disable this feature.
15543  *
15544  * When enabled, #GtkWidget::has-tooltip will be set to %TRUE and
15545  * @tree_view will connect a #GtkWidget::query-tooltip signal handler.
15546  *
15547  * Note that the signal handler sets the text with gtk_tooltip_set_markup(),
15548  * so &amp;, &lt;, etc have to be escaped in the text.
15549  *
15550  * Since: 2.12
15551  */
15552 void
15553 gtk_tree_view_set_tooltip_column (GtkTreeView *tree_view,
15554                                   gint         column)
15555 {
15556   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15557
15558   if (column == tree_view->priv->tooltip_column)
15559     return;
15560
15561   if (column == -1)
15562     {
15563       g_signal_handlers_disconnect_by_func (tree_view,
15564                                             gtk_tree_view_set_tooltip_query_cb,
15565                                             NULL);
15566       gtk_widget_set_has_tooltip (GTK_WIDGET (tree_view), FALSE);
15567     }
15568   else
15569     {
15570       if (tree_view->priv->tooltip_column == -1)
15571         {
15572           g_signal_connect (tree_view, "query-tooltip",
15573                             G_CALLBACK (gtk_tree_view_set_tooltip_query_cb), NULL);
15574           gtk_widget_set_has_tooltip (GTK_WIDGET (tree_view), TRUE);
15575         }
15576     }
15577
15578   tree_view->priv->tooltip_column = column;
15579   g_object_notify (G_OBJECT (tree_view), "tooltip-column");
15580 }
15581
15582 /**
15583  * gtk_tree_view_get_tooltip_column:
15584  * @tree_view: a #GtkTreeView
15585  *
15586  * Returns the column of @tree_view's model which is being used for
15587  * displaying tooltips on @tree_view's rows.
15588  *
15589  * Return value: the index of the tooltip column that is currently being
15590  * used, or -1 if this is disabled.
15591  *
15592  * Since: 2.12
15593  */
15594 gint
15595 gtk_tree_view_get_tooltip_column (GtkTreeView *tree_view)
15596 {
15597   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
15598
15599   return tree_view->priv->tooltip_column;
15600 }
15601
15602 #define __GTK_TREE_VIEW_C__
15603 #include "gtkaliasdef.c"