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