]> Pileus Git - ~andy/gtk/blob - gtk/gtktreeview.c
treeview: propagate the selected state from the row
[~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
23 #include <math.h>
24 #include <string.h>
25
26 #include "gtktreeview.h"
27 #include "gtkrbtree.h"
28 #include "gtktreednd.h"
29 #include "gtktreeprivate.h"
30 #include "gtkcellrenderer.h"
31 #include "gtkmainprivate.h"
32 #include "gtkmarshalers.h"
33 #include "gtkbuildable.h"
34 #include "gtkbutton.h"
35 #include "gtkalignment.h"
36 #include "gtklabel.h"
37 #include "gtkhbox.h"
38 #include "gtkvbox.h"
39 #include "gtkarrow.h"
40 #include "gtkintl.h"
41 #include "gtkbindings.h"
42 #include "gtkcontainer.h"
43 #include "gtkentry.h"
44 #include "gtkframe.h"
45 #include "gtktreemodelsort.h"
46 #include "gtktooltip.h"
47 #include "gtkscrollable.h"
48 #include "gtkcelllayout.h"
49 #include "gtkprivate.h"
50 #include "gtkwidgetprivate.h"
51 #include "gtkentryprivate.h"
52 #include "gtkstylecontextprivate.h"
53 #include "gtktypebuiltins.h"
54
55
56 /**
57  * SECTION:gtktreeview
58  * @Short_description: A widget for displaying both trees and lists
59  * @Title: GtkTreeView
60  * @See_also: #GtkTreeViewColumn, #GtkTreeSelection, #GtkTreeDnd, #GtkTreeMode,
61  *   #GtkTreeSortable, #GtkTreeModelSort, #GtkListStore, #GtkTreeStore,
62  *   #GtkCellRenderer, #GtkCellEditable, #GtkCellRendererPixbuf,
63  *   #GtkCellRendererText, #GtkCellRendererToggle
64  *
65  * Widget that displays any object that implements the #GtkTreeModel interface.
66  *
67  * Please refer to the <link linkend="TreeWidget">tree widget conceptual
68  * overview</link> for an overview of all the objects and data types related
69  * to the tree widget and how they work together.
70  *
71  * Several different coordinate systems are exposed in the GtkTreeView API.
72  * These are:
73  *
74  * <inlinegraphic fileref="tree-view-coordinates.png" format="PNG"></inlinegraphic>
75  * <variablelist><title>Coordinate systems in GtkTreeView API</title>
76  * <varlistentry><term>Widget coordinates</term>
77  * <listitem>
78  * <para>
79  * Coordinates relative to the widget (usually <literal>widget->window</literal>).
80  * </para>
81  * </listitem>
82  * </varlistentry>
83  * <varlistentry><term>Bin window coordinates</term>
84  * <listitem>
85  * <para>
86  * Coordinates relative to the window that GtkTreeView renders to.
87  * </para>
88  * </listitem>
89  * </varlistentry>
90  * <varlistentry><term>Tree coordinates</term>
91  * <listitem>
92  * <para>
93  * Coordinates relative to the entire scrollable area of GtkTreeView. These
94  * coordinates start at (0, 0) for row 0 of the tree.
95  * </para>
96  * </listitem>
97  * </varlistentry>
98  * </variablelist>
99  *
100  * Several functions are available for converting between the different
101  * coordinate systems.  The most common translations are between widget and bin
102  * window coordinates and between bin window and tree coordinates. For the
103  * former you can use gtk_tree_view_convert_widget_to_bin_window_coords()
104  * (and vice versa), for the latter gtk_tree_view_convert_bin_window_to_tree_coords()
105  * (and vice versa).
106  *
107  * <refsect2 id="GtkTreeView-BUILDER-UI">
108  * <title>GtkTreeView as GtkBuildable</title>
109  * The GtkTreeView implementation of the GtkBuildable interface accepts
110  * #GtkTreeViewColumn objects as &lt;child&gt; elements and exposes the
111  * internal #GtkTreeSelection in UI definitions.
112  * <example>
113  * <title>A UI definition fragment with GtkTreeView</title>
114  * <programlisting><![CDATA[
115  * <object class="GtkTreeView" id="treeview">
116  *   <property name="model">liststore1</property>
117  *   <child>
118  *     <object class="GtkTreeViewColumn" id="test-column">
119  *       <property name="title">Test</property>
120  *       <child>
121  *         <object class="GtkCellRendererText" id="test-renderer"/>
122  *         <attributes>
123  *           <attribute name="text">1</attribute>
124  *         </attributes>
125  *       </child>
126  *     </object>
127  *   </child>
128  *   <child internal-child="selection">
129  *     <object class="GtkTreeSelection" id="selection">
130  *       <signal name="changed" handler="on_treeview_selection_changed"/>
131  *     </object>
132  *   </child>
133  * </object>
134  * ]]></programlisting>
135  * </example>
136  * </refsect2>
137  */
138
139 enum
140 {
141   DRAG_COLUMN_WINDOW_STATE_UNSET = 0,
142   DRAG_COLUMN_WINDOW_STATE_ORIGINAL = 1,
143   DRAG_COLUMN_WINDOW_STATE_ARROW = 2,
144   DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT = 3,
145   DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT = 4
146 };
147
148 enum
149 {
150   RUBBER_BAND_OFF = 0,
151   RUBBER_BAND_MAYBE_START = 1,
152   RUBBER_BAND_ACTIVE = 2
153 };
154
155  /* This lovely little value is used to determine how far away from the title bar
156   * you can move the mouse and still have a column drag work.
157   */
158 #define TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER(tree_view) (10*gtk_tree_view_get_effective_header_height(tree_view))
159
160 #ifdef __GNUC__
161
162 #define TREE_VIEW_INTERNAL_ASSERT(expr, ret)     G_STMT_START{          \
163      if (!(expr))                                                       \
164        {                                                                \
165          g_log (G_LOG_DOMAIN,                                           \
166                 G_LOG_LEVEL_CRITICAL,                                   \
167                 "%s (%s): assertion `%s' failed.\n"                     \
168                 "There is a disparity between the internal view of the GtkTreeView,\n"    \
169                 "and the GtkTreeModel.  This generally means that the model has changed\n"\
170                 "without letting the view know.  Any display from now on is likely to\n"  \
171                 "be incorrect.\n",                                                        \
172                 G_STRLOC,                                               \
173                 G_STRFUNC,                                              \
174                 #expr);                                                 \
175          return ret;                                                    \
176        };                               }G_STMT_END
177
178 #define TREE_VIEW_INTERNAL_ASSERT_VOID(expr)     G_STMT_START{          \
179      if (!(expr))                                                       \
180        {                                                                \
181          g_log (G_LOG_DOMAIN,                                           \
182                 G_LOG_LEVEL_CRITICAL,                                   \
183                 "%s (%s): assertion `%s' failed.\n"                     \
184                 "There is a disparity between the internal view of the GtkTreeView,\n"    \
185                 "and the GtkTreeModel.  This generally means that the model has changed\n"\
186                 "without letting the view know.  Any display from now on is likely to\n"  \
187                 "be incorrect.\n",                                                        \
188                 G_STRLOC,                                               \
189                 G_STRFUNC,                                              \
190                 #expr);                                                 \
191          return;                                                        \
192        };                               }G_STMT_END
193
194 #else
195
196 #define TREE_VIEW_INTERNAL_ASSERT(expr, ret)     G_STMT_START{          \
197      if (!(expr))                                                       \
198        {                                                                \
199          g_log (G_LOG_DOMAIN,                                           \
200                 G_LOG_LEVEL_CRITICAL,                                   \
201                 "file %s: line %d: assertion `%s' failed.\n"       \
202                 "There is a disparity between the internal view of the GtkTreeView,\n"    \
203                 "and the GtkTreeModel.  This generally means that the model has changed\n"\
204                 "without letting the view know.  Any display from now on is likely to\n"  \
205                 "be incorrect.\n",                                                        \
206                 __FILE__,                                               \
207                 __LINE__,                                               \
208                 #expr);                                                 \
209          return ret;                                                    \
210        };                               }G_STMT_END
211
212 #define TREE_VIEW_INTERNAL_ASSERT_VOID(expr)     G_STMT_START{          \
213      if (!(expr))                                                       \
214        {                                                                \
215          g_log (G_LOG_DOMAIN,                                           \
216                 G_LOG_LEVEL_CRITICAL,                                   \
217                 "file %s: line %d: assertion '%s' failed.\n"            \
218                 "There is a disparity between the internal view of the GtkTreeView,\n"    \
219                 "and the GtkTreeModel.  This generally means that the model has changed\n"\
220                 "without letting the view know.  Any display from now on is likely to\n"  \
221                 "be incorrect.\n",                                                        \
222                 __FILE__,                                               \
223                 __LINE__,                                               \
224                 #expr);                                                 \
225          return;                                                        \
226        };                               }G_STMT_END
227 #endif
228
229 #define GTK_TREE_VIEW_PRIORITY_VALIDATE (GDK_PRIORITY_REDRAW + 5)
230 #define GTK_TREE_VIEW_PRIORITY_SCROLL_SYNC (GTK_TREE_VIEW_PRIORITY_VALIDATE + 2)
231 #define GTK_TREE_VIEW_TIME_MS_PER_IDLE 30
232 #define SCROLL_EDGE_SIZE 15
233 #define EXPANDER_EXTRA_PADDING 4
234 #define GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT 5000
235 #define AUTO_EXPAND_TIMEOUT 500
236
237 /* Translate from bin_window coordinates to rbtree (tree coordinates) and
238  * vice versa.
239  */
240 #define TREE_WINDOW_Y_TO_RBTREE_Y(tree_view,y) ((y) + tree_view->priv->dy)
241 #define RBTREE_Y_TO_TREE_WINDOW_Y(tree_view,y) ((y) - tree_view->priv->dy)
242
243 typedef struct _GtkTreeViewColumnReorder GtkTreeViewColumnReorder;
244 struct _GtkTreeViewColumnReorder
245 {
246   gint left_align;
247   gint right_align;
248   GtkTreeViewColumn *left_column;
249   GtkTreeViewColumn *right_column;
250 };
251
252 typedef struct _GtkTreeViewChild GtkTreeViewChild;
253 struct _GtkTreeViewChild
254 {
255   GtkWidget *widget;
256   gint x;
257   gint y;
258   gint width;
259   gint height;
260 };
261
262
263 typedef struct _TreeViewDragInfo TreeViewDragInfo;
264 struct _TreeViewDragInfo
265 {
266   GdkModifierType start_button_mask;
267   GtkTargetList *_unused_source_target_list;
268   GdkDragAction source_actions;
269
270   GtkTargetList *_unused_dest_target_list;
271
272   guint source_set : 1;
273   guint dest_set : 1;
274 };
275
276
277 struct _GtkTreeViewPrivate
278 {
279   GtkTreeModel *model;
280
281   /* tree information */
282   GtkRBTree *tree;
283
284   /* Container info */
285   GList *children;
286   gint width;
287   gint height;
288
289   /* Adjustments */
290   GtkAdjustment *hadjustment;
291   GtkAdjustment *vadjustment;
292   gint           min_display_width;
293   gint           min_display_height;
294
295   /* Sub windows */
296   GdkWindow *bin_window;
297   GdkWindow *header_window;
298
299   /* Scroll position state keeping */
300   GtkTreeRowReference *top_row;
301   gint top_row_dy;
302   /* dy == y pos of top_row + top_row_dy */
303   /* we cache it for simplicity of the code */
304   gint dy;
305
306   guint presize_handler_timer;
307   guint validate_rows_timer;
308   guint scroll_sync_timer;
309
310   /* Indentation and expander layout */
311   gint expander_size;
312   GtkTreeViewColumn *expander_column;
313
314   gint level_indentation;
315
316   /* Key navigation (focus), selection */
317   gint cursor_offset;
318
319   GtkTreeRowReference *anchor;
320   GtkTreeRowReference *cursor;
321
322   GtkTreeViewColumn *focus_column;
323
324   /* Current pressed node, previously pressed, prelight */
325   GtkRBNode *button_pressed_node;
326   GtkRBTree *button_pressed_tree;
327
328   gint pressed_button;
329   gint press_start_x;
330   gint press_start_y;
331
332   gint event_last_x;
333   gint event_last_y;
334
335   guint last_button_time;
336   gint last_button_x;
337   gint last_button_y;
338
339   GtkRBNode *prelight_node;
340   GtkRBTree *prelight_tree;
341
342   /* Cell Editing */
343   GtkTreeViewColumn *edited_column;
344
345   /* The node that's currently being collapsed or expanded */
346   GtkRBNode *expanded_collapsed_node;
347   GtkRBTree *expanded_collapsed_tree;
348   guint expand_collapse_timeout;
349
350   /* Auto expand/collapse timeout in hover mode */
351   guint auto_expand_timeout;
352
353   /* Selection information */
354   GtkTreeSelection *selection;
355
356   /* Header information */
357   gint n_columns;
358   GList *columns;
359   gint header_height;
360
361   GtkTreeViewColumnDropFunc column_drop_func;
362   gpointer column_drop_func_data;
363   GDestroyNotify column_drop_func_data_destroy;
364   GList *column_drag_info;
365   GtkTreeViewColumnReorder *cur_reorder;
366
367   gint prev_width_before_expander;
368
369   /* Interactive Header reordering */
370   GdkWindow *drag_window;
371   GdkWindow *drag_highlight_window;
372   GtkTreeViewColumn *drag_column;
373   gint drag_column_x;
374
375   /* Interactive Header Resizing */
376   gint drag_pos;
377   gint x_drag;
378
379   /* Non-interactive Header Resizing, expand flag support */
380   gint prev_width;
381
382   gint last_extra_space;
383   gint last_extra_space_per_column;
384   gint last_number_of_expand_columns;
385
386   /* ATK Hack */
387   GtkTreeDestroyCountFunc destroy_count_func;
388   gpointer destroy_count_data;
389   GDestroyNotify destroy_count_destroy;
390
391   /* Scroll timeout (e.g. during dnd, rubber banding) */
392   guint scroll_timeout;
393
394   /* Row drag-and-drop */
395   GtkTreeRowReference *drag_dest_row;
396   GtkTreeViewDropPosition drag_dest_pos;
397   guint open_dest_timeout;
398
399   /* Rubber banding */
400   gint rubber_band_status;
401   gint rubber_band_x;
402   gint rubber_band_y;
403   gint rubber_band_shift;
404   gint rubber_band_ctrl;
405
406   GtkRBNode *rubber_band_start_node;
407   GtkRBTree *rubber_band_start_tree;
408
409   GtkRBNode *rubber_band_end_node;
410   GtkRBTree *rubber_band_end_tree;
411
412   /* fixed height */
413   gint fixed_height;
414
415   /* Scroll-to functionality when unrealized */
416   GtkTreeRowReference *scroll_to_path;
417   GtkTreeViewColumn *scroll_to_column;
418   gfloat scroll_to_row_align;
419   gfloat scroll_to_col_align;
420
421   /* Interactive search */
422   gint selected_iter;
423   gint search_column;
424   GtkTreeViewSearchPositionFunc search_position_func;
425   GtkTreeViewSearchEqualFunc search_equal_func;
426   gpointer search_user_data;
427   GDestroyNotify search_destroy;
428   gpointer search_position_user_data;
429   GDestroyNotify search_position_destroy;
430   GtkWidget *search_window;
431   GtkWidget *search_entry;
432   gulong search_entry_changed_id;
433   guint typeselect_flush_timeout;
434
435   /* Grid and tree lines */
436   GtkTreeViewGridLines grid_lines;
437   double grid_line_dashes[2];
438   int grid_line_width;
439
440   gboolean tree_lines_enabled;
441   double tree_line_dashes[2];
442   int tree_line_width;
443
444   /* Row separators */
445   GtkTreeViewRowSeparatorFunc row_separator_func;
446   gpointer row_separator_data;
447   GDestroyNotify row_separator_destroy;
448
449   /* Tooltip support */
450   gint tooltip_column;
451
452   /* Here comes the bitfield */
453   guint scroll_to_use_align : 1;
454
455   guint fixed_height_mode : 1;
456   guint fixed_height_check : 1;
457
458   guint reorderable : 1;
459   guint header_has_focus : 1;
460   guint drag_column_window_state : 3;
461   /* hint to display rows in alternating colors */
462   guint has_rules : 1;
463   guint mark_rows_col_dirty : 1;
464
465   /* for DnD */
466   guint empty_view_drop : 1;
467
468   guint ctrl_pressed : 1;
469   guint shift_pressed : 1;
470
471   guint init_hadjust_value : 1;
472
473   guint in_top_row_to_dy : 1;
474
475   /* interactive search */
476   guint enable_search : 1;
477   guint disable_popdown : 1;
478   guint search_custom_entry_set : 1;
479   
480   guint hover_selection : 1;
481   guint hover_expand : 1;
482   guint imcontext_changed : 1;
483
484   guint rubber_banding_enable : 1;
485
486   guint in_grab : 1;
487
488   guint post_validation_flag : 1;
489
490   /* Whether our key press handler is to avoid sending an unhandled binding to the search entry */
491   guint search_entry_avoid_unhandled_binding : 1;
492
493   /* GtkScrollablePolicy needs to be checked when
494    * driving the scrollable adjustment values */
495   guint hscroll_policy : 1;
496   guint vscroll_policy : 1;
497
498   /* GtkTreeView flags */
499   guint is_list : 1;
500   guint show_expanders : 1;
501   guint in_column_resize : 1;
502   guint arrow_prelit : 1;
503   guint headers_visible : 1;
504   guint draw_keyfocus : 1;
505   guint model_setup : 1;
506   guint in_column_drag : 1;
507 };
508
509
510 /* Signals */
511 enum
512 {
513   ROW_ACTIVATED,
514   TEST_EXPAND_ROW,
515   TEST_COLLAPSE_ROW,
516   ROW_EXPANDED,
517   ROW_COLLAPSED,
518   COLUMNS_CHANGED,
519   CURSOR_CHANGED,
520   MOVE_CURSOR,
521   SELECT_ALL,
522   UNSELECT_ALL,
523   SELECT_CURSOR_ROW,
524   TOGGLE_CURSOR_ROW,
525   EXPAND_COLLAPSE_CURSOR_ROW,
526   SELECT_CURSOR_PARENT,
527   START_INTERACTIVE_SEARCH,
528   LAST_SIGNAL
529 };
530
531 /* Properties */
532 enum {
533   PROP_0,
534   PROP_MODEL,
535   PROP_HADJUSTMENT,
536   PROP_VADJUSTMENT,
537   PROP_HSCROLL_POLICY,
538   PROP_VSCROLL_POLICY,
539   PROP_HEADERS_VISIBLE,
540   PROP_HEADERS_CLICKABLE,
541   PROP_EXPANDER_COLUMN,
542   PROP_REORDERABLE,
543   PROP_RULES_HINT,
544   PROP_ENABLE_SEARCH,
545   PROP_SEARCH_COLUMN,
546   PROP_FIXED_HEIGHT_MODE,
547   PROP_HOVER_SELECTION,
548   PROP_HOVER_EXPAND,
549   PROP_SHOW_EXPANDERS,
550   PROP_LEVEL_INDENTATION,
551   PROP_RUBBER_BANDING,
552   PROP_ENABLE_GRID_LINES,
553   PROP_ENABLE_TREE_LINES,
554   PROP_TOOLTIP_COLUMN
555 };
556
557 /* object signals */
558 static void     gtk_tree_view_finalize             (GObject          *object);
559 static void     gtk_tree_view_set_property         (GObject         *object,
560                                                     guint            prop_id,
561                                                     const GValue    *value,
562                                                     GParamSpec      *pspec);
563 static void     gtk_tree_view_get_property         (GObject         *object,
564                                                     guint            prop_id,
565                                                     GValue          *value,
566                                                     GParamSpec      *pspec);
567
568 /* gtkwidget signals */
569 static void     gtk_tree_view_destroy              (GtkWidget        *widget);
570 static void     gtk_tree_view_realize              (GtkWidget        *widget);
571 static void     gtk_tree_view_unrealize            (GtkWidget        *widget);
572 static void     gtk_tree_view_map                  (GtkWidget        *widget);
573 static void     gtk_tree_view_get_preferred_width  (GtkWidget        *widget,
574                                                     gint             *minimum,
575                                                     gint             *natural);
576 static void     gtk_tree_view_get_preferred_height (GtkWidget        *widget,
577                                                     gint             *minimum,
578                                                     gint             *natural);
579 static void     gtk_tree_view_size_request         (GtkWidget        *widget,
580                                                     GtkRequisition   *requisition,
581                                                     gboolean          may_validate);
582 static void     gtk_tree_view_size_allocate        (GtkWidget        *widget,
583                                                     GtkAllocation    *allocation);
584 static gboolean gtk_tree_view_draw                 (GtkWidget        *widget,
585                                                     cairo_t          *cr);
586 static gboolean gtk_tree_view_key_press            (GtkWidget        *widget,
587                                                     GdkEventKey      *event);
588 static gboolean gtk_tree_view_key_release          (GtkWidget        *widget,
589                                                     GdkEventKey      *event);
590 static gboolean gtk_tree_view_motion               (GtkWidget        *widget,
591                                                     GdkEventMotion   *event);
592 static gboolean gtk_tree_view_enter_notify         (GtkWidget        *widget,
593                                                     GdkEventCrossing *event);
594 static gboolean gtk_tree_view_leave_notify         (GtkWidget        *widget,
595                                                     GdkEventCrossing *event);
596 static gboolean gtk_tree_view_button_press         (GtkWidget        *widget,
597                                                     GdkEventButton   *event);
598 static gboolean gtk_tree_view_button_release       (GtkWidget        *widget,
599                                                     GdkEventButton   *event);
600 static gboolean gtk_tree_view_grab_broken          (GtkWidget          *widget,
601                                                     GdkEventGrabBroken *event);
602 #if 0
603 static gboolean gtk_tree_view_configure            (GtkWidget         *widget,
604                                                     GdkEventConfigure *event);
605 #endif
606
607 static GtkWidgetPath * gtk_tree_view_get_path_for_child (GtkContainer *container,
608                                                          GtkWidget    *child);
609
610 static void     gtk_tree_view_set_focus_child      (GtkContainer     *container,
611                                                     GtkWidget        *child);
612 static gint     gtk_tree_view_focus_out            (GtkWidget        *widget,
613                                                     GdkEventFocus    *event);
614 static gint     gtk_tree_view_focus                (GtkWidget        *widget,
615                                                     GtkDirectionType  direction);
616 static void     gtk_tree_view_grab_focus           (GtkWidget        *widget);
617 static void     gtk_tree_view_style_updated        (GtkWidget        *widget);
618 static void     gtk_tree_view_grab_notify          (GtkWidget        *widget,
619                                                     gboolean          was_grabbed);
620 static void     gtk_tree_view_state_flags_changed  (GtkWidget        *widget,
621                                                     GtkStateFlags     previous_state);
622
623 /* container signals */
624 static void     gtk_tree_view_remove               (GtkContainer     *container,
625                                                     GtkWidget        *widget);
626 static void     gtk_tree_view_forall               (GtkContainer     *container,
627                                                     gboolean          include_internals,
628                                                     GtkCallback       callback,
629                                                     gpointer          callback_data);
630
631 /* Source side drag signals */
632 static void gtk_tree_view_drag_begin       (GtkWidget        *widget,
633                                             GdkDragContext   *context);
634 static void gtk_tree_view_drag_end         (GtkWidget        *widget,
635                                             GdkDragContext   *context);
636 static void gtk_tree_view_drag_data_get    (GtkWidget        *widget,
637                                             GdkDragContext   *context,
638                                             GtkSelectionData *selection_data,
639                                             guint             info,
640                                             guint             time);
641 static void gtk_tree_view_drag_data_delete (GtkWidget        *widget,
642                                             GdkDragContext   *context);
643
644 /* Target side drag signals */
645 static void     gtk_tree_view_drag_leave         (GtkWidget        *widget,
646                                                   GdkDragContext   *context,
647                                                   guint             time);
648 static gboolean gtk_tree_view_drag_motion        (GtkWidget        *widget,
649                                                   GdkDragContext   *context,
650                                                   gint              x,
651                                                   gint              y,
652                                                   guint             time);
653 static gboolean gtk_tree_view_drag_drop          (GtkWidget        *widget,
654                                                   GdkDragContext   *context,
655                                                   gint              x,
656                                                   gint              y,
657                                                   guint             time);
658 static void     gtk_tree_view_drag_data_received (GtkWidget        *widget,
659                                                   GdkDragContext   *context,
660                                                   gint              x,
661                                                   gint              y,
662                                                   GtkSelectionData *selection_data,
663                                                   guint             info,
664                                                   guint             time);
665
666 /* tree_model signals */
667 static void     gtk_tree_view_set_hadjustment             (GtkTreeView     *tree_view,
668                                                            GtkAdjustment   *adjustment);
669 static void     gtk_tree_view_set_vadjustment             (GtkTreeView     *tree_view,
670                                                            GtkAdjustment   *adjustment);
671 static gboolean gtk_tree_view_real_move_cursor            (GtkTreeView     *tree_view,
672                                                            GtkMovementStep  step,
673                                                            gint             count);
674 static gboolean gtk_tree_view_real_select_all             (GtkTreeView     *tree_view);
675 static gboolean gtk_tree_view_real_unselect_all           (GtkTreeView     *tree_view);
676 static gboolean gtk_tree_view_real_select_cursor_row      (GtkTreeView     *tree_view,
677                                                            gboolean         start_editing);
678 static gboolean gtk_tree_view_real_toggle_cursor_row      (GtkTreeView     *tree_view);
679 static gboolean gtk_tree_view_real_expand_collapse_cursor_row (GtkTreeView     *tree_view,
680                                                                gboolean         logical,
681                                                                gboolean         expand,
682                                                                gboolean         open_all);
683 static gboolean gtk_tree_view_real_select_cursor_parent   (GtkTreeView     *tree_view);
684 static void gtk_tree_view_row_changed                     (GtkTreeModel    *model,
685                                                            GtkTreePath     *path,
686                                                            GtkTreeIter     *iter,
687                                                            gpointer         data);
688 static void gtk_tree_view_row_inserted                    (GtkTreeModel    *model,
689                                                            GtkTreePath     *path,
690                                                            GtkTreeIter     *iter,
691                                                            gpointer         data);
692 static void gtk_tree_view_row_has_child_toggled           (GtkTreeModel    *model,
693                                                            GtkTreePath     *path,
694                                                            GtkTreeIter     *iter,
695                                                            gpointer         data);
696 static void gtk_tree_view_row_deleted                     (GtkTreeModel    *model,
697                                                            GtkTreePath     *path,
698                                                            gpointer         data);
699 static void gtk_tree_view_rows_reordered                  (GtkTreeModel    *model,
700                                                            GtkTreePath     *parent,
701                                                            GtkTreeIter     *iter,
702                                                            gint            *new_order,
703                                                            gpointer         data);
704
705 /* Incremental reflow */
706 static gboolean validate_row             (GtkTreeView *tree_view,
707                                           GtkRBTree   *tree,
708                                           GtkRBNode   *node,
709                                           GtkTreeIter *iter,
710                                           GtkTreePath *path);
711 static void     validate_visible_area    (GtkTreeView *tree_view);
712 static gboolean validate_rows_handler    (GtkTreeView *tree_view);
713 static gboolean do_validate_rows         (GtkTreeView *tree_view,
714                                           gboolean     size_request);
715 static gboolean validate_rows            (GtkTreeView *tree_view);
716 static gboolean presize_handler_callback (gpointer     data);
717 static void     install_presize_handler  (GtkTreeView *tree_view);
718 static void     install_scroll_sync_handler (GtkTreeView *tree_view);
719 static void     gtk_tree_view_set_top_row   (GtkTreeView *tree_view,
720                                              GtkTreePath *path,
721                                              gint         offset);
722 static void     gtk_tree_view_dy_to_top_row (GtkTreeView *tree_view);
723 static void     gtk_tree_view_top_row_to_dy (GtkTreeView *tree_view);
724 static void     invalidate_empty_focus      (GtkTreeView *tree_view);
725
726 /* Internal functions */
727 static gboolean gtk_tree_view_is_expander_column             (GtkTreeView        *tree_view,
728                                                               GtkTreeViewColumn  *column);
729 static inline gboolean gtk_tree_view_draw_expanders          (GtkTreeView        *tree_view);
730 static void     gtk_tree_view_add_move_binding               (GtkBindingSet      *binding_set,
731                                                               guint               keyval,
732                                                               guint               modmask,
733                                                               gboolean            add_shifted_binding,
734                                                               GtkMovementStep     step,
735                                                               gint                count);
736 static gint     gtk_tree_view_unref_and_check_selection_tree (GtkTreeView        *tree_view,
737                                                               GtkRBTree          *tree);
738 static void     gtk_tree_view_queue_draw_path                (GtkTreeView        *tree_view,
739                                                               GtkTreePath        *path,
740                                                               const GdkRectangle *clip_rect);
741 static void     gtk_tree_view_queue_draw_arrow               (GtkTreeView        *tree_view,
742                                                               GtkRBTree          *tree,
743                                                               GtkRBNode          *node);
744 static void     gtk_tree_view_draw_arrow                     (GtkTreeView        *tree_view,
745                                                               cairo_t            *cr,
746                                                               GtkRBTree          *tree,
747                                                               GtkRBNode          *node,
748                                                               gint                x,
749                                                               gint                y);
750 static void     gtk_tree_view_get_arrow_xrange               (GtkTreeView        *tree_view,
751                                                               GtkRBTree          *tree,
752                                                               gint               *x1,
753                                                               gint               *x2);
754 static gint     gtk_tree_view_new_column_width               (GtkTreeView        *tree_view,
755                                                               gint                i,
756                                                               gint               *x);
757 static void     gtk_tree_view_adjustment_changed             (GtkAdjustment      *adjustment,
758                                                               GtkTreeView        *tree_view);
759 static void     gtk_tree_view_build_tree                     (GtkTreeView        *tree_view,
760                                                               GtkRBTree          *tree,
761                                                               GtkTreeIter        *iter,
762                                                               gint                depth,
763                                                               gboolean            recurse);
764 static void     gtk_tree_view_clamp_node_visible             (GtkTreeView        *tree_view,
765                                                               GtkRBTree          *tree,
766                                                               GtkRBNode          *node);
767 static void     gtk_tree_view_clamp_column_visible           (GtkTreeView        *tree_view,
768                                                               GtkTreeViewColumn  *column,
769                                                               gboolean            focus_to_cell);
770 static gboolean gtk_tree_view_maybe_begin_dragging_row       (GtkTreeView        *tree_view,
771                                                               GdkEventMotion     *event);
772 static void     gtk_tree_view_focus_to_cursor                (GtkTreeView        *tree_view);
773 static void     gtk_tree_view_move_cursor_up_down            (GtkTreeView        *tree_view,
774                                                               gint                count);
775 static void     gtk_tree_view_move_cursor_page_up_down       (GtkTreeView        *tree_view,
776                                                               gint                count);
777 static void     gtk_tree_view_move_cursor_left_right         (GtkTreeView        *tree_view,
778                                                               gint                count);
779 static void     gtk_tree_view_move_cursor_start_end          (GtkTreeView        *tree_view,
780                                                               gint                count);
781 static gboolean gtk_tree_view_real_collapse_row              (GtkTreeView        *tree_view,
782                                                               GtkTreePath        *path,
783                                                               GtkRBTree          *tree,
784                                                               GtkRBNode          *node,
785                                                               gboolean            animate);
786 static gboolean gtk_tree_view_real_expand_row                (GtkTreeView        *tree_view,
787                                                               GtkTreePath        *path,
788                                                               GtkRBTree          *tree,
789                                                               GtkRBNode          *node,
790                                                               gboolean            open_all,
791                                                               gboolean            animate);
792 static void     gtk_tree_view_real_set_cursor                (GtkTreeView        *tree_view,
793                                                               GtkTreePath        *path,
794                                                               gboolean            clear_and_select,
795                                                               gboolean            clamp_node);
796 static gboolean gtk_tree_view_has_can_focus_cell             (GtkTreeView        *tree_view);
797 static void     column_sizing_notify                         (GObject            *object,
798                                                               GParamSpec         *pspec,
799                                                               gpointer            data);
800 static void     gtk_tree_view_stop_rubber_band               (GtkTreeView        *tree_view);
801 static void     update_prelight                              (GtkTreeView        *tree_view,
802                                                               int                 x,
803                                                               int                 y);
804
805 static inline gint gtk_tree_view_get_effective_header_height (GtkTreeView *tree_view);
806
807 static inline gint gtk_tree_view_get_cell_area_y_offset      (GtkTreeView *tree_view,
808                                                               GtkRBTree   *tree,
809                                                               GtkRBNode   *node,
810                                                               gint         vertical_separator);
811 static inline gint gtk_tree_view_get_cell_area_height        (GtkTreeView *tree_view,
812                                                               GtkRBNode   *node,
813                                                               gint         vertical_separator);
814
815 static inline gint gtk_tree_view_get_row_y_offset            (GtkTreeView *tree_view,
816                                                               GtkRBTree   *tree,
817                                                               GtkRBNode   *node);
818 static inline gint gtk_tree_view_get_row_height              (GtkTreeView *tree_view,
819                                                               GtkRBNode   *node);
820
821 /* interactive search */
822 static void     gtk_tree_view_ensure_interactive_directory (GtkTreeView *tree_view);
823 static void     gtk_tree_view_search_dialog_hide        (GtkWidget        *search_dialog,
824                                                          GtkTreeView      *tree_view,
825                                                          GdkDevice        *device);
826 static void     gtk_tree_view_search_position_func      (GtkTreeView      *tree_view,
827                                                          GtkWidget        *search_dialog,
828                                                          gpointer          user_data);
829 static void     gtk_tree_view_search_disable_popdown    (GtkEntry         *entry,
830                                                          GtkMenu          *menu,
831                                                          gpointer          data);
832 static void     gtk_tree_view_search_preedit_changed    (GtkIMContext     *im_context,
833                                                          GtkTreeView      *tree_view);
834 static void     gtk_tree_view_search_activate           (GtkEntry         *entry,
835                                                          GtkTreeView      *tree_view);
836 static gboolean gtk_tree_view_real_search_enable_popdown(gpointer          data);
837 static void     gtk_tree_view_search_enable_popdown     (GtkWidget        *widget,
838                                                          gpointer          data);
839 static gboolean gtk_tree_view_search_delete_event       (GtkWidget        *widget,
840                                                          GdkEventAny      *event,
841                                                          GtkTreeView      *tree_view);
842 static gboolean gtk_tree_view_search_button_press_event (GtkWidget        *widget,
843                                                          GdkEventButton   *event,
844                                                          GtkTreeView      *tree_view);
845 static gboolean gtk_tree_view_search_scroll_event       (GtkWidget        *entry,
846                                                          GdkEventScroll   *event,
847                                                          GtkTreeView      *tree_view);
848 static gboolean gtk_tree_view_search_key_press_event    (GtkWidget        *entry,
849                                                          GdkEventKey      *event,
850                                                          GtkTreeView      *tree_view);
851 static gboolean gtk_tree_view_search_move               (GtkWidget        *window,
852                                                          GtkTreeView      *tree_view,
853                                                          gboolean          up);
854 static gboolean gtk_tree_view_search_equal_func         (GtkTreeModel     *model,
855                                                          gint              column,
856                                                          const gchar      *key,
857                                                          GtkTreeIter      *iter,
858                                                          gpointer          search_data);
859 static gboolean gtk_tree_view_search_iter               (GtkTreeModel     *model,
860                                                          GtkTreeSelection *selection,
861                                                          GtkTreeIter      *iter,
862                                                          const gchar      *text,
863                                                          gint             *count,
864                                                          gint              n);
865 static void     gtk_tree_view_search_init               (GtkWidget        *entry,
866                                                          GtkTreeView      *tree_view);
867 static void     gtk_tree_view_put                       (GtkTreeView      *tree_view,
868                                                          GtkWidget        *child_widget,
869                                                          gint              x,
870                                                          gint              y,
871                                                          gint              width,
872                                                          gint              height);
873 static gboolean gtk_tree_view_start_editing             (GtkTreeView      *tree_view,
874                                                          GtkTreePath      *cursor_path,
875                                                          gboolean          edit_only);
876 static void gtk_tree_view_stop_editing                  (GtkTreeView *tree_view,
877                                                          gboolean     cancel_editing);
878 static gboolean gtk_tree_view_real_start_interactive_search (GtkTreeView *tree_view,
879                                                              GdkDevice   *device,
880                                                              gboolean     keybinding);
881 static gboolean gtk_tree_view_start_interactive_search      (GtkTreeView *tree_view);
882 static GtkTreeViewColumn *gtk_tree_view_get_drop_column (GtkTreeView       *tree_view,
883                                                          GtkTreeViewColumn *column,
884                                                          gint               drop_position);
885
886 /* GtkBuildable */
887 static void     gtk_tree_view_buildable_add_child          (GtkBuildable      *tree_view,
888                                                             GtkBuilder        *builder,
889                                                             GObject           *child,
890                                                             const gchar       *type);
891 static GObject *gtk_tree_view_buildable_get_internal_child (GtkBuildable      *buildable,
892                                                             GtkBuilder        *builder,
893                                                             const gchar       *childname);
894 static void     gtk_tree_view_buildable_init               (GtkBuildableIface *iface);
895
896
897 static gboolean scroll_row_timeout                   (gpointer     data);
898 static void     add_scroll_timeout                   (GtkTreeView *tree_view);
899 static void     remove_scroll_timeout                (GtkTreeView *tree_view);
900
901 static guint tree_view_signals [LAST_SIGNAL] = { 0 };
902
903 \f
904
905 /* GType Methods
906  */
907
908 G_DEFINE_TYPE_WITH_CODE (GtkTreeView, gtk_tree_view, GTK_TYPE_CONTAINER,
909                          G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
910                                                 gtk_tree_view_buildable_init)
911                          G_IMPLEMENT_INTERFACE (GTK_TYPE_SCROLLABLE, NULL))
912
913 static void
914 gtk_tree_view_class_init (GtkTreeViewClass *class)
915 {
916   GObjectClass *o_class;
917   GtkWidgetClass *widget_class;
918   GtkContainerClass *container_class;
919   GtkBindingSet *binding_set;
920
921   binding_set = gtk_binding_set_by_class (class);
922
923   o_class = (GObjectClass *) class;
924   widget_class = (GtkWidgetClass *) class;
925   container_class = (GtkContainerClass *) class;
926
927   /* GObject signals */
928   o_class->set_property = gtk_tree_view_set_property;
929   o_class->get_property = gtk_tree_view_get_property;
930   o_class->finalize = gtk_tree_view_finalize;
931
932   /* GtkWidget signals */
933   widget_class->destroy = gtk_tree_view_destroy;
934   widget_class->map = gtk_tree_view_map;
935   widget_class->realize = gtk_tree_view_realize;
936   widget_class->unrealize = gtk_tree_view_unrealize;
937   widget_class->get_preferred_width = gtk_tree_view_get_preferred_width;
938   widget_class->get_preferred_height = gtk_tree_view_get_preferred_height;
939   widget_class->size_allocate = gtk_tree_view_size_allocate;
940   widget_class->button_press_event = gtk_tree_view_button_press;
941   widget_class->button_release_event = gtk_tree_view_button_release;
942   widget_class->grab_broken_event = gtk_tree_view_grab_broken;
943   /*widget_class->configure_event = gtk_tree_view_configure;*/
944   widget_class->motion_notify_event = gtk_tree_view_motion;
945   widget_class->draw = gtk_tree_view_draw;
946   widget_class->key_press_event = gtk_tree_view_key_press;
947   widget_class->key_release_event = gtk_tree_view_key_release;
948   widget_class->enter_notify_event = gtk_tree_view_enter_notify;
949   widget_class->leave_notify_event = gtk_tree_view_leave_notify;
950   widget_class->focus_out_event = gtk_tree_view_focus_out;
951   widget_class->drag_begin = gtk_tree_view_drag_begin;
952   widget_class->drag_end = gtk_tree_view_drag_end;
953   widget_class->drag_data_get = gtk_tree_view_drag_data_get;
954   widget_class->drag_data_delete = gtk_tree_view_drag_data_delete;
955   widget_class->drag_leave = gtk_tree_view_drag_leave;
956   widget_class->drag_motion = gtk_tree_view_drag_motion;
957   widget_class->drag_drop = gtk_tree_view_drag_drop;
958   widget_class->drag_data_received = gtk_tree_view_drag_data_received;
959   widget_class->focus = gtk_tree_view_focus;
960   widget_class->grab_focus = gtk_tree_view_grab_focus;
961   widget_class->style_updated = gtk_tree_view_style_updated;
962   widget_class->grab_notify = gtk_tree_view_grab_notify;
963   widget_class->state_flags_changed = gtk_tree_view_state_flags_changed;
964
965   /* GtkContainer signals */
966   container_class->remove = gtk_tree_view_remove;
967   container_class->forall = gtk_tree_view_forall;
968   container_class->set_focus_child = gtk_tree_view_set_focus_child;
969   container_class->get_path_for_child = gtk_tree_view_get_path_for_child;
970
971   class->move_cursor = gtk_tree_view_real_move_cursor;
972   class->select_all = gtk_tree_view_real_select_all;
973   class->unselect_all = gtk_tree_view_real_unselect_all;
974   class->select_cursor_row = gtk_tree_view_real_select_cursor_row;
975   class->toggle_cursor_row = gtk_tree_view_real_toggle_cursor_row;
976   class->expand_collapse_cursor_row = gtk_tree_view_real_expand_collapse_cursor_row;
977   class->select_cursor_parent = gtk_tree_view_real_select_cursor_parent;
978   class->start_interactive_search = gtk_tree_view_start_interactive_search;
979
980   /* Properties */
981
982   g_object_class_install_property (o_class,
983                                    PROP_MODEL,
984                                    g_param_spec_object ("model",
985                                                         P_("TreeView Model"),
986                                                         P_("The model for the tree view"),
987                                                         GTK_TYPE_TREE_MODEL,
988                                                         GTK_PARAM_READWRITE));
989
990   g_object_class_override_property (o_class, PROP_HADJUSTMENT,    "hadjustment");
991   g_object_class_override_property (o_class, PROP_VADJUSTMENT,    "vadjustment");
992   g_object_class_override_property (o_class, PROP_HSCROLL_POLICY, "hscroll-policy");
993   g_object_class_override_property (o_class, PROP_VSCROLL_POLICY, "vscroll-policy");
994
995   g_object_class_install_property (o_class,
996                                    PROP_HEADERS_VISIBLE,
997                                    g_param_spec_boolean ("headers-visible",
998                                                          P_("Headers Visible"),
999                                                          P_("Show the column header buttons"),
1000                                                          TRUE,
1001                                                          GTK_PARAM_READWRITE));
1002
1003   g_object_class_install_property (o_class,
1004                                    PROP_HEADERS_CLICKABLE,
1005                                    g_param_spec_boolean ("headers-clickable",
1006                                                          P_("Headers Clickable"),
1007                                                          P_("Column headers respond to click events"),
1008                                                          TRUE,
1009                                                          GTK_PARAM_READWRITE));
1010
1011   g_object_class_install_property (o_class,
1012                                    PROP_EXPANDER_COLUMN,
1013                                    g_param_spec_object ("expander-column",
1014                                                         P_("Expander Column"),
1015                                                         P_("Set the column for the expander column"),
1016                                                         GTK_TYPE_TREE_VIEW_COLUMN,
1017                                                         GTK_PARAM_READWRITE));
1018
1019   g_object_class_install_property (o_class,
1020                                    PROP_REORDERABLE,
1021                                    g_param_spec_boolean ("reorderable",
1022                                                          P_("Reorderable"),
1023                                                          P_("View is reorderable"),
1024                                                          FALSE,
1025                                                          GTK_PARAM_READWRITE));
1026
1027   g_object_class_install_property (o_class,
1028                                    PROP_RULES_HINT,
1029                                    g_param_spec_boolean ("rules-hint",
1030                                                          P_("Rules Hint"),
1031                                                          P_("Set a hint to the theme engine to draw rows in alternating colors"),
1032                                                          FALSE,
1033                                                          GTK_PARAM_READWRITE));
1034
1035     g_object_class_install_property (o_class,
1036                                      PROP_ENABLE_SEARCH,
1037                                      g_param_spec_boolean ("enable-search",
1038                                                            P_("Enable Search"),
1039                                                            P_("View allows user to search through columns interactively"),
1040                                                            TRUE,
1041                                                            GTK_PARAM_READWRITE));
1042
1043     g_object_class_install_property (o_class,
1044                                      PROP_SEARCH_COLUMN,
1045                                      g_param_spec_int ("search-column",
1046                                                        P_("Search Column"),
1047                                                        P_("Model column to search through during interactive search"),
1048                                                        -1,
1049                                                        G_MAXINT,
1050                                                        -1,
1051                                                        GTK_PARAM_READWRITE));
1052
1053     /**
1054      * GtkTreeView:fixed-height-mode:
1055      *
1056      * Setting the ::fixed-height-mode property to %TRUE speeds up 
1057      * #GtkTreeView by assuming that all rows have the same height. 
1058      * Only enable this option if all rows are the same height.  
1059      * Please see gtk_tree_view_set_fixed_height_mode() for more 
1060      * information on this option.
1061      *
1062      * Since: 2.4
1063      **/
1064     g_object_class_install_property (o_class,
1065                                      PROP_FIXED_HEIGHT_MODE,
1066                                      g_param_spec_boolean ("fixed-height-mode",
1067                                                            P_("Fixed Height Mode"),
1068                                                            P_("Speeds up GtkTreeView by assuming that all rows have the same height"),
1069                                                            FALSE,
1070                                                            GTK_PARAM_READWRITE));
1071     
1072     /**
1073      * GtkTreeView:hover-selection:
1074      * 
1075      * Enables or disables the hover selection mode of @tree_view.
1076      * Hover selection makes the selected row follow the pointer.
1077      * Currently, this works only for the selection modes 
1078      * %GTK_SELECTION_SINGLE and %GTK_SELECTION_BROWSE.
1079      *
1080      * This mode is primarily intended for treeviews in popups, e.g.
1081      * in #GtkComboBox or #GtkEntryCompletion.
1082      *
1083      * Since: 2.6
1084      */
1085     g_object_class_install_property (o_class,
1086                                      PROP_HOVER_SELECTION,
1087                                      g_param_spec_boolean ("hover-selection",
1088                                                            P_("Hover Selection"),
1089                                                            P_("Whether the selection should follow the pointer"),
1090                                                            FALSE,
1091                                                            GTK_PARAM_READWRITE));
1092
1093     /**
1094      * GtkTreeView:hover-expand:
1095      * 
1096      * Enables or disables the hover expansion mode of @tree_view.
1097      * Hover expansion makes rows expand or collapse if the pointer moves 
1098      * over them.
1099      *
1100      * This mode is primarily intended for treeviews in popups, e.g.
1101      * in #GtkComboBox or #GtkEntryCompletion.
1102      *
1103      * Since: 2.6
1104      */
1105     g_object_class_install_property (o_class,
1106                                      PROP_HOVER_EXPAND,
1107                                      g_param_spec_boolean ("hover-expand",
1108                                                            P_("Hover Expand"),
1109                                                            P_("Whether rows should be expanded/collapsed when the pointer moves over them"),
1110                                                            FALSE,
1111                                                            GTK_PARAM_READWRITE));
1112
1113     /**
1114      * GtkTreeView:show-expanders:
1115      *
1116      * %TRUE if the view has expanders.
1117      *
1118      * Since: 2.12
1119      */
1120     g_object_class_install_property (o_class,
1121                                      PROP_SHOW_EXPANDERS,
1122                                      g_param_spec_boolean ("show-expanders",
1123                                                            P_("Show Expanders"),
1124                                                            P_("View has expanders"),
1125                                                            TRUE,
1126                                                            GTK_PARAM_READWRITE));
1127
1128     /**
1129      * GtkTreeView:level-indentation:
1130      *
1131      * Extra indentation for each level.
1132      *
1133      * Since: 2.12
1134      */
1135     g_object_class_install_property (o_class,
1136                                      PROP_LEVEL_INDENTATION,
1137                                      g_param_spec_int ("level-indentation",
1138                                                        P_("Level Indentation"),
1139                                                        P_("Extra indentation for each level"),
1140                                                        0,
1141                                                        G_MAXINT,
1142                                                        0,
1143                                                        GTK_PARAM_READWRITE));
1144
1145     g_object_class_install_property (o_class,
1146                                      PROP_RUBBER_BANDING,
1147                                      g_param_spec_boolean ("rubber-banding",
1148                                                            P_("Rubber Banding"),
1149                                                            P_("Whether to enable selection of multiple items by dragging the mouse pointer"),
1150                                                            FALSE,
1151                                                            GTK_PARAM_READWRITE));
1152
1153     g_object_class_install_property (o_class,
1154                                      PROP_ENABLE_GRID_LINES,
1155                                      g_param_spec_enum ("enable-grid-lines",
1156                                                         P_("Enable Grid Lines"),
1157                                                         P_("Whether grid lines should be drawn in the tree view"),
1158                                                         GTK_TYPE_TREE_VIEW_GRID_LINES,
1159                                                         GTK_TREE_VIEW_GRID_LINES_NONE,
1160                                                         GTK_PARAM_READWRITE));
1161
1162     g_object_class_install_property (o_class,
1163                                      PROP_ENABLE_TREE_LINES,
1164                                      g_param_spec_boolean ("enable-tree-lines",
1165                                                            P_("Enable Tree Lines"),
1166                                                            P_("Whether tree lines should be drawn in the tree view"),
1167                                                            FALSE,
1168                                                            GTK_PARAM_READWRITE));
1169
1170     g_object_class_install_property (o_class,
1171                                      PROP_TOOLTIP_COLUMN,
1172                                      g_param_spec_int ("tooltip-column",
1173                                                        P_("Tooltip Column"),
1174                                                        P_("The column in the model containing the tooltip texts for the rows"),
1175                                                        -1,
1176                                                        G_MAXINT,
1177                                                        -1,
1178                                                        GTK_PARAM_READWRITE));
1179
1180   /* Style properties */
1181 #define _TREE_VIEW_EXPANDER_SIZE 12
1182 #define _TREE_VIEW_VERTICAL_SEPARATOR 2
1183 #define _TREE_VIEW_HORIZONTAL_SEPARATOR 2
1184
1185   gtk_widget_class_install_style_property (widget_class,
1186                                            g_param_spec_int ("expander-size",
1187                                                              P_("Expander Size"),
1188                                                              P_("Size of the expander arrow"),
1189                                                              0,
1190                                                              G_MAXINT,
1191                                                              _TREE_VIEW_EXPANDER_SIZE,
1192                                                              GTK_PARAM_READABLE));
1193
1194   gtk_widget_class_install_style_property (widget_class,
1195                                            g_param_spec_int ("vertical-separator",
1196                                                              P_("Vertical Separator Width"),
1197                                                              P_("Vertical space between cells.  Must be an even number"),
1198                                                              0,
1199                                                              G_MAXINT,
1200                                                              _TREE_VIEW_VERTICAL_SEPARATOR,
1201                                                              GTK_PARAM_READABLE));
1202
1203   gtk_widget_class_install_style_property (widget_class,
1204                                            g_param_spec_int ("horizontal-separator",
1205                                                              P_("Horizontal Separator Width"),
1206                                                              P_("Horizontal space between cells.  Must be an even number"),
1207                                                              0,
1208                                                              G_MAXINT,
1209                                                              _TREE_VIEW_HORIZONTAL_SEPARATOR,
1210                                                              GTK_PARAM_READABLE));
1211
1212   gtk_widget_class_install_style_property (widget_class,
1213                                            g_param_spec_boolean ("allow-rules",
1214                                                                  P_("Allow Rules"),
1215                                                                  P_("Allow drawing of alternating color rows"),
1216                                                                  TRUE,
1217                                                                  GTK_PARAM_READABLE));
1218
1219   gtk_widget_class_install_style_property (widget_class,
1220                                            g_param_spec_boolean ("indent-expanders",
1221                                                                  P_("Indent Expanders"),
1222                                                                  P_("Make the expanders indented"),
1223                                                                  TRUE,
1224                                                                  GTK_PARAM_READABLE));
1225
1226   gtk_widget_class_install_style_property (widget_class,
1227                                            g_param_spec_boxed ("even-row-color",
1228                                                                P_("Even Row Color"),
1229                                                                P_("Color to use for even rows"),
1230                                                                GDK_TYPE_COLOR,
1231                                                                GTK_PARAM_READABLE));
1232
1233   gtk_widget_class_install_style_property (widget_class,
1234                                            g_param_spec_boxed ("odd-row-color",
1235                                                                P_("Odd Row Color"),
1236                                                                P_("Color to use for odd rows"),
1237                                                                GDK_TYPE_COLOR,
1238                                                                GTK_PARAM_READABLE));
1239
1240   gtk_widget_class_install_style_property (widget_class,
1241                                            g_param_spec_int ("grid-line-width",
1242                                                              P_("Grid line width"),
1243                                                              P_("Width, in pixels, of the tree view grid lines"),
1244                                                              0, G_MAXINT, 1,
1245                                                              GTK_PARAM_READABLE));
1246
1247   gtk_widget_class_install_style_property (widget_class,
1248                                            g_param_spec_int ("tree-line-width",
1249                                                              P_("Tree line width"),
1250                                                              P_("Width, in pixels, of the tree view lines"),
1251                                                              0, G_MAXINT, 1,
1252                                                              GTK_PARAM_READABLE));
1253
1254   gtk_widget_class_install_style_property (widget_class,
1255                                            g_param_spec_string ("grid-line-pattern",
1256                                                                 P_("Grid line pattern"),
1257                                                                 P_("Dash pattern used to draw the tree view grid lines"),
1258                                                                 "\1\1",
1259                                                                 GTK_PARAM_READABLE));
1260
1261   gtk_widget_class_install_style_property (widget_class,
1262                                            g_param_spec_string ("tree-line-pattern",
1263                                                                 P_("Tree line pattern"),
1264                                                                 P_("Dash pattern used to draw the tree view lines"),
1265                                                                 "\1\1",
1266                                                                 GTK_PARAM_READABLE));
1267
1268   /* Signals */
1269   /**
1270    * GtkTreeView::row-activated:
1271    * @tree_view: the object on which the signal is emitted
1272    * @path: the #GtkTreePath for the activated row
1273    * @column: the #GtkTreeViewColumn in which the activation occurred
1274    *
1275    * The "row-activated" signal is emitted when the method
1276    * gtk_tree_view_row_activated() is called or the user double clicks 
1277    * a treeview row. It is also emitted when a non-editable row is 
1278    * selected and one of the keys: Space, Shift+Space, Return or 
1279    * Enter is pressed.
1280    * 
1281    * For selection handling refer to the <link linkend="TreeWidget">tree 
1282    * widget conceptual overview</link> as well as #GtkTreeSelection.
1283    */
1284   tree_view_signals[ROW_ACTIVATED] =
1285     g_signal_new (I_("row-activated"),
1286                   G_TYPE_FROM_CLASS (o_class),
1287                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1288                   G_STRUCT_OFFSET (GtkTreeViewClass, row_activated),
1289                   NULL, NULL,
1290                   _gtk_marshal_VOID__BOXED_OBJECT,
1291                   G_TYPE_NONE, 2,
1292                   GTK_TYPE_TREE_PATH,
1293                   GTK_TYPE_TREE_VIEW_COLUMN);
1294
1295   /**
1296    * GtkTreeView::test-expand-row:
1297    * @tree_view: the object on which the signal is emitted
1298    * @iter: the tree iter of the row to expand
1299    * @path: a tree path that points to the row 
1300    * 
1301    * The given row is about to be expanded (show its children nodes). Use this
1302    * signal if you need to control the expandability of individual rows.
1303    *
1304    * Returns: %FALSE to allow expansion, %TRUE to reject
1305    */
1306   tree_view_signals[TEST_EXPAND_ROW] =
1307     g_signal_new (I_("test-expand-row"),
1308                   G_TYPE_FROM_CLASS (o_class),
1309                   G_SIGNAL_RUN_LAST,
1310                   G_STRUCT_OFFSET (GtkTreeViewClass, test_expand_row),
1311                   _gtk_boolean_handled_accumulator, NULL,
1312                   _gtk_marshal_BOOLEAN__BOXED_BOXED,
1313                   G_TYPE_BOOLEAN, 2,
1314                   GTK_TYPE_TREE_ITER,
1315                   GTK_TYPE_TREE_PATH);
1316
1317   /**
1318    * GtkTreeView::test-collapse-row:
1319    * @tree_view: the object on which the signal is emitted
1320    * @iter: the tree iter of the row to collapse
1321    * @path: a tree path that points to the row 
1322    * 
1323    * The given row is about to be collapsed (hide its children nodes). Use this
1324    * signal if you need to control the collapsibility of individual rows.
1325    *
1326    * Returns: %FALSE to allow collapsing, %TRUE to reject
1327    */
1328   tree_view_signals[TEST_COLLAPSE_ROW] =
1329     g_signal_new (I_("test-collapse-row"),
1330                   G_TYPE_FROM_CLASS (o_class),
1331                   G_SIGNAL_RUN_LAST,
1332                   G_STRUCT_OFFSET (GtkTreeViewClass, test_collapse_row),
1333                   _gtk_boolean_handled_accumulator, NULL,
1334                   _gtk_marshal_BOOLEAN__BOXED_BOXED,
1335                   G_TYPE_BOOLEAN, 2,
1336                   GTK_TYPE_TREE_ITER,
1337                   GTK_TYPE_TREE_PATH);
1338
1339   /**
1340    * GtkTreeView::row-expanded:
1341    * @tree_view: the object on which the signal is emitted
1342    * @iter: the tree iter of the expanded row
1343    * @path: a tree path that points to the row 
1344    * 
1345    * The given row has been expanded (child nodes are shown).
1346    */
1347   tree_view_signals[ROW_EXPANDED] =
1348     g_signal_new (I_("row-expanded"),
1349                   G_TYPE_FROM_CLASS (o_class),
1350                   G_SIGNAL_RUN_LAST,
1351                   G_STRUCT_OFFSET (GtkTreeViewClass, row_expanded),
1352                   NULL, NULL,
1353                   _gtk_marshal_VOID__BOXED_BOXED,
1354                   G_TYPE_NONE, 2,
1355                   GTK_TYPE_TREE_ITER,
1356                   GTK_TYPE_TREE_PATH);
1357
1358   /**
1359    * GtkTreeView::row-collapsed:
1360    * @tree_view: the object on which the signal is emitted
1361    * @iter: the tree iter of the collapsed row
1362    * @path: a tree path that points to the row 
1363    * 
1364    * The given row has been collapsed (child nodes are hidden).
1365    */
1366   tree_view_signals[ROW_COLLAPSED] =
1367     g_signal_new (I_("row-collapsed"),
1368                   G_TYPE_FROM_CLASS (o_class),
1369                   G_SIGNAL_RUN_LAST,
1370                   G_STRUCT_OFFSET (GtkTreeViewClass, row_collapsed),
1371                   NULL, NULL,
1372                   _gtk_marshal_VOID__BOXED_BOXED,
1373                   G_TYPE_NONE, 2,
1374                   GTK_TYPE_TREE_ITER,
1375                   GTK_TYPE_TREE_PATH);
1376
1377   /**
1378    * GtkTreeView::columns-changed:
1379    * @tree_view: the object on which the signal is emitted 
1380    * 
1381    * The number of columns of the treeview has changed.
1382    */
1383   tree_view_signals[COLUMNS_CHANGED] =
1384     g_signal_new (I_("columns-changed"),
1385                   G_TYPE_FROM_CLASS (o_class),
1386                   G_SIGNAL_RUN_LAST,
1387                   G_STRUCT_OFFSET (GtkTreeViewClass, columns_changed),
1388                   NULL, NULL,
1389                   _gtk_marshal_VOID__VOID,
1390                   G_TYPE_NONE, 0);
1391
1392   /**
1393    * GtkTreeView::cursor-changed:
1394    * @tree_view: the object on which the signal is emitted
1395    * 
1396    * The position of the cursor (focused cell) has changed.
1397    */
1398   tree_view_signals[CURSOR_CHANGED] =
1399     g_signal_new (I_("cursor-changed"),
1400                   G_TYPE_FROM_CLASS (o_class),
1401                   G_SIGNAL_RUN_LAST,
1402                   G_STRUCT_OFFSET (GtkTreeViewClass, cursor_changed),
1403                   NULL, NULL,
1404                   _gtk_marshal_VOID__VOID,
1405                   G_TYPE_NONE, 0);
1406
1407   tree_view_signals[MOVE_CURSOR] =
1408     g_signal_new (I_("move-cursor"),
1409                   G_TYPE_FROM_CLASS (o_class),
1410                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1411                   G_STRUCT_OFFSET (GtkTreeViewClass, move_cursor),
1412                   NULL, NULL,
1413                   _gtk_marshal_BOOLEAN__ENUM_INT,
1414                   G_TYPE_BOOLEAN, 2,
1415                   GTK_TYPE_MOVEMENT_STEP,
1416                   G_TYPE_INT);
1417
1418   tree_view_signals[SELECT_ALL] =
1419     g_signal_new (I_("select-all"),
1420                   G_TYPE_FROM_CLASS (o_class),
1421                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1422                   G_STRUCT_OFFSET (GtkTreeViewClass, select_all),
1423                   NULL, NULL,
1424                   _gtk_marshal_BOOLEAN__VOID,
1425                   G_TYPE_BOOLEAN, 0);
1426
1427   tree_view_signals[UNSELECT_ALL] =
1428     g_signal_new (I_("unselect-all"),
1429                   G_TYPE_FROM_CLASS (o_class),
1430                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1431                   G_STRUCT_OFFSET (GtkTreeViewClass, unselect_all),
1432                   NULL, NULL,
1433                   _gtk_marshal_BOOLEAN__VOID,
1434                   G_TYPE_BOOLEAN, 0);
1435
1436   tree_view_signals[SELECT_CURSOR_ROW] =
1437     g_signal_new (I_("select-cursor-row"),
1438                   G_TYPE_FROM_CLASS (o_class),
1439                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1440                   G_STRUCT_OFFSET (GtkTreeViewClass, select_cursor_row),
1441                   NULL, NULL,
1442                   _gtk_marshal_BOOLEAN__BOOLEAN,
1443                   G_TYPE_BOOLEAN, 1,
1444                   G_TYPE_BOOLEAN);
1445
1446   tree_view_signals[TOGGLE_CURSOR_ROW] =
1447     g_signal_new (I_("toggle-cursor-row"),
1448                   G_TYPE_FROM_CLASS (o_class),
1449                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1450                   G_STRUCT_OFFSET (GtkTreeViewClass, toggle_cursor_row),
1451                   NULL, NULL,
1452                   _gtk_marshal_BOOLEAN__VOID,
1453                   G_TYPE_BOOLEAN, 0);
1454
1455   tree_view_signals[EXPAND_COLLAPSE_CURSOR_ROW] =
1456     g_signal_new (I_("expand-collapse-cursor-row"),
1457                   G_TYPE_FROM_CLASS (o_class),
1458                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1459                   G_STRUCT_OFFSET (GtkTreeViewClass, expand_collapse_cursor_row),
1460                   NULL, NULL,
1461                   _gtk_marshal_BOOLEAN__BOOLEAN_BOOLEAN_BOOLEAN,
1462                   G_TYPE_BOOLEAN, 3,
1463                   G_TYPE_BOOLEAN,
1464                   G_TYPE_BOOLEAN,
1465                   G_TYPE_BOOLEAN);
1466
1467   tree_view_signals[SELECT_CURSOR_PARENT] =
1468     g_signal_new (I_("select-cursor-parent"),
1469                   G_TYPE_FROM_CLASS (o_class),
1470                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1471                   G_STRUCT_OFFSET (GtkTreeViewClass, select_cursor_parent),
1472                   NULL, NULL,
1473                   _gtk_marshal_BOOLEAN__VOID,
1474                   G_TYPE_BOOLEAN, 0);
1475
1476   tree_view_signals[START_INTERACTIVE_SEARCH] =
1477     g_signal_new (I_("start-interactive-search"),
1478                   G_TYPE_FROM_CLASS (o_class),
1479                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1480                   G_STRUCT_OFFSET (GtkTreeViewClass, start_interactive_search),
1481                   NULL, NULL,
1482                   _gtk_marshal_BOOLEAN__VOID,
1483                   G_TYPE_BOOLEAN, 0);
1484
1485   /* Key bindings */
1486   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Up, 0, TRUE,
1487                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
1488   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Up, 0, TRUE,
1489                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
1490
1491   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Down, 0, TRUE,
1492                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
1493   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Down, 0, TRUE,
1494                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
1495
1496   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_p, GDK_CONTROL_MASK, FALSE,
1497                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
1498
1499   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_n, GDK_CONTROL_MASK, FALSE,
1500                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
1501
1502   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Home, 0, TRUE,
1503                                   GTK_MOVEMENT_BUFFER_ENDS, -1);
1504   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Home, 0, TRUE,
1505                                   GTK_MOVEMENT_BUFFER_ENDS, -1);
1506
1507   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_End, 0, TRUE,
1508                                   GTK_MOVEMENT_BUFFER_ENDS, 1);
1509   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_End, 0, TRUE,
1510                                   GTK_MOVEMENT_BUFFER_ENDS, 1);
1511
1512   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Page_Up, 0, TRUE,
1513                                   GTK_MOVEMENT_PAGES, -1);
1514   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Page_Up, 0, TRUE,
1515                                   GTK_MOVEMENT_PAGES, -1);
1516
1517   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Page_Down, 0, TRUE,
1518                                   GTK_MOVEMENT_PAGES, 1);
1519   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Page_Down, 0, TRUE,
1520                                   GTK_MOVEMENT_PAGES, 1);
1521
1522
1523   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Right, 0, "move-cursor", 2,
1524                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1525                                 G_TYPE_INT, 1);
1526
1527   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Left, 0, "move-cursor", 2,
1528                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1529                                 G_TYPE_INT, -1);
1530
1531   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Right, 0, "move-cursor", 2,
1532                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1533                                 G_TYPE_INT, 1);
1534
1535   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Left, 0, "move-cursor", 2,
1536                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1537                                 G_TYPE_INT, -1);
1538
1539   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Right, GDK_CONTROL_MASK,
1540                                 "move-cursor", 2,
1541                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1542                                 G_TYPE_INT, 1);
1543
1544   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Left, GDK_CONTROL_MASK,
1545                                 "move-cursor", 2,
1546                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1547                                 G_TYPE_INT, -1);
1548
1549   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Right, GDK_CONTROL_MASK,
1550                                 "move-cursor", 2,
1551                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1552                                 G_TYPE_INT, 1);
1553
1554   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Left, GDK_CONTROL_MASK,
1555                                 "move-cursor", 2,
1556                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1557                                 G_TYPE_INT, -1);
1558
1559   gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, GDK_CONTROL_MASK, "toggle-cursor-row", 0);
1560   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Space, GDK_CONTROL_MASK, "toggle-cursor-row", 0);
1561
1562   gtk_binding_entry_add_signal (binding_set, GDK_KEY_a, GDK_CONTROL_MASK, "select-all", 0);
1563   gtk_binding_entry_add_signal (binding_set, GDK_KEY_slash, GDK_CONTROL_MASK, "select-all", 0);
1564
1565   gtk_binding_entry_add_signal (binding_set, GDK_KEY_A, GDK_CONTROL_MASK | GDK_SHIFT_MASK, "unselect-all", 0);
1566   gtk_binding_entry_add_signal (binding_set, GDK_KEY_backslash, GDK_CONTROL_MASK, "unselect-all", 0);
1567
1568   gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, GDK_SHIFT_MASK, "select-cursor-row", 1,
1569                                 G_TYPE_BOOLEAN, TRUE);
1570   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Space, GDK_SHIFT_MASK, "select-cursor-row", 1,
1571                                 G_TYPE_BOOLEAN, TRUE);
1572
1573   gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, 0, "select-cursor-row", 1,
1574                                 G_TYPE_BOOLEAN, TRUE);
1575   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Space, 0, "select-cursor-row", 1,
1576                                 G_TYPE_BOOLEAN, TRUE);
1577   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Return, 0, "select-cursor-row", 1,
1578                                 G_TYPE_BOOLEAN, TRUE);
1579   gtk_binding_entry_add_signal (binding_set, GDK_KEY_ISO_Enter, 0, "select-cursor-row", 1,
1580                                 G_TYPE_BOOLEAN, TRUE);
1581   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Enter, 0, "select-cursor-row", 1,
1582                                 G_TYPE_BOOLEAN, TRUE);
1583
1584   /* expand and collapse rows */
1585   gtk_binding_entry_add_signal (binding_set, GDK_KEY_plus, 0, "expand-collapse-cursor-row", 3,
1586                                 G_TYPE_BOOLEAN, TRUE,
1587                                 G_TYPE_BOOLEAN, TRUE,
1588                                 G_TYPE_BOOLEAN, FALSE);
1589
1590   gtk_binding_entry_add_signal (binding_set, GDK_KEY_asterisk, 0,
1591                                 "expand-collapse-cursor-row", 3,
1592                                 G_TYPE_BOOLEAN, TRUE,
1593                                 G_TYPE_BOOLEAN, TRUE,
1594                                 G_TYPE_BOOLEAN, TRUE);
1595   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Multiply, 0,
1596                                 "expand-collapse-cursor-row", 3,
1597                                 G_TYPE_BOOLEAN, TRUE,
1598                                 G_TYPE_BOOLEAN, TRUE,
1599                                 G_TYPE_BOOLEAN, TRUE);
1600
1601   gtk_binding_entry_add_signal (binding_set, GDK_KEY_slash, 0,
1602                                 "expand-collapse-cursor-row", 3,
1603                                 G_TYPE_BOOLEAN, TRUE,
1604                                 G_TYPE_BOOLEAN, FALSE,
1605                                 G_TYPE_BOOLEAN, FALSE);
1606   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Divide, 0,
1607                                 "expand-collapse-cursor-row", 3,
1608                                 G_TYPE_BOOLEAN, TRUE,
1609                                 G_TYPE_BOOLEAN, FALSE,
1610                                 G_TYPE_BOOLEAN, FALSE);
1611
1612   /* Not doable on US keyboards */
1613   gtk_binding_entry_add_signal (binding_set, GDK_KEY_plus, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1614                                 G_TYPE_BOOLEAN, TRUE,
1615                                 G_TYPE_BOOLEAN, TRUE,
1616                                 G_TYPE_BOOLEAN, TRUE);
1617   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Add, 0, "expand-collapse-cursor-row", 3,
1618                                 G_TYPE_BOOLEAN, TRUE,
1619                                 G_TYPE_BOOLEAN, TRUE,
1620                                 G_TYPE_BOOLEAN, FALSE);
1621   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Add, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1622                                 G_TYPE_BOOLEAN, TRUE,
1623                                 G_TYPE_BOOLEAN, TRUE,
1624                                 G_TYPE_BOOLEAN, TRUE);
1625   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Add, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1626                                 G_TYPE_BOOLEAN, TRUE,
1627                                 G_TYPE_BOOLEAN, TRUE,
1628                                 G_TYPE_BOOLEAN, TRUE);
1629   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Right, GDK_SHIFT_MASK,
1630                                 "expand-collapse-cursor-row", 3,
1631                                 G_TYPE_BOOLEAN, FALSE,
1632                                 G_TYPE_BOOLEAN, TRUE,
1633                                 G_TYPE_BOOLEAN, TRUE);
1634   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Right, GDK_SHIFT_MASK,
1635                                 "expand-collapse-cursor-row", 3,
1636                                 G_TYPE_BOOLEAN, FALSE,
1637                                 G_TYPE_BOOLEAN, TRUE,
1638                                 G_TYPE_BOOLEAN, TRUE);
1639   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Right,
1640                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1641                                 "expand-collapse-cursor-row", 3,
1642                                 G_TYPE_BOOLEAN, FALSE,
1643                                 G_TYPE_BOOLEAN, TRUE,
1644                                 G_TYPE_BOOLEAN, TRUE);
1645   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Right,
1646                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1647                                 "expand-collapse-cursor-row", 3,
1648                                 G_TYPE_BOOLEAN, FALSE,
1649                                 G_TYPE_BOOLEAN, TRUE,
1650                                 G_TYPE_BOOLEAN, TRUE);
1651
1652   gtk_binding_entry_add_signal (binding_set, GDK_KEY_minus, 0, "expand-collapse-cursor-row", 3,
1653                                 G_TYPE_BOOLEAN, TRUE,
1654                                 G_TYPE_BOOLEAN, FALSE,
1655                                 G_TYPE_BOOLEAN, FALSE);
1656   gtk_binding_entry_add_signal (binding_set, GDK_KEY_minus, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1657                                 G_TYPE_BOOLEAN, TRUE,
1658                                 G_TYPE_BOOLEAN, FALSE,
1659                                 G_TYPE_BOOLEAN, TRUE);
1660   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Subtract, 0, "expand-collapse-cursor-row", 3,
1661                                 G_TYPE_BOOLEAN, TRUE,
1662                                 G_TYPE_BOOLEAN, FALSE,
1663                                 G_TYPE_BOOLEAN, FALSE);
1664   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Subtract, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1665                                 G_TYPE_BOOLEAN, TRUE,
1666                                 G_TYPE_BOOLEAN, FALSE,
1667                                 G_TYPE_BOOLEAN, TRUE);
1668   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Left, GDK_SHIFT_MASK,
1669                                 "expand-collapse-cursor-row", 3,
1670                                 G_TYPE_BOOLEAN, FALSE,
1671                                 G_TYPE_BOOLEAN, FALSE,
1672                                 G_TYPE_BOOLEAN, TRUE);
1673   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Left, GDK_SHIFT_MASK,
1674                                 "expand-collapse-cursor-row", 3,
1675                                 G_TYPE_BOOLEAN, FALSE,
1676                                 G_TYPE_BOOLEAN, FALSE,
1677                                 G_TYPE_BOOLEAN, TRUE);
1678   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Left,
1679                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1680                                 "expand-collapse-cursor-row", 3,
1681                                 G_TYPE_BOOLEAN, FALSE,
1682                                 G_TYPE_BOOLEAN, FALSE,
1683                                 G_TYPE_BOOLEAN, TRUE);
1684   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Left,
1685                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1686                                 "expand-collapse-cursor-row", 3,
1687                                 G_TYPE_BOOLEAN, FALSE,
1688                                 G_TYPE_BOOLEAN, FALSE,
1689                                 G_TYPE_BOOLEAN, TRUE);
1690
1691   gtk_binding_entry_add_signal (binding_set, GDK_KEY_BackSpace, 0, "select-cursor-parent", 0);
1692   gtk_binding_entry_add_signal (binding_set, GDK_KEY_BackSpace, GDK_CONTROL_MASK, "select-cursor-parent", 0);
1693
1694   gtk_binding_entry_add_signal (binding_set, GDK_KEY_f, GDK_CONTROL_MASK, "start-interactive-search", 0);
1695
1696   gtk_binding_entry_add_signal (binding_set, GDK_KEY_F, GDK_CONTROL_MASK, "start-interactive-search", 0);
1697
1698   g_type_class_add_private (o_class, sizeof (GtkTreeViewPrivate));
1699 }
1700
1701 static void
1702 gtk_tree_view_init (GtkTreeView *tree_view)
1703 {
1704   tree_view->priv = G_TYPE_INSTANCE_GET_PRIVATE (tree_view, GTK_TYPE_TREE_VIEW, GtkTreeViewPrivate);
1705
1706   gtk_widget_set_can_focus (GTK_WIDGET (tree_view), TRUE);
1707   gtk_widget_set_redraw_on_allocate (GTK_WIDGET (tree_view), FALSE);
1708
1709   tree_view->priv->show_expanders = TRUE;
1710   tree_view->priv->draw_keyfocus = TRUE;
1711   tree_view->priv->headers_visible = TRUE;
1712
1713   /* We need some padding */
1714   tree_view->priv->dy = 0;
1715   tree_view->priv->cursor_offset = 0;
1716   tree_view->priv->n_columns = 0;
1717   tree_view->priv->header_height = 1;
1718   tree_view->priv->x_drag = 0;
1719   tree_view->priv->drag_pos = -1;
1720   tree_view->priv->header_has_focus = FALSE;
1721   tree_view->priv->pressed_button = -1;
1722   tree_view->priv->press_start_x = -1;
1723   tree_view->priv->press_start_y = -1;
1724   tree_view->priv->reorderable = FALSE;
1725   tree_view->priv->presize_handler_timer = 0;
1726   tree_view->priv->scroll_sync_timer = 0;
1727   tree_view->priv->fixed_height = -1;
1728   tree_view->priv->fixed_height_mode = FALSE;
1729   tree_view->priv->fixed_height_check = 0;
1730   tree_view->priv->selection = _gtk_tree_selection_new_with_tree_view (tree_view);
1731   tree_view->priv->enable_search = TRUE;
1732   tree_view->priv->search_column = -1;
1733   tree_view->priv->search_position_func = gtk_tree_view_search_position_func;
1734   tree_view->priv->search_equal_func = gtk_tree_view_search_equal_func;
1735   tree_view->priv->search_custom_entry_set = FALSE;
1736   tree_view->priv->typeselect_flush_timeout = 0;
1737   tree_view->priv->init_hadjust_value = TRUE;    
1738   tree_view->priv->width = 0;
1739           
1740   tree_view->priv->hover_selection = FALSE;
1741   tree_view->priv->hover_expand = FALSE;
1742
1743   tree_view->priv->level_indentation = 0;
1744
1745   tree_view->priv->rubber_banding_enable = FALSE;
1746
1747   tree_view->priv->grid_lines = GTK_TREE_VIEW_GRID_LINES_NONE;
1748   tree_view->priv->tree_lines_enabled = FALSE;
1749
1750   tree_view->priv->tooltip_column = -1;
1751
1752   tree_view->priv->post_validation_flag = FALSE;
1753
1754   tree_view->priv->last_button_x = -1;
1755   tree_view->priv->last_button_y = -1;
1756
1757   tree_view->priv->event_last_x = -10000;
1758   tree_view->priv->event_last_y = -10000;
1759
1760   gtk_tree_view_set_vadjustment (tree_view, NULL);
1761   gtk_tree_view_set_hadjustment (tree_view, NULL);
1762 }
1763
1764 \f
1765
1766 /* GObject Methods
1767  */
1768
1769 static void
1770 gtk_tree_view_set_property (GObject         *object,
1771                             guint            prop_id,
1772                             const GValue    *value,
1773                             GParamSpec      *pspec)
1774 {
1775   GtkTreeView *tree_view;
1776
1777   tree_view = GTK_TREE_VIEW (object);
1778
1779   switch (prop_id)
1780     {
1781     case PROP_MODEL:
1782       gtk_tree_view_set_model (tree_view, g_value_get_object (value));
1783       break;
1784     case PROP_HADJUSTMENT:
1785       gtk_tree_view_set_hadjustment (tree_view, g_value_get_object (value));
1786       break;
1787     case PROP_VADJUSTMENT:
1788       gtk_tree_view_set_vadjustment (tree_view, g_value_get_object (value));
1789       break;
1790     case PROP_HSCROLL_POLICY:
1791       tree_view->priv->hscroll_policy = g_value_get_enum (value);
1792       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
1793       break;
1794     case PROP_VSCROLL_POLICY:
1795       tree_view->priv->vscroll_policy = g_value_get_enum (value);
1796       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
1797       break;
1798     case PROP_HEADERS_VISIBLE:
1799       gtk_tree_view_set_headers_visible (tree_view, g_value_get_boolean (value));
1800       break;
1801     case PROP_HEADERS_CLICKABLE:
1802       gtk_tree_view_set_headers_clickable (tree_view, g_value_get_boolean (value));
1803       break;
1804     case PROP_EXPANDER_COLUMN:
1805       gtk_tree_view_set_expander_column (tree_view, g_value_get_object (value));
1806       break;
1807     case PROP_REORDERABLE:
1808       gtk_tree_view_set_reorderable (tree_view, g_value_get_boolean (value));
1809       break;
1810     case PROP_RULES_HINT:
1811       gtk_tree_view_set_rules_hint (tree_view, g_value_get_boolean (value));
1812       break;
1813     case PROP_ENABLE_SEARCH:
1814       gtk_tree_view_set_enable_search (tree_view, g_value_get_boolean (value));
1815       break;
1816     case PROP_SEARCH_COLUMN:
1817       gtk_tree_view_set_search_column (tree_view, g_value_get_int (value));
1818       break;
1819     case PROP_FIXED_HEIGHT_MODE:
1820       gtk_tree_view_set_fixed_height_mode (tree_view, g_value_get_boolean (value));
1821       break;
1822     case PROP_HOVER_SELECTION:
1823       tree_view->priv->hover_selection = g_value_get_boolean (value);
1824       break;
1825     case PROP_HOVER_EXPAND:
1826       tree_view->priv->hover_expand = g_value_get_boolean (value);
1827       break;
1828     case PROP_SHOW_EXPANDERS:
1829       gtk_tree_view_set_show_expanders (tree_view, g_value_get_boolean (value));
1830       break;
1831     case PROP_LEVEL_INDENTATION:
1832       tree_view->priv->level_indentation = g_value_get_int (value);
1833       break;
1834     case PROP_RUBBER_BANDING:
1835       tree_view->priv->rubber_banding_enable = g_value_get_boolean (value);
1836       break;
1837     case PROP_ENABLE_GRID_LINES:
1838       gtk_tree_view_set_grid_lines (tree_view, g_value_get_enum (value));
1839       break;
1840     case PROP_ENABLE_TREE_LINES:
1841       gtk_tree_view_set_enable_tree_lines (tree_view, g_value_get_boolean (value));
1842       break;
1843     case PROP_TOOLTIP_COLUMN:
1844       gtk_tree_view_set_tooltip_column (tree_view, g_value_get_int (value));
1845       break;
1846     default:
1847       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1848       break;
1849     }
1850 }
1851
1852 static void
1853 gtk_tree_view_get_property (GObject    *object,
1854                             guint       prop_id,
1855                             GValue     *value,
1856                             GParamSpec *pspec)
1857 {
1858   GtkTreeView *tree_view;
1859
1860   tree_view = GTK_TREE_VIEW (object);
1861
1862   switch (prop_id)
1863     {
1864     case PROP_MODEL:
1865       g_value_set_object (value, tree_view->priv->model);
1866       break;
1867     case PROP_HADJUSTMENT:
1868       g_value_set_object (value, tree_view->priv->hadjustment);
1869       break;
1870     case PROP_VADJUSTMENT:
1871       g_value_set_object (value, tree_view->priv->vadjustment);
1872       break;
1873     case PROP_HSCROLL_POLICY:
1874       g_value_set_enum (value, tree_view->priv->hscroll_policy);
1875       break;
1876     case PROP_VSCROLL_POLICY:
1877       g_value_set_enum (value, tree_view->priv->vscroll_policy);
1878       break;
1879     case PROP_HEADERS_VISIBLE:
1880       g_value_set_boolean (value, gtk_tree_view_get_headers_visible (tree_view));
1881       break;
1882     case PROP_HEADERS_CLICKABLE:
1883       g_value_set_boolean (value, gtk_tree_view_get_headers_clickable (tree_view));
1884       break;
1885     case PROP_EXPANDER_COLUMN:
1886       g_value_set_object (value, tree_view->priv->expander_column);
1887       break;
1888     case PROP_REORDERABLE:
1889       g_value_set_boolean (value, tree_view->priv->reorderable);
1890       break;
1891     case PROP_RULES_HINT:
1892       g_value_set_boolean (value, tree_view->priv->has_rules);
1893       break;
1894     case PROP_ENABLE_SEARCH:
1895       g_value_set_boolean (value, tree_view->priv->enable_search);
1896       break;
1897     case PROP_SEARCH_COLUMN:
1898       g_value_set_int (value, tree_view->priv->search_column);
1899       break;
1900     case PROP_FIXED_HEIGHT_MODE:
1901       g_value_set_boolean (value, tree_view->priv->fixed_height_mode);
1902       break;
1903     case PROP_HOVER_SELECTION:
1904       g_value_set_boolean (value, tree_view->priv->hover_selection);
1905       break;
1906     case PROP_HOVER_EXPAND:
1907       g_value_set_boolean (value, tree_view->priv->hover_expand);
1908       break;
1909     case PROP_SHOW_EXPANDERS:
1910       g_value_set_boolean (value, tree_view->priv->show_expanders);
1911       break;
1912     case PROP_LEVEL_INDENTATION:
1913       g_value_set_int (value, tree_view->priv->level_indentation);
1914       break;
1915     case PROP_RUBBER_BANDING:
1916       g_value_set_boolean (value, tree_view->priv->rubber_banding_enable);
1917       break;
1918     case PROP_ENABLE_GRID_LINES:
1919       g_value_set_enum (value, tree_view->priv->grid_lines);
1920       break;
1921     case PROP_ENABLE_TREE_LINES:
1922       g_value_set_boolean (value, tree_view->priv->tree_lines_enabled);
1923       break;
1924     case PROP_TOOLTIP_COLUMN:
1925       g_value_set_int (value, tree_view->priv->tooltip_column);
1926       break;
1927     default:
1928       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1929       break;
1930     }
1931 }
1932
1933 static void
1934 gtk_tree_view_finalize (GObject *object)
1935 {
1936   G_OBJECT_CLASS (gtk_tree_view_parent_class)->finalize (object);
1937 }
1938
1939
1940 static GtkBuildableIface *parent_buildable_iface;
1941
1942 static void
1943 gtk_tree_view_buildable_init (GtkBuildableIface *iface)
1944 {
1945   parent_buildable_iface = g_type_interface_peek_parent (iface);
1946   iface->add_child = gtk_tree_view_buildable_add_child;
1947   iface->get_internal_child = gtk_tree_view_buildable_get_internal_child;
1948 }
1949
1950 static void
1951 gtk_tree_view_buildable_add_child (GtkBuildable *tree_view,
1952                                    GtkBuilder  *builder,
1953                                    GObject     *child,
1954                                    const gchar *type)
1955 {
1956   gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), GTK_TREE_VIEW_COLUMN (child));
1957 }
1958
1959 static GObject *
1960 gtk_tree_view_buildable_get_internal_child (GtkBuildable      *buildable,
1961                                             GtkBuilder        *builder,
1962                                             const gchar       *childname)
1963 {
1964     if (strcmp (childname, "selection") == 0)
1965       return G_OBJECT (GTK_TREE_VIEW (buildable)->priv->selection);
1966     
1967     return parent_buildable_iface->get_internal_child (buildable,
1968                                                        builder,
1969                                                        childname);
1970 }
1971
1972 /* GtkWidget Methods
1973  */
1974
1975 static void
1976 gtk_tree_view_free_rbtree (GtkTreeView *tree_view)
1977 {
1978   _gtk_rbtree_free (tree_view->priv->tree);
1979   
1980   tree_view->priv->tree = NULL;
1981   tree_view->priv->button_pressed_node = NULL;
1982   tree_view->priv->button_pressed_tree = NULL;
1983   tree_view->priv->prelight_tree = NULL;
1984   tree_view->priv->prelight_node = NULL;
1985   tree_view->priv->expanded_collapsed_node = NULL;
1986   tree_view->priv->expanded_collapsed_tree = NULL;
1987 }
1988
1989 static void
1990 gtk_tree_view_destroy (GtkWidget *widget)
1991 {
1992   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
1993   GList *list;
1994
1995   gtk_tree_view_stop_editing (tree_view, TRUE);
1996
1997   if (tree_view->priv->columns != NULL)
1998     {
1999       list = tree_view->priv->columns;
2000       while (list)
2001         {
2002           GtkTreeViewColumn *column;
2003           column = GTK_TREE_VIEW_COLUMN (list->data);
2004           list = list->next;
2005           gtk_tree_view_remove_column (tree_view, column);
2006         }
2007       tree_view->priv->columns = NULL;
2008     }
2009
2010   if (tree_view->priv->tree != NULL)
2011     {
2012       gtk_tree_view_unref_and_check_selection_tree (tree_view, tree_view->priv->tree);
2013
2014       gtk_tree_view_free_rbtree (tree_view);
2015     }
2016
2017   if (tree_view->priv->selection != NULL)
2018     {
2019       _gtk_tree_selection_set_tree_view (tree_view->priv->selection, NULL);
2020       g_object_unref (tree_view->priv->selection);
2021       tree_view->priv->selection = NULL;
2022     }
2023
2024   if (tree_view->priv->scroll_to_path != NULL)
2025     {
2026       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
2027       tree_view->priv->scroll_to_path = NULL;
2028     }
2029
2030   if (tree_view->priv->drag_dest_row != NULL)
2031     {
2032       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
2033       tree_view->priv->drag_dest_row = NULL;
2034     }
2035
2036   if (tree_view->priv->top_row != NULL)
2037     {
2038       gtk_tree_row_reference_free (tree_view->priv->top_row);
2039       tree_view->priv->top_row = NULL;
2040     }
2041
2042   if (tree_view->priv->column_drop_func_data &&
2043       tree_view->priv->column_drop_func_data_destroy)
2044     {
2045       tree_view->priv->column_drop_func_data_destroy (tree_view->priv->column_drop_func_data);
2046       tree_view->priv->column_drop_func_data = NULL;
2047     }
2048
2049   if (tree_view->priv->destroy_count_destroy &&
2050       tree_view->priv->destroy_count_data)
2051     {
2052       tree_view->priv->destroy_count_destroy (tree_view->priv->destroy_count_data);
2053       tree_view->priv->destroy_count_data = NULL;
2054     }
2055
2056   gtk_tree_row_reference_free (tree_view->priv->cursor);
2057   tree_view->priv->cursor = NULL;
2058
2059   gtk_tree_row_reference_free (tree_view->priv->anchor);
2060   tree_view->priv->anchor = NULL;
2061
2062   /* destroy interactive search dialog */
2063   if (tree_view->priv->search_window)
2064     {
2065       gtk_widget_destroy (tree_view->priv->search_window);
2066       tree_view->priv->search_window = NULL;
2067       tree_view->priv->search_entry = NULL;
2068       if (tree_view->priv->typeselect_flush_timeout)
2069         {
2070           g_source_remove (tree_view->priv->typeselect_flush_timeout);
2071           tree_view->priv->typeselect_flush_timeout = 0;
2072         }
2073     }
2074
2075   if (tree_view->priv->search_destroy && tree_view->priv->search_user_data)
2076     {
2077       tree_view->priv->search_destroy (tree_view->priv->search_user_data);
2078       tree_view->priv->search_user_data = NULL;
2079     }
2080
2081   if (tree_view->priv->search_position_destroy && tree_view->priv->search_position_user_data)
2082     {
2083       tree_view->priv->search_position_destroy (tree_view->priv->search_position_user_data);
2084       tree_view->priv->search_position_user_data = NULL;
2085     }
2086
2087   if (tree_view->priv->row_separator_destroy && tree_view->priv->row_separator_data)
2088     {
2089       tree_view->priv->row_separator_destroy (tree_view->priv->row_separator_data);
2090       tree_view->priv->row_separator_data = NULL;
2091     }
2092   
2093   gtk_tree_view_set_model (tree_view, NULL);
2094
2095   if (tree_view->priv->hadjustment)
2096     {
2097       g_object_unref (tree_view->priv->hadjustment);
2098       tree_view->priv->hadjustment = NULL;
2099     }
2100   if (tree_view->priv->vadjustment)
2101     {
2102       g_object_unref (tree_view->priv->vadjustment);
2103       tree_view->priv->vadjustment = NULL;
2104     }
2105
2106   GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->destroy (widget);
2107 }
2108
2109 /* GtkWidget::map helper */
2110 static void
2111 gtk_tree_view_map_buttons (GtkTreeView *tree_view)
2112 {
2113   GList *list;
2114
2115   g_return_if_fail (gtk_widget_get_mapped (GTK_WIDGET (tree_view)));
2116
2117   if (tree_view->priv->headers_visible)
2118     {
2119       GtkTreeViewColumn *column;
2120       GtkWidget         *button;
2121       GdkWindow         *window;
2122
2123       for (list = tree_view->priv->columns; list; list = list->next)
2124         {
2125           column = list->data;
2126           button = gtk_tree_view_column_get_button (column);
2127
2128           if (gtk_tree_view_column_get_visible (column) && button)
2129             gtk_widget_show_now (button);
2130
2131           if (gtk_widget_get_visible (button) &&
2132               !gtk_widget_get_mapped (button))
2133             gtk_widget_map (button);
2134         }
2135       for (list = tree_view->priv->columns; list; list = list->next)
2136         {
2137           column = list->data;
2138           if (gtk_tree_view_column_get_visible (column) == FALSE)
2139             continue;
2140
2141           window = _gtk_tree_view_column_get_window (column);
2142           if (gtk_tree_view_column_get_resizable (column))
2143             {
2144               gdk_window_raise (window);
2145               gdk_window_show (window);
2146             }
2147           else
2148             gdk_window_hide (window);
2149         }
2150       gdk_window_show (tree_view->priv->header_window);
2151     }
2152 }
2153
2154 static void
2155 gtk_tree_view_map (GtkWidget *widget)
2156 {
2157   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2158   GList *tmp_list;
2159
2160   gtk_widget_set_mapped (widget, TRUE);
2161
2162   tmp_list = tree_view->priv->children;
2163   while (tmp_list)
2164     {
2165       GtkTreeViewChild *child = tmp_list->data;
2166       tmp_list = tmp_list->next;
2167
2168       if (gtk_widget_get_visible (child->widget))
2169         {
2170           if (!gtk_widget_get_mapped (child->widget))
2171             gtk_widget_map (child->widget);
2172         }
2173     }
2174   gdk_window_show (tree_view->priv->bin_window);
2175
2176   gtk_tree_view_map_buttons (tree_view);
2177
2178   gdk_window_show (gtk_widget_get_window (widget));
2179 }
2180
2181 static void
2182 gtk_tree_view_realize (GtkWidget *widget)
2183 {
2184   GtkAllocation allocation;
2185   GtkStyleContext *context;
2186   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2187   GdkWindow *window;
2188   GdkWindowAttr attributes;
2189   GList *tmp_list;
2190   gint attributes_mask;
2191
2192   gtk_widget_set_realized (widget, TRUE);
2193
2194   gtk_widget_get_allocation (widget, &allocation);
2195
2196   /* Make the main, clipping window */
2197   attributes.window_type = GDK_WINDOW_CHILD;
2198   attributes.x = allocation.x;
2199   attributes.y = allocation.y;
2200   attributes.width = allocation.width;
2201   attributes.height = allocation.height;
2202   attributes.wclass = GDK_INPUT_OUTPUT;
2203   attributes.visual = gtk_widget_get_visual (widget);
2204   attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK;
2205
2206   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
2207
2208   window = gdk_window_new (gtk_widget_get_parent_window (widget),
2209                            &attributes, attributes_mask);
2210   gtk_widget_set_window (widget, window);
2211   gdk_window_set_user_data (window, widget);
2212
2213   gtk_widget_get_allocation (widget, &allocation);
2214
2215   /* Make the window for the tree */
2216   attributes.x = 0;
2217   attributes.y = gtk_tree_view_get_effective_header_height (tree_view);
2218   attributes.width = MAX (tree_view->priv->width, allocation.width);
2219   attributes.height = allocation.height;
2220   attributes.event_mask = (GDK_EXPOSURE_MASK |
2221                            GDK_SCROLL_MASK |
2222                            GDK_POINTER_MOTION_MASK |
2223                            GDK_ENTER_NOTIFY_MASK |
2224                            GDK_LEAVE_NOTIFY_MASK |
2225                            GDK_BUTTON_PRESS_MASK |
2226                            GDK_BUTTON_RELEASE_MASK |
2227                            gtk_widget_get_events (widget));
2228
2229   tree_view->priv->bin_window = gdk_window_new (window,
2230                                                 &attributes, attributes_mask);
2231   gdk_window_set_user_data (tree_view->priv->bin_window, widget);
2232
2233   gtk_widget_get_allocation (widget, &allocation);
2234
2235   /* Make the column header window */
2236   attributes.x = 0;
2237   attributes.y = 0;
2238   attributes.width = MAX (tree_view->priv->width, allocation.width);
2239   attributes.height = tree_view->priv->header_height;
2240   attributes.event_mask = (GDK_EXPOSURE_MASK |
2241                            GDK_SCROLL_MASK |
2242                            GDK_ENTER_NOTIFY_MASK |
2243                            GDK_LEAVE_NOTIFY_MASK |
2244                            GDK_BUTTON_PRESS_MASK |
2245                            GDK_BUTTON_RELEASE_MASK |
2246                            GDK_KEY_PRESS_MASK |
2247                            GDK_KEY_RELEASE_MASK |
2248                            gtk_widget_get_events (widget));
2249
2250   tree_view->priv->header_window = gdk_window_new (window,
2251                                                    &attributes, attributes_mask);
2252   gdk_window_set_user_data (tree_view->priv->header_window, widget);
2253
2254   context = gtk_widget_get_style_context (widget);
2255
2256   gtk_style_context_save (context);
2257   gtk_style_context_add_class (context, GTK_STYLE_CLASS_VIEW);
2258   gtk_style_context_set_background (context, tree_view->priv->bin_window);
2259   gtk_style_context_restore (context);
2260
2261   gtk_style_context_set_background (context, tree_view->priv->header_window);
2262
2263   tmp_list = tree_view->priv->children;
2264   while (tmp_list)
2265     {
2266       GtkTreeViewChild *child = tmp_list->data;
2267       tmp_list = tmp_list->next;
2268
2269       gtk_widget_set_parent_window (child->widget, tree_view->priv->bin_window);
2270     }
2271
2272   for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
2273     _gtk_tree_view_column_realize_button (GTK_TREE_VIEW_COLUMN (tmp_list->data));
2274
2275   /* Need to call those here, since they create GCs */
2276   gtk_tree_view_set_grid_lines (tree_view, tree_view->priv->grid_lines);
2277   gtk_tree_view_set_enable_tree_lines (tree_view, tree_view->priv->tree_lines_enabled);
2278
2279   install_presize_handler (tree_view); 
2280 }
2281
2282 static void
2283 gtk_tree_view_unrealize (GtkWidget *widget)
2284 {
2285   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2286   GtkTreeViewPrivate *priv = tree_view->priv;
2287   GtkStyleContext *context;
2288   GList *list;
2289
2290   if (priv->scroll_timeout != 0)
2291     {
2292       g_source_remove (priv->scroll_timeout);
2293       priv->scroll_timeout = 0;
2294     }
2295
2296   if (priv->auto_expand_timeout != 0)
2297     {
2298       g_source_remove (priv->auto_expand_timeout);
2299       priv->auto_expand_timeout = 0;
2300     }
2301
2302   if (priv->open_dest_timeout != 0)
2303     {
2304       g_source_remove (priv->open_dest_timeout);
2305       priv->open_dest_timeout = 0;
2306     }
2307
2308   context = gtk_widget_get_style_context (widget);
2309   gtk_style_context_cancel_animations (context, NULL);
2310
2311   if (priv->presize_handler_timer != 0)
2312     {
2313       g_source_remove (priv->presize_handler_timer);
2314       priv->presize_handler_timer = 0;
2315     }
2316
2317   if (priv->validate_rows_timer != 0)
2318     {
2319       g_source_remove (priv->validate_rows_timer);
2320       priv->validate_rows_timer = 0;
2321     }
2322
2323   if (priv->scroll_sync_timer != 0)
2324     {
2325       g_source_remove (priv->scroll_sync_timer);
2326       priv->scroll_sync_timer = 0;
2327     }
2328
2329   if (priv->typeselect_flush_timeout)
2330     {
2331       g_source_remove (priv->typeselect_flush_timeout);
2332       priv->typeselect_flush_timeout = 0;
2333     }
2334   
2335   for (list = priv->columns; list; list = list->next)
2336     _gtk_tree_view_column_unrealize_button (GTK_TREE_VIEW_COLUMN (list->data));
2337
2338   gdk_window_set_user_data (priv->bin_window, NULL);
2339   gdk_window_destroy (priv->bin_window);
2340   priv->bin_window = NULL;
2341
2342   gdk_window_set_user_data (priv->header_window, NULL);
2343   gdk_window_destroy (priv->header_window);
2344   priv->header_window = NULL;
2345
2346   if (priv->drag_window)
2347     {
2348       gdk_window_set_user_data (priv->drag_window, NULL);
2349       gdk_window_destroy (priv->drag_window);
2350       priv->drag_window = NULL;
2351     }
2352
2353   if (priv->drag_highlight_window)
2354     {
2355       gdk_window_set_user_data (priv->drag_highlight_window, NULL);
2356       gdk_window_destroy (priv->drag_highlight_window);
2357       priv->drag_highlight_window = NULL;
2358     }
2359
2360   GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->unrealize (widget);
2361 }
2362
2363 /* GtkWidget::size_request helper */
2364 static void
2365 gtk_tree_view_size_request_columns (GtkTreeView *tree_view)
2366 {
2367   GList *list;
2368
2369   tree_view->priv->header_height = 0;
2370
2371   if (tree_view->priv->model)
2372     {
2373       for (list = tree_view->priv->columns; list; list = list->next)
2374         {
2375           GtkRequisition     requisition;
2376           GtkTreeViewColumn *column = list->data;
2377           GtkWidget         *button = gtk_tree_view_column_get_button (column);
2378
2379           if (button == NULL)
2380             continue;
2381
2382           column = list->data;
2383
2384           gtk_widget_get_preferred_size (button, &requisition, NULL);
2385           tree_view->priv->header_height = MAX (tree_view->priv->header_height, requisition.height);
2386         }
2387     }
2388 }
2389
2390
2391 /* Called only by ::size_request */
2392 static void
2393 gtk_tree_view_update_size (GtkTreeView *tree_view)
2394 {
2395   GList *list;
2396   GtkTreeViewColumn *column;
2397   gint i;
2398
2399   if (tree_view->priv->model == NULL)
2400     {
2401       tree_view->priv->width = 0;
2402       tree_view->priv->prev_width = 0;                   
2403       tree_view->priv->height = 0;
2404       return;
2405     }
2406
2407   tree_view->priv->prev_width = tree_view->priv->width;  
2408   tree_view->priv->width = 0;
2409
2410   /* keep this in sync with size_allocate below */
2411   for (list = tree_view->priv->columns, i = 0; list; list = list->next, i++)
2412     {
2413       column = list->data;
2414       if (!gtk_tree_view_column_get_visible (column))
2415         continue;
2416
2417       tree_view->priv->width += _gtk_tree_view_column_request_width (column);
2418     }
2419
2420   if (tree_view->priv->tree == NULL)
2421     tree_view->priv->height = 0;
2422   else
2423     tree_view->priv->height = tree_view->priv->tree->root->offset;
2424 }
2425
2426 static void
2427 gtk_tree_view_size_request (GtkWidget      *widget,
2428                             GtkRequisition *requisition,
2429                             gboolean        may_validate)
2430 {
2431   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2432
2433   if (may_validate)
2434     {
2435       /* we validate some rows initially just to make sure we have some size.
2436        * In practice, with a lot of static lists, this should get a good width.
2437        */
2438       do_validate_rows (tree_view, FALSE);
2439     }
2440
2441   gtk_tree_view_size_request_columns (tree_view);
2442   gtk_tree_view_update_size (GTK_TREE_VIEW (widget));
2443
2444   requisition->width = tree_view->priv->width;
2445   requisition->height = tree_view->priv->height + gtk_tree_view_get_effective_header_height (tree_view);
2446 }
2447
2448 static void
2449 gtk_tree_view_get_preferred_width (GtkWidget *widget,
2450                                    gint      *minimum,
2451                                    gint      *natural)
2452 {
2453   GtkRequisition requisition;
2454
2455   gtk_tree_view_size_request (widget, &requisition, TRUE);
2456
2457   *minimum = *natural = requisition.width;
2458 }
2459
2460 static void
2461 gtk_tree_view_get_preferred_height (GtkWidget *widget,
2462                                     gint      *minimum,
2463                                     gint      *natural)
2464 {
2465   GtkRequisition requisition;
2466
2467   gtk_tree_view_size_request (widget, &requisition, TRUE);
2468
2469   *minimum = *natural = requisition.height;
2470 }
2471
2472 static int
2473 gtk_tree_view_calculate_width_before_expander (GtkTreeView *tree_view)
2474 {
2475   int width = 0;
2476   GList *list;
2477   gboolean rtl;
2478
2479   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2480   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
2481        list->data != tree_view->priv->expander_column;
2482        list = (rtl ? list->prev : list->next))
2483     {
2484       GtkTreeViewColumn *column = list->data;
2485
2486       width += gtk_tree_view_column_get_width (column);
2487     }
2488
2489   return width;
2490 }
2491
2492 static void
2493 invalidate_column (GtkTreeView       *tree_view,
2494                    GtkTreeViewColumn *column)
2495 {
2496   gint column_offset = 0;
2497   GList *list;
2498   GtkWidget *widget = GTK_WIDGET (tree_view);
2499   gboolean rtl;
2500
2501   if (!gtk_widget_get_realized (widget))
2502     return;
2503
2504   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2505   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
2506        list;
2507        list = (rtl ? list->prev : list->next))
2508     {
2509       GtkTreeViewColumn *tmpcolumn = list->data;
2510       if (tmpcolumn == column)
2511         {
2512           GtkAllocation allocation;
2513           GdkRectangle invalid_rect;
2514
2515           gtk_widget_get_allocation (widget, &allocation);
2516           invalid_rect.x = column_offset;
2517           invalid_rect.y = 0;
2518           invalid_rect.width = gtk_tree_view_column_get_width (column);
2519           invalid_rect.height = allocation.height;
2520
2521           gdk_window_invalidate_rect (gtk_widget_get_window (widget), &invalid_rect, TRUE);
2522           break;
2523         }
2524
2525       column_offset += gtk_tree_view_column_get_width (tmpcolumn);
2526     }
2527 }
2528
2529 static void
2530 invalidate_last_column (GtkTreeView *tree_view)
2531 {
2532   GList *last_column;
2533   gboolean rtl;
2534
2535   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2536
2537   for (last_column = (rtl ? g_list_first (tree_view->priv->columns) : g_list_last (tree_view->priv->columns));
2538        last_column;
2539        last_column = (rtl ? last_column->next : last_column->prev))
2540     {
2541       if (gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (last_column->data)))
2542         {
2543           invalidate_column (tree_view, last_column->data);
2544           return;
2545         }
2546     }
2547 }
2548
2549 /* GtkWidget::size_allocate helper */
2550 static void
2551 gtk_tree_view_size_allocate_columns (GtkWidget *widget,
2552                                      gboolean  *width_changed)
2553 {
2554   GtkTreeView *tree_view;
2555   GList *list, *first_column, *last_column;
2556   GtkTreeViewColumn *column;
2557   GtkAllocation widget_allocation;
2558   gint width = 0;
2559   gint extra, extra_per_column, extra_for_last;
2560   gint full_requested_width = 0;
2561   gint number_of_expand_columns = 0;
2562   gboolean column_changed = FALSE;
2563   gboolean rtl;
2564   gboolean update_expand;
2565   
2566   tree_view = GTK_TREE_VIEW (widget);
2567
2568   for (last_column = g_list_last (tree_view->priv->columns);
2569        last_column &&
2570        !(gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (last_column->data)));
2571        last_column = last_column->prev)
2572     ;
2573   if (last_column == NULL)
2574     return;
2575
2576   for (first_column = g_list_first (tree_view->priv->columns);
2577        first_column &&
2578        !(gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (first_column->data)));
2579        first_column = first_column->next)
2580     ;
2581
2582   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
2583
2584   /* find out how many extra space and expandable columns we have */
2585   for (list = tree_view->priv->columns; list != last_column->next; list = list->next)
2586     {
2587       column = (GtkTreeViewColumn *)list->data;
2588
2589       if (!gtk_tree_view_column_get_visible (column))
2590         continue;
2591
2592       full_requested_width += _gtk_tree_view_column_request_width (column);
2593
2594       if (gtk_tree_view_column_get_expand (column))
2595         number_of_expand_columns++;
2596     }
2597
2598   /* Only update the expand value if the width of the widget has changed,
2599    * or the number of expand columns has changed, or if there are no expand
2600    * columns, or if we didn't have an size-allocation yet after the
2601    * last validated node.
2602    */
2603   update_expand = (width_changed && *width_changed == TRUE)
2604       || number_of_expand_columns != tree_view->priv->last_number_of_expand_columns
2605       || number_of_expand_columns == 0
2606       || tree_view->priv->post_validation_flag == TRUE;
2607
2608   tree_view->priv->post_validation_flag = FALSE;
2609
2610   gtk_widget_get_allocation (widget, &widget_allocation);
2611   if (!update_expand)
2612     {
2613       extra = tree_view->priv->last_extra_space;
2614       extra_for_last = MAX (widget_allocation.width - full_requested_width - extra, 0);
2615     }
2616   else
2617     {
2618       extra = MAX (widget_allocation.width - full_requested_width, 0);
2619       extra_for_last = 0;
2620
2621       tree_view->priv->last_extra_space = extra;
2622     }
2623
2624   if (number_of_expand_columns > 0)
2625     extra_per_column = extra/number_of_expand_columns;
2626   else
2627     extra_per_column = 0;
2628
2629   if (update_expand)
2630     {
2631       tree_view->priv->last_extra_space_per_column = extra_per_column;
2632       tree_view->priv->last_number_of_expand_columns = number_of_expand_columns;
2633     }
2634
2635   for (list = (rtl ? last_column : first_column); 
2636        list != (rtl ? first_column->prev : last_column->next);
2637        list = (rtl ? list->prev : list->next)) 
2638     {
2639       gint old_width, column_width;
2640
2641       column = list->data;
2642       old_width = gtk_tree_view_column_get_width (column);
2643
2644       if (!gtk_tree_view_column_get_visible (column))
2645         continue;
2646
2647       /* We need to handle the dragged button specially.
2648        */
2649       if (column == tree_view->priv->drag_column)
2650         {
2651           GtkAllocation drag_allocation;
2652           GtkWidget    *button;
2653
2654           button = gtk_tree_view_column_get_button (tree_view->priv->drag_column);
2655
2656           drag_allocation.x = 0;
2657           drag_allocation.y = 0;
2658           drag_allocation.width = gdk_window_get_width (tree_view->priv->drag_window);
2659           drag_allocation.height = gdk_window_get_height (tree_view->priv->drag_window);
2660           gtk_widget_size_allocate (button, &drag_allocation);
2661           width += drag_allocation.width;
2662           continue;
2663         }
2664
2665       column_width = _gtk_tree_view_column_request_width (column);
2666
2667       if (gtk_tree_view_column_get_expand (column))
2668         {
2669           if (number_of_expand_columns == 1)
2670             {
2671               /* We add the remander to the last column as
2672                * */
2673               column_width += extra;
2674             }
2675           else
2676             {
2677               column_width += extra_per_column;
2678               extra -= extra_per_column;
2679               number_of_expand_columns --;
2680             }
2681         }
2682       else if (number_of_expand_columns == 0 &&
2683                list == last_column)
2684         {
2685           column_width += extra;
2686         }
2687
2688       /* In addition to expand, the last column can get even more
2689        * extra space so all available space is filled up.
2690        */
2691       if (extra_for_last > 0 && list == last_column)
2692         column_width += extra_for_last;
2693
2694       _gtk_tree_view_column_allocate (column, width, column_width);
2695
2696       width += column_width;
2697
2698       if (column_width > old_width)
2699         column_changed = TRUE;
2700     }
2701
2702   /* We change the width here.  The user might have been resizing columns,
2703    * so the total width of the tree view changes.
2704    */
2705   tree_view->priv->width = width;
2706   if (width_changed)
2707     *width_changed = TRUE;
2708
2709   if (column_changed)
2710     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
2711 }
2712
2713
2714 static void
2715 gtk_tree_view_size_allocate (GtkWidget     *widget,
2716                              GtkAllocation *allocation)
2717 {
2718   GtkAllocation widget_allocation;
2719   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2720   GList *tmp_list;
2721   gboolean width_changed = FALSE;
2722   gint old_width;
2723
2724   gtk_widget_get_allocation (widget, &widget_allocation);
2725   old_width = widget_allocation.width;
2726   if (allocation->width != widget_allocation.width)
2727     width_changed = TRUE;
2728
2729   gtk_widget_set_allocation (widget, allocation);
2730
2731   tmp_list = tree_view->priv->children;
2732
2733   while (tmp_list)
2734     {
2735       GtkAllocation allocation;
2736
2737       GtkTreeViewChild *child = tmp_list->data;
2738       tmp_list = tmp_list->next;
2739
2740       /* totally ignore our child's requisition */
2741       allocation.x = child->x;
2742       allocation.y = child->y;
2743       allocation.width = child->width;
2744       allocation.height = child->height;
2745       gtk_widget_size_allocate (child->widget, &allocation);
2746     }
2747
2748   /* We size-allocate the columns first because the width of the
2749    * tree view (used in updating the adjustments below) might change.
2750    */
2751   gtk_tree_view_size_allocate_columns (widget, &width_changed);
2752
2753   g_object_freeze_notify (G_OBJECT (tree_view->priv->hadjustment));
2754   gtk_adjustment_set_page_size (tree_view->priv->hadjustment,
2755                                 allocation->width);
2756   gtk_adjustment_set_page_increment (tree_view->priv->hadjustment,
2757                                      allocation->width * 0.9);
2758   gtk_adjustment_set_step_increment (tree_view->priv->hadjustment,
2759                                      allocation->width * 0.1);
2760   gtk_adjustment_set_lower (tree_view->priv->hadjustment, 0);
2761   gtk_adjustment_set_upper (tree_view->priv->hadjustment,
2762                             MAX (gtk_adjustment_get_page_size (tree_view->priv->hadjustment),
2763                                  tree_view->priv->width));
2764   g_object_thaw_notify (G_OBJECT (tree_view->priv->hadjustment));
2765
2766   if (gtk_widget_get_direction(widget) == GTK_TEXT_DIR_RTL)   
2767     {
2768       if (allocation->width < tree_view->priv->width)
2769         {
2770           if (tree_view->priv->init_hadjust_value)
2771             {
2772               gtk_adjustment_set_value (tree_view->priv->hadjustment,
2773                                         MAX (tree_view->priv->width -
2774                                              allocation->width, 0));
2775               tree_view->priv->init_hadjust_value = FALSE;
2776             }
2777           else if (allocation->width != old_width)
2778             {
2779               gtk_adjustment_set_value (tree_view->priv->hadjustment,
2780                                         CLAMP (gtk_adjustment_get_value (tree_view->priv->hadjustment) - allocation->width + old_width,
2781                                                0,
2782                                                tree_view->priv->width - allocation->width));
2783             }
2784           else
2785             gtk_adjustment_set_value (tree_view->priv->hadjustment,
2786                                       CLAMP (tree_view->priv->width - (tree_view->priv->prev_width - gtk_adjustment_get_value (tree_view->priv->hadjustment)),
2787                                              0,
2788                                              tree_view->priv->width - allocation->width));
2789         }
2790       else
2791         {
2792           gtk_adjustment_set_value (tree_view->priv->hadjustment, 0);
2793           tree_view->priv->init_hadjust_value = TRUE;
2794         }
2795     }
2796   else
2797     if (gtk_adjustment_get_value (tree_view->priv->hadjustment) + allocation->width > tree_view->priv->width)
2798       gtk_adjustment_set_value (tree_view->priv->hadjustment,
2799                                 MAX (tree_view->priv->width -
2800                                      allocation->width, 0));
2801
2802   g_object_freeze_notify (G_OBJECT (tree_view->priv->vadjustment));
2803   gtk_adjustment_set_page_size (tree_view->priv->vadjustment,
2804                                 allocation->height -
2805                                 gtk_tree_view_get_effective_header_height (tree_view));
2806   gtk_adjustment_set_step_increment (tree_view->priv->vadjustment,
2807                                      gtk_adjustment_get_page_size (tree_view->priv->vadjustment) * 0.1);
2808   gtk_adjustment_set_page_increment (tree_view->priv->vadjustment,
2809                                      gtk_adjustment_get_page_size (tree_view->priv->vadjustment) * 0.9);
2810   gtk_adjustment_set_lower (tree_view->priv->vadjustment, 0);
2811   gtk_adjustment_set_upper (tree_view->priv->vadjustment,
2812                             MAX (gtk_adjustment_get_page_size (tree_view->priv->vadjustment),
2813                                  tree_view->priv->height));
2814   g_object_thaw_notify (G_OBJECT (tree_view->priv->vadjustment));
2815
2816   /* now the adjustments and window sizes are in sync, we can sync toprow/dy again */
2817   if (tree_view->priv->height <= gtk_adjustment_get_page_size (tree_view->priv->vadjustment))
2818     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
2819   else if (gtk_adjustment_get_value (tree_view->priv->vadjustment) + gtk_adjustment_get_page_size (tree_view->priv->vadjustment) > tree_view->priv->height)
2820     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment),
2821                               tree_view->priv->height - gtk_adjustment_get_page_size (tree_view->priv->vadjustment));
2822   else if (gtk_tree_row_reference_valid (tree_view->priv->top_row))
2823     gtk_tree_view_top_row_to_dy (tree_view);
2824   else
2825     gtk_tree_view_dy_to_top_row (tree_view);
2826   
2827   if (gtk_widget_get_realized (widget))
2828     {
2829       gdk_window_move_resize (gtk_widget_get_window (widget),
2830                               allocation->x, allocation->y,
2831                               allocation->width, allocation->height);
2832       gdk_window_move_resize (tree_view->priv->header_window,
2833                               - (gint) gtk_adjustment_get_value (tree_view->priv->hadjustment),
2834                               0,
2835                               MAX (tree_view->priv->width, allocation->width),
2836                               tree_view->priv->header_height);
2837       gdk_window_move_resize (tree_view->priv->bin_window,
2838                               - (gint) gtk_adjustment_get_value (tree_view->priv->hadjustment),
2839                               gtk_tree_view_get_effective_header_height (tree_view),
2840                               MAX (tree_view->priv->width, allocation->width),
2841                               allocation->height - gtk_tree_view_get_effective_header_height (tree_view));
2842     }
2843
2844   if (tree_view->priv->tree == NULL)
2845     invalidate_empty_focus (tree_view);
2846
2847   if (gtk_widget_get_realized (widget))
2848     {
2849       gboolean has_expand_column = FALSE;
2850       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
2851         {
2852           if (gtk_tree_view_column_get_expand (GTK_TREE_VIEW_COLUMN (tmp_list->data)))
2853             {
2854               has_expand_column = TRUE;
2855               break;
2856             }
2857         }
2858
2859       if (width_changed && tree_view->priv->expander_column)
2860         {
2861           /* Might seem awkward, but is the best heuristic I could come up
2862            * with.  Only if the width of the columns before the expander
2863            * changes, we will update the prelight status.  It is this
2864            * width that makes the expander move vertically.  Always updating
2865            * prelight status causes trouble with hover selections.
2866            */
2867           gint width_before_expander;
2868
2869           width_before_expander = gtk_tree_view_calculate_width_before_expander (tree_view);
2870
2871           if (tree_view->priv->prev_width_before_expander
2872               != width_before_expander)
2873               update_prelight (tree_view,
2874                                tree_view->priv->event_last_x,
2875                                tree_view->priv->event_last_y);
2876
2877           tree_view->priv->prev_width_before_expander = width_before_expander;
2878         }
2879
2880       /* This little hack only works if we have an LTR locale, and no column has the  */
2881       if (width_changed)
2882         {
2883           if (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_LTR &&
2884               ! has_expand_column)
2885             invalidate_last_column (tree_view);
2886           else
2887             gtk_widget_queue_draw (widget);
2888         }
2889     }
2890 }
2891
2892 /* Grabs the focus and unsets the GTK_TREE_VIEW_DRAW_KEYFOCUS flag */
2893 static void
2894 grab_focus_and_unset_draw_keyfocus (GtkTreeView *tree_view)
2895 {
2896   GtkWidget *widget = GTK_WIDGET (tree_view);
2897
2898   if (gtk_widget_get_can_focus (widget) && !gtk_widget_has_focus (widget))
2899     gtk_widget_grab_focus (widget);
2900   tree_view->priv->draw_keyfocus = 0;
2901 }
2902
2903 static inline gboolean
2904 row_is_separator (GtkTreeView *tree_view,
2905                   GtkTreeIter *iter,
2906                   GtkTreePath *path)
2907 {
2908   gboolean is_separator = FALSE;
2909
2910   if (tree_view->priv->row_separator_func)
2911     {
2912       GtkTreeIter tmpiter;
2913
2914       if (iter)
2915         tmpiter = *iter;
2916       else
2917         {
2918           if (!gtk_tree_model_get_iter (tree_view->priv->model, &tmpiter, path))
2919             return FALSE;
2920         }
2921
2922       is_separator = tree_view->priv->row_separator_func (tree_view->priv->model,
2923                                                           &tmpiter,
2924                                                           tree_view->priv->row_separator_data);
2925     }
2926
2927   return is_separator;
2928 }
2929
2930 static gboolean
2931 gtk_tree_view_button_press (GtkWidget      *widget,
2932                             GdkEventButton *event)
2933 {
2934   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2935   GList *list;
2936   GtkTreeViewColumn *column = NULL;
2937   gint i;
2938   GdkRectangle background_area;
2939   GdkRectangle cell_area;
2940   gint vertical_separator;
2941   gint horizontal_separator;
2942   gboolean path_is_selectable;
2943   gboolean rtl;
2944
2945   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
2946   gtk_tree_view_stop_editing (tree_view, FALSE);
2947   gtk_widget_style_get (widget,
2948                         "vertical-separator", &vertical_separator,
2949                         "horizontal-separator", &horizontal_separator,
2950                         NULL);
2951
2952   /* Because grab_focus can cause reentrancy, we delay grab_focus until after
2953    * we're done handling the button press.
2954    */
2955
2956   if (event->window == tree_view->priv->bin_window)
2957     {
2958       GtkRBNode *node;
2959       GtkRBTree *tree;
2960       GtkTreePath *path;
2961       gint depth;
2962       gint new_y;
2963       gint y_offset;
2964       gint dval;
2965       gint pre_val, aft_val;
2966       GtkTreeViewColumn *column = NULL;
2967       gint column_handled_click = FALSE;
2968       gboolean row_double_click = FALSE;
2969       gboolean rtl;
2970       gboolean node_selected;
2971
2972       /* Empty tree? */
2973       if (tree_view->priv->tree == NULL)
2974         {
2975           grab_focus_and_unset_draw_keyfocus (tree_view);
2976           return TRUE;
2977         }
2978
2979       /* are we in an arrow? */
2980       if (tree_view->priv->prelight_node &&
2981           tree_view->priv->arrow_prelit &&
2982           gtk_tree_view_draw_expanders (tree_view))
2983         {
2984           if (event->button == 1)
2985             {
2986               gtk_grab_add (widget);
2987               tree_view->priv->button_pressed_node = tree_view->priv->prelight_node;
2988               tree_view->priv->button_pressed_tree = tree_view->priv->prelight_tree;
2989               gtk_tree_view_queue_draw_arrow (GTK_TREE_VIEW (widget),
2990                                               tree_view->priv->prelight_tree,
2991                                               tree_view->priv->prelight_node);
2992             }
2993
2994           grab_focus_and_unset_draw_keyfocus (tree_view);
2995           return TRUE;
2996         }
2997
2998       /* find the node that was clicked */
2999       new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
3000       if (new_y < 0)
3001         new_y = 0;
3002       y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
3003
3004       if (node == NULL)
3005         {
3006           /* We clicked in dead space */
3007           grab_focus_and_unset_draw_keyfocus (tree_view);
3008           return TRUE;
3009         }
3010
3011       /* Get the path and the node */
3012       path = _gtk_tree_view_find_path (tree_view, tree, node);
3013       path_is_selectable = !row_is_separator (tree_view, NULL, path);
3014
3015       if (!path_is_selectable)
3016         {
3017           gtk_tree_path_free (path);
3018           grab_focus_and_unset_draw_keyfocus (tree_view);
3019           return TRUE;
3020         }
3021
3022       depth = gtk_tree_path_get_depth (path);
3023       background_area.y = y_offset + event->y;
3024       background_area.height = gtk_tree_view_get_row_height (tree_view, node);
3025       background_area.x = 0;
3026
3027
3028       /* Let the column have a chance at selecting it. */
3029       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
3030       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
3031            list; list = (rtl ? list->prev : list->next))
3032         {
3033           GtkTreeViewColumn *candidate = list->data;
3034
3035           if (!gtk_tree_view_column_get_visible (candidate))
3036             continue;
3037
3038           background_area.width = gtk_tree_view_column_get_width (candidate);
3039           if ((background_area.x > (gint) event->x) ||
3040               (background_area.x + background_area.width <= (gint) event->x))
3041             {
3042               background_area.x += background_area.width;
3043               continue;
3044             }
3045
3046           /* we found the focus column */
3047           column = candidate;
3048           cell_area = background_area;
3049           cell_area.width -= horizontal_separator;
3050           cell_area.height -= vertical_separator;
3051           cell_area.x += horizontal_separator/2;
3052           cell_area.y += vertical_separator/2;
3053           if (gtk_tree_view_is_expander_column (tree_view, column))
3054             {
3055               if (!rtl)
3056                 cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
3057               cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
3058
3059               if (gtk_tree_view_draw_expanders (tree_view))
3060                 {
3061                   if (!rtl)
3062                     cell_area.x += depth * tree_view->priv->expander_size;
3063                   cell_area.width -= depth * tree_view->priv->expander_size;
3064                 }
3065             }
3066           break;
3067         }
3068
3069       if (column == NULL)
3070         {
3071           gtk_tree_path_free (path);
3072           grab_focus_and_unset_draw_keyfocus (tree_view);
3073           return FALSE;
3074         }
3075
3076       tree_view->priv->focus_column = column;
3077
3078       /* decide if we edit */
3079       if (event->type == GDK_BUTTON_PRESS && event->button == 1 &&
3080           !(event->state & gtk_accelerator_get_default_mod_mask ()))
3081         {
3082           GtkTreePath *anchor;
3083           GtkTreeIter iter;
3084
3085           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
3086           gtk_tree_view_column_cell_set_cell_data (column,
3087                                                    tree_view->priv->model,
3088                                                    &iter,
3089                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
3090                                                    node->children?TRUE:FALSE);
3091
3092           if (tree_view->priv->anchor)
3093             anchor = gtk_tree_row_reference_get_path (tree_view->priv->anchor);
3094           else
3095             anchor = NULL;
3096
3097           if ((anchor && !gtk_tree_path_compare (anchor, path))
3098               || !_gtk_tree_view_column_has_editable_cell (column))
3099             {
3100               GtkCellEditable *cell_editable = NULL;
3101
3102               /* FIXME: get the right flags */
3103               guint flags = 0;
3104
3105               if (_gtk_tree_view_column_cell_event (column,
3106                                                     (GdkEvent *)event,
3107                                                     &cell_area, flags))
3108                 {
3109                   GtkCellArea *area = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (column));
3110                   cell_editable = gtk_cell_area_get_edit_widget (area);
3111
3112                   if (cell_editable != NULL)
3113                     {
3114                       gtk_tree_path_free (path);
3115                       gtk_tree_path_free (anchor);
3116                       return TRUE;
3117                     }
3118                   column_handled_click = TRUE;
3119                 }
3120             }
3121           if (anchor)
3122             gtk_tree_path_free (anchor);
3123         }
3124
3125       /* select */
3126       node_selected = GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED);
3127       pre_val = gtk_adjustment_get_value (tree_view->priv->vadjustment);
3128
3129       /* we only handle selection modifications on the first button press
3130        */
3131       if (event->type == GDK_BUTTON_PRESS)
3132         {
3133           GtkCellRenderer *focus_cell;
3134
3135           if ((event->state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
3136             tree_view->priv->ctrl_pressed = TRUE;
3137           if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
3138             tree_view->priv->shift_pressed = TRUE;
3139
3140           /* We update the focus cell here, this is also needed if the
3141            * column does not contain an editable cell.  In this case,
3142            * GtkCellArea did not receive the event for processing (and
3143            * could not update the focus cell).
3144            */
3145           focus_cell = _gtk_tree_view_column_get_cell_at_pos (column,
3146                                                               &cell_area,
3147                                                               &background_area,
3148                                                               event->x,
3149                                                               event->y);
3150
3151           if (focus_cell)
3152             gtk_tree_view_column_focus_cell (column, focus_cell);
3153
3154           if (event->state & GDK_CONTROL_MASK)
3155             {
3156               gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
3157               gtk_tree_view_real_toggle_cursor_row (tree_view);
3158             }
3159           else if (event->state & GDK_SHIFT_MASK)
3160             {
3161               gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
3162               gtk_tree_view_real_select_cursor_row (tree_view, FALSE);
3163             }
3164           else
3165             {
3166               gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
3167             }
3168
3169           tree_view->priv->ctrl_pressed = FALSE;
3170           tree_view->priv->shift_pressed = FALSE;
3171         }
3172
3173       /* the treeview may have been scrolled because of _set_cursor,
3174        * correct here
3175        */
3176
3177       aft_val = gtk_adjustment_get_value (tree_view->priv->vadjustment);
3178       dval = pre_val - aft_val;
3179
3180       cell_area.y += dval;
3181       background_area.y += dval;
3182
3183       /* Save press to possibly begin a drag
3184        */
3185       if (!column_handled_click &&
3186           !tree_view->priv->in_grab &&
3187           tree_view->priv->pressed_button < 0)
3188         {
3189           tree_view->priv->pressed_button = event->button;
3190           tree_view->priv->press_start_x = event->x;
3191           tree_view->priv->press_start_y = event->y;
3192
3193           if (tree_view->priv->rubber_banding_enable
3194               && !node_selected
3195               && gtk_tree_selection_get_mode (tree_view->priv->selection) == GTK_SELECTION_MULTIPLE)
3196             {
3197               tree_view->priv->press_start_y += tree_view->priv->dy;
3198               tree_view->priv->rubber_band_x = event->x;
3199               tree_view->priv->rubber_band_y = event->y + tree_view->priv->dy;
3200               tree_view->priv->rubber_band_status = RUBBER_BAND_MAYBE_START;
3201
3202               if ((event->state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
3203                 tree_view->priv->rubber_band_ctrl = TRUE;
3204               if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
3205                 tree_view->priv->rubber_band_shift = TRUE;
3206             }
3207         }
3208
3209       /* Test if a double click happened on the same row. */
3210       if (event->button == 1 && event->type == GDK_BUTTON_PRESS)
3211         {
3212           int double_click_time, double_click_distance;
3213
3214           g_object_get (gtk_settings_get_default (),
3215                         "gtk-double-click-time", &double_click_time,
3216                         "gtk-double-click-distance", &double_click_distance,
3217                         NULL);
3218
3219           /* Same conditions as _gdk_event_button_generate */
3220           if (tree_view->priv->last_button_x != -1 &&
3221               (event->time < tree_view->priv->last_button_time + double_click_time) &&
3222               (ABS (event->x - tree_view->priv->last_button_x) <= double_click_distance) &&
3223               (ABS (event->y - tree_view->priv->last_button_y) <= double_click_distance))
3224             {
3225               /* We do no longer compare paths of this row and the
3226                * row clicked previously.  We use the double click
3227                * distance to decide whether this is a valid click,
3228                * allowing the mouse to slightly move over another row.
3229                */
3230               row_double_click = TRUE;
3231
3232               tree_view->priv->last_button_time = 0;
3233               tree_view->priv->last_button_x = -1;
3234               tree_view->priv->last_button_y = -1;
3235             }
3236           else
3237             {
3238               tree_view->priv->last_button_time = event->time;
3239               tree_view->priv->last_button_x = event->x;
3240               tree_view->priv->last_button_y = event->y;
3241             }
3242         }
3243
3244       if (row_double_click)
3245         {
3246           gtk_grab_remove (widget);
3247           gtk_tree_view_row_activated (tree_view, path, column);
3248
3249           if (tree_view->priv->pressed_button == event->button)
3250             tree_view->priv->pressed_button = -1;
3251         }
3252
3253       gtk_tree_path_free (path);
3254
3255       /* If we activated the row through a double click we don't want to grab
3256        * focus back, as moving focus to another widget is pretty common.
3257        */
3258       if (!row_double_click)
3259         grab_focus_and_unset_draw_keyfocus (tree_view);
3260
3261       return TRUE;
3262     }
3263
3264   /* We didn't click in the window.  Let's check to see if we clicked on a column resize window.
3265    */
3266   for (i = 0, list = tree_view->priv->columns; list; list = list->next, i++)
3267     {
3268       column = list->data;
3269       if (event->window == _gtk_tree_view_column_get_window (column) &&
3270           gtk_tree_view_column_get_resizable (column) &&
3271           _gtk_tree_view_column_get_window (column))
3272         {
3273           GtkWidget *button;
3274           GtkAllocation button_allocation;
3275           gpointer drag_data;
3276
3277           if (event->type == GDK_2BUTTON_PRESS &&
3278               gtk_tree_view_column_get_sizing (column) != GTK_TREE_VIEW_COLUMN_AUTOSIZE)
3279             {
3280               _gtk_tree_view_column_set_use_resized_width (column, FALSE);
3281               _gtk_tree_view_column_autosize (tree_view, column);
3282               return TRUE;
3283             }
3284
3285           if (gdk_device_grab (gdk_event_get_device ((GdkEvent*)event),
3286                                _gtk_tree_view_column_get_window (column),
3287                                GDK_OWNERSHIP_NONE,
3288                                FALSE,
3289                                GDK_POINTER_MOTION_HINT_MASK
3290                                 | GDK_BUTTON1_MOTION_MASK
3291                                 | GDK_BUTTON_RELEASE_MASK,
3292                                NULL,
3293                                event->time) != GDK_GRAB_SUCCESS)
3294             return FALSE;
3295
3296           gtk_grab_add (widget);
3297           tree_view->priv->in_column_resize = TRUE;
3298
3299           _gtk_tree_view_column_set_resized_width (column, gtk_tree_view_column_get_width (column) -
3300                                                    tree_view->priv->last_extra_space_per_column);
3301
3302           /* block attached dnd signal handler */
3303           drag_data = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
3304           if (drag_data)
3305             g_signal_handlers_block_matched (widget,
3306                                              G_SIGNAL_MATCH_DATA,
3307                                              0, 0, NULL, NULL,
3308                                              drag_data);
3309
3310           button = gtk_tree_view_column_get_button (column);
3311           gtk_widget_get_allocation (button, &button_allocation);
3312           tree_view->priv->drag_pos = i;
3313           tree_view->priv->x_drag = button_allocation.x + (rtl ? 0 : button_allocation.width);
3314
3315           if (!gtk_widget_has_focus (widget))
3316             gtk_widget_grab_focus (widget);
3317
3318           return TRUE;
3319         }
3320     }
3321   return FALSE;
3322 }
3323
3324 /* GtkWidget::button_release_event helper */
3325 static gboolean
3326 gtk_tree_view_button_release_drag_column (GtkWidget      *widget,
3327                                           GdkEventButton *event)
3328 {
3329   GtkTreeView *tree_view;
3330   GtkWidget *button;
3331   GList *l;
3332   gboolean rtl;
3333   GdkDevice *device, *other;
3334
3335   tree_view = GTK_TREE_VIEW (widget);
3336
3337   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
3338   device = gdk_event_get_device ((GdkEvent*)event);
3339   other = gdk_device_get_associated_device (device);
3340   gdk_device_ungrab (device, event->time);
3341   gdk_device_ungrab (other, event->time);
3342
3343   /* Move the button back */
3344   button = gtk_tree_view_column_get_button (tree_view->priv->drag_column);
3345   g_object_ref (button);
3346   gtk_container_remove (GTK_CONTAINER (tree_view), button);
3347   gtk_widget_set_parent_window (button, tree_view->priv->header_window);
3348   gtk_widget_set_parent (button, GTK_WIDGET (tree_view));
3349   g_object_unref (button);
3350   gtk_widget_queue_resize (widget);
3351   if (gtk_tree_view_column_get_resizable (tree_view->priv->drag_column))
3352     {
3353       gdk_window_raise (_gtk_tree_view_column_get_window (tree_view->priv->drag_column));
3354       gdk_window_show (_gtk_tree_view_column_get_window (tree_view->priv->drag_column));
3355     }
3356   else
3357     gdk_window_hide (_gtk_tree_view_column_get_window (tree_view->priv->drag_column));
3358
3359   gtk_widget_grab_focus (button);
3360
3361   if (rtl)
3362     {
3363       if (tree_view->priv->cur_reorder &&
3364           tree_view->priv->cur_reorder->right_column != tree_view->priv->drag_column)
3365         gtk_tree_view_move_column_after (tree_view, tree_view->priv->drag_column,
3366                                          tree_view->priv->cur_reorder->right_column);
3367     }
3368   else
3369     {
3370       if (tree_view->priv->cur_reorder &&
3371           tree_view->priv->cur_reorder->left_column != tree_view->priv->drag_column)
3372         gtk_tree_view_move_column_after (tree_view, tree_view->priv->drag_column,
3373                                          tree_view->priv->cur_reorder->left_column);
3374     }
3375   tree_view->priv->drag_column = NULL;
3376   gdk_window_hide (tree_view->priv->drag_window);
3377
3378   for (l = tree_view->priv->column_drag_info; l != NULL; l = l->next)
3379     g_slice_free (GtkTreeViewColumnReorder, l->data);
3380   g_list_free (tree_view->priv->column_drag_info);
3381   tree_view->priv->column_drag_info = NULL;
3382   tree_view->priv->cur_reorder = NULL;
3383
3384   if (tree_view->priv->drag_highlight_window)
3385     gdk_window_hide (tree_view->priv->drag_highlight_window);
3386
3387   /* Reset our flags */
3388   tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_UNSET;
3389   tree_view->priv->in_column_drag = FALSE;
3390
3391   return TRUE;
3392 }
3393
3394 /* GtkWidget::button_release_event helper */
3395 static gboolean
3396 gtk_tree_view_button_release_column_resize (GtkWidget      *widget,
3397                                             GdkEventButton *event)
3398 {
3399   GtkTreeView *tree_view;
3400   gpointer drag_data;
3401
3402   tree_view = GTK_TREE_VIEW (widget);
3403
3404   tree_view->priv->drag_pos = -1;
3405
3406   /* unblock attached dnd signal handler */
3407   drag_data = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
3408   if (drag_data)
3409     g_signal_handlers_unblock_matched (widget,
3410                                        G_SIGNAL_MATCH_DATA,
3411                                        0, 0, NULL, NULL,
3412                                        drag_data);
3413
3414   tree_view->priv->in_column_resize = FALSE;
3415   gtk_grab_remove (widget);
3416   gdk_device_ungrab (gdk_event_get_device ((GdkEvent*)event), event->time);
3417   return TRUE;
3418 }
3419
3420 static gboolean
3421 gtk_tree_view_button_release (GtkWidget      *widget,
3422                               GdkEventButton *event)
3423 {
3424   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
3425
3426   if (tree_view->priv->in_column_drag)
3427     return gtk_tree_view_button_release_drag_column (widget, event);
3428
3429   if (tree_view->priv->rubber_band_status)
3430     gtk_tree_view_stop_rubber_band (tree_view);
3431
3432   if (tree_view->priv->pressed_button == event->button)
3433     tree_view->priv->pressed_button = -1;
3434
3435   if (tree_view->priv->in_column_resize)
3436     return gtk_tree_view_button_release_column_resize (widget, event);
3437
3438   if (tree_view->priv->button_pressed_node == NULL)
3439     return FALSE;
3440
3441   if (event->button == 1)
3442     {
3443       if (tree_view->priv->button_pressed_node == tree_view->priv->prelight_node &&
3444           tree_view->priv->arrow_prelit)
3445         {
3446           GtkTreePath *path = NULL;
3447
3448           path = _gtk_tree_view_find_path (tree_view,
3449                                            tree_view->priv->button_pressed_tree,
3450                                            tree_view->priv->button_pressed_node);
3451           /* Actually activate the node */
3452           if (tree_view->priv->button_pressed_node->children == NULL)
3453             gtk_tree_view_real_expand_row (tree_view, path,
3454                                            tree_view->priv->button_pressed_tree,
3455                                            tree_view->priv->button_pressed_node,
3456                                            FALSE, TRUE);
3457           else
3458             gtk_tree_view_real_collapse_row (GTK_TREE_VIEW (widget), path,
3459                                              tree_view->priv->button_pressed_tree,
3460                                              tree_view->priv->button_pressed_node, TRUE);
3461           gtk_tree_path_free (path);
3462         }
3463
3464       gtk_grab_remove (widget);
3465       tree_view->priv->button_pressed_tree = NULL;
3466       tree_view->priv->button_pressed_node = NULL;
3467     }
3468
3469   return TRUE;
3470 }
3471
3472 static gboolean
3473 gtk_tree_view_grab_broken (GtkWidget          *widget,
3474                            GdkEventGrabBroken *event)
3475 {
3476   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
3477
3478   if (tree_view->priv->in_column_drag)
3479     gtk_tree_view_button_release_drag_column (widget, (GdkEventButton *)event);
3480
3481   if (tree_view->priv->in_column_resize)
3482     gtk_tree_view_button_release_column_resize (widget, (GdkEventButton *)event);
3483
3484   return TRUE;
3485 }
3486
3487 #if 0
3488 static gboolean
3489 gtk_tree_view_configure (GtkWidget *widget,
3490                          GdkEventConfigure *event)
3491 {
3492   GtkTreeView *tree_view;
3493
3494   tree_view = GTK_TREE_VIEW (widget);
3495   tree_view->priv->search_position_func (tree_view, tree_view->priv->search_window);
3496
3497   return FALSE;
3498 }
3499 #endif
3500
3501 /* GtkWidget::motion_event function set.
3502  */
3503
3504 static gboolean
3505 coords_are_over_arrow (GtkTreeView *tree_view,
3506                        GtkRBTree   *tree,
3507                        GtkRBNode   *node,
3508                        /* these are in bin window coords */
3509                        gint         x,
3510                        gint         y)
3511 {
3512   GdkRectangle arrow;
3513   gint x2;
3514
3515   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
3516     return FALSE;
3517
3518   if ((node->flags & GTK_RBNODE_IS_PARENT) == 0)
3519     return FALSE;
3520
3521   arrow.y = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
3522   arrow.height = gtk_tree_view_get_row_height (tree_view, node);
3523
3524   gtk_tree_view_get_arrow_xrange (tree_view, tree, &arrow.x, &x2);
3525
3526   arrow.width = x2 - arrow.x;
3527
3528   return (x >= arrow.x &&
3529           x < (arrow.x + arrow.width) &&
3530           y >= arrow.y &&
3531           y < (arrow.y + arrow.height));
3532 }
3533
3534 static gboolean
3535 auto_expand_timeout (gpointer data)
3536 {
3537   GtkTreeView *tree_view = GTK_TREE_VIEW (data);
3538   GtkTreePath *path;
3539
3540   if (tree_view->priv->prelight_node)
3541     {
3542       path = _gtk_tree_view_find_path (tree_view,
3543                                        tree_view->priv->prelight_tree,
3544                                        tree_view->priv->prelight_node);   
3545
3546       if (tree_view->priv->prelight_node->children)
3547         gtk_tree_view_collapse_row (tree_view, path);
3548       else
3549         gtk_tree_view_expand_row (tree_view, path, FALSE);
3550
3551       gtk_tree_path_free (path);
3552     }
3553
3554   tree_view->priv->auto_expand_timeout = 0;
3555
3556   return FALSE;
3557 }
3558
3559 static void
3560 remove_auto_expand_timeout (GtkTreeView *tree_view)
3561 {
3562   if (tree_view->priv->auto_expand_timeout != 0)
3563     {
3564       g_source_remove (tree_view->priv->auto_expand_timeout);
3565       tree_view->priv->auto_expand_timeout = 0;
3566     }
3567 }
3568
3569 static void
3570 do_prelight (GtkTreeView *tree_view,
3571              GtkRBTree   *tree,
3572              GtkRBNode   *node,
3573              /* these are in bin_window coords */
3574              gint         x,
3575              gint         y)
3576 {
3577   if (tree_view->priv->prelight_tree == tree &&
3578       tree_view->priv->prelight_node == node)
3579     {
3580       /*  We are still on the same node,
3581           but we might need to take care of the arrow  */
3582
3583       if (tree && node && gtk_tree_view_draw_expanders (tree_view))
3584         {
3585           gboolean over_arrow;
3586
3587           over_arrow = coords_are_over_arrow (tree_view, tree, node, x, y);
3588
3589           if (over_arrow != tree_view->priv->arrow_prelit)
3590             {
3591               if (over_arrow)
3592                 tree_view->priv->arrow_prelit = TRUE;
3593               else
3594                 tree_view->priv->arrow_prelit = FALSE;
3595
3596               gtk_tree_view_queue_draw_arrow (tree_view, tree, node);
3597             }
3598         }
3599
3600       return;
3601     }
3602
3603   if (tree_view->priv->prelight_tree && tree_view->priv->prelight_node)
3604     {
3605       /*  Unprelight the old node and arrow  */
3606
3607       GTK_RBNODE_UNSET_FLAG (tree_view->priv->prelight_node,
3608                              GTK_RBNODE_IS_PRELIT);
3609
3610       if (tree_view->priv->arrow_prelit
3611           && gtk_tree_view_draw_expanders (tree_view))
3612         {
3613           tree_view->priv->arrow_prelit = FALSE;
3614           
3615           gtk_tree_view_queue_draw_arrow (tree_view,
3616                                           tree_view->priv->prelight_tree,
3617                                           tree_view->priv->prelight_node);
3618         }
3619
3620       _gtk_tree_view_queue_draw_node (tree_view,
3621                                       tree_view->priv->prelight_tree,
3622                                       tree_view->priv->prelight_node,
3623                                       NULL);
3624     }
3625
3626
3627   if (tree_view->priv->hover_expand)
3628     remove_auto_expand_timeout (tree_view);
3629
3630   /*  Set the new prelight values  */
3631   tree_view->priv->prelight_node = node;
3632   tree_view->priv->prelight_tree = tree;
3633
3634   if (!node || !tree)
3635     return;
3636
3637   /*  Prelight the new node and arrow  */
3638
3639   if (gtk_tree_view_draw_expanders (tree_view)
3640       && coords_are_over_arrow (tree_view, tree, node, x, y))
3641     {
3642       tree_view->priv->arrow_prelit = TRUE;
3643
3644       gtk_tree_view_queue_draw_arrow (tree_view, tree, node);
3645     }
3646
3647   GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_PRELIT);
3648
3649   _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
3650
3651   if (tree_view->priv->hover_expand)
3652     {
3653       tree_view->priv->auto_expand_timeout = 
3654         gdk_threads_add_timeout (AUTO_EXPAND_TIMEOUT, auto_expand_timeout, tree_view);
3655     }
3656 }
3657
3658 static void
3659 prelight_or_select (GtkTreeView *tree_view,
3660                     GtkRBTree   *tree,
3661                     GtkRBNode   *node,
3662                     /* these are in bin_window coords */
3663                     gint         x,
3664                     gint         y)
3665 {
3666   GtkSelectionMode mode = gtk_tree_selection_get_mode (tree_view->priv->selection);
3667   
3668   if (tree_view->priv->hover_selection &&
3669       (mode == GTK_SELECTION_SINGLE || mode == GTK_SELECTION_BROWSE) &&
3670       !(tree_view->priv->edited_column &&
3671         gtk_cell_area_get_edit_widget 
3672         (gtk_cell_layout_get_area (GTK_CELL_LAYOUT (tree_view->priv->edited_column)))))
3673     {
3674       if (node)
3675         {
3676           if (!GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
3677             {
3678               GtkTreePath *path;
3679               
3680               path = _gtk_tree_view_find_path (tree_view, tree, node);
3681               gtk_tree_selection_select_path (tree_view->priv->selection, path);
3682               if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
3683                 {
3684                   tree_view->priv->draw_keyfocus = FALSE;
3685                   gtk_tree_view_real_set_cursor (tree_view, path, FALSE, FALSE);
3686                 }
3687               gtk_tree_path_free (path);
3688             }
3689         }
3690
3691       else if (mode == GTK_SELECTION_SINGLE)
3692         gtk_tree_selection_unselect_all (tree_view->priv->selection);
3693     }
3694
3695     do_prelight (tree_view, tree, node, x, y);
3696 }
3697
3698 static void
3699 ensure_unprelighted (GtkTreeView *tree_view)
3700 {
3701   do_prelight (tree_view,
3702                NULL, NULL,
3703                -1000, -1000); /* coords not possibly over an arrow */
3704
3705   g_assert (tree_view->priv->prelight_node == NULL);
3706 }
3707
3708 static void
3709 update_prelight (GtkTreeView *tree_view,
3710                  gint         x,
3711                  gint         y)
3712 {
3713   int new_y;
3714   GtkRBTree *tree;
3715   GtkRBNode *node;
3716
3717   if (tree_view->priv->tree == NULL)
3718     return;
3719
3720   if (x == -10000)
3721     {
3722       ensure_unprelighted (tree_view);
3723       return;
3724     }
3725
3726   new_y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, y);
3727   if (new_y < 0)
3728     new_y = 0;
3729
3730   _gtk_rbtree_find_offset (tree_view->priv->tree,
3731                            new_y, &tree, &node);
3732
3733   if (node)
3734     prelight_or_select (tree_view, tree, node, x, y);
3735 }
3736
3737
3738
3739
3740 /* Our motion arrow is either a box (in the case of the original spot)
3741  * or an arrow.  It is expander_size wide.
3742  */
3743 /*
3744  * 11111111111111
3745  * 01111111111110
3746  * 00111111111100
3747  * 00011111111000
3748  * 00001111110000
3749  * 00000111100000
3750  * 00000111100000
3751  * 00000111100000
3752  * ~ ~ ~ ~ ~ ~ ~
3753  * 00000111100000
3754  * 00000111100000
3755  * 00000111100000
3756  * 00001111110000
3757  * 00011111111000
3758  * 00111111111100
3759  * 01111111111110
3760  * 11111111111111
3761  */
3762
3763 static void
3764 gtk_tree_view_motion_draw_column_motion_arrow (GtkTreeView *tree_view)
3765 {
3766   GtkTreeViewColumnReorder *reorder = tree_view->priv->cur_reorder;
3767   GtkWidget *widget = GTK_WIDGET (tree_view);
3768   cairo_surface_t *mask_image;
3769   cairo_region_t *mask_region;
3770   gint x;
3771   gint y;
3772   gint width;
3773   gint height;
3774   gint arrow_type = DRAG_COLUMN_WINDOW_STATE_UNSET;
3775   GdkWindowAttr attributes;
3776   guint attributes_mask;
3777   cairo_t *cr;
3778
3779   if (!reorder ||
3780       reorder->left_column == tree_view->priv->drag_column ||
3781       reorder->right_column == tree_view->priv->drag_column)
3782     arrow_type = DRAG_COLUMN_WINDOW_STATE_ORIGINAL;
3783   else if (reorder->left_column || reorder->right_column)
3784     {
3785       GtkAllocation left_allocation, right_allocation;
3786       GdkRectangle visible_rect;
3787       GtkWidget *button;
3788
3789       gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
3790       if (reorder->left_column)
3791         {
3792           button = gtk_tree_view_column_get_button (reorder->left_column);
3793           gtk_widget_get_allocation (button, &left_allocation);
3794           x = left_allocation.x + left_allocation.width;
3795         }
3796       else
3797         {
3798           button = gtk_tree_view_column_get_button (reorder->right_column);
3799           gtk_widget_get_allocation (button, &right_allocation);
3800           x = right_allocation.x;
3801         }
3802
3803       if (x < visible_rect.x)
3804         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT;
3805       else if (x > visible_rect.x + visible_rect.width)
3806         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT;
3807       else
3808         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW;
3809     }
3810
3811   /* We want to draw the rectangle over the initial location. */
3812   if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ORIGINAL)
3813     {
3814       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ORIGINAL)
3815         {
3816           GtkAllocation drag_allocation;
3817           GtkWidget    *button;
3818
3819           if (tree_view->priv->drag_highlight_window)
3820             {
3821               gdk_window_set_user_data (tree_view->priv->drag_highlight_window,
3822                                         NULL);
3823               gdk_window_destroy (tree_view->priv->drag_highlight_window);
3824             }
3825
3826           button = gtk_tree_view_column_get_button (tree_view->priv->drag_column);
3827           attributes.window_type = GDK_WINDOW_CHILD;
3828           attributes.wclass = GDK_INPUT_OUTPUT;
3829           attributes.x = tree_view->priv->drag_column_x;
3830           attributes.y = 0;
3831           gtk_widget_get_allocation (button, &drag_allocation);
3832           width = attributes.width = drag_allocation.width;
3833           height = attributes.height = drag_allocation.height;
3834           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
3835           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3836           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
3837           tree_view->priv->drag_highlight_window = gdk_window_new (tree_view->priv->header_window, &attributes, attributes_mask);
3838           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
3839
3840           mask_image = cairo_image_surface_create (CAIRO_FORMAT_A1, width, height);
3841           cr = cairo_create (mask_image);
3842
3843           cairo_rectangle (cr, 1, 1, width - 2, height - 2);
3844           cairo_stroke (cr);
3845           cairo_destroy (cr);
3846
3847           mask_region = gdk_cairo_region_create_from_surface (mask_image);
3848           gdk_window_shape_combine_region (tree_view->priv->drag_highlight_window,
3849                                            mask_region, 0, 0);
3850
3851           cairo_region_destroy (mask_region);
3852           cairo_surface_destroy (mask_image);
3853
3854           tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_ORIGINAL;
3855         }
3856     }
3857   else if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW)
3858     {
3859       GtkAllocation button_allocation;
3860       GtkWidget    *button;
3861
3862       width = tree_view->priv->expander_size;
3863
3864       /* Get x, y, width, height of arrow */
3865       gdk_window_get_origin (tree_view->priv->header_window, &x, &y);
3866       if (reorder->left_column)
3867         {
3868           button = gtk_tree_view_column_get_button (reorder->left_column);
3869           gtk_widget_get_allocation (button, &button_allocation);
3870           x += button_allocation.x + button_allocation.width - width/2;
3871           height = button_allocation.height;
3872         }
3873       else
3874         {
3875           button = gtk_tree_view_column_get_button (reorder->right_column);
3876           gtk_widget_get_allocation (button, &button_allocation);
3877           x += button_allocation.x - width/2;
3878           height = button_allocation.height;
3879         }
3880       y -= tree_view->priv->expander_size/2; /* The arrow takes up only half the space */
3881       height += tree_view->priv->expander_size;
3882
3883       /* Create the new window */
3884       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW)
3885         {
3886           if (tree_view->priv->drag_highlight_window)
3887             {
3888               gdk_window_set_user_data (tree_view->priv->drag_highlight_window,
3889                                         NULL);
3890               gdk_window_destroy (tree_view->priv->drag_highlight_window);
3891             }
3892
3893           attributes.window_type = GDK_WINDOW_TEMP;
3894           attributes.wclass = GDK_INPUT_OUTPUT;
3895           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
3896           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3897           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
3898           attributes.x = x;
3899           attributes.y = y;
3900           attributes.width = width;
3901           attributes.height = height;
3902           tree_view->priv->drag_highlight_window = gdk_window_new (gtk_widget_get_root_window (widget),
3903                                                                    &attributes, attributes_mask);
3904           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
3905
3906           mask_image = cairo_image_surface_create (CAIRO_FORMAT_A1, width, height);
3907
3908           cr = cairo_create (mask_image);
3909           cairo_move_to (cr, 0, 0);
3910           cairo_line_to (cr, width, 0);
3911           cairo_line_to (cr, width / 2., width / 2);
3912           cairo_move_to (cr, 0, height);
3913           cairo_line_to (cr, width, height);
3914           cairo_line_to (cr, width / 2., height - width / 2.);
3915           cairo_fill (cr);
3916           cairo_destroy (cr);
3917
3918           mask_region = gdk_cairo_region_create_from_surface (mask_image);
3919           gdk_window_shape_combine_region (tree_view->priv->drag_highlight_window,
3920                                            mask_region, 0, 0);
3921
3922           cairo_region_destroy (mask_region);
3923           cairo_surface_destroy (mask_image);
3924         }
3925
3926       tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_ARROW;
3927       gdk_window_move (tree_view->priv->drag_highlight_window, x, y);
3928     }
3929   else if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT ||
3930            arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
3931     {
3932       GtkAllocation allocation;
3933       GtkWidget    *button;
3934
3935       width = tree_view->priv->expander_size;
3936
3937       /* Get x, y, width, height of arrow */
3938       width = width/2; /* remember, the arrow only takes half the available width */
3939       gdk_window_get_origin (gtk_widget_get_window (widget),
3940                              &x, &y);
3941       if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
3942         {
3943           gtk_widget_get_allocation (widget, &allocation);
3944           x += allocation.width - width;
3945         }
3946
3947       if (reorder->left_column)
3948         {
3949           button = gtk_tree_view_column_get_button (reorder->left_column);
3950           gtk_widget_get_allocation (button, &allocation);
3951           height = allocation.height;
3952         }
3953       else
3954         {
3955           button = gtk_tree_view_column_get_button (reorder->right_column);
3956           gtk_widget_get_allocation (button, &allocation);
3957           height = allocation.height;
3958         }
3959
3960       y -= tree_view->priv->expander_size;
3961       height += 2*tree_view->priv->expander_size;
3962
3963       /* Create the new window */
3964       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT &&
3965           tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
3966         {
3967           if (tree_view->priv->drag_highlight_window)
3968             {
3969               gdk_window_set_user_data (tree_view->priv->drag_highlight_window,
3970                                         NULL);
3971               gdk_window_destroy (tree_view->priv->drag_highlight_window);
3972             }
3973
3974           attributes.window_type = GDK_WINDOW_TEMP;
3975           attributes.wclass = GDK_INPUT_OUTPUT;
3976           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
3977           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3978           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
3979           attributes.x = x;
3980           attributes.y = y;
3981           attributes.width = width;
3982           attributes.height = height;
3983           tree_view->priv->drag_highlight_window = gdk_window_new (NULL, &attributes, attributes_mask);
3984           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
3985
3986           mask_image = cairo_image_surface_create (CAIRO_FORMAT_A1, width, height);
3987
3988           cr = cairo_create (mask_image);
3989           /* mirror if we're on the left */
3990           if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT)
3991             {
3992               cairo_translate (cr, width, 0);
3993               cairo_scale (cr, -1, 1);
3994             }
3995           cairo_move_to (cr, 0, 0);
3996           cairo_line_to (cr, width, width);
3997           cairo_line_to (cr, 0, tree_view->priv->expander_size);
3998           cairo_move_to (cr, 0, height);
3999           cairo_line_to (cr, width, height - width);
4000           cairo_line_to (cr, 0, height - tree_view->priv->expander_size);
4001           cairo_fill (cr);
4002           cairo_destroy (cr);
4003
4004           mask_region = gdk_cairo_region_create_from_surface (mask_image);
4005           gdk_window_shape_combine_region (tree_view->priv->drag_highlight_window,
4006                                            mask_region, 0, 0);
4007
4008           cairo_region_destroy (mask_region);
4009           cairo_surface_destroy (mask_image);
4010         }
4011
4012       tree_view->priv->drag_column_window_state = arrow_type;
4013       gdk_window_move (tree_view->priv->drag_highlight_window, x, y);
4014    }
4015   else
4016     {
4017       g_warning (G_STRLOC"Invalid GtkTreeViewColumnReorder struct");
4018       gdk_window_hide (tree_view->priv->drag_highlight_window);
4019       return;
4020     }
4021
4022   gdk_window_show (tree_view->priv->drag_highlight_window);
4023   gdk_window_raise (tree_view->priv->drag_highlight_window);
4024 }
4025
4026 static gboolean
4027 gtk_tree_view_motion_resize_column (GtkWidget      *widget,
4028                                     GdkEventMotion *event)
4029 {
4030   gint x;
4031   gint new_width;
4032   GtkTreeViewColumn *column;
4033   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
4034
4035   column = gtk_tree_view_get_column (tree_view, tree_view->priv->drag_pos);
4036
4037   if (event->is_hint || event->window != gtk_widget_get_window (widget))
4038     gtk_widget_get_pointer (widget, &x, NULL);
4039   else
4040     x = event->x;
4041
4042   if (tree_view->priv->hadjustment)
4043     x += gtk_adjustment_get_value (tree_view->priv->hadjustment);
4044
4045   new_width = gtk_tree_view_new_column_width (tree_view,
4046                                               tree_view->priv->drag_pos, &x);
4047   if (x != tree_view->priv->x_drag &&
4048       (new_width != gtk_tree_view_column_get_fixed_width (column)))
4049     {
4050       _gtk_tree_view_column_set_use_resized_width (column, TRUE);
4051
4052       if (gtk_tree_view_column_get_expand (column))
4053         new_width -= tree_view->priv->last_extra_space_per_column;
4054
4055       _gtk_tree_view_column_set_resized_width (column, new_width);
4056
4057
4058       gtk_widget_queue_resize (widget);
4059     }
4060
4061   return FALSE;
4062 }
4063
4064
4065 static void
4066 gtk_tree_view_update_current_reorder (GtkTreeView *tree_view)
4067 {
4068   GtkTreeViewColumnReorder *reorder = NULL;
4069   GList *list;
4070   gint mouse_x;
4071
4072   gdk_window_get_pointer (tree_view->priv->header_window, &mouse_x, NULL, NULL);
4073   for (list = tree_view->priv->column_drag_info; list; list = list->next)
4074     {
4075       reorder = (GtkTreeViewColumnReorder *) list->data;
4076       if (mouse_x >= reorder->left_align && mouse_x < reorder->right_align)
4077         break;
4078       reorder = NULL;
4079     }
4080
4081   /*  if (reorder && reorder == tree_view->priv->cur_reorder)
4082       return;*/
4083
4084   tree_view->priv->cur_reorder = reorder;
4085   gtk_tree_view_motion_draw_column_motion_arrow (tree_view);
4086 }
4087
4088 static void
4089 gtk_tree_view_vertical_autoscroll (GtkTreeView *tree_view)
4090 {
4091   GdkRectangle visible_rect;
4092   gint y;
4093   gint offset;
4094
4095   gdk_window_get_pointer (tree_view->priv->bin_window, NULL, &y, NULL);
4096   y += tree_view->priv->dy;
4097
4098   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
4099
4100   /* see if we are near the edge. */
4101   offset = y - (visible_rect.y + 2 * SCROLL_EDGE_SIZE);
4102   if (offset > 0)
4103     {
4104       offset = y - (visible_rect.y + visible_rect.height - 2 * SCROLL_EDGE_SIZE);
4105       if (offset < 0)
4106         return;
4107     }
4108
4109   gtk_adjustment_set_value (tree_view->priv->vadjustment,
4110                             MAX (gtk_adjustment_get_value (tree_view->priv->vadjustment) + offset, 0.0));
4111 }
4112
4113 static gboolean
4114 gtk_tree_view_horizontal_autoscroll (GtkTreeView *tree_view)
4115 {
4116   GdkRectangle visible_rect;
4117   gint x;
4118   gint offset;
4119
4120   gdk_window_get_pointer (tree_view->priv->bin_window, &x, NULL, NULL);
4121
4122   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
4123
4124   /* See if we are near the edge. */
4125   offset = x - (visible_rect.x + SCROLL_EDGE_SIZE);
4126   if (offset > 0)
4127     {
4128       offset = x - (visible_rect.x + visible_rect.width - SCROLL_EDGE_SIZE);
4129       if (offset < 0)
4130         return TRUE;
4131     }
4132   offset = offset/3;
4133
4134   gtk_adjustment_set_value (tree_view->priv->hadjustment,
4135                             MAX (gtk_adjustment_get_value (tree_view->priv->hadjustment) + offset, 0.0));
4136
4137   return TRUE;
4138
4139 }
4140
4141 static gboolean
4142 gtk_tree_view_motion_drag_column (GtkWidget      *widget,
4143                                   GdkEventMotion *event)
4144 {
4145   GtkAllocation allocation, button_allocation;
4146   GtkTreeView *tree_view = (GtkTreeView *) widget;
4147   GtkTreeViewColumn *column = tree_view->priv->drag_column;
4148   GtkWidget *button;
4149   gint x, y;
4150
4151   /* Sanity Check */
4152   if ((column == NULL) ||
4153       (event->window != tree_view->priv->drag_window))
4154     return FALSE;
4155
4156   button = gtk_tree_view_column_get_button (column);
4157
4158   /* Handle moving the header */
4159   gdk_window_get_position (tree_view->priv->drag_window, &x, &y);
4160   gtk_widget_get_allocation (widget, &allocation);
4161   gtk_widget_get_allocation (button, &button_allocation);
4162   x = CLAMP (x + (gint)event->x - _gtk_tree_view_column_get_drag_x (column), 0,
4163              MAX (tree_view->priv->width, allocation.width) - button_allocation.width);
4164   gdk_window_move (tree_view->priv->drag_window, x, y);
4165   
4166   /* autoscroll, if needed */
4167   gtk_tree_view_horizontal_autoscroll (tree_view);
4168   /* Update the current reorder position and arrow; */
4169   gtk_tree_view_update_current_reorder (tree_view);
4170
4171   return TRUE;
4172 }
4173
4174 static void
4175 gtk_tree_view_stop_rubber_band (GtkTreeView *tree_view)
4176 {
4177   remove_scroll_timeout (tree_view);
4178   gtk_grab_remove (GTK_WIDGET (tree_view));
4179
4180   if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
4181     {
4182       GtkTreePath *tmp_path;
4183
4184       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
4185
4186       /* The anchor path should be set to the start path */
4187       tmp_path = _gtk_tree_view_find_path (tree_view,
4188                                            tree_view->priv->rubber_band_start_tree,
4189                                            tree_view->priv->rubber_band_start_node);
4190
4191       if (tree_view->priv->anchor)
4192         gtk_tree_row_reference_free (tree_view->priv->anchor);
4193
4194       tree_view->priv->anchor =
4195         gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
4196                                           tree_view->priv->model,
4197                                           tmp_path);
4198
4199       gtk_tree_path_free (tmp_path);
4200
4201       /* ... and the cursor to the end path */
4202       tmp_path = _gtk_tree_view_find_path (tree_view,
4203                                            tree_view->priv->rubber_band_end_tree,
4204                                            tree_view->priv->rubber_band_end_node);
4205       gtk_tree_view_real_set_cursor (GTK_TREE_VIEW (tree_view), tmp_path, FALSE, FALSE);
4206       gtk_tree_path_free (tmp_path);
4207
4208       _gtk_tree_selection_emit_changed (tree_view->priv->selection);
4209     }
4210
4211   /* Clear status variables */
4212   tree_view->priv->rubber_band_status = RUBBER_BAND_OFF;
4213   tree_view->priv->rubber_band_shift = 0;
4214   tree_view->priv->rubber_band_ctrl = 0;
4215
4216   tree_view->priv->rubber_band_start_node = NULL;
4217   tree_view->priv->rubber_band_start_tree = NULL;
4218   tree_view->priv->rubber_band_end_node = NULL;
4219   tree_view->priv->rubber_band_end_tree = NULL;
4220 }
4221
4222 static void
4223 gtk_tree_view_update_rubber_band_selection_range (GtkTreeView *tree_view,
4224                                                  GtkRBTree   *start_tree,
4225                                                  GtkRBNode   *start_node,
4226                                                  GtkRBTree   *end_tree,
4227                                                  GtkRBNode   *end_node,
4228                                                  gboolean     select,
4229                                                  gboolean     skip_start,
4230                                                  gboolean     skip_end)
4231 {
4232   if (start_node == end_node)
4233     return;
4234
4235   /* We skip the first node and jump inside the loop */
4236   if (skip_start)
4237     goto skip_first;
4238
4239   do
4240     {
4241       /* Small optimization by assuming insensitive nodes are never
4242        * selected.
4243        */
4244       if (!GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
4245         {
4246           GtkTreePath *path;
4247           gboolean selectable;
4248
4249           path = _gtk_tree_view_find_path (tree_view, start_tree, start_node);
4250           selectable = _gtk_tree_selection_row_is_selectable (tree_view->priv->selection, start_node, path);
4251           gtk_tree_path_free (path);
4252
4253           if (!selectable)
4254             goto node_not_selectable;
4255         }
4256
4257       if (select)
4258         {
4259           if (tree_view->priv->rubber_band_shift)
4260             GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4261           else if (tree_view->priv->rubber_band_ctrl)
4262             {
4263               /* Toggle the selection state */
4264               if (GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
4265                 GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4266               else
4267                 GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4268             }
4269           else
4270             GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4271         }
4272       else
4273         {
4274           /* Mirror the above */
4275           if (tree_view->priv->rubber_band_shift)
4276             GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4277           else if (tree_view->priv->rubber_band_ctrl)
4278             {
4279               /* Toggle the selection state */
4280               if (GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
4281                 GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4282               else
4283                 GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4284             }
4285           else
4286             GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4287         }
4288
4289       _gtk_tree_view_queue_draw_node (tree_view, start_tree, start_node, NULL);
4290
4291 node_not_selectable:
4292       if (start_node == end_node)
4293         break;
4294
4295 skip_first:
4296
4297       if (start_node->children)
4298         {
4299           start_tree = start_node->children;
4300           start_node = start_tree->root;
4301           while (start_node->left != start_tree->nil)
4302             start_node = start_node->left;
4303         }
4304       else
4305         {
4306           _gtk_rbtree_next_full (start_tree, start_node, &start_tree, &start_node);
4307
4308           if (!start_tree)
4309             /* Ran out of tree */
4310             break;
4311         }
4312
4313       if (skip_end && start_node == end_node)
4314         break;
4315     }
4316   while (TRUE);
4317 }
4318
4319 static void
4320 gtk_tree_view_update_rubber_band_selection (GtkTreeView *tree_view)
4321 {
4322   GtkRBTree *start_tree, *end_tree;
4323   GtkRBNode *start_node, *end_node;
4324
4325   _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);
4326   _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);
4327
4328   /* Handle the start area first */
4329   if (!tree_view->priv->rubber_band_start_node)
4330     {
4331       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4332                                                        start_tree,
4333                                                        start_node,
4334                                                        end_tree,
4335                                                        end_node,
4336                                                        TRUE,
4337                                                        FALSE,
4338                                                        FALSE);
4339     }
4340   else if (_gtk_rbtree_node_find_offset (start_tree, start_node) <
4341            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_start_tree, tree_view->priv->rubber_band_start_node))
4342     {
4343       /* New node is above the old one; selection became bigger */
4344       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4345                                                        start_tree,
4346                                                        start_node,
4347                                                        tree_view->priv->rubber_band_start_tree,
4348                                                        tree_view->priv->rubber_band_start_node,
4349                                                        TRUE,
4350                                                        FALSE,
4351                                                        TRUE);
4352     }
4353   else if (_gtk_rbtree_node_find_offset (start_tree, start_node) >
4354            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_start_tree, tree_view->priv->rubber_band_start_node))
4355     {
4356       /* New node is below the old one; selection became smaller */
4357       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4358                                                        tree_view->priv->rubber_band_start_tree,
4359                                                        tree_view->priv->rubber_band_start_node,
4360                                                        start_tree,
4361                                                        start_node,
4362                                                        FALSE,
4363                                                        FALSE,
4364                                                        TRUE);
4365     }
4366
4367   tree_view->priv->rubber_band_start_tree = start_tree;
4368   tree_view->priv->rubber_band_start_node = start_node;
4369
4370   /* Next, handle the end area */
4371   if (!tree_view->priv->rubber_band_end_node)
4372     {
4373       /* In the event this happens, start_node was also NULL; this case is
4374        * handled above.
4375        */
4376     }
4377   else if (!end_node)
4378     {
4379       /* Find the last node in the tree */
4380       _gtk_rbtree_find_offset (tree_view->priv->tree, tree_view->priv->height - 1,
4381                                &end_tree, &end_node);
4382
4383       /* Selection reached end of the tree */
4384       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4385                                                        tree_view->priv->rubber_band_end_tree,
4386                                                        tree_view->priv->rubber_band_end_node,
4387                                                        end_tree,
4388                                                        end_node,
4389                                                        TRUE,
4390                                                        TRUE,
4391                                                        FALSE);
4392     }
4393   else if (_gtk_rbtree_node_find_offset (end_tree, end_node) >
4394            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_end_tree, tree_view->priv->rubber_band_end_node))
4395     {
4396       /* New node is below the old one; selection became bigger */
4397       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4398                                                        tree_view->priv->rubber_band_end_tree,
4399                                                        tree_view->priv->rubber_band_end_node,
4400                                                        end_tree,
4401                                                        end_node,
4402                                                        TRUE,
4403                                                        TRUE,
4404                                                        FALSE);
4405     }
4406   else if (_gtk_rbtree_node_find_offset (end_tree, end_node) <
4407            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_end_tree, tree_view->priv->rubber_band_end_node))
4408     {
4409       /* New node is above the old one; selection became smaller */
4410       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4411                                                        end_tree,
4412                                                        end_node,
4413                                                        tree_view->priv->rubber_band_end_tree,
4414                                                        tree_view->priv->rubber_band_end_node,
4415                                                        FALSE,
4416                                                        TRUE,
4417                                                        FALSE);
4418     }
4419
4420   tree_view->priv->rubber_band_end_tree = end_tree;
4421   tree_view->priv->rubber_band_end_node = end_node;
4422 }
4423
4424 static void
4425 gtk_tree_view_update_rubber_band (GtkTreeView *tree_view)
4426 {
4427   gint x, y;
4428   GdkRectangle old_area;
4429   GdkRectangle new_area;
4430   GdkRectangle common;
4431   cairo_region_t *invalid_region;
4432
4433   old_area.x = MIN (tree_view->priv->press_start_x, tree_view->priv->rubber_band_x);
4434   old_area.y = MIN (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y) - tree_view->priv->dy;
4435   old_area.width = ABS (tree_view->priv->rubber_band_x - tree_view->priv->press_start_x) + 1;
4436   old_area.height = ABS (tree_view->priv->rubber_band_y - tree_view->priv->press_start_y) + 1;
4437
4438   gdk_window_get_pointer (tree_view->priv->bin_window, &x, &y, NULL);
4439
4440   x = MAX (x, 0);
4441   y = MAX (y, 0) + tree_view->priv->dy;
4442
4443   new_area.x = MIN (tree_view->priv->press_start_x, x);
4444   new_area.y = MIN (tree_view->priv->press_start_y, y) - tree_view->priv->dy;
4445   new_area.width = ABS (x - tree_view->priv->press_start_x) + 1;
4446   new_area.height = ABS (y - tree_view->priv->press_start_y) + 1;
4447
4448   invalid_region = cairo_region_create_rectangle (&old_area);
4449   cairo_region_union_rectangle (invalid_region, &new_area);
4450
4451   gdk_rectangle_intersect (&old_area, &new_area, &common);
4452   if (common.width > 2 && common.height > 2)
4453     {
4454       cairo_region_t *common_region;
4455
4456       /* make sure the border is invalidated */
4457       common.x += 1;
4458       common.y += 1;
4459       common.width -= 2;
4460       common.height -= 2;
4461
4462       common_region = cairo_region_create_rectangle (&common);
4463
4464       cairo_region_subtract (invalid_region, common_region);
4465       cairo_region_destroy (common_region);
4466     }
4467
4468   gdk_window_invalidate_region (tree_view->priv->bin_window, invalid_region, TRUE);
4469
4470   cairo_region_destroy (invalid_region);
4471
4472   tree_view->priv->rubber_band_x = x;
4473   tree_view->priv->rubber_band_y = y;
4474
4475   gtk_tree_view_update_rubber_band_selection (tree_view);
4476 }
4477
4478 static void
4479 gtk_tree_view_paint_rubber_band (GtkTreeView  *tree_view,
4480                                  cairo_t      *cr)
4481 {
4482   GdkRectangle rect;
4483   GtkStyleContext *context;
4484
4485   cairo_save (cr);
4486
4487   context = gtk_widget_get_style_context (GTK_WIDGET (tree_view));
4488
4489   gtk_style_context_save (context);
4490   gtk_style_context_add_class (context, GTK_STYLE_CLASS_RUBBERBAND);
4491
4492   rect.x = MIN (tree_view->priv->press_start_x, tree_view->priv->rubber_band_x);
4493   rect.y = MIN (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y) - tree_view->priv->dy;
4494   rect.width = ABS (tree_view->priv->press_start_x - tree_view->priv->rubber_band_x) + 1;
4495   rect.height = ABS (tree_view->priv->press_start_y - tree_view->priv->rubber_band_y) + 1;
4496
4497   gdk_cairo_rectangle (cr, &rect);
4498   cairo_clip (cr);
4499
4500   gtk_render_background (context, cr,
4501                          rect.x, rect.y,
4502                          rect.width, rect.height);
4503   gtk_render_frame (context, cr,
4504                     rect.x, rect.y,
4505                     rect.width, rect.height);
4506
4507   gtk_style_context_restore (context);
4508   cairo_restore (cr);
4509 }
4510
4511 static gboolean
4512 gtk_tree_view_motion_bin_window (GtkWidget      *widget,
4513                                  GdkEventMotion *event)
4514 {
4515   GtkTreeView *tree_view;
4516   GtkRBTree *tree;
4517   GtkRBNode *node;
4518   gint new_y;
4519
4520   tree_view = (GtkTreeView *) widget;
4521
4522   if (tree_view->priv->tree == NULL)
4523     return FALSE;
4524
4525   if (tree_view->priv->rubber_band_status == RUBBER_BAND_MAYBE_START)
4526     {
4527       gtk_grab_add (GTK_WIDGET (tree_view));
4528       gtk_tree_view_update_rubber_band (tree_view);
4529
4530       tree_view->priv->rubber_band_status = RUBBER_BAND_ACTIVE;
4531     }
4532   else if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
4533     {
4534       gtk_tree_view_update_rubber_band (tree_view);
4535
4536       add_scroll_timeout (tree_view);
4537     }
4538
4539   /* only check for an initiated drag when a button is pressed */
4540   if (tree_view->priv->pressed_button >= 0
4541       && !tree_view->priv->rubber_band_status)
4542     gtk_tree_view_maybe_begin_dragging_row (tree_view, event);
4543
4544   new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
4545   if (new_y < 0)
4546     new_y = 0;
4547
4548   _gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
4549
4550   /* If we are currently pressing down a button, we don't want to prelight anything else. */
4551   if ((tree_view->priv->button_pressed_node != NULL) &&
4552       (tree_view->priv->button_pressed_node != node))
4553     node = NULL;
4554
4555   tree_view->priv->event_last_x = event->x;
4556   tree_view->priv->event_last_y = event->y;
4557
4558   prelight_or_select (tree_view, tree, node, event->x, event->y);
4559
4560   return TRUE;
4561 }
4562
4563 static gboolean
4564 gtk_tree_view_motion (GtkWidget      *widget,
4565                       GdkEventMotion *event)
4566 {
4567   GtkTreeView *tree_view;
4568
4569   tree_view = (GtkTreeView *) widget;
4570
4571   /* Resizing a column */
4572   if (tree_view->priv->in_column_resize)
4573     return gtk_tree_view_motion_resize_column (widget, event);
4574
4575   /* Drag column */
4576   if (tree_view->priv->in_column_drag)
4577     return gtk_tree_view_motion_drag_column (widget, event);
4578
4579   /* Sanity check it */
4580   if (event->window == tree_view->priv->bin_window)
4581     return gtk_tree_view_motion_bin_window (widget, event);
4582
4583   return FALSE;
4584 }
4585
4586 /* Invalidate the focus rectangle near the edge of the bin_window; used when
4587  * the tree is empty.
4588  */
4589 static void
4590 invalidate_empty_focus (GtkTreeView *tree_view)
4591 {
4592   GdkRectangle area;
4593
4594   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
4595     return;
4596
4597   area.x = 0;
4598   area.y = 0;
4599   area.width = gdk_window_get_width (tree_view->priv->bin_window);
4600   area.height = gdk_window_get_height (tree_view->priv->bin_window);
4601   gdk_window_invalidate_rect (tree_view->priv->bin_window, &area, FALSE);
4602 }
4603
4604 /* Draws a focus rectangle near the edge of the bin_window; used when the tree
4605  * is empty.
4606  */
4607 static void
4608 draw_empty_focus (GtkTreeView *tree_view, cairo_t *cr)
4609 {
4610   GtkWidget *widget = GTK_WIDGET (tree_view);
4611   gint w, h;
4612
4613   if (!gtk_widget_has_focus (widget))
4614     return;
4615
4616   w = gdk_window_get_width (tree_view->priv->bin_window) - 2;
4617   h = gdk_window_get_height (tree_view->priv->bin_window) - 2;
4618
4619   if (w > 0 && h > 0)
4620     {
4621       GtkStyleContext *context;
4622       GtkStateFlags state;
4623
4624       context = gtk_widget_get_style_context (widget);
4625       state = gtk_widget_get_state_flags (widget);
4626
4627       gtk_style_context_save (context);
4628       gtk_style_context_set_state (context, state);
4629
4630       gtk_render_focus (context, cr, 1, 1, w, h);
4631
4632       gtk_style_context_restore (context);
4633     }
4634 }
4635
4636 typedef enum {
4637   GTK_TREE_VIEW_GRID_LINE,
4638   GTK_TREE_VIEW_TREE_LINE,
4639   GTK_TREE_VIEW_FOREGROUND_LINE
4640 } GtkTreeViewLineType;
4641
4642 static void
4643 gtk_tree_view_draw_line (GtkTreeView         *tree_view,
4644                          cairo_t             *cr,
4645                          GtkTreeViewLineType  type,
4646                          int                  x1,
4647                          int                  y1,
4648                          int                  x2,
4649                          int                  y2)
4650 {
4651   cairo_save (cr);
4652
4653   switch (type)
4654     {
4655     case GTK_TREE_VIEW_TREE_LINE:
4656       cairo_set_source_rgb (cr, 0, 0, 0);
4657       cairo_set_line_width (cr, tree_view->priv->tree_line_width);
4658       if (tree_view->priv->tree_line_dashes[0])
4659         cairo_set_dash (cr, 
4660                         tree_view->priv->tree_line_dashes,
4661                         2, 0.5);
4662       break;
4663     case GTK_TREE_VIEW_GRID_LINE:
4664       cairo_set_source_rgb (cr, 0, 0, 0);
4665       cairo_set_line_width (cr, tree_view->priv->grid_line_width);
4666       if (tree_view->priv->grid_line_dashes[0])
4667         cairo_set_dash (cr, 
4668                         tree_view->priv->grid_line_dashes,
4669                         2, 0.5);
4670       break;
4671     default:
4672       g_assert_not_reached ();
4673       /* fall through */
4674     case GTK_TREE_VIEW_FOREGROUND_LINE:
4675       {
4676         GtkStyleContext *context;
4677         GtkStateFlags state;
4678         GdkRGBA color;
4679
4680         context = gtk_widget_get_style_context (GTK_WIDGET (tree_view));
4681         state = gtk_widget_get_state_flags (GTK_WIDGET (tree_view));
4682
4683         cairo_set_line_width (cr, 1.0);
4684         gtk_style_context_get_color (context, state, &color);
4685         gdk_cairo_set_source_rgba (cr, &color);
4686       }
4687
4688       break;
4689     }
4690
4691   cairo_move_to (cr, x1 + 0.5, y1 + 0.5);
4692   cairo_line_to (cr, x2 + 0.5, y2 + 0.5);
4693   cairo_stroke (cr);
4694
4695   cairo_restore (cr);
4696 }
4697                          
4698 static void
4699 gtk_tree_view_draw_grid_lines (GtkTreeView    *tree_view,
4700                                cairo_t        *cr,
4701                                gint            n_visible_columns)
4702 {
4703   GList *list = tree_view->priv->columns;
4704   gint i = 0;
4705   gint current_x = 0;
4706
4707   if (tree_view->priv->grid_lines != GTK_TREE_VIEW_GRID_LINES_VERTICAL
4708       && tree_view->priv->grid_lines != GTK_TREE_VIEW_GRID_LINES_BOTH)
4709     return;
4710
4711   /* Only draw the lines for visible rows and columns */
4712   for (list = tree_view->priv->columns; list; list = list->next, i++)
4713     {
4714       GtkTreeViewColumn *column = list->data;
4715
4716       /* We don't want a line for the last column */
4717       if (i == n_visible_columns - 1)
4718         break;
4719
4720       if (!gtk_tree_view_column_get_visible (column))
4721         continue;
4722
4723       current_x += gtk_tree_view_column_get_width (column);
4724
4725       gtk_tree_view_draw_line (tree_view, cr,
4726                                GTK_TREE_VIEW_GRID_LINE,
4727                                current_x - 1, 0,
4728                                current_x - 1, tree_view->priv->height);
4729     }
4730 }
4731
4732 /* Warning: Very scary function.
4733  * Modify at your own risk
4734  *
4735  * KEEP IN SYNC WITH gtk_tree_view_create_row_drag_icon()!
4736  * FIXME: It's not...
4737  */
4738 static gboolean
4739 gtk_tree_view_bin_draw (GtkWidget      *widget,
4740                         cairo_t        *cr)
4741 {
4742   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
4743   GtkTreePath *path;
4744   GtkRBTree *tree;
4745   GList *list;
4746   GtkRBNode *node;
4747   GtkRBNode *cursor = NULL;
4748   GtkRBTree *cursor_tree = NULL;
4749   GtkRBNode *drag_highlight = NULL;
4750   GtkRBTree *drag_highlight_tree = NULL;
4751   GtkTreeIter iter;
4752   gint new_y;
4753   gint y_offset, cell_offset;
4754   gint max_height;
4755   gint depth;
4756   GdkRectangle background_area;
4757   GdkRectangle cell_area;
4758   GdkRectangle clip;
4759   guint flags;
4760   gint highlight_x;
4761   gint expander_cell_width;
4762   gint bin_window_width;
4763   gint bin_window_height;
4764   GtkTreePath *cursor_path;
4765   GtkTreePath *drag_dest_path;
4766   GList *first_column, *last_column;
4767   gint vertical_separator;
4768   gint horizontal_separator;
4769   gint focus_line_width;
4770   gboolean allow_rules;
4771   gboolean has_can_focus_cell;
4772   gboolean rtl;
4773   gint n_visible_columns;
4774   gint pointer_x, pointer_y;
4775   gint grid_line_width;
4776   gboolean got_pointer = FALSE;
4777   gboolean draw_vgrid_lines, draw_hgrid_lines;
4778   GtkStyleContext *context;
4779   GtkStateFlags state;
4780
4781   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
4782   context = gtk_widget_get_style_context (widget);
4783   state = gtk_widget_get_state_flags (widget);
4784
4785   gtk_widget_style_get (widget,
4786                         "horizontal-separator", &horizontal_separator,
4787                         "vertical-separator", &vertical_separator,
4788                         "allow-rules", &allow_rules,
4789                         "focus-line-width", &focus_line_width,
4790                         NULL);
4791
4792   if (tree_view->priv->tree == NULL)
4793     {
4794       draw_empty_focus (tree_view, cr);
4795       return TRUE;
4796     }
4797
4798   bin_window_width = gdk_window_get_width (tree_view->priv->bin_window);
4799   bin_window_height = gdk_window_get_height (tree_view->priv->bin_window);
4800   cairo_rectangle (cr, 0, 0, bin_window_width, bin_window_height);
4801   cairo_clip (cr);
4802   if (!gdk_cairo_get_clip_rectangle (cr, &clip))
4803     return TRUE;
4804
4805   new_y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, clip.y);
4806
4807   if (new_y < 0)
4808     new_y = 0;
4809   y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
4810
4811   if (tree_view->priv->height < bin_window_height)
4812     {
4813       gtk_style_context_save (context);
4814       gtk_style_context_set_state (context, state);
4815       gtk_style_context_add_class (context, GTK_STYLE_CLASS_CELL);
4816
4817       gtk_render_background (context, cr,
4818                              0, tree_view->priv->height,
4819                              bin_window_width,
4820                              bin_window_height - tree_view->priv->height);
4821
4822       gtk_style_context_restore (context);
4823     }
4824
4825   if (node == NULL)
4826     return TRUE;
4827
4828   /* find the path for the node */
4829   path = _gtk_tree_view_find_path ((GtkTreeView *)widget,
4830                                    tree,
4831                                    node);
4832   gtk_tree_model_get_iter (tree_view->priv->model,
4833                            &iter,
4834                            path);
4835   depth = gtk_tree_path_get_depth (path);
4836   gtk_tree_path_free (path);
4837   
4838   cursor_path = NULL;
4839   drag_dest_path = NULL;
4840
4841   if (tree_view->priv->cursor)
4842     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
4843
4844   if (cursor_path)
4845     _gtk_tree_view_find_node (tree_view, cursor_path,
4846                               &cursor_tree, &cursor);
4847
4848   if (tree_view->priv->drag_dest_row)
4849     drag_dest_path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
4850
4851   if (drag_dest_path)
4852     _gtk_tree_view_find_node (tree_view, drag_dest_path,
4853                               &drag_highlight_tree, &drag_highlight);
4854
4855   draw_vgrid_lines =
4856     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_VERTICAL
4857     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
4858   draw_hgrid_lines =
4859     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_HORIZONTAL
4860     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
4861
4862   if (draw_vgrid_lines || draw_hgrid_lines)
4863     gtk_widget_style_get (widget, "grid-line-width", &grid_line_width, NULL);
4864   
4865   n_visible_columns = 0;
4866   for (list = tree_view->priv->columns; list; list = list->next)
4867     {
4868       if (!gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (list->data)))
4869         continue;
4870       n_visible_columns ++;
4871     }
4872
4873   /* Find the last column */
4874   for (last_column = g_list_last (tree_view->priv->columns);
4875        last_column &&
4876        !(gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (last_column->data)));
4877        last_column = last_column->prev)
4878     ;
4879
4880   /* and the first */
4881   for (first_column = g_list_first (tree_view->priv->columns);
4882        first_column &&
4883        !(gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (first_column->data)));
4884        first_column = first_column->next)
4885     ;
4886
4887   /* Actually process the expose event.  To do this, we want to
4888    * start at the first node of the event, and walk the tree in
4889    * order, drawing each successive node.
4890    */
4891
4892   do
4893     {
4894       gboolean parity;
4895       gboolean is_separator = FALSE;
4896       gboolean is_first = FALSE;
4897       gboolean is_last = FALSE;
4898       gint n_col = 0;
4899
4900       is_separator = row_is_separator (tree_view, &iter, NULL);
4901
4902       max_height = gtk_tree_view_get_row_height (tree_view, node);
4903
4904       cell_offset = 0;
4905       highlight_x = 0; /* should match x coord of first cell */
4906       expander_cell_width = 0;
4907
4908       background_area.y = y_offset + clip.y;
4909       background_area.height = max_height;
4910
4911       flags = 0;
4912
4913       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PRELIT))
4914         flags |= GTK_CELL_RENDERER_PRELIT;
4915
4916       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
4917         flags |= GTK_CELL_RENDERER_SELECTED;
4918
4919       parity = _gtk_rbtree_node_find_parity (tree, node);
4920
4921       /* we *need* to set cell data on all cells before the call
4922        * to _has_can_focus_cell, else _has_can_focus_cell() does not
4923        * return a correct value.
4924        */
4925       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
4926            list;
4927            list = (rtl ? list->prev : list->next))
4928         {
4929           GtkTreeViewColumn *column = list->data;
4930           gtk_tree_view_column_cell_set_cell_data (column,
4931                                                    tree_view->priv->model,
4932                                                    &iter,
4933                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
4934                                                    node->children?TRUE:FALSE);
4935         }
4936
4937       has_can_focus_cell = gtk_tree_view_has_can_focus_cell (tree_view);
4938
4939       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
4940            list;
4941            list = (rtl ? list->prev : list->next))
4942         {
4943           GtkTreeViewColumn *column = list->data;
4944           GtkRegionFlags row_flags = 0, column_flags = 0;
4945           GtkStateFlags state = 0;
4946           gint width;
4947           gboolean draw_focus;
4948
4949           if (!gtk_tree_view_column_get_visible (column))
4950             continue;
4951
4952           n_col++;
4953           width = gtk_tree_view_column_get_width (column);
4954
4955           if (cell_offset > clip.x + clip.width ||
4956               cell_offset + width < clip.x)
4957             {
4958               cell_offset += width;
4959               continue;
4960             }
4961
4962           if (gtk_tree_view_column_get_sort_indicator (column))
4963             flags |= GTK_CELL_RENDERER_SORTED;
4964           else
4965             flags &= ~GTK_CELL_RENDERER_SORTED;
4966
4967           if (cursor == node)
4968             flags |= GTK_CELL_RENDERER_FOCUSED;
4969           else
4970             flags &= ~GTK_CELL_RENDERER_FOCUSED;
4971
4972           background_area.x = cell_offset;
4973           background_area.width = width;
4974
4975           cell_area = background_area;
4976           cell_area.y += vertical_separator / 2;
4977           cell_area.x += horizontal_separator / 2;
4978           cell_area.height -= vertical_separator;
4979           cell_area.width -= horizontal_separator;
4980
4981           if (draw_vgrid_lines)
4982             {
4983               if (list == first_column)
4984                 {
4985                   cell_area.width -= grid_line_width / 2;
4986                 }
4987               else if (list == last_column)
4988                 {
4989                   cell_area.x += grid_line_width / 2;
4990                   cell_area.width -= grid_line_width / 2;
4991                 }
4992               else
4993                 {
4994                   cell_area.x += grid_line_width / 2;
4995                   cell_area.width -= grid_line_width;
4996                 }
4997             }
4998
4999           if (draw_hgrid_lines)
5000             {
5001               cell_area.y += grid_line_width / 2;
5002               cell_area.height -= grid_line_width;
5003             }
5004
5005           if (!gdk_rectangle_intersect (&clip, &background_area, NULL))
5006             {
5007               cell_offset += gtk_tree_view_column_get_width (column);
5008               continue;
5009             }
5010
5011           gtk_tree_view_column_cell_set_cell_data (column,
5012                                                    tree_view->priv->model,
5013                                                    &iter,
5014                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
5015                                                    node->children?TRUE:FALSE);
5016
5017           /* Select the detail for drawing the cell.  relevant
5018            * factors are parity, sortedness, and whether to
5019            * display rules.
5020            */
5021           if (allow_rules && tree_view->priv->has_rules)
5022             {
5023               if (parity)
5024                 row_flags |= GTK_REGION_ODD;
5025               else
5026                 row_flags |= GTK_REGION_EVEN;
5027             }
5028
5029           if ((flags & GTK_CELL_RENDERER_SORTED) &&
5030               n_visible_columns >= 3)
5031             column_flags |= GTK_REGION_SORTED;
5032
5033           is_first = (rtl ? !list->next : !list->prev);
5034           is_last = (rtl ? !list->prev : !list->next);
5035
5036           if (is_first)
5037             column_flags |= GTK_REGION_FIRST;
5038
5039           if (is_last)
5040             column_flags |= GTK_REGION_LAST;
5041
5042           if ((n_col % 2) == 0)
5043             column_flags |= GTK_REGION_EVEN;
5044           else
5045             column_flags |= GTK_REGION_ODD;
5046
5047           gtk_style_context_save (context);
5048
5049           state = gtk_cell_renderer_get_state (NULL, widget, flags);
5050           gtk_style_context_set_state (context, state);
5051
5052           gtk_style_context_add_class (context, GTK_STYLE_CLASS_CELL);
5053           gtk_style_context_add_region (context, GTK_STYLE_REGION_ROW, row_flags);
5054           gtk_style_context_add_region (context, GTK_STYLE_REGION_COLUMN, column_flags);
5055
5056           if (node == cursor && has_can_focus_cell
5057               && ((column == tree_view->priv->focus_column
5058                    && tree_view->priv->draw_keyfocus &&
5059                    gtk_widget_has_focus (widget))
5060                   || (column == tree_view->priv->edited_column)))
5061             draw_focus = TRUE;
5062           else
5063             draw_focus = FALSE;
5064
5065           /* Draw background */
5066           gtk_render_background (context, cr,
5067                                  background_area.x,
5068                                  background_area.y,
5069                                  background_area.width,
5070                                  background_area.height);
5071
5072           if (gtk_tree_view_is_expander_column (tree_view, column))
5073             {
5074               if (!rtl)
5075                 cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
5076               cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
5077
5078               if (gtk_tree_view_draw_expanders (tree_view))
5079                 {
5080                   if (!rtl)
5081                     cell_area.x += depth * tree_view->priv->expander_size;
5082                   cell_area.width -= depth * tree_view->priv->expander_size;
5083                 }
5084
5085               /* If we have an expander column, the highlight underline
5086                * starts with that column, so that it indicates which
5087                * level of the tree we're dropping at.
5088                */
5089               highlight_x = cell_area.x;
5090               expander_cell_width = cell_area.width;
5091
5092               if (is_separator)
5093                 gtk_render_line (context, cr,
5094                                  cell_area.x,
5095                                  cell_area.y + cell_area.height / 2,
5096                                  cell_area.x + cell_area.width,
5097                                  cell_area.y + cell_area.height / 2);
5098               else
5099                 _gtk_tree_view_column_cell_render (column,
5100                                                    cr,
5101                                                    &background_area,
5102                                                    &cell_area,
5103                                                    flags,
5104                                                    draw_focus);
5105               if (gtk_tree_view_draw_expanders (tree_view)
5106                   && (node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT)
5107                 {
5108                   if (!got_pointer)
5109                     {
5110                       gdk_window_get_pointer (tree_view->priv->bin_window, 
5111                                               &pointer_x, &pointer_y, NULL);
5112                       got_pointer = TRUE;
5113                     }
5114
5115                   gtk_tree_view_draw_arrow (GTK_TREE_VIEW (widget),
5116                                             cr,
5117                                             tree,
5118                                             node,
5119                                             pointer_x, pointer_y);
5120                 }
5121             }
5122           else
5123             {
5124               if (is_separator)
5125                 gtk_render_line (context, cr,
5126                                  cell_area.x,
5127                                  cell_area.y + cell_area.height / 2,
5128                                  cell_area.x + cell_area.width,
5129                                  cell_area.y + cell_area.height / 2);
5130               else
5131                 _gtk_tree_view_column_cell_render (column,
5132                                                    cr,
5133                                                    &background_area,
5134                                                    &cell_area,
5135                                                    flags,
5136                                                    draw_focus);
5137             }
5138
5139           if (draw_hgrid_lines)
5140             {
5141               if (background_area.y > 0)
5142                 gtk_tree_view_draw_line (tree_view, cr,
5143                                          GTK_TREE_VIEW_GRID_LINE,
5144                                          background_area.x, background_area.y,
5145                                          background_area.x + background_area.width,
5146                                          background_area.y);
5147
5148               if (y_offset + max_height >= clip.height)
5149                 gtk_tree_view_draw_line (tree_view, cr,
5150                                          GTK_TREE_VIEW_GRID_LINE,
5151                                          background_area.x, background_area.y + max_height,
5152                                          background_area.x + background_area.width,
5153                                          background_area.y + max_height);
5154             }
5155
5156           if (gtk_tree_view_is_expander_column (tree_view, column) &&
5157               tree_view->priv->tree_lines_enabled)
5158             {
5159               gint x = background_area.x;
5160               gint mult = rtl ? -1 : 1;
5161               gint y0 = background_area.y;
5162               gint y1 = background_area.y + background_area.height/2;
5163               gint y2 = background_area.y + background_area.height;
5164
5165               if (rtl)
5166                 x += background_area.width - 1;
5167
5168               if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT
5169                   && depth > 1)
5170                 {
5171                   gtk_tree_view_draw_line (tree_view, cr,
5172                                            GTK_TREE_VIEW_TREE_LINE,
5173                                            x + tree_view->priv->expander_size * (depth - 1.5) * mult,
5174                                            y1,
5175                                            x + tree_view->priv->expander_size * (depth - 1.1) * mult,
5176                                            y1);
5177                 }
5178               else if (depth > 1)
5179                 {
5180                   gtk_tree_view_draw_line (tree_view, cr,
5181                                            GTK_TREE_VIEW_TREE_LINE,
5182                                            x + tree_view->priv->expander_size * (depth - 1.5) * mult,
5183                                            y1,
5184                                            x + tree_view->priv->expander_size * (depth - 0.5) * mult,
5185                                            y1);
5186                 }
5187
5188               if (depth > 1)
5189                 {
5190                   gint i;
5191                   GtkRBNode *tmp_node;
5192                   GtkRBTree *tmp_tree;
5193
5194                   if (!_gtk_rbtree_next (tree, node))
5195                     gtk_tree_view_draw_line (tree_view, cr,
5196                                              GTK_TREE_VIEW_TREE_LINE,
5197                                              x + tree_view->priv->expander_size * (depth - 1.5) * mult,
5198                                              y0,
5199                                              x + tree_view->priv->expander_size * (depth - 1.5) * mult,
5200                                              y1);
5201                   else
5202                     gtk_tree_view_draw_line (tree_view, cr,
5203                                              GTK_TREE_VIEW_TREE_LINE,
5204                                              x + tree_view->priv->expander_size * (depth - 1.5) * mult,
5205                                              y0,
5206                                              x + tree_view->priv->expander_size * (depth - 1.5) * mult,
5207                                              y2);
5208
5209                   tmp_node = tree->parent_node;
5210                   tmp_tree = tree->parent_tree;
5211
5212                   for (i = depth - 2; i > 0; i--)
5213                     {
5214                       if (_gtk_rbtree_next (tmp_tree, tmp_node))
5215                         gtk_tree_view_draw_line (tree_view, cr,
5216                                                  GTK_TREE_VIEW_TREE_LINE,
5217                                                  x + tree_view->priv->expander_size * (i - 0.5) * mult,
5218                                                  y0,
5219                                                  x + tree_view->priv->expander_size * (i - 0.5) * mult,
5220                                                  y2);
5221
5222                       tmp_node = tmp_tree->parent_node;
5223                       tmp_tree = tmp_tree->parent_tree;
5224                     }
5225                 }
5226             }
5227
5228           gtk_style_context_restore (context);
5229           cell_offset += gtk_tree_view_column_get_width (column);
5230         }
5231
5232       if (node == drag_highlight)
5233         {
5234           /* Draw indicator for the drop
5235            */
5236           gint highlight_y = -1;
5237           GtkRBTree *tree = NULL;
5238           GtkRBNode *node = NULL;
5239
5240           switch (tree_view->priv->drag_dest_pos)
5241             {
5242             case GTK_TREE_VIEW_DROP_BEFORE:
5243               highlight_y = background_area.y - 1;
5244               if (highlight_y < 0)
5245                       highlight_y = 0;
5246               break;
5247
5248             case GTK_TREE_VIEW_DROP_AFTER:
5249               highlight_y = background_area.y + background_area.height - 1;
5250               break;
5251
5252             case GTK_TREE_VIEW_DROP_INTO_OR_BEFORE:
5253             case GTK_TREE_VIEW_DROP_INTO_OR_AFTER:
5254               _gtk_tree_view_find_node (tree_view, drag_dest_path, &tree, &node);
5255
5256               if (tree == NULL)
5257                 break;
5258
5259               gtk_render_focus (context, cr,
5260                                 0, gtk_tree_view_get_row_y_offset (tree_view, tree, node)
5261                                    - focus_line_width / 2,
5262                                 gdk_window_get_width (tree_view->priv->bin_window),
5263                                 gtk_tree_view_get_row_height (tree_view, node)
5264                                    - focus_line_width + 1);
5265               break;
5266             }
5267
5268           if (highlight_y >= 0)
5269             {
5270               gtk_tree_view_draw_line (tree_view, cr,
5271                                        GTK_TREE_VIEW_FOREGROUND_LINE,
5272                                        rtl ? highlight_x + expander_cell_width : highlight_x,
5273                                        highlight_y,
5274                                        rtl ? 0 : bin_window_width,
5275                                        highlight_y);
5276             }
5277         }
5278
5279       /* draw the big row-spanning focus rectangle, if needed */
5280       if (!has_can_focus_cell && node == cursor &&
5281           tree_view->priv->draw_keyfocus &&
5282           gtk_widget_has_focus (widget))
5283         {
5284           gint tmp_y, tmp_height;
5285           GtkStateFlags focus_rect_state = 0;
5286
5287           gtk_style_context_save (context);
5288
5289           focus_rect_state = gtk_cell_renderer_get_state (NULL, widget, flags);
5290           gtk_style_context_set_state (context, focus_rect_state);
5291
5292           if (draw_hgrid_lines)
5293             {
5294               tmp_y = gtk_tree_view_get_row_y_offset (tree_view, tree, node) + grid_line_width / 2;
5295               tmp_height = gtk_tree_view_get_row_height (tree_view, node) - grid_line_width;
5296             }
5297           else
5298             {
5299               tmp_y = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
5300               tmp_height = gtk_tree_view_get_row_height (tree_view, node);
5301             }
5302
5303           gtk_render_focus (context, cr,
5304                             0, tmp_y,
5305                             gdk_window_get_width (tree_view->priv->bin_window),
5306                             tmp_height);
5307
5308           gtk_style_context_restore (context);
5309         }
5310
5311       y_offset += max_height;
5312       if (node->children)
5313         {
5314           GtkTreeIter parent = iter;
5315           gboolean has_child;
5316
5317           tree = node->children;
5318           node = tree->root;
5319
5320           g_assert (node != tree->nil);
5321
5322           while (node->left != tree->nil)
5323             node = node->left;
5324           has_child = gtk_tree_model_iter_children (tree_view->priv->model,
5325                                                     &iter,
5326                                                     &parent);
5327           depth++;
5328
5329           /* Sanity Check! */
5330           TREE_VIEW_INTERNAL_ASSERT (has_child, FALSE);
5331         }
5332       else
5333         {
5334           gboolean done = FALSE;
5335
5336           do
5337             {
5338               node = _gtk_rbtree_next (tree, node);
5339               if (node != NULL)
5340                 {
5341                   gboolean has_next = gtk_tree_model_iter_next (tree_view->priv->model, &iter);
5342                   done = TRUE;
5343
5344                   /* Sanity Check! */
5345                   TREE_VIEW_INTERNAL_ASSERT (has_next, FALSE);
5346                 }
5347               else
5348                 {
5349                   GtkTreeIter parent_iter = iter;
5350                   gboolean has_parent;
5351
5352                   node = tree->parent_node;
5353                   tree = tree->parent_tree;
5354                   if (tree == NULL)
5355                     /* we should go to done to free some memory */
5356                     goto done;
5357                   has_parent = gtk_tree_model_iter_parent (tree_view->priv->model,
5358                                                            &iter,
5359                                                            &parent_iter);
5360                   depth--;
5361
5362                   /* Sanity check */
5363                   TREE_VIEW_INTERNAL_ASSERT (has_parent, FALSE);
5364                 }
5365             }
5366           while (!done);
5367         }
5368     }
5369   while (y_offset < clip.height);
5370
5371 done:
5372   gtk_tree_view_draw_grid_lines (tree_view, cr, n_visible_columns);
5373
5374   if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
5375     gtk_tree_view_paint_rubber_band (tree_view, cr);
5376
5377   if (cursor_path)
5378     gtk_tree_path_free (cursor_path);
5379
5380   if (drag_dest_path)
5381     gtk_tree_path_free (drag_dest_path);
5382
5383   return FALSE;
5384 }
5385
5386 static gboolean
5387 gtk_tree_view_draw (GtkWidget *widget,
5388                     cairo_t   *cr)
5389 {
5390   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
5391   GtkWidget   *button;
5392
5393   if (gtk_cairo_should_draw_window (cr, tree_view->priv->bin_window))
5394     {
5395       GtkStyleContext *context;
5396       GList *tmp_list;
5397
5398       context = gtk_widget_get_style_context (widget);
5399
5400       cairo_save (cr);
5401
5402       gtk_style_context_save (context);
5403       gtk_style_context_add_class (context, GTK_STYLE_CLASS_VIEW);
5404
5405       gtk_cairo_transform_to_window (cr, widget, tree_view->priv->bin_window);
5406
5407       gtk_tree_view_bin_draw (widget, cr);
5408
5409       gtk_style_context_restore (context);
5410       cairo_restore (cr);
5411
5412       /* We can't just chain up to Container::draw as it will try to send the
5413        * event to the headers, so we handle propagating it to our children
5414        * (eg. widgets being edited) ourselves.
5415        */
5416       tmp_list = tree_view->priv->children;
5417       while (tmp_list)
5418         {
5419           GtkTreeViewChild *child = tmp_list->data;
5420           tmp_list = tmp_list->next;
5421
5422           gtk_container_propagate_draw (GTK_CONTAINER (tree_view), child->widget, cr);
5423         }
5424     }
5425
5426   if (gtk_cairo_should_draw_window (cr, tree_view->priv->header_window))
5427     {
5428       GList *list;
5429       
5430       for (list = tree_view->priv->columns; list != NULL; list = list->next)
5431         {
5432           GtkTreeViewColumn *column = list->data;
5433
5434           if (column == tree_view->priv->drag_column)
5435             continue;
5436
5437           if (gtk_tree_view_column_get_visible (column))
5438             {
5439               button = gtk_tree_view_column_get_button (column);
5440               gtk_container_propagate_draw (GTK_CONTAINER (tree_view),
5441                                             button, cr);
5442             }
5443         }
5444     }
5445   
5446   if (tree_view->priv->drag_window &&
5447       gtk_cairo_should_draw_window (cr, tree_view->priv->drag_window))
5448     {
5449       button = gtk_tree_view_column_get_button (tree_view->priv->drag_column);
5450       gtk_container_propagate_draw (GTK_CONTAINER (tree_view),
5451                                     button, cr);
5452     }
5453
5454   return TRUE;
5455 }
5456
5457 enum
5458 {
5459   DROP_HOME,
5460   DROP_RIGHT,
5461   DROP_LEFT,
5462   DROP_END
5463 };
5464
5465 /* returns 0x1 when no column has been found -- yes it's hackish */
5466 static GtkTreeViewColumn *
5467 gtk_tree_view_get_drop_column (GtkTreeView       *tree_view,
5468                                GtkTreeViewColumn *column,
5469                                gint               drop_position)
5470 {
5471   GtkTreeViewColumn *left_column = NULL;
5472   GtkTreeViewColumn *cur_column = NULL;
5473   GList *tmp_list;
5474
5475   if (!gtk_tree_view_column_get_reorderable (column))
5476     return (GtkTreeViewColumn *)0x1;
5477
5478   switch (drop_position)
5479     {
5480       case DROP_HOME:
5481         /* find first column where we can drop */
5482         tmp_list = tree_view->priv->columns;
5483         if (column == GTK_TREE_VIEW_COLUMN (tmp_list->data))
5484           return (GtkTreeViewColumn *)0x1;
5485
5486         while (tmp_list)
5487           {
5488             g_assert (tmp_list);
5489
5490             cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5491             tmp_list = tmp_list->next;
5492
5493             if (left_column &&
5494                 gtk_tree_view_column_get_visible (left_column) == FALSE)
5495               continue;
5496
5497             if (!tree_view->priv->column_drop_func)
5498               return left_column;
5499
5500             if (!tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5501               {
5502                 left_column = cur_column;
5503                 continue;
5504               }
5505
5506             return left_column;
5507           }
5508
5509         if (!tree_view->priv->column_drop_func)
5510           return left_column;
5511
5512         if (tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data))
5513           return left_column;
5514         else
5515           return (GtkTreeViewColumn *)0x1;
5516         break;
5517
5518       case DROP_RIGHT:
5519         /* find first column after column where we can drop */
5520         tmp_list = tree_view->priv->columns;
5521
5522         for (; tmp_list; tmp_list = tmp_list->next)
5523           if (GTK_TREE_VIEW_COLUMN (tmp_list->data) == column)
5524             break;
5525
5526         if (!tmp_list || !tmp_list->next)
5527           return (GtkTreeViewColumn *)0x1;
5528
5529         tmp_list = tmp_list->next;
5530         left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5531         tmp_list = tmp_list->next;
5532
5533         while (tmp_list)
5534           {
5535             g_assert (tmp_list);
5536
5537             cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5538             tmp_list = tmp_list->next;
5539
5540             if (left_column &&
5541                 gtk_tree_view_column_get_visible (left_column) == FALSE)
5542               {
5543                 left_column = cur_column;
5544                 if (tmp_list)
5545                   tmp_list = tmp_list->next;
5546                 continue;
5547               }
5548
5549             if (!tree_view->priv->column_drop_func)
5550               return left_column;
5551
5552             if (!tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5553               {
5554                 left_column = cur_column;
5555                 continue;
5556               }
5557
5558             return left_column;
5559           }
5560
5561         if (!tree_view->priv->column_drop_func)
5562           return left_column;
5563
5564         if (tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data))
5565           return left_column;
5566         else
5567           return (GtkTreeViewColumn *)0x1;
5568         break;
5569
5570       case DROP_LEFT:
5571         /* find first column before column where we can drop */
5572         tmp_list = tree_view->priv->columns;
5573
5574         for (; tmp_list; tmp_list = tmp_list->next)
5575           if (GTK_TREE_VIEW_COLUMN (tmp_list->data) == column)
5576             break;
5577
5578         if (!tmp_list || !tmp_list->prev)
5579           return (GtkTreeViewColumn *)0x1;
5580
5581         tmp_list = tmp_list->prev;
5582         cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5583         tmp_list = tmp_list->prev;
5584
5585         while (tmp_list)
5586           {
5587             g_assert (tmp_list);
5588
5589             left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5590
5591             if (left_column &&
5592                 gtk_tree_view_column_get_visible (left_column) == FALSE)
5593               {
5594                 /*if (!tmp_list->prev)
5595                   return (GtkTreeViewColumn *)0x1;
5596                   */
5597 /*
5598                 cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->prev->data);
5599                 tmp_list = tmp_list->prev->prev;
5600                 continue;*/
5601
5602                 cur_column = left_column;
5603                 if (tmp_list)
5604                   tmp_list = tmp_list->prev;
5605                 continue;
5606               }
5607
5608             if (!tree_view->priv->column_drop_func)
5609               return left_column;
5610
5611             if (tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5612               return left_column;
5613
5614             cur_column = left_column;
5615             tmp_list = tmp_list->prev;
5616           }
5617
5618         if (!tree_view->priv->column_drop_func)
5619           return NULL;
5620
5621         if (tree_view->priv->column_drop_func (tree_view, column, NULL, cur_column, tree_view->priv->column_drop_func_data))
5622           return NULL;
5623         else
5624           return (GtkTreeViewColumn *)0x1;
5625         break;
5626
5627       case DROP_END:
5628         /* same as DROP_HOME case, but doing it backwards */
5629         tmp_list = g_list_last (tree_view->priv->columns);
5630         cur_column = NULL;
5631
5632         if (column == GTK_TREE_VIEW_COLUMN (tmp_list->data))
5633           return (GtkTreeViewColumn *)0x1;
5634
5635         while (tmp_list)
5636           {
5637             g_assert (tmp_list);
5638
5639             left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5640
5641             if (left_column &&
5642                 gtk_tree_view_column_get_visible (left_column) == FALSE)
5643               {
5644                 cur_column = left_column;
5645                 tmp_list = tmp_list->prev;
5646               }
5647
5648             if (!tree_view->priv->column_drop_func)
5649               return left_column;
5650
5651             if (tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5652               return left_column;
5653
5654             cur_column = left_column;
5655             tmp_list = tmp_list->prev;
5656           }
5657
5658         if (!tree_view->priv->column_drop_func)
5659           return NULL;
5660
5661         if (tree_view->priv->column_drop_func (tree_view, column, NULL, cur_column, tree_view->priv->column_drop_func_data))
5662           return NULL;
5663         else
5664           return (GtkTreeViewColumn *)0x1;
5665         break;
5666     }
5667
5668   return (GtkTreeViewColumn *)0x1;
5669 }
5670
5671 static gboolean
5672 gtk_tree_view_key_press (GtkWidget   *widget,
5673                          GdkEventKey *event)
5674 {
5675   GtkTreeView *tree_view = (GtkTreeView *) widget;
5676   GtkWidget   *button;
5677
5678   if (tree_view->priv->rubber_band_status)
5679     {
5680       if (event->keyval == GDK_KEY_Escape)
5681         gtk_tree_view_stop_rubber_band (tree_view);
5682
5683       return TRUE;
5684     }
5685
5686   if (tree_view->priv->in_column_drag)
5687     {
5688       if (event->keyval == GDK_KEY_Escape)
5689         {
5690           tree_view->priv->cur_reorder = NULL;
5691           gtk_tree_view_button_release_drag_column (widget, NULL);
5692         }
5693       return TRUE;
5694     }
5695
5696   if (tree_view->priv->headers_visible)
5697     {
5698       GList *focus_column;
5699       gboolean rtl;
5700
5701       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
5702
5703       for (focus_column = tree_view->priv->columns;
5704            focus_column;
5705            focus_column = focus_column->next)
5706         {
5707           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
5708           
5709           button = gtk_tree_view_column_get_button (column);
5710           if (gtk_widget_has_focus (button))
5711             break;
5712         }
5713
5714       if (focus_column &&
5715           (event->state & GDK_SHIFT_MASK) && (event->state & GDK_MOD1_MASK) &&
5716           (event->keyval == GDK_KEY_Left || event->keyval == GDK_KEY_KP_Left
5717            || event->keyval == GDK_KEY_Right || event->keyval == GDK_KEY_KP_Right))
5718         {
5719           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
5720           gint max_width, min_width;
5721
5722           if (!gtk_tree_view_column_get_resizable (column))
5723             {
5724               gtk_widget_error_bell (widget);
5725               return TRUE;
5726             }
5727
5728           if (event->keyval == (rtl ? GDK_KEY_Right : GDK_KEY_Left)
5729               || event->keyval == (rtl ? GDK_KEY_KP_Right : GDK_KEY_KP_Left))
5730             {
5731               GtkRequisition button_req;
5732               gint old_width = _gtk_tree_view_column_get_resized_width (column);
5733               gint new_width;
5734
5735               button = gtk_tree_view_column_get_button (column);
5736
5737               gtk_widget_get_preferred_size (button, &button_req, NULL);
5738
5739               new_width = MAX (old_width, gtk_tree_view_column_get_width (column));
5740               new_width -= 2;
5741               if (new_width < 0)
5742                 new_width = 0;
5743
5744               _gtk_tree_view_column_set_resized_width (column, new_width);
5745
5746               min_width = gtk_tree_view_column_get_min_width (column);
5747               if (min_width == -1)
5748                 new_width = MAX (button_req.width, new_width);
5749               else
5750                 {
5751                   new_width = MAX (min_width, new_width);
5752                 }
5753
5754               max_width = gtk_tree_view_column_get_max_width (column);
5755               if (max_width != -1)
5756                 new_width = MIN (new_width, max_width);
5757
5758               _gtk_tree_view_column_set_use_resized_width (column, TRUE);
5759
5760               if (new_width != old_width)
5761                 {
5762                   _gtk_tree_view_column_set_resized_width (column, new_width);
5763                   gtk_widget_queue_resize (widget);
5764                 }
5765               else
5766                 gtk_widget_error_bell (widget);
5767             }
5768           else if (event->keyval == (rtl ? GDK_KEY_Left : GDK_KEY_Right)
5769                    || event->keyval == (rtl ? GDK_KEY_KP_Left : GDK_KEY_KP_Right))
5770             {
5771               gint old_width = _gtk_tree_view_column_get_resized_width (column);
5772               gint new_width;
5773
5774               new_width = MAX (old_width, gtk_tree_view_column_get_width (column));
5775               new_width += 2;
5776
5777               max_width = gtk_tree_view_column_get_max_width (column);
5778               if (max_width != -1)
5779                 new_width = MIN (new_width, max_width);
5780
5781               _gtk_tree_view_column_set_use_resized_width (column, TRUE);
5782
5783               if (new_width != old_width)
5784                 {
5785                   _gtk_tree_view_column_set_resized_width (column, new_width);
5786                   gtk_widget_queue_resize (widget);
5787                 }
5788               else
5789                 gtk_widget_error_bell (widget);
5790             }
5791
5792           return TRUE;
5793         }
5794
5795       if (focus_column &&
5796           (event->state & GDK_MOD1_MASK) &&
5797           (event->keyval == GDK_KEY_Left || event->keyval == GDK_KEY_KP_Left
5798            || event->keyval == GDK_KEY_Right || event->keyval == GDK_KEY_KP_Right
5799            || event->keyval == GDK_KEY_Home || event->keyval == GDK_KEY_KP_Home
5800            || event->keyval == GDK_KEY_End || event->keyval == GDK_KEY_KP_End))
5801         {
5802           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
5803
5804           if (event->keyval == (rtl ? GDK_KEY_Right : GDK_KEY_Left)
5805               || event->keyval == (rtl ? GDK_KEY_KP_Right : GDK_KEY_KP_Left))
5806             {
5807               GtkTreeViewColumn *col;
5808               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_LEFT);
5809               if (col != (GtkTreeViewColumn *)0x1)
5810                 gtk_tree_view_move_column_after (tree_view, column, col);
5811               else
5812                 gtk_widget_error_bell (widget);
5813             }
5814           else if (event->keyval == (rtl ? GDK_KEY_Left : GDK_KEY_Right)
5815                    || event->keyval == (rtl ? GDK_KEY_KP_Left : GDK_KEY_KP_Right))
5816             {
5817               GtkTreeViewColumn *col;
5818               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_RIGHT);
5819               if (col != (GtkTreeViewColumn *)0x1)
5820                 gtk_tree_view_move_column_after (tree_view, column, col);
5821               else
5822                 gtk_widget_error_bell (widget);
5823             }
5824           else if (event->keyval == GDK_KEY_Home || event->keyval == GDK_KEY_KP_Home)
5825             {
5826               GtkTreeViewColumn *col;
5827               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_HOME);
5828               if (col != (GtkTreeViewColumn *)0x1)
5829                 gtk_tree_view_move_column_after (tree_view, column, col);
5830               else
5831                 gtk_widget_error_bell (widget);
5832             }
5833           else if (event->keyval == GDK_KEY_End || event->keyval == GDK_KEY_KP_End)
5834             {
5835               GtkTreeViewColumn *col;
5836               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_END);
5837               if (col != (GtkTreeViewColumn *)0x1)
5838                 gtk_tree_view_move_column_after (tree_view, column, col);
5839               else
5840                 gtk_widget_error_bell (widget);
5841             }
5842
5843           return TRUE;
5844         }
5845     }
5846
5847   /* Chain up to the parent class.  It handles the keybindings. */
5848   if (GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->key_press_event (widget, event))
5849     return TRUE;
5850
5851   if (tree_view->priv->search_entry_avoid_unhandled_binding)
5852     {
5853       tree_view->priv->search_entry_avoid_unhandled_binding = FALSE;
5854       return FALSE;
5855     }
5856
5857   /* We pass the event to the search_entry.  If its text changes, then we start
5858    * the typeahead find capabilities. */
5859   if (gtk_widget_has_focus (GTK_WIDGET (tree_view))
5860       && tree_view->priv->enable_search
5861       && !tree_view->priv->search_custom_entry_set)
5862     {
5863       GdkEvent *new_event;
5864       char *old_text;
5865       const char *new_text;
5866       gboolean retval;
5867       GdkScreen *screen;
5868       gboolean text_modified;
5869       gulong popup_menu_id;
5870
5871       gtk_tree_view_ensure_interactive_directory (tree_view);
5872
5873       /* Make a copy of the current text */
5874       old_text = g_strdup (gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry)));
5875       new_event = gdk_event_copy ((GdkEvent *) event);
5876       g_object_unref (((GdkEventKey *) new_event)->window);
5877       ((GdkEventKey *) new_event)->window = g_object_ref (gtk_widget_get_window (tree_view->priv->search_window));
5878       gtk_widget_realize (tree_view->priv->search_window);
5879
5880       popup_menu_id = g_signal_connect (tree_view->priv->search_entry, 
5881                                         "popup-menu", G_CALLBACK (gtk_true),
5882                                         NULL);
5883
5884       /* Move the entry off screen */
5885       screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
5886       gtk_window_move (GTK_WINDOW (tree_view->priv->search_window),
5887                        gdk_screen_get_width (screen) + 1,
5888                        gdk_screen_get_height (screen) + 1);
5889       gtk_widget_show (tree_view->priv->search_window);
5890
5891       /* Send the event to the window.  If the preedit_changed signal is emitted
5892        * during this event, we will set priv->imcontext_changed  */
5893       tree_view->priv->imcontext_changed = FALSE;
5894       retval = gtk_widget_event (tree_view->priv->search_window, new_event);
5895       gdk_event_free (new_event);
5896       gtk_widget_hide (tree_view->priv->search_window);
5897
5898       g_signal_handler_disconnect (tree_view->priv->search_entry, 
5899                                    popup_menu_id);
5900
5901       /* We check to make sure that the entry tried to handle the text, and that
5902        * the text has changed.
5903        */
5904       new_text = gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry));
5905       text_modified = strcmp (old_text, new_text) != 0;
5906       g_free (old_text);
5907       if (tree_view->priv->imcontext_changed ||    /* we're in a preedit */
5908           (retval && text_modified))               /* ...or the text was modified */
5909         {
5910           if (gtk_tree_view_real_start_interactive_search (tree_view,
5911                                                            gdk_event_get_device ((GdkEvent *) event),
5912                                                            FALSE))
5913             {
5914               gtk_widget_grab_focus (GTK_WIDGET (tree_view));
5915               return TRUE;
5916             }
5917           else
5918             {
5919               gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
5920               return FALSE;
5921             }
5922         }
5923     }
5924
5925   return FALSE;
5926 }
5927
5928 static gboolean
5929 gtk_tree_view_key_release (GtkWidget   *widget,
5930                            GdkEventKey *event)
5931 {
5932   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
5933
5934   if (tree_view->priv->rubber_band_status)
5935     return TRUE;
5936
5937   return GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->key_release_event (widget, event);
5938 }
5939
5940 /* FIXME Is this function necessary? Can I get an enter_notify event
5941  * w/o either an expose event or a mouse motion event?
5942  */
5943 static gboolean
5944 gtk_tree_view_enter_notify (GtkWidget        *widget,
5945                             GdkEventCrossing *event)
5946 {
5947   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
5948   GtkRBTree *tree;
5949   GtkRBNode *node;
5950   gint new_y;
5951
5952   /* Sanity check it */
5953   if (event->window != tree_view->priv->bin_window)
5954     return FALSE;
5955
5956   if (tree_view->priv->tree == NULL)
5957     return FALSE;
5958
5959   if (event->mode == GDK_CROSSING_GRAB ||
5960       event->mode == GDK_CROSSING_GTK_GRAB ||
5961       event->mode == GDK_CROSSING_GTK_UNGRAB ||
5962       event->mode == GDK_CROSSING_STATE_CHANGED)
5963     return TRUE;
5964
5965   /* find the node internally */
5966   new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
5967   if (new_y < 0)
5968     new_y = 0;
5969   _gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
5970
5971   tree_view->priv->event_last_x = event->x;
5972   tree_view->priv->event_last_y = event->y;
5973
5974   if ((tree_view->priv->button_pressed_node == NULL) ||
5975       (tree_view->priv->button_pressed_node == node))
5976     prelight_or_select (tree_view, tree, node, event->x, event->y);
5977
5978   return TRUE;
5979 }
5980
5981 static gboolean
5982 gtk_tree_view_leave_notify (GtkWidget        *widget,
5983                             GdkEventCrossing *event)
5984 {
5985   GtkTreeView *tree_view;
5986
5987   if (event->mode == GDK_CROSSING_GRAB)
5988     return TRUE;
5989
5990   tree_view = GTK_TREE_VIEW (widget);
5991
5992   if (tree_view->priv->prelight_node)
5993     _gtk_tree_view_queue_draw_node (tree_view,
5994                                    tree_view->priv->prelight_tree,
5995                                    tree_view->priv->prelight_node,
5996                                    NULL);
5997
5998   tree_view->priv->event_last_x = -10000;
5999   tree_view->priv->event_last_y = -10000;
6000
6001   prelight_or_select (tree_view,
6002                       NULL, NULL,
6003                       -1000, -1000); /* coords not possibly over an arrow */
6004
6005   return TRUE;
6006 }
6007
6008
6009 static gint
6010 gtk_tree_view_focus_out (GtkWidget     *widget,
6011                          GdkEventFocus *event)
6012 {
6013   GtkTreeView *tree_view;
6014
6015   tree_view = GTK_TREE_VIEW (widget);
6016
6017   gtk_widget_queue_draw (widget);
6018
6019   /* destroy interactive search dialog */
6020   if (tree_view->priv->search_window)
6021     gtk_tree_view_search_dialog_hide (tree_view->priv->search_window, tree_view,
6022                                       gdk_event_get_device ((GdkEvent *) event));
6023
6024   return FALSE;
6025 }
6026
6027
6028 /* Incremental Reflow
6029  */
6030
6031 static void
6032 gtk_tree_view_node_queue_redraw (GtkTreeView *tree_view,
6033                                  GtkRBTree   *tree,
6034                                  GtkRBNode   *node)
6035 {
6036   GtkAllocation allocation;
6037   gint y;
6038
6039   y = _gtk_rbtree_node_find_offset (tree, node)
6040     - gtk_adjustment_get_value (tree_view->priv->vadjustment)
6041     + gtk_tree_view_get_effective_header_height (tree_view);
6042
6043   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
6044   gtk_widget_queue_draw_area (GTK_WIDGET (tree_view),
6045                               0, y,
6046                               allocation.width,
6047                               GTK_RBNODE_GET_HEIGHT (node));
6048 }
6049
6050 static gboolean
6051 node_is_visible (GtkTreeView *tree_view,
6052                  GtkRBTree   *tree,
6053                  GtkRBNode   *node)
6054 {
6055   int y;
6056   int height;
6057
6058   y = _gtk_rbtree_node_find_offset (tree, node);
6059   height = gtk_tree_view_get_row_height (tree_view, node);
6060
6061   if (y >= gtk_adjustment_get_value (tree_view->priv->vadjustment) &&
6062       y + height <= (gtk_adjustment_get_value (tree_view->priv->vadjustment)
6063                      + gtk_adjustment_get_page_size (tree_view->priv->vadjustment)))
6064     return TRUE;
6065
6066   return FALSE;
6067 }
6068
6069 /* Returns TRUE if it updated the size
6070  */
6071 static gboolean
6072 validate_row (GtkTreeView *tree_view,
6073               GtkRBTree   *tree,
6074               GtkRBNode   *node,
6075               GtkTreeIter *iter,
6076               GtkTreePath *path)
6077 {
6078   GtkTreeViewColumn *column;
6079   GList *list, *first_column, *last_column;
6080   gint height = 0;
6081   gint horizontal_separator;
6082   gint vertical_separator;
6083   gint depth = gtk_tree_path_get_depth (path);
6084   gboolean retval = FALSE;
6085   gboolean is_separator = FALSE;
6086   gboolean draw_vgrid_lines, draw_hgrid_lines;
6087   gint focus_pad;
6088   gint grid_line_width;
6089   gboolean wide_separators;
6090   gint separator_height;
6091
6092   /* double check the row needs validating */
6093   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) &&
6094       ! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6095     return FALSE;
6096
6097   is_separator = row_is_separator (tree_view, iter, NULL);
6098
6099   gtk_widget_style_get (GTK_WIDGET (tree_view),
6100                         "focus-padding", &focus_pad,
6101                         "horizontal-separator", &horizontal_separator,
6102                         "vertical-separator", &vertical_separator,
6103                         "grid-line-width", &grid_line_width,
6104                         "wide-separators",  &wide_separators,
6105                         "separator-height", &separator_height,
6106                         NULL);
6107   
6108   draw_vgrid_lines =
6109     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_VERTICAL
6110     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
6111   draw_hgrid_lines =
6112     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_HORIZONTAL
6113     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
6114
6115   for (last_column = g_list_last (tree_view->priv->columns);
6116        last_column &&
6117        !(gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (last_column->data)));
6118        last_column = last_column->prev)
6119     ;
6120
6121   for (first_column = g_list_first (tree_view->priv->columns);
6122        first_column &&
6123        !(gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (first_column->data)));
6124        first_column = first_column->next)
6125     ;
6126
6127   for (list = tree_view->priv->columns; list; list = list->next)
6128     {
6129       gint padding = 0;
6130       gint original_width;
6131       gint new_width;
6132       gint row_height;
6133
6134       column = list->data;
6135
6136       if (!gtk_tree_view_column_get_visible (column))
6137         continue;
6138
6139       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID) && 
6140           !_gtk_tree_view_column_cell_get_dirty (column))
6141         continue;
6142
6143       original_width = _gtk_tree_view_column_get_requested_width (column);
6144
6145       gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, iter,
6146                                                GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
6147                                                node->children?TRUE:FALSE);
6148       gtk_tree_view_column_cell_get_size (column,
6149                                           NULL, NULL, NULL,
6150                                           NULL, &row_height);
6151
6152       if (!is_separator)
6153         {
6154           row_height += vertical_separator;
6155           height = MAX (height, row_height);
6156           height = MAX (height, tree_view->priv->expander_size);
6157         }
6158       else
6159         {
6160           if (wide_separators)
6161             height = separator_height + 2 * focus_pad;
6162           else
6163             height = 2 + 2 * focus_pad;
6164         }
6165
6166       if (gtk_tree_view_is_expander_column (tree_view, column))
6167         {
6168           padding += horizontal_separator + (depth - 1) * tree_view->priv->level_indentation;
6169
6170           if (gtk_tree_view_draw_expanders (tree_view))
6171             padding += depth * tree_view->priv->expander_size;
6172         }
6173       else
6174         padding += horizontal_separator;
6175
6176       if (draw_vgrid_lines)
6177         {
6178           if (list->data == first_column || list->data == last_column)
6179             padding += grid_line_width / 2.0;
6180           else
6181             padding += grid_line_width;
6182         }
6183
6184       /* Update the padding for the column */
6185       _gtk_tree_view_column_push_padding (column, padding);
6186       new_width = _gtk_tree_view_column_get_requested_width (column);
6187
6188       if (new_width > original_width)
6189         retval = TRUE;
6190     }
6191
6192   if (draw_hgrid_lines)
6193     height += grid_line_width;
6194
6195   if (height != GTK_RBNODE_GET_HEIGHT (node))
6196     {
6197       retval = TRUE;
6198       _gtk_rbtree_node_set_height (tree, node, height);
6199     }
6200   _gtk_rbtree_node_mark_valid (tree, node);
6201   tree_view->priv->post_validation_flag = TRUE;
6202
6203   return retval;
6204 }
6205
6206
6207 static void
6208 validate_visible_area (GtkTreeView *tree_view)
6209 {
6210   GtkAllocation allocation;
6211   GtkTreePath *path = NULL;
6212   GtkTreePath *above_path = NULL;
6213   GtkTreeIter iter;
6214   GtkRBTree *tree = NULL;
6215   GtkRBNode *node = NULL;
6216   gboolean need_redraw = FALSE;
6217   gboolean size_changed = FALSE;
6218   gint total_height;
6219   gint area_above = 0;
6220   gint area_below = 0;
6221
6222   if (tree_view->priv->tree == NULL)
6223     return;
6224
6225   if (! GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID) &&
6226       tree_view->priv->scroll_to_path == NULL)
6227     return;
6228
6229   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
6230   total_height = allocation.height - gtk_tree_view_get_effective_header_height (tree_view);
6231
6232   if (total_height == 0)
6233     return;
6234
6235   /* First, we check to see if we need to scroll anywhere
6236    */
6237   if (tree_view->priv->scroll_to_path)
6238     {
6239       path = gtk_tree_row_reference_get_path (tree_view->priv->scroll_to_path);
6240       if (path && !_gtk_tree_view_find_node (tree_view, path, &tree, &node))
6241         {
6242           /* we are going to scroll, and will update dy */
6243           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6244           if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6245               GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6246             {
6247               _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
6248               if (validate_row (tree_view, tree, node, &iter, path))
6249                 size_changed = TRUE;
6250             }
6251
6252           if (tree_view->priv->scroll_to_use_align)
6253             {
6254               gint height = gtk_tree_view_get_row_height (tree_view, node);
6255               area_above = (total_height - height) *
6256                 tree_view->priv->scroll_to_row_align;
6257               area_below = total_height - area_above - height;
6258               area_above = MAX (area_above, 0);
6259               area_below = MAX (area_below, 0);
6260             }
6261           else
6262             {
6263               /* two cases:
6264                * 1) row not visible
6265                * 2) row visible
6266                */
6267               gint dy;
6268               gint height = gtk_tree_view_get_row_height (tree_view, node);
6269
6270               dy = _gtk_rbtree_node_find_offset (tree, node);
6271
6272               if (dy >= gtk_adjustment_get_value (tree_view->priv->vadjustment) &&
6273                   dy + height <= (gtk_adjustment_get_value (tree_view->priv->vadjustment)
6274                                   + gtk_adjustment_get_page_size (tree_view->priv->vadjustment)))
6275                 {
6276                   /* row visible: keep the row at the same position */
6277                   area_above = dy - gtk_adjustment_get_value (tree_view->priv->vadjustment);
6278                   area_below = (gtk_adjustment_get_value (tree_view->priv->vadjustment) +
6279                                 gtk_adjustment_get_page_size (tree_view->priv->vadjustment))
6280                                - dy - height;
6281                 }
6282               else
6283                 {
6284                   /* row not visible */
6285                   if (dy >= 0
6286                       && dy + height <= gtk_adjustment_get_page_size (tree_view->priv->vadjustment))
6287                     {
6288                       /* row at the beginning -- fixed */
6289                       area_above = dy;
6290                       area_below = gtk_adjustment_get_page_size (tree_view->priv->vadjustment)
6291                                    - area_above - height;
6292                     }
6293                   else if (dy >= (gtk_adjustment_get_upper (tree_view->priv->vadjustment) -
6294                                   gtk_adjustment_get_page_size (tree_view->priv->vadjustment)))
6295                     {
6296                       /* row at the end -- fixed */
6297                       area_above = dy - (gtk_adjustment_get_upper (tree_view->priv->vadjustment) -
6298                                    gtk_adjustment_get_page_size (tree_view->priv->vadjustment));
6299                       area_below = gtk_adjustment_get_page_size (tree_view->priv->vadjustment) -
6300                                    area_above - height;
6301
6302                       if (area_below < 0)
6303                         {
6304                           area_above = gtk_adjustment_get_page_size (tree_view->priv->vadjustment) - height;
6305                           area_below = 0;
6306                         }
6307                     }
6308                   else
6309                     {
6310                       /* row somewhere in the middle, bring it to the top
6311                        * of the view
6312                        */
6313                       area_above = 0;
6314                       area_below = total_height - height;
6315                     }
6316                 }
6317             }
6318         }
6319       else
6320         /* the scroll to isn't valid; ignore it.
6321          */
6322         {
6323           if (tree_view->priv->scroll_to_path && !path)
6324             {
6325               gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
6326               tree_view->priv->scroll_to_path = NULL;
6327             }
6328           if (path)
6329             gtk_tree_path_free (path);
6330           path = NULL;
6331         }      
6332     }
6333
6334   /* We didn't have a scroll_to set, so we just handle things normally
6335    */
6336   if (path == NULL)
6337     {
6338       gint offset;
6339
6340       offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
6341                                         TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, 0),
6342                                         &tree, &node);
6343       if (node == NULL)
6344         {
6345           /* In this case, nothing has been validated */
6346           path = gtk_tree_path_new_first ();
6347           _gtk_tree_view_find_node (tree_view, path, &tree, &node);
6348         }
6349       else
6350         {
6351           path = _gtk_tree_view_find_path (tree_view, tree, node);
6352           total_height += offset;
6353         }
6354
6355       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6356
6357       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6358           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6359         {
6360           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
6361           if (validate_row (tree_view, tree, node, &iter, path))
6362             size_changed = TRUE;
6363         }
6364       area_above = 0;
6365       area_below = total_height - gtk_tree_view_get_row_height (tree_view, node);
6366     }
6367
6368   above_path = gtk_tree_path_copy (path);
6369
6370   /* if we do not validate any row above the new top_row, we will make sure
6371    * that the row immediately above top_row has been validated. (if we do not
6372    * do this, _gtk_rbtree_find_offset will find the row above top_row, because
6373    * when invalidated that row's height will be zero. and this will mess up
6374    * scrolling).
6375    */
6376   if (area_above == 0)
6377     {
6378       GtkRBTree *tmptree;
6379       GtkRBNode *tmpnode;
6380
6381       _gtk_tree_view_find_node (tree_view, above_path, &tmptree, &tmpnode);
6382       _gtk_rbtree_prev_full (tmptree, tmpnode, &tmptree, &tmpnode);
6383
6384       if (tmpnode)
6385         {
6386           GtkTreePath *tmppath;
6387           GtkTreeIter tmpiter;
6388
6389           tmppath = _gtk_tree_view_find_path (tree_view, tmptree, tmpnode);
6390           gtk_tree_model_get_iter (tree_view->priv->model, &tmpiter, tmppath);
6391
6392           if (GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_INVALID) ||
6393               GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_COLUMN_INVALID))
6394             {
6395               _gtk_tree_view_queue_draw_node (tree_view, tmptree, tmpnode, NULL);
6396               if (validate_row (tree_view, tmptree, tmpnode, &tmpiter, tmppath))
6397                 size_changed = TRUE;
6398             }
6399
6400           gtk_tree_path_free (tmppath);
6401         }
6402     }
6403
6404   /* Now, we walk forwards and backwards, measuring rows. Unfortunately,
6405    * backwards is much slower then forward, as there is no iter_prev function.
6406    * We go forwards first in case we run out of tree.  Then we go backwards to
6407    * fill out the top.
6408    */
6409   while (node && area_below > 0)
6410     {
6411       if (node->children)
6412         {
6413           GtkTreeIter parent = iter;
6414           gboolean has_child;
6415
6416           tree = node->children;
6417           node = tree->root;
6418
6419           g_assert (node != tree->nil);
6420
6421           while (node->left != tree->nil)
6422             node = node->left;
6423           has_child = gtk_tree_model_iter_children (tree_view->priv->model,
6424                                                     &iter,
6425                                                     &parent);
6426           TREE_VIEW_INTERNAL_ASSERT_VOID (has_child);
6427           gtk_tree_path_down (path);
6428         }
6429       else
6430         {
6431           gboolean done = FALSE;
6432           do
6433             {
6434               node = _gtk_rbtree_next (tree, node);
6435               if (node != NULL)
6436                 {
6437                   gboolean has_next = gtk_tree_model_iter_next (tree_view->priv->model, &iter);
6438                   done = TRUE;
6439                   gtk_tree_path_next (path);
6440
6441                   /* Sanity Check! */
6442                   TREE_VIEW_INTERNAL_ASSERT_VOID (has_next);
6443                 }
6444               else
6445                 {
6446                   GtkTreeIter parent_iter = iter;
6447                   gboolean has_parent;
6448
6449                   node = tree->parent_node;
6450                   tree = tree->parent_tree;
6451                   if (tree == NULL)
6452                     break;
6453                   has_parent = gtk_tree_model_iter_parent (tree_view->priv->model,
6454                                                            &iter,
6455                                                            &parent_iter);
6456                   gtk_tree_path_up (path);
6457
6458                   /* Sanity check */
6459                   TREE_VIEW_INTERNAL_ASSERT_VOID (has_parent);
6460                 }
6461             }
6462           while (!done);
6463         }
6464
6465       if (!node)
6466         break;
6467
6468       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6469           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6470         {
6471           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
6472           if (validate_row (tree_view, tree, node, &iter, path))
6473               size_changed = TRUE;
6474         }
6475
6476       area_below -= gtk_tree_view_get_row_height (tree_view, node);
6477     }
6478   gtk_tree_path_free (path);
6479
6480   /* If we ran out of tree, and have extra area_below left, we need to add it
6481    * to area_above */
6482   if (area_below > 0)
6483     area_above += area_below;
6484
6485   _gtk_tree_view_find_node (tree_view, above_path, &tree, &node);
6486
6487   /* We walk backwards */
6488   while (area_above > 0)
6489     {
6490       _gtk_rbtree_prev_full (tree, node, &tree, &node);
6491
6492       /* Always find the new path in the tree.  We cannot just assume
6493        * a gtk_tree_path_prev() is enough here, as there might be children
6494        * in between this node and the previous sibling node.  If this
6495        * appears to be a performance hotspot in profiles, we can look into
6496        * intrigate logic for keeping path, node and iter in sync like
6497        * we do for forward walks.  (Which will be hard because of the lacking
6498        * iter_prev).
6499        */
6500
6501       if (node == NULL)
6502         break;
6503
6504       gtk_tree_path_free (above_path);
6505       above_path = _gtk_tree_view_find_path (tree_view, tree, node);
6506
6507       gtk_tree_model_get_iter (tree_view->priv->model, &iter, above_path);
6508
6509       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6510           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6511         {
6512           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
6513           if (validate_row (tree_view, tree, node, &iter, above_path))
6514             size_changed = TRUE;
6515         }
6516       area_above -= gtk_tree_view_get_row_height (tree_view, node);
6517     }
6518
6519   /* if we scrolled to a path, we need to set the dy here,
6520    * and sync the top row accordingly
6521    */
6522   if (tree_view->priv->scroll_to_path)
6523     {
6524       gtk_tree_view_set_top_row (tree_view, above_path, -area_above);
6525       gtk_tree_view_top_row_to_dy (tree_view);
6526
6527       need_redraw = TRUE;
6528     }
6529   else if (tree_view->priv->height <= gtk_adjustment_get_page_size (tree_view->priv->vadjustment))
6530     {
6531       /* when we are not scrolling, we should never set dy to something
6532        * else than zero. we update top_row to be in sync with dy = 0.
6533        */
6534       gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
6535       gtk_tree_view_dy_to_top_row (tree_view);
6536     }
6537   else if (gtk_adjustment_get_value (tree_view->priv->vadjustment) + gtk_adjustment_get_page_size (tree_view->priv->vadjustment) > tree_view->priv->height)
6538     {
6539       gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), tree_view->priv->height - gtk_adjustment_get_page_size (tree_view->priv->vadjustment));
6540       gtk_tree_view_dy_to_top_row (tree_view);
6541     }
6542   else
6543     gtk_tree_view_top_row_to_dy (tree_view);
6544
6545   /* update width/height and queue a resize */
6546   if (size_changed)
6547     {
6548       GtkRequisition requisition;
6549
6550       /* We temporarily guess a size, under the assumption that it will be the
6551        * same when we get our next size_allocate.  If we don't do this, we'll be
6552        * in an inconsistent state if we call top_row_to_dy. */
6553
6554       gtk_widget_get_preferred_size (GTK_WIDGET (tree_view),
6555                                      &requisition, NULL);
6556       gtk_adjustment_set_upper (tree_view->priv->hadjustment,
6557                                 MAX (gtk_adjustment_get_upper (tree_view->priv->hadjustment), requisition.width));
6558       gtk_adjustment_set_upper (tree_view->priv->vadjustment,
6559                                 MAX (gtk_adjustment_get_upper (tree_view->priv->vadjustment), requisition.height));
6560       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6561     }
6562
6563   if (tree_view->priv->scroll_to_path)
6564     {
6565       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
6566       tree_view->priv->scroll_to_path = NULL;
6567     }
6568
6569   if (above_path)
6570     gtk_tree_path_free (above_path);
6571
6572   if (tree_view->priv->scroll_to_column)
6573     {
6574       tree_view->priv->scroll_to_column = NULL;
6575     }
6576   if (need_redraw)
6577     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
6578 }
6579
6580 static void
6581 initialize_fixed_height_mode (GtkTreeView *tree_view)
6582 {
6583   if (!tree_view->priv->tree)
6584     return;
6585
6586   if (tree_view->priv->fixed_height < 0)
6587     {
6588       GtkTreeIter iter;
6589       GtkTreePath *path;
6590
6591       GtkRBTree *tree = NULL;
6592       GtkRBNode *node = NULL;
6593
6594       tree = tree_view->priv->tree;
6595       node = tree->root;
6596
6597       path = _gtk_tree_view_find_path (tree_view, tree, node);
6598       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6599
6600       validate_row (tree_view, tree, node, &iter, path);
6601
6602       gtk_tree_path_free (path);
6603
6604       tree_view->priv->fixed_height = gtk_tree_view_get_row_height (tree_view, node);
6605     }
6606
6607    _gtk_rbtree_set_fixed_height (tree_view->priv->tree,
6608                                  tree_view->priv->fixed_height, TRUE);
6609 }
6610
6611 /* Our strategy for finding nodes to validate is a little convoluted.  We find
6612  * the left-most uninvalidated node.  We then try walking right, validating
6613  * nodes.  Once we find a valid node, we repeat the previous process of finding
6614  * the first invalid node.
6615  */
6616
6617 static gboolean
6618 do_validate_rows (GtkTreeView *tree_view, gboolean queue_resize)
6619 {
6620   GtkRBTree *tree = NULL;
6621   GtkRBNode *node = NULL;
6622   gboolean validated_area = FALSE;
6623   gint retval = TRUE;
6624   GtkTreePath *path = NULL;
6625   GtkTreeIter iter;
6626   GTimer *timer;
6627   gint i = 0;
6628
6629   gint prev_height = -1;
6630   gboolean fixed_height = TRUE;
6631
6632   g_assert (tree_view);
6633
6634   if (tree_view->priv->tree == NULL)
6635       return FALSE;
6636
6637   if (tree_view->priv->fixed_height_mode)
6638     {
6639       if (tree_view->priv->fixed_height < 0)
6640         initialize_fixed_height_mode (tree_view);
6641
6642       return FALSE;
6643     }
6644
6645   timer = g_timer_new ();
6646   g_timer_start (timer);
6647
6648   do
6649     {
6650       if (! GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID))
6651         {
6652           retval = FALSE;
6653           goto done;
6654         }
6655
6656       if (path != NULL)
6657         {
6658           node = _gtk_rbtree_next (tree, node);
6659           if (node != NULL)
6660             {
6661               TREE_VIEW_INTERNAL_ASSERT (gtk_tree_model_iter_next (tree_view->priv->model, &iter), FALSE);
6662               gtk_tree_path_next (path);
6663             }
6664           else
6665             {
6666               gtk_tree_path_free (path);
6667               path = NULL;
6668             }
6669         }
6670
6671       if (path == NULL)
6672         {
6673           tree = tree_view->priv->tree;
6674           node = tree_view->priv->tree->root;
6675
6676           g_assert (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_DESCENDANTS_INVALID));
6677
6678           do
6679             {
6680               if (node->left != tree->nil &&
6681                   GTK_RBNODE_FLAG_SET (node->left, GTK_RBNODE_DESCENDANTS_INVALID))
6682                 {
6683                   node = node->left;
6684                 }
6685               else if (node->right != tree->nil &&
6686                        GTK_RBNODE_FLAG_SET (node->right, GTK_RBNODE_DESCENDANTS_INVALID))
6687                 {
6688                   node = node->right;
6689                 }
6690               else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6691                        GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6692                 {
6693                   break;
6694                 }
6695               else if (node->children != NULL)
6696                 {
6697                   tree = node->children;
6698                   node = tree->root;
6699                 }
6700               else
6701                 /* RBTree corruption!  All bad */
6702                 g_assert_not_reached ();
6703             }
6704           while (TRUE);
6705           path = _gtk_tree_view_find_path (tree_view, tree, node);
6706           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6707         }
6708
6709       validated_area = validate_row (tree_view, tree, node, &iter, path) ||
6710                        validated_area;
6711
6712       if (!tree_view->priv->fixed_height_check)
6713         {
6714           gint height;
6715
6716           height = gtk_tree_view_get_row_height (tree_view, node);
6717           if (prev_height < 0)
6718             prev_height = height;
6719           else if (prev_height != height)
6720             fixed_height = FALSE;
6721         }
6722
6723       i++;
6724     }
6725   while (g_timer_elapsed (timer, NULL) < GTK_TREE_VIEW_TIME_MS_PER_IDLE / 1000.);
6726
6727   if (!tree_view->priv->fixed_height_check)
6728    {
6729      if (fixed_height)
6730        _gtk_rbtree_set_fixed_height (tree_view->priv->tree, prev_height, FALSE);
6731
6732      tree_view->priv->fixed_height_check = 1;
6733    }
6734   
6735  done:
6736   if (validated_area)
6737     {
6738       GtkRequisition requisition;
6739
6740       /* We temporarily guess a size, under the assumption that it will be the
6741        * same when we get our next size_allocate.  If we don't do this, we'll be
6742        * in an inconsistent state when we call top_row_to_dy. */
6743
6744       /* FIXME: This is called from size_request, for some reason it is not infinitely
6745        * recursing, we cannot call gtk_widget_get_preferred_size() here because that's
6746        * not allowed (from inside ->get_preferred_width/height() implementations, one
6747        * should call the vfuncs directly). However what is desired here is the full
6748        * size including any margins and limited by any alignment (i.e. after 
6749        * GtkWidget:adjust_size_request() is called).
6750        *
6751        * Currently bypassing this but the real solution is to not update the scroll adjustments
6752        * untill we've recieved an allocation (never update scroll adjustments from size-requests).
6753        */
6754       gtk_tree_view_size_request (GTK_WIDGET (tree_view), &requisition, FALSE);
6755
6756       gtk_adjustment_set_upper (tree_view->priv->hadjustment,
6757                                 MAX (gtk_adjustment_get_upper (tree_view->priv->hadjustment), requisition.width));
6758       gtk_adjustment_set_upper (tree_view->priv->vadjustment,
6759                                 MAX (gtk_adjustment_get_upper (tree_view->priv->vadjustment), requisition.height));
6760
6761       if (queue_resize)
6762         gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6763     }
6764
6765   if (path) gtk_tree_path_free (path);
6766   g_timer_destroy (timer);
6767
6768   return retval;
6769 }
6770
6771 static gboolean
6772 validate_rows (GtkTreeView *tree_view)
6773 {
6774   gboolean retval;
6775   
6776   retval = do_validate_rows (tree_view, TRUE);
6777   
6778   if (! retval && tree_view->priv->validate_rows_timer)
6779     {
6780       g_source_remove (tree_view->priv->validate_rows_timer);
6781       tree_view->priv->validate_rows_timer = 0;
6782     }
6783
6784   return retval;
6785 }
6786
6787 static gboolean
6788 validate_rows_handler (GtkTreeView *tree_view)
6789 {
6790   gboolean retval;
6791
6792   retval = do_validate_rows (tree_view, TRUE);
6793   if (! retval && tree_view->priv->validate_rows_timer)
6794     {
6795       g_source_remove (tree_view->priv->validate_rows_timer);
6796       tree_view->priv->validate_rows_timer = 0;
6797     }
6798
6799   return retval;
6800 }
6801
6802 static gboolean
6803 do_presize_handler (GtkTreeView *tree_view)
6804 {
6805   if (tree_view->priv->mark_rows_col_dirty)
6806     {
6807       if (tree_view->priv->tree)
6808         _gtk_rbtree_column_invalid (tree_view->priv->tree);
6809       tree_view->priv->mark_rows_col_dirty = FALSE;
6810     }
6811   validate_visible_area (tree_view);
6812   tree_view->priv->presize_handler_timer = 0;
6813
6814   if (tree_view->priv->fixed_height_mode)
6815     {
6816       GtkRequisition requisition;
6817
6818       gtk_widget_get_preferred_size (GTK_WIDGET (tree_view),
6819                                      &requisition, NULL);
6820
6821       gtk_adjustment_set_upper (tree_view->priv->hadjustment,
6822                                 MAX (gtk_adjustment_get_upper (tree_view->priv->hadjustment), requisition.width));
6823       gtk_adjustment_set_upper (tree_view->priv->vadjustment,
6824                                 MAX (gtk_adjustment_get_upper (tree_view->priv->vadjustment), requisition.height));
6825       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6826     }
6827                    
6828   return FALSE;
6829 }
6830
6831 static gboolean
6832 presize_handler_callback (gpointer data)
6833 {
6834   do_presize_handler (GTK_TREE_VIEW (data));
6835                    
6836   return FALSE;
6837 }
6838
6839 static void
6840 install_presize_handler (GtkTreeView *tree_view)
6841 {
6842   if (! gtk_widget_get_realized (GTK_WIDGET (tree_view)))
6843     return;
6844
6845   if (! tree_view->priv->presize_handler_timer)
6846     {
6847       tree_view->priv->presize_handler_timer =
6848         gdk_threads_add_idle_full (GTK_PRIORITY_RESIZE - 2, presize_handler_callback, tree_view, NULL);
6849     }
6850   if (! tree_view->priv->validate_rows_timer)
6851     {
6852       tree_view->priv->validate_rows_timer =
6853         gdk_threads_add_idle_full (GTK_TREE_VIEW_PRIORITY_VALIDATE, (GSourceFunc) validate_rows_handler, tree_view, NULL);
6854     }
6855 }
6856
6857 static void
6858 gtk_tree_view_bin_process_updates (GtkTreeView *tree_view)
6859 {
6860   /* Prior to drawing, we make sure the visible area is validated. */
6861   if (tree_view->priv->presize_handler_timer)
6862     {
6863       g_source_remove (tree_view->priv->presize_handler_timer);
6864       tree_view->priv->presize_handler_timer = 0;
6865
6866       do_presize_handler (tree_view);
6867     }
6868
6869   gdk_window_process_updates (tree_view->priv->bin_window, TRUE);
6870 }
6871
6872 static gboolean
6873 scroll_sync_handler (GtkTreeView *tree_view)
6874 {
6875   if (tree_view->priv->height <= gtk_adjustment_get_page_size (tree_view->priv->vadjustment))
6876     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
6877   else if (gtk_tree_row_reference_valid (tree_view->priv->top_row))
6878     gtk_tree_view_top_row_to_dy (tree_view);
6879   else
6880     gtk_tree_view_dy_to_top_row (tree_view);
6881
6882   tree_view->priv->scroll_sync_timer = 0;
6883
6884   return FALSE;
6885 }
6886
6887 static void
6888 install_scroll_sync_handler (GtkTreeView *tree_view)
6889 {
6890   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
6891     return;
6892
6893   if (!tree_view->priv->scroll_sync_timer)
6894     {
6895       tree_view->priv->scroll_sync_timer =
6896         gdk_threads_add_idle_full (GTK_TREE_VIEW_PRIORITY_SCROLL_SYNC, (GSourceFunc) scroll_sync_handler, tree_view, NULL);
6897     }
6898 }
6899
6900 static void
6901 gtk_tree_view_set_top_row (GtkTreeView *tree_view,
6902                            GtkTreePath *path,
6903                            gint         offset)
6904 {
6905   gtk_tree_row_reference_free (tree_view->priv->top_row);
6906
6907   if (!path)
6908     {
6909       tree_view->priv->top_row = NULL;
6910       tree_view->priv->top_row_dy = 0;
6911     }
6912   else
6913     {
6914       tree_view->priv->top_row = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
6915       tree_view->priv->top_row_dy = offset;
6916     }
6917 }
6918
6919 /* Always call this iff dy is in the visible range.  If the tree is empty, then
6920  * it's set to be NULL, and top_row_dy is 0;
6921  */
6922 static void
6923 gtk_tree_view_dy_to_top_row (GtkTreeView *tree_view)
6924 {
6925   gint offset;
6926   GtkTreePath *path;
6927   GtkRBTree *tree;
6928   GtkRBNode *node;
6929
6930   if (tree_view->priv->tree == NULL)
6931     {
6932       gtk_tree_view_set_top_row (tree_view, NULL, 0);
6933     }
6934   else
6935     {
6936       offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
6937                                         tree_view->priv->dy,
6938                                         &tree, &node);
6939
6940       if (tree == NULL)
6941         {
6942           gtk_tree_view_set_top_row (tree_view, NULL, 0);
6943         }
6944       else
6945         {
6946           path = _gtk_tree_view_find_path (tree_view, tree, node);
6947           gtk_tree_view_set_top_row (tree_view, path, offset);
6948           gtk_tree_path_free (path);
6949         }
6950     }
6951 }
6952
6953 static void
6954 gtk_tree_view_top_row_to_dy (GtkTreeView *tree_view)
6955 {
6956   GtkTreePath *path;
6957   GtkRBTree *tree;
6958   GtkRBNode *node;
6959   int new_dy;
6960
6961   /* Avoid recursive calls */
6962   if (tree_view->priv->in_top_row_to_dy)
6963     return;
6964
6965   if (tree_view->priv->top_row)
6966     path = gtk_tree_row_reference_get_path (tree_view->priv->top_row);
6967   else
6968     path = NULL;
6969
6970   if (!path)
6971     tree = NULL;
6972   else
6973     _gtk_tree_view_find_node (tree_view, path, &tree, &node);
6974
6975   if (path)
6976     gtk_tree_path_free (path);
6977
6978   if (tree == NULL)
6979     {
6980       /* keep dy and set new toprow */
6981       gtk_tree_row_reference_free (tree_view->priv->top_row);
6982       tree_view->priv->top_row = NULL;
6983       tree_view->priv->top_row_dy = 0;
6984       /* DO NOT install the idle handler */
6985       gtk_tree_view_dy_to_top_row (tree_view);
6986       return;
6987     }
6988
6989   if (gtk_tree_view_get_row_height (tree_view, node)
6990       < tree_view->priv->top_row_dy)
6991     {
6992       /* new top row -- do NOT install the idle handler */
6993       gtk_tree_view_dy_to_top_row (tree_view);
6994       return;
6995     }
6996
6997   new_dy = _gtk_rbtree_node_find_offset (tree, node);
6998   new_dy += tree_view->priv->top_row_dy;
6999
7000   if (new_dy + gtk_adjustment_get_page_size (tree_view->priv->vadjustment) > tree_view->priv->height)
7001     new_dy = tree_view->priv->height - gtk_adjustment_get_page_size (tree_view->priv->vadjustment);
7002
7003   new_dy = MAX (0, new_dy);
7004
7005   tree_view->priv->in_top_row_to_dy = TRUE;
7006   gtk_adjustment_set_value (tree_view->priv->vadjustment, (gdouble)new_dy);
7007   tree_view->priv->in_top_row_to_dy = FALSE;
7008 }
7009
7010
7011 void
7012 _gtk_tree_view_install_mark_rows_col_dirty (GtkTreeView *tree_view,
7013                                             gboolean     install_handler)
7014 {
7015   tree_view->priv->mark_rows_col_dirty = TRUE;
7016
7017   if (install_handler)
7018     install_presize_handler (tree_view);
7019 }
7020
7021 /*
7022  * This function works synchronously (due to the while (validate_rows...)
7023  * loop).
7024  *
7025  * There was a check for column_type != GTK_TREE_VIEW_COLUMN_AUTOSIZE
7026  * here. You now need to check that yourself.
7027  */
7028 void
7029 _gtk_tree_view_column_autosize (GtkTreeView *tree_view,
7030                                 GtkTreeViewColumn *column)
7031 {
7032   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7033   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (column));
7034
7035   _gtk_tree_view_column_cell_set_dirty (column, FALSE);
7036
7037   do_presize_handler (tree_view);
7038   while (validate_rows (tree_view));
7039
7040   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
7041 }
7042
7043 /* Drag-and-drop */
7044
7045 static void
7046 set_source_row (GdkDragContext *context,
7047                 GtkTreeModel   *model,
7048                 GtkTreePath    *source_row)
7049 {
7050   g_object_set_data_full (G_OBJECT (context),
7051                           I_("gtk-tree-view-source-row"),
7052                           source_row ? gtk_tree_row_reference_new (model, source_row) : NULL,
7053                           (GDestroyNotify) (source_row ? gtk_tree_row_reference_free : NULL));
7054 }
7055
7056 static GtkTreePath*
7057 get_source_row (GdkDragContext *context)
7058 {
7059   GtkTreeRowReference *ref =
7060     g_object_get_data (G_OBJECT (context), "gtk-tree-view-source-row");
7061
7062   if (ref)
7063     return gtk_tree_row_reference_get_path (ref);
7064   else
7065     return NULL;
7066 }
7067
7068 typedef struct
7069 {
7070   GtkTreeRowReference *dest_row;
7071   guint                path_down_mode   : 1;
7072   guint                empty_view_drop  : 1;
7073   guint                drop_append_mode : 1;
7074 }
7075 DestRow;
7076
7077 static void
7078 dest_row_free (gpointer data)
7079 {
7080   DestRow *dr = (DestRow *)data;
7081
7082   gtk_tree_row_reference_free (dr->dest_row);
7083   g_slice_free (DestRow, dr);
7084 }
7085
7086 static void
7087 set_dest_row (GdkDragContext *context,
7088               GtkTreeModel   *model,
7089               GtkTreePath    *dest_row,
7090               gboolean        path_down_mode,
7091               gboolean        empty_view_drop,
7092               gboolean        drop_append_mode)
7093 {
7094   DestRow *dr;
7095
7096   if (!dest_row)
7097     {
7098       g_object_set_data_full (G_OBJECT (context), I_("gtk-tree-view-dest-row"),
7099                               NULL, NULL);
7100       return;
7101     }
7102
7103   dr = g_slice_new (DestRow);
7104
7105   dr->dest_row = gtk_tree_row_reference_new (model, dest_row);
7106   dr->path_down_mode = path_down_mode != FALSE;
7107   dr->empty_view_drop = empty_view_drop != FALSE;
7108   dr->drop_append_mode = drop_append_mode != FALSE;
7109
7110   g_object_set_data_full (G_OBJECT (context), I_("gtk-tree-view-dest-row"),
7111                           dr, (GDestroyNotify) dest_row_free);
7112 }
7113
7114 static GtkTreePath*
7115 get_dest_row (GdkDragContext *context,
7116               gboolean       *path_down_mode)
7117 {
7118   DestRow *dr =
7119     g_object_get_data (G_OBJECT (context), "gtk-tree-view-dest-row");
7120
7121   if (dr)
7122     {
7123       GtkTreePath *path = NULL;
7124
7125       if (path_down_mode)
7126         *path_down_mode = dr->path_down_mode;
7127
7128       if (dr->dest_row)
7129         path = gtk_tree_row_reference_get_path (dr->dest_row);
7130       else if (dr->empty_view_drop)
7131         path = gtk_tree_path_new_from_indices (0, -1);
7132       else
7133         path = NULL;
7134
7135       if (path && dr->drop_append_mode)
7136         gtk_tree_path_next (path);
7137
7138       return path;
7139     }
7140   else
7141     return NULL;
7142 }
7143
7144 /* Get/set whether drag_motion requested the drag data and
7145  * drag_data_received should thus not actually insert the data,
7146  * since the data doesn't result from a drop.
7147  */
7148 static void
7149 set_status_pending (GdkDragContext *context,
7150                     GdkDragAction   suggested_action)
7151 {
7152   g_object_set_data (G_OBJECT (context),
7153                      I_("gtk-tree-view-status-pending"),
7154                      GINT_TO_POINTER (suggested_action));
7155 }
7156
7157 static GdkDragAction
7158 get_status_pending (GdkDragContext *context)
7159 {
7160   return GPOINTER_TO_INT (g_object_get_data (G_OBJECT (context),
7161                                              "gtk-tree-view-status-pending"));
7162 }
7163
7164 static TreeViewDragInfo*
7165 get_info (GtkTreeView *tree_view)
7166 {
7167   return g_object_get_data (G_OBJECT (tree_view), "gtk-tree-view-drag-info");
7168 }
7169
7170 static void
7171 destroy_info (TreeViewDragInfo *di)
7172 {
7173   g_slice_free (TreeViewDragInfo, di);
7174 }
7175
7176 static TreeViewDragInfo*
7177 ensure_info (GtkTreeView *tree_view)
7178 {
7179   TreeViewDragInfo *di;
7180
7181   di = get_info (tree_view);
7182
7183   if (di == NULL)
7184     {
7185       di = g_slice_new0 (TreeViewDragInfo);
7186
7187       g_object_set_data_full (G_OBJECT (tree_view),
7188                               I_("gtk-tree-view-drag-info"),
7189                               di,
7190                               (GDestroyNotify) destroy_info);
7191     }
7192
7193   return di;
7194 }
7195
7196 static void
7197 remove_info (GtkTreeView *tree_view)
7198 {
7199   g_object_set_data (G_OBJECT (tree_view), I_("gtk-tree-view-drag-info"), NULL);
7200 }
7201
7202 #if 0
7203 static gint
7204 drag_scan_timeout (gpointer data)
7205 {
7206   GtkTreeView *tree_view;
7207   gint x, y;
7208   GdkModifierType state;
7209   GtkTreePath *path = NULL;
7210   GtkTreeViewColumn *column = NULL;
7211   GdkRectangle visible_rect;
7212
7213   GDK_THREADS_ENTER ();
7214
7215   tree_view = GTK_TREE_VIEW (data);
7216
7217   gdk_window_get_pointer (tree_view->priv->bin_window,
7218                           &x, &y, &state);
7219
7220   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
7221
7222   /* See if we are near the edge. */
7223   if ((x - visible_rect.x) < SCROLL_EDGE_SIZE ||
7224       (visible_rect.x + visible_rect.width - x) < SCROLL_EDGE_SIZE ||
7225       (y - visible_rect.y) < SCROLL_EDGE_SIZE ||
7226       (visible_rect.y + visible_rect.height - y) < SCROLL_EDGE_SIZE)
7227     {
7228       gtk_tree_view_get_path_at_pos (tree_view,
7229                                      tree_view->priv->bin_window,
7230                                      x, y,
7231                                      &path,
7232                                      &column,
7233                                      NULL,
7234                                      NULL);
7235
7236       if (path != NULL)
7237         {
7238           gtk_tree_view_scroll_to_cell (tree_view,
7239                                         path,
7240                                         column,
7241                                         TRUE,
7242                                         0.5, 0.5);
7243
7244           gtk_tree_path_free (path);
7245         }
7246     }
7247
7248   GDK_THREADS_LEAVE ();
7249
7250   return TRUE;
7251 }
7252 #endif /* 0 */
7253
7254 static void
7255 add_scroll_timeout (GtkTreeView *tree_view)
7256 {
7257   if (tree_view->priv->scroll_timeout == 0)
7258     {
7259       tree_view->priv->scroll_timeout =
7260         gdk_threads_add_timeout (150, scroll_row_timeout, tree_view);
7261     }
7262 }
7263
7264 static void
7265 remove_scroll_timeout (GtkTreeView *tree_view)
7266 {
7267   if (tree_view->priv->scroll_timeout != 0)
7268     {
7269       g_source_remove (tree_view->priv->scroll_timeout);
7270       tree_view->priv->scroll_timeout = 0;
7271     }
7272 }
7273
7274 static gboolean
7275 check_model_dnd (GtkTreeModel *model,
7276                  GType         required_iface,
7277                  const gchar  *signal)
7278 {
7279   if (model == NULL || !G_TYPE_CHECK_INSTANCE_TYPE ((model), required_iface))
7280     {
7281       g_warning ("You must override the default '%s' handler "
7282                  "on GtkTreeView when using models that don't support "
7283                  "the %s interface and enabling drag-and-drop. The simplest way to do this "
7284                  "is to connect to '%s' and call "
7285                  "g_signal_stop_emission_by_name() in your signal handler to prevent "
7286                  "the default handler from running. Look at the source code "
7287                  "for the default handler in gtktreeview.c to get an idea what "
7288                  "your handler should do. (gtktreeview.c is in the GTK source "
7289                  "code.) If you're using GTK from a language other than C, "
7290                  "there may be a more natural way to override default handlers, e.g. via derivation.",
7291                  signal, g_type_name (required_iface), signal);
7292       return FALSE;
7293     }
7294   else
7295     return TRUE;
7296 }
7297
7298 static void
7299 remove_open_timeout (GtkTreeView *tree_view)
7300 {
7301   if (tree_view->priv->open_dest_timeout != 0)
7302     {
7303       g_source_remove (tree_view->priv->open_dest_timeout);
7304       tree_view->priv->open_dest_timeout = 0;
7305     }
7306 }
7307
7308
7309 static gint
7310 open_row_timeout (gpointer data)
7311 {
7312   GtkTreeView *tree_view = data;
7313   GtkTreePath *dest_path = NULL;
7314   GtkTreeViewDropPosition pos;
7315   gboolean result = FALSE;
7316
7317   gtk_tree_view_get_drag_dest_row (tree_view,
7318                                    &dest_path,
7319                                    &pos);
7320
7321   if (dest_path &&
7322       (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
7323        pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
7324     {
7325       gtk_tree_view_expand_row (tree_view, dest_path, FALSE);
7326       tree_view->priv->open_dest_timeout = 0;
7327
7328       gtk_tree_path_free (dest_path);
7329     }
7330   else
7331     {
7332       if (dest_path)
7333         gtk_tree_path_free (dest_path);
7334
7335       result = TRUE;
7336     }
7337
7338   return result;
7339 }
7340
7341 static gboolean
7342 scroll_row_timeout (gpointer data)
7343 {
7344   GtkTreeView *tree_view = data;
7345
7346   gtk_tree_view_vertical_autoscroll (tree_view);
7347
7348   if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
7349     gtk_tree_view_update_rubber_band (tree_view);
7350
7351   return TRUE;
7352 }
7353
7354 /* Returns TRUE if event should not be propagated to parent widgets */
7355 static gboolean
7356 set_destination_row (GtkTreeView    *tree_view,
7357                      GdkDragContext *context,
7358                      /* coordinates relative to the widget */
7359                      gint            x,
7360                      gint            y,
7361                      GdkDragAction  *suggested_action,
7362                      GdkAtom        *target)
7363 {
7364   GtkTreePath *path = NULL;
7365   GtkTreeViewDropPosition pos;
7366   GtkTreeViewDropPosition old_pos;
7367   TreeViewDragInfo *di;
7368   GtkWidget *widget;
7369   GtkTreePath *old_dest_path = NULL;
7370   gboolean can_drop = FALSE;
7371
7372   *suggested_action = 0;
7373   *target = GDK_NONE;
7374
7375   widget = GTK_WIDGET (tree_view);
7376
7377   di = get_info (tree_view);
7378
7379   if (di == NULL || y - gtk_tree_view_get_effective_header_height (tree_view) < 0)
7380     {
7381       /* someone unset us as a drag dest, note that if
7382        * we return FALSE drag_leave isn't called
7383        */
7384
7385       gtk_tree_view_set_drag_dest_row (tree_view,
7386                                        NULL,
7387                                        GTK_TREE_VIEW_DROP_BEFORE);
7388
7389       remove_scroll_timeout (GTK_TREE_VIEW (widget));
7390       remove_open_timeout (GTK_TREE_VIEW (widget));
7391
7392       return FALSE; /* no longer a drop site */
7393     }
7394
7395   *target = gtk_drag_dest_find_target (widget, context,
7396                                        gtk_drag_dest_get_target_list (widget));
7397   if (*target == GDK_NONE)
7398     {
7399       return FALSE;
7400     }
7401
7402   if (!gtk_tree_view_get_dest_row_at_pos (tree_view,
7403                                           x, y,
7404                                           &path,
7405                                           &pos))
7406     {
7407       gint n_children;
7408       GtkTreeModel *model;
7409
7410       remove_open_timeout (tree_view);
7411
7412       /* the row got dropped on empty space, let's setup a special case
7413        */
7414
7415       if (path)
7416         gtk_tree_path_free (path);
7417
7418       model = gtk_tree_view_get_model (tree_view);
7419
7420       n_children = gtk_tree_model_iter_n_children (model, NULL);
7421       if (n_children)
7422         {
7423           pos = GTK_TREE_VIEW_DROP_AFTER;
7424           path = gtk_tree_path_new_from_indices (n_children - 1, -1);
7425         }
7426       else
7427         {
7428           pos = GTK_TREE_VIEW_DROP_BEFORE;
7429           path = gtk_tree_path_new_from_indices (0, -1);
7430         }
7431
7432       can_drop = TRUE;
7433
7434       goto out;
7435     }
7436
7437   g_assert (path);
7438
7439   /* If we left the current row's "open" zone, unset the timeout for
7440    * opening the row
7441    */
7442   gtk_tree_view_get_drag_dest_row (tree_view,
7443                                    &old_dest_path,
7444                                    &old_pos);
7445
7446   if (old_dest_path &&
7447       (gtk_tree_path_compare (path, old_dest_path) != 0 ||
7448        !(pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
7449          pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE)))
7450     remove_open_timeout (tree_view);
7451
7452   if (old_dest_path)
7453     gtk_tree_path_free (old_dest_path);
7454
7455   if (TRUE /* FIXME if the location droppable predicate */)
7456     {
7457       can_drop = TRUE;
7458     }
7459
7460 out:
7461   if (can_drop)
7462     {
7463       GtkWidget *source_widget;
7464
7465       *suggested_action = gdk_drag_context_get_suggested_action (context);
7466       source_widget = gtk_drag_get_source_widget (context);
7467
7468       if (source_widget == widget)
7469         {
7470           /* Default to MOVE, unless the user has
7471            * pressed ctrl or shift to affect available actions
7472            */
7473           if ((gdk_drag_context_get_actions (context) & GDK_ACTION_MOVE) != 0)
7474             *suggested_action = GDK_ACTION_MOVE;
7475         }
7476
7477       gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7478                                        path, pos);
7479     }
7480   else
7481     {
7482       /* can't drop here */
7483       remove_open_timeout (tree_view);
7484
7485       gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7486                                        NULL,
7487                                        GTK_TREE_VIEW_DROP_BEFORE);
7488     }
7489
7490   if (path)
7491     gtk_tree_path_free (path);
7492
7493   return TRUE;
7494 }
7495
7496 static GtkTreePath*
7497 get_logical_dest_row (GtkTreeView *tree_view,
7498                       gboolean    *path_down_mode,
7499                       gboolean    *drop_append_mode)
7500 {
7501   /* adjust path to point to the row the drop goes in front of */
7502   GtkTreePath *path = NULL;
7503   GtkTreeViewDropPosition pos;
7504
7505   g_return_val_if_fail (path_down_mode != NULL, NULL);
7506   g_return_val_if_fail (drop_append_mode != NULL, NULL);
7507
7508   *path_down_mode = FALSE;
7509   *drop_append_mode = 0;
7510
7511   gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
7512
7513   if (path == NULL)
7514     return NULL;
7515
7516   if (pos == GTK_TREE_VIEW_DROP_BEFORE)
7517     ; /* do nothing */
7518   else if (pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE ||
7519            pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER)
7520     *path_down_mode = TRUE;
7521   else
7522     {
7523       GtkTreeIter iter;
7524       GtkTreeModel *model = gtk_tree_view_get_model (tree_view);
7525
7526       g_assert (pos == GTK_TREE_VIEW_DROP_AFTER);
7527
7528       if (!gtk_tree_model_get_iter (model, &iter, path) ||
7529           !gtk_tree_model_iter_next (model, &iter))
7530         *drop_append_mode = 1;
7531       else
7532         {
7533           *drop_append_mode = 0;
7534           gtk_tree_path_next (path);
7535         }
7536     }
7537
7538   return path;
7539 }
7540
7541 static gboolean
7542 gtk_tree_view_maybe_begin_dragging_row (GtkTreeView      *tree_view,
7543                                         GdkEventMotion   *event)
7544 {
7545   GtkWidget *widget = GTK_WIDGET (tree_view);
7546   GdkDragContext *context;
7547   TreeViewDragInfo *di;
7548   GtkTreePath *path = NULL;
7549   gint button;
7550   gint cell_x, cell_y;
7551   GtkTreeModel *model;
7552   gboolean retval = FALSE;
7553
7554   di = get_info (tree_view);
7555
7556   if (di == NULL || !di->source_set)
7557     goto out;
7558
7559   if (tree_view->priv->pressed_button < 0)
7560     goto out;
7561
7562   if (!gtk_drag_check_threshold (widget,
7563                                  tree_view->priv->press_start_x,
7564                                  tree_view->priv->press_start_y,
7565                                  event->x, event->y))
7566     goto out;
7567
7568   model = gtk_tree_view_get_model (tree_view);
7569
7570   if (model == NULL)
7571     goto out;
7572
7573   button = tree_view->priv->pressed_button;
7574   tree_view->priv->pressed_button = -1;
7575
7576   gtk_tree_view_get_path_at_pos (tree_view,
7577                                  tree_view->priv->press_start_x,
7578                                  tree_view->priv->press_start_y,
7579                                  &path,
7580                                  NULL,
7581                                  &cell_x,
7582                                  &cell_y);
7583
7584   if (path == NULL)
7585     goto out;
7586
7587   if (!GTK_IS_TREE_DRAG_SOURCE (model) ||
7588       !gtk_tree_drag_source_row_draggable (GTK_TREE_DRAG_SOURCE (model),
7589                                            path))
7590     goto out;
7591
7592   if (!(GDK_BUTTON1_MASK << (button - 1) & di->start_button_mask))
7593     goto out;
7594
7595   /* Now we can begin the drag */
7596
7597   retval = TRUE;
7598
7599   context = gtk_drag_begin (widget,
7600                             gtk_drag_source_get_target_list (widget),
7601                             di->source_actions,
7602                             button,
7603                             (GdkEvent*)event);
7604
7605   set_source_row (context, model, path);
7606
7607  out:
7608   if (path)
7609     gtk_tree_path_free (path);
7610
7611   return retval;
7612 }
7613
7614
7615 static void
7616 gtk_tree_view_drag_begin (GtkWidget      *widget,
7617                           GdkDragContext *context)
7618 {
7619   GtkTreeView *tree_view;
7620   GtkTreePath *path = NULL;
7621   gint cell_x, cell_y;
7622   cairo_surface_t *row_pix;
7623   TreeViewDragInfo *di;
7624
7625   tree_view = GTK_TREE_VIEW (widget);
7626
7627   /* if the user uses a custom DND source impl, we don't set the icon here */
7628   di = get_info (tree_view);
7629
7630   if (di == NULL || !di->source_set)
7631     return;
7632
7633   gtk_tree_view_get_path_at_pos (tree_view,
7634                                  tree_view->priv->press_start_x,
7635                                  tree_view->priv->press_start_y,
7636                                  &path,
7637                                  NULL,
7638                                  &cell_x,
7639                                  &cell_y);
7640
7641   g_return_if_fail (path != NULL);
7642
7643   row_pix = gtk_tree_view_create_row_drag_icon (tree_view,
7644                                                 path);
7645   cairo_surface_set_device_offset (row_pix,
7646                                    /* the + 1 is for the black border in the icon */
7647                                    - (tree_view->priv->press_start_x + 1),
7648                                    - (cell_y + 1));
7649
7650   gtk_drag_set_icon_surface (context, row_pix);
7651
7652   cairo_surface_destroy (row_pix);
7653   gtk_tree_path_free (path);
7654 }
7655
7656 static void
7657 gtk_tree_view_drag_end (GtkWidget      *widget,
7658                         GdkDragContext *context)
7659 {
7660   /* do nothing */
7661 }
7662
7663 /* Default signal implementations for the drag signals */
7664 static void
7665 gtk_tree_view_drag_data_get (GtkWidget        *widget,
7666                              GdkDragContext   *context,
7667                              GtkSelectionData *selection_data,
7668                              guint             info,
7669                              guint             time)
7670 {
7671   GtkTreeView *tree_view;
7672   GtkTreeModel *model;
7673   TreeViewDragInfo *di;
7674   GtkTreePath *source_row;
7675
7676   tree_view = GTK_TREE_VIEW (widget);
7677
7678   model = gtk_tree_view_get_model (tree_view);
7679
7680   if (model == NULL)
7681     return;
7682
7683   di = get_info (GTK_TREE_VIEW (widget));
7684
7685   if (di == NULL)
7686     return;
7687
7688   source_row = get_source_row (context);
7689
7690   if (source_row == NULL)
7691     return;
7692
7693   /* We can implement the GTK_TREE_MODEL_ROW target generically for
7694    * any model; for DragSource models there are some other targets
7695    * we also support.
7696    */
7697
7698   if (GTK_IS_TREE_DRAG_SOURCE (model) &&
7699       gtk_tree_drag_source_drag_data_get (GTK_TREE_DRAG_SOURCE (model),
7700                                           source_row,
7701                                           selection_data))
7702     goto done;
7703
7704   /* If drag_data_get does nothing, try providing row data. */
7705   if (gtk_selection_data_get_target (selection_data) == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
7706     {
7707       gtk_tree_set_row_drag_data (selection_data,
7708                                   model,
7709                                   source_row);
7710     }
7711
7712  done:
7713   gtk_tree_path_free (source_row);
7714 }
7715
7716
7717 static void
7718 gtk_tree_view_drag_data_delete (GtkWidget      *widget,
7719                                 GdkDragContext *context)
7720 {
7721   TreeViewDragInfo *di;
7722   GtkTreeModel *model;
7723   GtkTreeView *tree_view;
7724   GtkTreePath *source_row;
7725
7726   tree_view = GTK_TREE_VIEW (widget);
7727   model = gtk_tree_view_get_model (tree_view);
7728
7729   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_SOURCE, "drag_data_delete"))
7730     return;
7731
7732   di = get_info (tree_view);
7733
7734   if (di == NULL)
7735     return;
7736
7737   source_row = get_source_row (context);
7738
7739   if (source_row == NULL)
7740     return;
7741
7742   gtk_tree_drag_source_drag_data_delete (GTK_TREE_DRAG_SOURCE (model),
7743                                          source_row);
7744
7745   gtk_tree_path_free (source_row);
7746
7747   set_source_row (context, NULL, NULL);
7748 }
7749
7750 static void
7751 gtk_tree_view_drag_leave (GtkWidget      *widget,
7752                           GdkDragContext *context,
7753                           guint             time)
7754 {
7755   /* unset any highlight row */
7756   gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7757                                    NULL,
7758                                    GTK_TREE_VIEW_DROP_BEFORE);
7759
7760   remove_scroll_timeout (GTK_TREE_VIEW (widget));
7761   remove_open_timeout (GTK_TREE_VIEW (widget));
7762 }
7763
7764
7765 static gboolean
7766 gtk_tree_view_drag_motion (GtkWidget        *widget,
7767                            GdkDragContext   *context,
7768                            /* coordinates relative to the widget */
7769                            gint              x,
7770                            gint              y,
7771                            guint             time)
7772 {
7773   gboolean empty;
7774   GtkTreePath *path = NULL;
7775   GtkTreeViewDropPosition pos;
7776   GtkTreeView *tree_view;
7777   GdkDragAction suggested_action = 0;
7778   GdkAtom target;
7779
7780   tree_view = GTK_TREE_VIEW (widget);
7781
7782   if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
7783     return FALSE;
7784
7785   gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
7786
7787   /* we only know this *after* set_desination_row */
7788   empty = tree_view->priv->empty_view_drop;
7789
7790   if (path == NULL && !empty)
7791     {
7792       /* Can't drop here. */
7793       gdk_drag_status (context, 0, time);
7794     }
7795   else
7796     {
7797       if (tree_view->priv->open_dest_timeout == 0 &&
7798           (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
7799            pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
7800         {
7801           tree_view->priv->open_dest_timeout =
7802             gdk_threads_add_timeout (AUTO_EXPAND_TIMEOUT, open_row_timeout, tree_view);
7803         }
7804       else
7805         {
7806           add_scroll_timeout (tree_view);
7807         }
7808
7809       if (target == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
7810         {
7811           /* Request data so we can use the source row when
7812            * determining whether to accept the drop
7813            */
7814           set_status_pending (context, suggested_action);
7815           gtk_drag_get_data (widget, context, target, time);
7816         }
7817       else
7818         {
7819           set_status_pending (context, 0);
7820           gdk_drag_status (context, suggested_action, time);
7821         }
7822     }
7823
7824   if (path)
7825     gtk_tree_path_free (path);
7826
7827   return TRUE;
7828 }
7829
7830
7831 static gboolean
7832 gtk_tree_view_drag_drop (GtkWidget        *widget,
7833                          GdkDragContext   *context,
7834                          /* coordinates relative to the widget */
7835                          gint              x,
7836                          gint              y,
7837                          guint             time)
7838 {
7839   GtkTreeView *tree_view;
7840   GtkTreePath *path;
7841   GdkDragAction suggested_action = 0;
7842   GdkAtom target = GDK_NONE;
7843   TreeViewDragInfo *di;
7844   GtkTreeModel *model;
7845   gboolean path_down_mode;
7846   gboolean drop_append_mode;
7847
7848   tree_view = GTK_TREE_VIEW (widget);
7849
7850   model = gtk_tree_view_get_model (tree_view);
7851
7852   remove_scroll_timeout (GTK_TREE_VIEW (widget));
7853   remove_open_timeout (GTK_TREE_VIEW (widget));
7854
7855   di = get_info (tree_view);
7856
7857   if (di == NULL)
7858     return FALSE;
7859
7860   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_drop"))
7861     return FALSE;
7862
7863   if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
7864     return FALSE;
7865
7866   path = get_logical_dest_row (tree_view, &path_down_mode, &drop_append_mode);
7867
7868   if (target != GDK_NONE && path != NULL)
7869     {
7870       /* in case a motion had requested drag data, change things so we
7871        * treat drag data receives as a drop.
7872        */
7873       set_status_pending (context, 0);
7874       set_dest_row (context, model, path,
7875                     path_down_mode, tree_view->priv->empty_view_drop,
7876                     drop_append_mode);
7877     }
7878
7879   if (path)
7880     gtk_tree_path_free (path);
7881
7882   /* Unset this thing */
7883   gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7884                                    NULL,
7885                                    GTK_TREE_VIEW_DROP_BEFORE);
7886
7887   if (target != GDK_NONE)
7888     {
7889       gtk_drag_get_data (widget, context, target, time);
7890       return TRUE;
7891     }
7892   else
7893     return FALSE;
7894 }
7895
7896 static void
7897 gtk_tree_view_drag_data_received (GtkWidget        *widget,
7898                                   GdkDragContext   *context,
7899                                   /* coordinates relative to the widget */
7900                                   gint              x,
7901                                   gint              y,
7902                                   GtkSelectionData *selection_data,
7903                                   guint             info,
7904                                   guint             time)
7905 {
7906   GtkTreePath *path;
7907   TreeViewDragInfo *di;
7908   gboolean accepted = FALSE;
7909   GtkTreeModel *model;
7910   GtkTreeView *tree_view;
7911   GtkTreePath *dest_row;
7912   GdkDragAction suggested_action;
7913   gboolean path_down_mode;
7914   gboolean drop_append_mode;
7915
7916   tree_view = GTK_TREE_VIEW (widget);
7917
7918   model = gtk_tree_view_get_model (tree_view);
7919
7920   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_data_received"))
7921     return;
7922
7923   di = get_info (tree_view);
7924
7925   if (di == NULL)
7926     return;
7927
7928   suggested_action = get_status_pending (context);
7929
7930   if (suggested_action)
7931     {
7932       /* We are getting this data due to a request in drag_motion,
7933        * rather than due to a request in drag_drop, so we are just
7934        * supposed to call drag_status, not actually paste in the
7935        * data.
7936        */
7937       path = get_logical_dest_row (tree_view, &path_down_mode,
7938                                    &drop_append_mode);
7939
7940       if (path == NULL)
7941         suggested_action = 0;
7942       else if (path_down_mode)
7943         gtk_tree_path_down (path);
7944
7945       if (suggested_action)
7946         {
7947           if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
7948                                                      path,
7949                                                      selection_data))
7950             {
7951               if (path_down_mode)
7952                 {
7953                   path_down_mode = FALSE;
7954                   gtk_tree_path_up (path);
7955
7956                   if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
7957                                                              path,
7958                                                              selection_data))
7959                     suggested_action = 0;
7960                 }
7961               else
7962                 suggested_action = 0;
7963             }
7964         }
7965
7966       gdk_drag_status (context, suggested_action, time);
7967
7968       if (path)
7969         gtk_tree_path_free (path);
7970
7971       /* If you can't drop, remove user drop indicator until the next motion */
7972       if (suggested_action == 0)
7973         gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7974                                          NULL,
7975                                          GTK_TREE_VIEW_DROP_BEFORE);
7976
7977       return;
7978     }
7979
7980   dest_row = get_dest_row (context, &path_down_mode);
7981
7982   if (dest_row == NULL)
7983     return;
7984
7985   if (gtk_selection_data_get_length (selection_data) >= 0)
7986     {
7987       if (path_down_mode)
7988         {
7989           gtk_tree_path_down (dest_row);
7990           if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
7991                                                      dest_row, selection_data))
7992             gtk_tree_path_up (dest_row);
7993         }
7994     }
7995
7996   if (gtk_selection_data_get_length (selection_data) >= 0)
7997     {
7998       if (gtk_tree_drag_dest_drag_data_received (GTK_TREE_DRAG_DEST (model),
7999                                                  dest_row,
8000                                                  selection_data))
8001         accepted = TRUE;
8002     }
8003
8004   gtk_drag_finish (context,
8005                    accepted,
8006                    (gdk_drag_context_get_selected_action (context) == GDK_ACTION_MOVE),
8007                    time);
8008
8009   if (gtk_tree_path_get_depth (dest_row) == 1
8010       && gtk_tree_path_get_indices (dest_row)[0] == 0)
8011     {
8012       /* special special case drag to "0", scroll to first item */
8013       if (!tree_view->priv->scroll_to_path)
8014         gtk_tree_view_scroll_to_cell (tree_view, dest_row, NULL, FALSE, 0.0, 0.0);
8015     }
8016
8017   gtk_tree_path_free (dest_row);
8018
8019   /* drop dest_row */
8020   set_dest_row (context, NULL, NULL, FALSE, FALSE, FALSE);
8021 }
8022
8023
8024
8025 /* GtkContainer Methods
8026  */
8027
8028
8029 static void
8030 gtk_tree_view_remove (GtkContainer *container,
8031                       GtkWidget    *widget)
8032 {
8033   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
8034   GtkTreeViewChild *child = NULL;
8035   GList *tmp_list;
8036
8037   tmp_list = tree_view->priv->children;
8038   while (tmp_list)
8039     {
8040       child = tmp_list->data;
8041       if (child->widget == widget)
8042         {
8043           gtk_widget_unparent (widget);
8044
8045           tree_view->priv->children = g_list_remove_link (tree_view->priv->children, tmp_list);
8046           g_list_free_1 (tmp_list);
8047           g_slice_free (GtkTreeViewChild, child);
8048           return;
8049         }
8050
8051       tmp_list = tmp_list->next;
8052     }
8053
8054   tmp_list = tree_view->priv->columns;
8055
8056   while (tmp_list)
8057     {
8058       GtkTreeViewColumn *column;
8059       GtkWidget         *button;
8060
8061       column = tmp_list->data;
8062       button = gtk_tree_view_column_get_button (column);
8063
8064       if (button == widget)
8065         {
8066           gtk_widget_unparent (widget);
8067           return;
8068         }
8069       tmp_list = tmp_list->next;
8070     }
8071 }
8072
8073 static void
8074 gtk_tree_view_forall (GtkContainer *container,
8075                       gboolean      include_internals,
8076                       GtkCallback   callback,
8077                       gpointer      callback_data)
8078 {
8079   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
8080   GtkTreeViewChild *child = NULL;
8081   GtkTreeViewColumn *column;
8082   GtkWidget *button;
8083   GList *tmp_list;
8084
8085   tmp_list = tree_view->priv->children;
8086   while (tmp_list)
8087     {
8088       child = tmp_list->data;
8089       tmp_list = tmp_list->next;
8090
8091       (* callback) (child->widget, callback_data);
8092     }
8093   if (include_internals == FALSE)
8094     return;
8095
8096   for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
8097     {
8098       column = tmp_list->data;
8099       button = gtk_tree_view_column_get_button (column);
8100
8101       if (button)
8102         (* callback) (button, callback_data);
8103     }
8104 }
8105
8106 /* Returns TRUE is any of the columns contains a cell that can-focus.
8107  * If this is not the case, a column-spanning focus rectangle will be
8108  * drawn.
8109  */
8110 static gboolean
8111 gtk_tree_view_has_can_focus_cell (GtkTreeView *tree_view)
8112 {
8113   GList *list;
8114
8115   for (list = tree_view->priv->columns; list; list = list->next)
8116     {
8117       GtkTreeViewColumn *column = list->data;
8118
8119       if (!gtk_tree_view_column_get_visible (column))
8120         continue;
8121       if (gtk_cell_area_is_activatable (gtk_cell_layout_get_area (GTK_CELL_LAYOUT (column))))
8122         return TRUE;
8123     }
8124
8125   return FALSE;
8126 }
8127
8128 static void
8129 column_sizing_notify (GObject    *object,
8130                       GParamSpec *pspec,
8131                       gpointer    data)
8132 {
8133   GtkTreeViewColumn *c = GTK_TREE_VIEW_COLUMN (object);
8134
8135   if (gtk_tree_view_column_get_sizing (c) != GTK_TREE_VIEW_COLUMN_FIXED)
8136     /* disable fixed height mode */
8137     g_object_set (data, "fixed-height-mode", FALSE, NULL);
8138 }
8139
8140 /**
8141  * gtk_tree_view_set_fixed_height_mode:
8142  * @tree_view: a #GtkTreeView 
8143  * @enable: %TRUE to enable fixed height mode
8144  * 
8145  * Enables or disables the fixed height mode of @tree_view. 
8146  * Fixed height mode speeds up #GtkTreeView by assuming that all 
8147  * rows have the same height. 
8148  * Only enable this option if all rows are the same height and all
8149  * columns are of type %GTK_TREE_VIEW_COLUMN_FIXED.
8150  *
8151  * Since: 2.6 
8152  **/
8153 void
8154 gtk_tree_view_set_fixed_height_mode (GtkTreeView *tree_view,
8155                                      gboolean     enable)
8156 {
8157   GList *l;
8158   
8159   enable = enable != FALSE;
8160
8161   if (enable == tree_view->priv->fixed_height_mode)
8162     return;
8163
8164   if (!enable)
8165     {
8166       tree_view->priv->fixed_height_mode = 0;
8167       tree_view->priv->fixed_height = -1;
8168
8169       /* force a revalidation */
8170       install_presize_handler (tree_view);
8171     }
8172   else 
8173     {
8174       /* make sure all columns are of type FIXED */
8175       for (l = tree_view->priv->columns; l; l = l->next)
8176         {
8177           GtkTreeViewColumn *c = l->data;
8178           
8179           g_return_if_fail (gtk_tree_view_column_get_sizing (c) == GTK_TREE_VIEW_COLUMN_FIXED);
8180         }
8181       
8182       /* yes, we really have to do this is in a separate loop */
8183       for (l = tree_view->priv->columns; l; l = l->next)
8184         g_signal_connect (l->data, "notify::sizing",
8185                           G_CALLBACK (column_sizing_notify), tree_view);
8186       
8187       tree_view->priv->fixed_height_mode = 1;
8188       tree_view->priv->fixed_height = -1;
8189       
8190       if (tree_view->priv->tree)
8191         initialize_fixed_height_mode (tree_view);
8192     }
8193
8194   g_object_notify (G_OBJECT (tree_view), "fixed-height-mode");
8195 }
8196
8197 /**
8198  * gtk_tree_view_get_fixed_height_mode:
8199  * @tree_view: a #GtkTreeView
8200  * 
8201  * Returns whether fixed height mode is turned on for @tree_view.
8202  * 
8203  * Return value: %TRUE if @tree_view is in fixed height mode
8204  * 
8205  * Since: 2.6
8206  **/
8207 gboolean
8208 gtk_tree_view_get_fixed_height_mode (GtkTreeView *tree_view)
8209 {
8210   return tree_view->priv->fixed_height_mode;
8211 }
8212
8213 /* Returns TRUE if the focus is within the headers, after the focus operation is
8214  * done
8215  */
8216 static gboolean
8217 gtk_tree_view_header_focus (GtkTreeView      *tree_view,
8218                             GtkDirectionType  dir,
8219                             gboolean          clamp_column_visible)
8220 {
8221   GtkTreeViewColumn *column;
8222   GtkWidget *focus_child;
8223   GtkWidget *button;
8224   GList *last_column, *first_column;
8225   GList *tmp_list;
8226   gboolean rtl;
8227
8228   if (! tree_view->priv->headers_visible)
8229     return FALSE;
8230
8231   focus_child = gtk_container_get_focus_child (GTK_CONTAINER (tree_view));
8232
8233   first_column = tree_view->priv->columns;
8234   while (first_column)
8235     {
8236       column = GTK_TREE_VIEW_COLUMN (first_column->data);
8237       button = gtk_tree_view_column_get_button (column);
8238
8239       if (gtk_widget_get_can_focus (button) &&
8240           gtk_tree_view_column_get_visible (column) &&
8241           (gtk_tree_view_column_get_clickable (column) ||
8242            gtk_tree_view_column_get_reorderable (column)))
8243         break;
8244       first_column = first_column->next;
8245     }
8246
8247   /* No headers are visible, or are focusable.  We can't focus in or out.
8248    */
8249   if (first_column == NULL)
8250     return FALSE;
8251
8252   last_column = g_list_last (tree_view->priv->columns);
8253   while (last_column)
8254     {
8255       column = GTK_TREE_VIEW_COLUMN (last_column->data);
8256       button = gtk_tree_view_column_get_button (column);
8257
8258       if (gtk_widget_get_can_focus (button) &&
8259           gtk_tree_view_column_get_visible (column) &&
8260           (gtk_tree_view_column_get_clickable (column) ||
8261            gtk_tree_view_column_get_reorderable (column)))
8262         break;
8263       last_column = last_column->prev;
8264     }
8265
8266
8267   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
8268
8269   switch (dir)
8270     {
8271     case GTK_DIR_TAB_BACKWARD:
8272     case GTK_DIR_TAB_FORWARD:
8273     case GTK_DIR_UP:
8274     case GTK_DIR_DOWN:
8275       if (focus_child == NULL)
8276         {
8277           if (tree_view->priv->focus_column != NULL)
8278             button = gtk_tree_view_column_get_button (tree_view->priv->focus_column);
8279           else 
8280             button = NULL;
8281
8282           if (button && gtk_widget_get_can_focus (button))
8283             focus_child = button;
8284           else
8285             focus_child = gtk_tree_view_column_get_button (GTK_TREE_VIEW_COLUMN (first_column->data));
8286
8287           gtk_widget_grab_focus (focus_child);
8288           break;
8289         }
8290       return FALSE;
8291
8292     case GTK_DIR_LEFT:
8293     case GTK_DIR_RIGHT:
8294       if (focus_child == NULL)
8295         {
8296           if (tree_view->priv->focus_column != NULL)
8297             focus_child = gtk_tree_view_column_get_button (tree_view->priv->focus_column);
8298           else if (dir == GTK_DIR_LEFT)
8299             focus_child = gtk_tree_view_column_get_button (GTK_TREE_VIEW_COLUMN (last_column->data));
8300           else
8301             focus_child = gtk_tree_view_column_get_button (GTK_TREE_VIEW_COLUMN (first_column->data));
8302
8303           gtk_widget_grab_focus (focus_child);
8304           break;
8305         }
8306
8307       if (gtk_widget_child_focus (focus_child, dir))
8308         {
8309           /* The focus moves inside the button. */
8310           /* This is probably a great example of bad UI */
8311           break;
8312         }
8313
8314       /* We need to move the focus among the row of buttons. */
8315       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
8316         if (gtk_tree_view_column_get_button (GTK_TREE_VIEW_COLUMN (tmp_list->data)) == focus_child)
8317           break;
8318
8319       if ((tmp_list == first_column && dir == (rtl ? GTK_DIR_RIGHT : GTK_DIR_LEFT))
8320           || (tmp_list == last_column && dir == (rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT)))
8321         {
8322           gtk_widget_error_bell (GTK_WIDGET (tree_view));
8323           break;
8324         }
8325
8326       while (tmp_list)
8327         {
8328           GtkTreeViewColumn *column;
8329           GtkWidget         *button;
8330
8331           if (dir == (rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT))
8332             tmp_list = tmp_list->next;
8333           else
8334             tmp_list = tmp_list->prev;
8335
8336           if (tmp_list == NULL)
8337             {
8338               g_warning ("Internal button not found");
8339               break;
8340             }
8341           column = tmp_list->data;
8342           button = gtk_tree_view_column_get_button (column);
8343           if (button &&
8344               gtk_tree_view_column_get_visible (column) &&
8345               gtk_widget_get_can_focus (button))
8346             {
8347               focus_child = button;
8348               gtk_widget_grab_focus (button);
8349               break;
8350             }
8351         }
8352       break;
8353     default:
8354       g_assert_not_reached ();
8355       break;
8356     }
8357
8358   /* if focus child is non-null, we assume it's been set to the current focus child
8359    */
8360   if (focus_child)
8361     {
8362       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
8363         if (gtk_tree_view_column_get_button (GTK_TREE_VIEW_COLUMN (tmp_list->data)) == focus_child)
8364           {
8365             tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
8366             break;
8367           }
8368
8369       if (clamp_column_visible)
8370         {
8371           gtk_tree_view_clamp_column_visible (tree_view,
8372                                               tree_view->priv->focus_column,
8373                                               FALSE);
8374         }
8375     }
8376
8377   return (focus_child != NULL);
8378 }
8379
8380 /* This function returns in 'path' the first focusable path, if the given path
8381  * is already focusable, it's the returned one.
8382  */
8383 static gboolean
8384 search_first_focusable_path (GtkTreeView  *tree_view,
8385                              GtkTreePath **path,
8386                              gboolean      search_forward,
8387                              GtkRBTree   **new_tree,
8388                              GtkRBNode   **new_node)
8389 {
8390   GtkRBTree *tree = NULL;
8391   GtkRBNode *node = NULL;
8392
8393   if (!path || !*path)
8394     return FALSE;
8395
8396   _gtk_tree_view_find_node (tree_view, *path, &tree, &node);
8397
8398   if (!tree || !node)
8399     return FALSE;
8400
8401   while (node && row_is_separator (tree_view, NULL, *path))
8402     {
8403       if (search_forward)
8404         _gtk_rbtree_next_full (tree, node, &tree, &node);
8405       else
8406         _gtk_rbtree_prev_full (tree, node, &tree, &node);
8407
8408       if (*path)
8409         gtk_tree_path_free (*path);
8410
8411       if (node)
8412         *path = _gtk_tree_view_find_path (tree_view, tree, node);
8413       else
8414         *path = NULL;
8415     }
8416
8417   if (new_tree)
8418     *new_tree = tree;
8419
8420   if (new_node)
8421     *new_node = node;
8422
8423   return (*path != NULL);
8424 }
8425
8426 static gint
8427 gtk_tree_view_focus (GtkWidget        *widget,
8428                      GtkDirectionType  direction)
8429 {
8430   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
8431   GtkContainer *container = GTK_CONTAINER (widget);
8432   GtkWidget *focus_child;
8433
8434   if (!gtk_widget_is_sensitive (widget) || !gtk_widget_get_can_focus (widget))
8435     return FALSE;
8436
8437   focus_child = gtk_container_get_focus_child (container);
8438
8439   gtk_tree_view_stop_editing (GTK_TREE_VIEW (widget), FALSE);
8440   /* Case 1.  Headers currently have focus. */
8441   if (focus_child)
8442     {
8443       switch (direction)
8444         {
8445         case GTK_DIR_LEFT:
8446         case GTK_DIR_RIGHT:
8447           gtk_tree_view_header_focus (tree_view, direction, TRUE);
8448           return TRUE;
8449         case GTK_DIR_TAB_BACKWARD:
8450         case GTK_DIR_UP:
8451           return FALSE;
8452         case GTK_DIR_TAB_FORWARD:
8453         case GTK_DIR_DOWN:
8454           gtk_widget_grab_focus (widget);
8455           return TRUE;
8456         default:
8457           g_assert_not_reached ();
8458           return FALSE;
8459         }
8460     }
8461
8462   /* Case 2. We don't have focus at all. */
8463   if (!gtk_widget_has_focus (widget))
8464     {
8465       gtk_widget_grab_focus (widget);
8466       return TRUE;
8467     }
8468
8469   /* Case 3. We have focus already. */
8470   if (direction == GTK_DIR_TAB_BACKWARD)
8471     return (gtk_tree_view_header_focus (tree_view, direction, FALSE));
8472   else if (direction == GTK_DIR_TAB_FORWARD)
8473     return FALSE;
8474
8475   /* Other directions caught by the keybindings */
8476   gtk_widget_grab_focus (widget);
8477   return TRUE;
8478 }
8479
8480 static void
8481 gtk_tree_view_grab_focus (GtkWidget *widget)
8482 {
8483   GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->grab_focus (widget);
8484
8485   gtk_tree_view_focus_to_cursor (GTK_TREE_VIEW (widget));
8486 }
8487
8488 static void
8489 gtk_tree_view_style_updated (GtkWidget *widget)
8490 {
8491   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
8492   GList *list;
8493   GtkTreeViewColumn *column;
8494
8495   GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->style_updated (widget);
8496
8497   if (gtk_widget_get_realized (widget))
8498     {
8499       GtkStyleContext *context;
8500
8501       context = gtk_widget_get_style_context (widget);
8502
8503       gtk_style_context_save (context);
8504       gtk_style_context_add_class (context, GTK_STYLE_CLASS_VIEW);
8505       gtk_style_context_set_background (context, tree_view->priv->bin_window);
8506       gtk_style_context_restore (context);
8507
8508       gtk_style_context_set_background (context, tree_view->priv->header_window);
8509
8510       gtk_tree_view_set_grid_lines (tree_view, tree_view->priv->grid_lines);
8511       gtk_tree_view_set_enable_tree_lines (tree_view, tree_view->priv->tree_lines_enabled);
8512     }
8513
8514   gtk_widget_style_get (widget,
8515                         "expander-size", &tree_view->priv->expander_size,
8516                         NULL);
8517   tree_view->priv->expander_size += EXPANDER_EXTRA_PADDING;
8518
8519   for (list = tree_view->priv->columns; list; list = list->next)
8520     {
8521       column = list->data;
8522       _gtk_tree_view_column_cell_set_dirty (column, TRUE);
8523     }
8524
8525   tree_view->priv->fixed_height = -1;
8526   _gtk_rbtree_mark_invalid (tree_view->priv->tree);
8527
8528   gtk_widget_queue_resize (widget);
8529 }
8530
8531
8532 static void
8533 gtk_tree_view_set_focus_child (GtkContainer *container,
8534                                GtkWidget    *child)
8535 {
8536   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
8537   GList *list;
8538
8539   for (list = tree_view->priv->columns; list; list = list->next)
8540     {
8541       if (gtk_tree_view_column_get_button (GTK_TREE_VIEW_COLUMN (list->data)) == child)
8542         {
8543           tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (list->data);
8544           break;
8545         }
8546     }
8547
8548   GTK_CONTAINER_CLASS (gtk_tree_view_parent_class)->set_focus_child (container, child);
8549 }
8550
8551 static GtkWidgetPath *
8552 gtk_tree_view_get_path_for_child (GtkContainer *container,
8553                                   GtkWidget    *child)
8554 {
8555   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
8556   GtkWidgetPath *path;
8557   gboolean rtl;
8558   GList *list;
8559   gint n_col = 0;
8560
8561   path = GTK_CONTAINER_CLASS (gtk_tree_view_parent_class)->get_path_for_child (container, child);
8562   rtl = (gtk_widget_get_direction (GTK_WIDGET (container)) == GTK_TEXT_DIR_RTL);
8563
8564   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
8565        list;
8566        list = (rtl ? list->prev : list->next))
8567     {
8568       GtkTreeViewColumn *column = list->data;
8569       GtkRegionFlags flags = 0;
8570
8571       if (!gtk_tree_view_column_get_visible (column))
8572         continue;
8573
8574       n_col++;
8575
8576       if (gtk_tree_view_column_get_widget (column) != child &&
8577           gtk_tree_view_column_get_button (column) != child)
8578         continue;
8579
8580       if ((n_col % 2) == 0)
8581         flags |= GTK_REGION_EVEN;
8582       else
8583         flags |= GTK_REGION_ODD;
8584
8585       if (n_col == 1)
8586         flags |= GTK_REGION_FIRST;
8587
8588       if ((rtl && !list->prev) ||
8589           (!rtl && !list->next))
8590         flags |= GTK_REGION_LAST;
8591
8592       gtk_widget_path_iter_add_region (path, -1, GTK_STYLE_REGION_COLUMN_HEADER, flags);
8593       break;
8594     }
8595
8596   return path;
8597 }
8598
8599 static gboolean
8600 gtk_tree_view_real_move_cursor (GtkTreeView       *tree_view,
8601                                 GtkMovementStep    step,
8602                                 gint               count)
8603 {
8604   GdkModifierType state;
8605
8606   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
8607   g_return_val_if_fail (step == GTK_MOVEMENT_LOGICAL_POSITIONS ||
8608                         step == GTK_MOVEMENT_VISUAL_POSITIONS ||
8609                         step == GTK_MOVEMENT_DISPLAY_LINES ||
8610                         step == GTK_MOVEMENT_PAGES ||
8611                         step == GTK_MOVEMENT_BUFFER_ENDS, FALSE);
8612
8613   if (tree_view->priv->tree == NULL)
8614     return FALSE;
8615   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
8616     return FALSE;
8617
8618   gtk_tree_view_stop_editing (tree_view, FALSE);
8619   tree_view->priv->draw_keyfocus = TRUE;
8620   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
8621
8622   if (gtk_get_current_event_state (&state))
8623     {
8624       if ((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
8625         tree_view->priv->ctrl_pressed = TRUE;
8626       if ((state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
8627         tree_view->priv->shift_pressed = TRUE;
8628     }
8629   /* else we assume not pressed */
8630
8631   switch (step)
8632     {
8633       /* currently we make no distinction.  When we go bi-di, we need to */
8634     case GTK_MOVEMENT_LOGICAL_POSITIONS:
8635     case GTK_MOVEMENT_VISUAL_POSITIONS:
8636       gtk_tree_view_move_cursor_left_right (tree_view, count);
8637       break;
8638     case GTK_MOVEMENT_DISPLAY_LINES:
8639       gtk_tree_view_move_cursor_up_down (tree_view, count);
8640       break;
8641     case GTK_MOVEMENT_PAGES:
8642       gtk_tree_view_move_cursor_page_up_down (tree_view, count);
8643       break;
8644     case GTK_MOVEMENT_BUFFER_ENDS:
8645       gtk_tree_view_move_cursor_start_end (tree_view, count);
8646       break;
8647     default:
8648       g_assert_not_reached ();
8649     }
8650
8651   tree_view->priv->ctrl_pressed = FALSE;
8652   tree_view->priv->shift_pressed = FALSE;
8653
8654   return TRUE;
8655 }
8656
8657 static void
8658 gtk_tree_view_put (GtkTreeView *tree_view,
8659                    GtkWidget   *child_widget,
8660                    /* in bin_window coordinates */
8661                    gint         x,
8662                    gint         y,
8663                    gint         width,
8664                    gint         height)
8665 {
8666   GtkTreeViewChild *child;
8667   
8668   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8669   g_return_if_fail (GTK_IS_WIDGET (child_widget));
8670
8671   child = g_slice_new (GtkTreeViewChild);
8672
8673   child->widget = child_widget;
8674   child->x = x;
8675   child->y = y;
8676   child->width = width;
8677   child->height = height;
8678
8679   tree_view->priv->children = g_list_append (tree_view->priv->children, child);
8680
8681   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
8682     gtk_widget_set_parent_window (child->widget, tree_view->priv->bin_window);
8683   
8684   gtk_widget_set_parent (child_widget, GTK_WIDGET (tree_view));
8685 }
8686
8687 void
8688 _gtk_tree_view_child_move_resize (GtkTreeView *tree_view,
8689                                   GtkWidget   *widget,
8690                                   /* in tree coordinates */
8691                                   gint         x,
8692                                   gint         y,
8693                                   gint         width,
8694                                   gint         height)
8695 {
8696   GtkTreeViewChild *child = NULL;
8697   GList *list;
8698   GdkRectangle allocation;
8699
8700   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8701   g_return_if_fail (GTK_IS_WIDGET (widget));
8702
8703   for (list = tree_view->priv->children; list; list = list->next)
8704     {
8705       if (((GtkTreeViewChild *)list->data)->widget == widget)
8706         {
8707           child = list->data;
8708           break;
8709         }
8710     }
8711   if (child == NULL)
8712     return;
8713
8714   allocation.x = child->x = x;
8715   allocation.y = child->y = y;
8716   allocation.width = child->width = width;
8717   allocation.height = child->height = height;
8718
8719   if (gtk_widget_get_realized (widget))
8720     gtk_widget_size_allocate (widget, &allocation);
8721 }
8722
8723
8724 /* TreeModel Callbacks
8725  */
8726
8727 static void
8728 gtk_tree_view_row_changed (GtkTreeModel *model,
8729                            GtkTreePath  *path,
8730                            GtkTreeIter  *iter,
8731                            gpointer      data)
8732 {
8733   GtkTreeView *tree_view = (GtkTreeView *)data;
8734   GtkRBTree *tree;
8735   GtkRBNode *node;
8736   gboolean free_path = FALSE;
8737   GList *list;
8738   GtkTreePath *cursor_path;
8739
8740   g_return_if_fail (path != NULL || iter != NULL);
8741
8742   if (tree_view->priv->cursor != NULL)
8743     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
8744   else
8745     cursor_path = NULL;
8746
8747   if (tree_view->priv->edited_column &&
8748       (cursor_path == NULL || gtk_tree_path_compare (cursor_path, path) == 0))
8749     gtk_tree_view_stop_editing (tree_view, TRUE);
8750
8751   if (cursor_path != NULL)
8752     gtk_tree_path_free (cursor_path);
8753
8754   if (path == NULL)
8755     {
8756       path = gtk_tree_model_get_path (model, iter);
8757       free_path = TRUE;
8758     }
8759   else if (iter == NULL)
8760     gtk_tree_model_get_iter (model, iter, path);
8761
8762   if (_gtk_tree_view_find_node (tree_view,
8763                                 path,
8764                                 &tree,
8765                                 &node))
8766     /* We aren't actually showing the node */
8767     goto done;
8768
8769   if (tree == NULL)
8770     goto done;
8771
8772   if (tree_view->priv->fixed_height_mode
8773       && tree_view->priv->fixed_height >= 0)
8774     {
8775       _gtk_rbtree_node_set_height (tree, node, tree_view->priv->fixed_height);
8776       if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
8777         gtk_tree_view_node_queue_redraw (tree_view, tree, node);
8778     }
8779   else
8780     {
8781       _gtk_rbtree_node_mark_invalid (tree, node);
8782       for (list = tree_view->priv->columns; list; list = list->next)
8783         {
8784           GtkTreeViewColumn *column;
8785
8786           column = list->data;
8787           if (!gtk_tree_view_column_get_visible (column))
8788             continue;
8789
8790           if (gtk_tree_view_column_get_sizing (column) == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
8791             {
8792               _gtk_tree_view_column_cell_set_dirty (column, TRUE);
8793             }
8794         }
8795     }
8796
8797  done:
8798   if (!tree_view->priv->fixed_height_mode &&
8799       gtk_widget_get_realized (GTK_WIDGET (tree_view)))
8800     install_presize_handler (tree_view);
8801   if (free_path)
8802     gtk_tree_path_free (path);
8803 }
8804
8805 static void
8806 gtk_tree_view_row_inserted (GtkTreeModel *model,
8807                             GtkTreePath  *path,
8808                             GtkTreeIter  *iter,
8809                             gpointer      data)
8810 {
8811   GtkTreeView *tree_view = (GtkTreeView *) data;
8812   gint *indices;
8813   GtkRBTree *tmptree, *tree;
8814   GtkRBNode *tmpnode = NULL;
8815   gint depth;
8816   gint i = 0;
8817   gint height;
8818   gboolean free_path = FALSE;
8819   gboolean node_visible = TRUE;
8820
8821   g_return_if_fail (path != NULL || iter != NULL);
8822
8823   if (tree_view->priv->fixed_height_mode
8824       && tree_view->priv->fixed_height >= 0)
8825     height = tree_view->priv->fixed_height;
8826   else
8827     height = 0;
8828
8829   if (path == NULL)
8830     {
8831       path = gtk_tree_model_get_path (model, iter);
8832       free_path = TRUE;
8833     }
8834   else if (iter == NULL)
8835     gtk_tree_model_get_iter (model, iter, path);
8836
8837   if (tree_view->priv->tree == NULL)
8838     tree_view->priv->tree = _gtk_rbtree_new ();
8839
8840   tmptree = tree = tree_view->priv->tree;
8841
8842   /* Update all row-references */
8843   gtk_tree_row_reference_inserted (G_OBJECT (data), path);
8844   depth = gtk_tree_path_get_depth (path);
8845   indices = gtk_tree_path_get_indices (path);
8846
8847   /* First, find the parent tree */
8848   while (i < depth - 1)
8849     {
8850       if (tmptree == NULL)
8851         {
8852           /* We aren't showing the node */
8853           node_visible = FALSE;
8854           goto done;
8855         }
8856
8857       tmpnode = _gtk_rbtree_find_count (tmptree, indices[i] + 1);
8858       if (tmpnode == NULL)
8859         {
8860           g_warning ("A node was inserted with a parent that's not in the tree.\n" \
8861                      "This possibly means that a GtkTreeModel inserted a child node\n" \
8862                      "before the parent was inserted.");
8863           goto done;
8864         }
8865       else if (!GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_IS_PARENT))
8866         {
8867           /* FIXME enforce correct behavior on model, probably */
8868           /* In theory, the model should have emitted has_child_toggled here.  We
8869            * try to catch it anyway, just to be safe, in case the model hasn't.
8870            */
8871           GtkTreePath *tmppath = _gtk_tree_view_find_path (tree_view,
8872                                                            tree,
8873                                                            tmpnode);
8874           gtk_tree_view_row_has_child_toggled (model, tmppath, NULL, data);
8875           gtk_tree_path_free (tmppath);
8876           goto done;
8877         }
8878
8879       tmptree = tmpnode->children;
8880       tree = tmptree;
8881       i++;
8882     }
8883
8884   if (tree == NULL)
8885     {
8886       node_visible = FALSE;
8887       goto done;
8888     }
8889
8890   /* ref the node */
8891   gtk_tree_model_ref_node (tree_view->priv->model, iter);
8892   if (indices[depth - 1] == 0)
8893     {
8894       tmpnode = _gtk_rbtree_find_count (tree, 1);
8895       tmpnode = _gtk_rbtree_insert_before (tree, tmpnode, height, FALSE);
8896     }
8897   else
8898     {
8899       tmpnode = _gtk_rbtree_find_count (tree, indices[depth - 1]);
8900       tmpnode = _gtk_rbtree_insert_after (tree, tmpnode, height, FALSE);
8901     }
8902
8903  done:
8904   if (height > 0)
8905     {
8906       if (tree)
8907         _gtk_rbtree_node_mark_valid (tree, tmpnode);
8908
8909       if (node_visible && node_is_visible (tree_view, tree, tmpnode))
8910         gtk_widget_queue_resize (GTK_WIDGET (tree_view));
8911       else
8912         gtk_widget_queue_resize_no_redraw (GTK_WIDGET (tree_view));
8913     }
8914   else
8915     install_presize_handler (tree_view);
8916   if (free_path)
8917     gtk_tree_path_free (path);
8918 }
8919
8920 static void
8921 gtk_tree_view_row_has_child_toggled (GtkTreeModel *model,
8922                                      GtkTreePath  *path,
8923                                      GtkTreeIter  *iter,
8924                                      gpointer      data)
8925 {
8926   GtkTreeView *tree_view = (GtkTreeView *)data;
8927   GtkTreeIter real_iter;
8928   gboolean has_child;
8929   GtkRBTree *tree;
8930   GtkRBNode *node;
8931   gboolean free_path = FALSE;
8932
8933   g_return_if_fail (path != NULL || iter != NULL);
8934
8935   if (iter)
8936     real_iter = *iter;
8937
8938   if (path == NULL)
8939     {
8940       path = gtk_tree_model_get_path (model, iter);
8941       free_path = TRUE;
8942     }
8943   else if (iter == NULL)
8944     gtk_tree_model_get_iter (model, &real_iter, path);
8945
8946   if (_gtk_tree_view_find_node (tree_view,
8947                                 path,
8948                                 &tree,
8949                                 &node))
8950     /* We aren't actually showing the node */
8951     goto done;
8952
8953   if (tree == NULL)
8954     goto done;
8955
8956   has_child = gtk_tree_model_iter_has_child (model, &real_iter);
8957   /* Sanity check.
8958    */
8959   if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT) == has_child)
8960     goto done;
8961
8962   if (has_child)
8963     GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_PARENT);
8964   else
8965     GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_PARENT);
8966
8967   if (has_child && tree_view->priv->is_list)
8968     {
8969       tree_view->priv->is_list = FALSE;
8970       if (tree_view->priv->show_expanders)
8971         {
8972           GList *list;
8973
8974           for (list = tree_view->priv->columns; list; list = list->next)
8975             if (gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (list->data)))
8976               {
8977                 _gtk_tree_view_column_cell_set_dirty (GTK_TREE_VIEW_COLUMN (list->data), TRUE);
8978                 break;
8979               }
8980         }
8981       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
8982     }
8983   else
8984     {
8985       _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
8986     }
8987
8988  done:
8989   if (free_path)
8990     gtk_tree_path_free (path);
8991 }
8992
8993 static void
8994 count_children_helper (GtkRBTree *tree,
8995                        GtkRBNode *node,
8996                        gpointer   data)
8997 {
8998   if (node->children)
8999     _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, data);
9000   (*((gint *)data))++;
9001 }
9002
9003 static void
9004 check_selection_helper (GtkRBTree *tree,
9005                         GtkRBNode *node,
9006                         gpointer   data)
9007 {
9008   gint *value = (gint *)data;
9009
9010   *value = GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED);
9011
9012   if (node->children && !*value)
9013     _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, check_selection_helper, data);
9014 }
9015
9016 static void
9017 gtk_tree_view_row_deleted (GtkTreeModel *model,
9018                            GtkTreePath  *path,
9019                            gpointer      data)
9020 {
9021   GtkTreeView *tree_view = (GtkTreeView *)data;
9022   GtkRBTree *tree;
9023   GtkRBNode *node;
9024   GList *list;
9025   gint selection_changed = FALSE;
9026   GtkStyleContext *context;
9027
9028   g_return_if_fail (path != NULL);
9029
9030   gtk_tree_row_reference_deleted (G_OBJECT (data), path);
9031
9032   if (_gtk_tree_view_find_node (tree_view, path, &tree, &node))
9033     return;
9034
9035   if (tree == NULL)
9036     return;
9037
9038   /* check if the selection has been changed */
9039   _gtk_rbtree_traverse (tree, node, G_POST_ORDER,
9040                         check_selection_helper, &selection_changed);
9041
9042   for (list = tree_view->priv->columns; list; list = list->next)
9043     if (gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (list->data)) &&
9044         gtk_tree_view_column_get_sizing (GTK_TREE_VIEW_COLUMN (list->data)) == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
9045       _gtk_tree_view_column_cell_set_dirty ((GtkTreeViewColumn *)list->data, TRUE);
9046
9047   /* Ensure we don't have a dangling pointer to a dead node */
9048   ensure_unprelighted (tree_view);
9049
9050   /* Cancel editting if we've started */
9051   gtk_tree_view_stop_editing (tree_view, TRUE);
9052
9053   if (tree_view->priv->destroy_count_func)
9054     {
9055       gint child_count = 0;
9056       if (node->children)
9057         _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, &child_count);
9058       tree_view->priv->destroy_count_func (tree_view, path, child_count, tree_view->priv->destroy_count_data);
9059     }
9060
9061   if (tree->root->count == 1)
9062     {
9063       if (tree_view->priv->tree == tree)
9064         tree_view->priv->tree = NULL;
9065
9066       _gtk_rbtree_remove (tree);
9067     }
9068   else
9069     {
9070       _gtk_rbtree_remove_node (tree, node);
9071     }
9072
9073   if (! gtk_tree_row_reference_valid (tree_view->priv->top_row))
9074     {
9075       gtk_tree_row_reference_free (tree_view->priv->top_row);
9076       tree_view->priv->top_row = NULL;
9077     }
9078
9079   /* Cancel any ongoing animation happening within the row */
9080   context = gtk_widget_get_style_context (GTK_WIDGET (tree_view));
9081   gtk_style_context_cancel_animations (context, node);
9082
9083   install_scroll_sync_handler (tree_view);
9084
9085   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
9086
9087   if (selection_changed)
9088     g_signal_emit_by_name (tree_view->priv->selection, "changed");
9089 }
9090
9091 static void
9092 gtk_tree_view_rows_reordered (GtkTreeModel *model,
9093                               GtkTreePath  *parent,
9094                               GtkTreeIter  *iter,
9095                               gint         *new_order,
9096                               gpointer      data)
9097 {
9098   GtkTreeView *tree_view = GTK_TREE_VIEW (data);
9099   GtkRBTree *tree;
9100   GtkRBNode *node;
9101   gint len;
9102
9103   len = gtk_tree_model_iter_n_children (model, iter);
9104
9105   if (len < 2)
9106     return;
9107
9108   gtk_tree_row_reference_reordered (G_OBJECT (data),
9109                                     parent,
9110                                     iter,
9111                                     new_order);
9112
9113   if (_gtk_tree_view_find_node (tree_view,
9114                                 parent,
9115                                 &tree,
9116                                 &node))
9117     return;
9118
9119   /* We need to special case the parent path */
9120   if (tree == NULL)
9121     tree = tree_view->priv->tree;
9122   else
9123     tree = node->children;
9124
9125   if (tree == NULL)
9126     return;
9127
9128   if (tree_view->priv->edited_column)
9129     gtk_tree_view_stop_editing (tree_view, TRUE);
9130
9131   /* we need to be unprelighted */
9132   ensure_unprelighted (tree_view);
9133
9134   _gtk_rbtree_reorder (tree, new_order, len);
9135
9136   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
9137
9138   gtk_tree_view_dy_to_top_row (tree_view);
9139 }
9140
9141
9142 /* Internal tree functions
9143  */
9144
9145
9146 static void
9147 gtk_tree_view_get_background_xrange (GtkTreeView       *tree_view,
9148                                      GtkRBTree         *tree,
9149                                      GtkTreeViewColumn *column,
9150                                      gint              *x1,
9151                                      gint              *x2)
9152 {
9153   GtkTreeViewColumn *tmp_column = NULL;
9154   gint total_width;
9155   GList *list;
9156   gboolean rtl;
9157
9158   if (x1)
9159     *x1 = 0;
9160
9161   if (x2)
9162     *x2 = 0;
9163
9164   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
9165
9166   total_width = 0;
9167   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
9168        list;
9169        list = (rtl ? list->prev : list->next))
9170     {
9171       tmp_column = list->data;
9172
9173       if (tmp_column == column)
9174         break;
9175
9176       if (gtk_tree_view_column_get_visible (tmp_column))
9177         total_width += gtk_tree_view_column_get_width (tmp_column);
9178     }
9179
9180   if (tmp_column != column)
9181     {
9182       g_warning (G_STRLOC": passed-in column isn't in the tree");
9183       return;
9184     }
9185
9186   if (x1)
9187     *x1 = total_width;
9188
9189   if (x2)
9190     {
9191       if (gtk_tree_view_column_get_visible (column))
9192         *x2 = total_width + gtk_tree_view_column_get_width (column);
9193       else
9194         *x2 = total_width; /* width of 0 */
9195     }
9196 }
9197
9198 static void
9199 gtk_tree_view_get_arrow_xrange (GtkTreeView *tree_view,
9200                                 GtkRBTree   *tree,
9201                                 gint        *x1,
9202                                 gint        *x2)
9203 {
9204   gint x_offset = 0;
9205   GList *list;
9206   GtkTreeViewColumn *tmp_column = NULL;
9207   gint total_width;
9208   gboolean indent_expanders;
9209   gboolean rtl;
9210
9211   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
9212
9213   total_width = 0;
9214   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
9215        list;
9216        list = (rtl ? list->prev : list->next))
9217     {
9218       tmp_column = list->data;
9219
9220       if (gtk_tree_view_is_expander_column (tree_view, tmp_column))
9221         {
9222           if (rtl)
9223             x_offset = total_width + gtk_tree_view_column_get_width (tmp_column) - tree_view->priv->expander_size;
9224           else
9225             x_offset = total_width;
9226           break;
9227         }
9228
9229       if (gtk_tree_view_column_get_visible (tmp_column))
9230         total_width += gtk_tree_view_column_get_width (tmp_column);
9231     }
9232
9233   gtk_widget_style_get (GTK_WIDGET (tree_view),
9234                         "indent-expanders", &indent_expanders,
9235                         NULL);
9236
9237   if (indent_expanders)
9238     {
9239       if (rtl)
9240         x_offset -= tree_view->priv->expander_size * _gtk_rbtree_get_depth (tree);
9241       else
9242         x_offset += tree_view->priv->expander_size * _gtk_rbtree_get_depth (tree);
9243     }
9244
9245   *x1 = x_offset;
9246
9247   if (tmp_column &&
9248       gtk_tree_view_column_get_visible (tmp_column))
9249     /* +1 because x2 isn't included in the range. */
9250     *x2 = *x1 + tree_view->priv->expander_size + 1;
9251   else
9252     *x2 = *x1;
9253 }
9254
9255 static void
9256 gtk_tree_view_build_tree (GtkTreeView *tree_view,
9257                           GtkRBTree   *tree,
9258                           GtkTreeIter *iter,
9259                           gint         depth,
9260                           gboolean     recurse)
9261 {
9262   GtkRBNode *temp = NULL;
9263   GtkTreePath *path = NULL;
9264
9265   do
9266     {
9267       gtk_tree_model_ref_node (tree_view->priv->model, iter);
9268       temp = _gtk_rbtree_insert_after (tree, temp, 0, FALSE);
9269
9270       if (tree_view->priv->fixed_height > 0)
9271         {
9272           if (GTK_RBNODE_FLAG_SET (temp, GTK_RBNODE_INVALID))
9273             {
9274               _gtk_rbtree_node_set_height (tree, temp, tree_view->priv->fixed_height);
9275               _gtk_rbtree_node_mark_valid (tree, temp);
9276             }
9277         }
9278
9279       if (tree_view->priv->is_list)
9280         continue;
9281
9282       if (recurse)
9283         {
9284           GtkTreeIter child;
9285
9286           if (!path)
9287             path = gtk_tree_model_get_path (tree_view->priv->model, iter);
9288           else
9289             gtk_tree_path_next (path);
9290
9291           if (gtk_tree_model_iter_children (tree_view->priv->model, &child, iter))
9292             {
9293               gboolean expand;
9294
9295               g_signal_emit (tree_view, tree_view_signals[TEST_EXPAND_ROW], 0, iter, path, &expand);
9296
9297               if (gtk_tree_model_iter_has_child (tree_view->priv->model, iter)
9298                   && !expand)
9299                 {
9300                   temp->children = _gtk_rbtree_new ();
9301                   temp->children->parent_tree = tree;
9302                   temp->children->parent_node = temp;
9303                   gtk_tree_view_build_tree (tree_view, temp->children, &child, depth + 1, recurse);
9304                 }
9305             }
9306         }
9307
9308       if (gtk_tree_model_iter_has_child (tree_view->priv->model, iter))
9309         {
9310           if ((temp->flags&GTK_RBNODE_IS_PARENT) != GTK_RBNODE_IS_PARENT)
9311             temp->flags ^= GTK_RBNODE_IS_PARENT;
9312         }
9313     }
9314   while (gtk_tree_model_iter_next (tree_view->priv->model, iter));
9315
9316   if (path)
9317     gtk_tree_path_free (path);
9318 }
9319
9320 /* Make sure the node is visible vertically */
9321 static void
9322 gtk_tree_view_clamp_node_visible (GtkTreeView *tree_view,
9323                                   GtkRBTree   *tree,
9324                                   GtkRBNode   *node)
9325 {
9326   gint node_dy, height;
9327   GtkTreePath *path = NULL;
9328
9329   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
9330     return;
9331
9332   /* just return if the node is visible, avoiding a costly expose */
9333   node_dy = _gtk_rbtree_node_find_offset (tree, node);
9334   height = gtk_tree_view_get_row_height (tree_view, node);
9335   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID)
9336       && node_dy >= gtk_adjustment_get_value (tree_view->priv->vadjustment)
9337       && node_dy + height <= (gtk_adjustment_get_value (tree_view->priv->vadjustment)
9338                               + gtk_adjustment_get_page_size (tree_view->priv->vadjustment)))
9339     return;
9340
9341   path = _gtk_tree_view_find_path (tree_view, tree, node);
9342   if (path)
9343     {
9344       /* We process updates because we want to clear old selected items when we scroll.
9345        * if this is removed, we get a "selection streak" at the bottom. */
9346       gtk_tree_view_bin_process_updates (tree_view);
9347
9348       gtk_tree_view_scroll_to_cell (tree_view, path, NULL, FALSE, 0.0, 0.0);
9349       gtk_tree_path_free (path);
9350     }
9351 }
9352
9353 static void
9354 gtk_tree_view_clamp_column_visible (GtkTreeView       *tree_view,
9355                                     GtkTreeViewColumn *column,
9356                                     gboolean           focus_to_cell)
9357 {
9358   GtkAllocation allocation;
9359   gint x, width;
9360
9361   if (column == NULL)
9362     return;
9363
9364   gtk_widget_get_allocation (gtk_tree_view_column_get_button (column), &allocation);
9365   x = allocation.x;
9366   width = allocation.width;
9367
9368   if (width > gtk_adjustment_get_page_size (tree_view->priv->hadjustment))
9369     {
9370       /* The column is larger than the horizontal page size.  If the
9371        * column has cells which can be focussed individually, then we make
9372        * sure the cell which gets focus is fully visible (if even the
9373        * focus cell is bigger than the page size, we make sure the
9374        * left-hand side of the cell is visible).
9375        *
9376        * If the column does not have an activatable cell, we
9377        * make sure the left-hand side of the column is visible.
9378        */
9379
9380       if (focus_to_cell && gtk_tree_view_has_can_focus_cell (tree_view))
9381         {
9382           GtkCellArea *cell_area;
9383           GtkCellRenderer *focus_cell;
9384
9385           cell_area = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (column));
9386           focus_cell = gtk_cell_area_get_focus_cell (cell_area);
9387
9388           if (gtk_tree_view_column_cell_get_position (column, focus_cell,
9389                                                       &x, &width))
9390             {
9391               if (width < gtk_adjustment_get_page_size (tree_view->priv->hadjustment))
9392                 {
9393                   if (gtk_adjustment_get_value (tree_view->priv->hadjustment) + gtk_adjustment_get_page_size (tree_view->priv->hadjustment) < x + width)
9394                     gtk_adjustment_set_value (tree_view->priv->hadjustment,
9395                                               x + width - gtk_adjustment_get_page_size (tree_view->priv->hadjustment));
9396                   else if (gtk_adjustment_get_value (tree_view->priv->hadjustment) > x)
9397                     gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
9398                 }
9399             }
9400         }
9401
9402       gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
9403     }
9404   else
9405     {
9406       if ((gtk_adjustment_get_value (tree_view->priv->hadjustment) + gtk_adjustment_get_page_size (tree_view->priv->hadjustment)) < (x + width))
9407           gtk_adjustment_set_value (tree_view->priv->hadjustment,
9408                                     x + width - gtk_adjustment_get_page_size (tree_view->priv->hadjustment));
9409       else if (gtk_adjustment_get_value (tree_view->priv->hadjustment) > x)
9410         gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
9411   }
9412 }
9413
9414 /* This function could be more efficient.  I'll optimize it if profiling seems
9415  * to imply that it is important */
9416 GtkTreePath *
9417 _gtk_tree_view_find_path (GtkTreeView *tree_view,
9418                           GtkRBTree   *tree,
9419                           GtkRBNode   *node)
9420 {
9421   GtkTreePath *path;
9422   GtkRBTree *tmp_tree;
9423   GtkRBNode *tmp_node, *last;
9424   gint count;
9425
9426   path = gtk_tree_path_new ();
9427
9428   g_return_val_if_fail (node != NULL, path);
9429   g_return_val_if_fail (node != tree->nil, path);
9430
9431   count = 1 + node->left->count;
9432
9433   last = node;
9434   tmp_node = node->parent;
9435   tmp_tree = tree;
9436   while (tmp_tree)
9437     {
9438       while (tmp_node != tmp_tree->nil)
9439         {
9440           if (tmp_node->right == last)
9441             count += 1 + tmp_node->left->count;
9442           last = tmp_node;
9443           tmp_node = tmp_node->parent;
9444         }
9445       gtk_tree_path_prepend_index (path, count - 1);
9446       last = tmp_tree->parent_node;
9447       tmp_tree = tmp_tree->parent_tree;
9448       if (last)
9449         {
9450           count = 1 + last->left->count;
9451           tmp_node = last->parent;
9452         }
9453     }
9454   return path;
9455 }
9456
9457 /* Returns TRUE if we ran out of tree before finding the path.  If the path is
9458  * invalid (ie. points to a node that's not in the tree), *tree and *node are
9459  * both set to NULL.
9460  */
9461 gboolean
9462 _gtk_tree_view_find_node (GtkTreeView  *tree_view,
9463                           GtkTreePath  *path,
9464                           GtkRBTree   **tree,
9465                           GtkRBNode   **node)
9466 {
9467   GtkRBNode *tmpnode = NULL;
9468   GtkRBTree *tmptree = tree_view->priv->tree;
9469   gint *indices = gtk_tree_path_get_indices (path);
9470   gint depth = gtk_tree_path_get_depth (path);
9471   gint i = 0;
9472
9473   *node = NULL;
9474   *tree = NULL;
9475
9476   if (depth == 0 || tmptree == NULL)
9477     return FALSE;
9478   do
9479     {
9480       tmpnode = _gtk_rbtree_find_count (tmptree, indices[i] + 1);
9481       ++i;
9482       if (tmpnode == NULL)
9483         {
9484           *tree = NULL;
9485           *node = NULL;
9486           return FALSE;
9487         }
9488       if (i >= depth)
9489         {
9490           *tree = tmptree;
9491           *node = tmpnode;
9492           return FALSE;
9493         }
9494       *tree = tmptree;
9495       *node = tmpnode;
9496       tmptree = tmpnode->children;
9497       if (tmptree == NULL)
9498         return TRUE;
9499     }
9500   while (1);
9501 }
9502
9503 static gboolean
9504 gtk_tree_view_is_expander_column (GtkTreeView       *tree_view,
9505                                   GtkTreeViewColumn *column)
9506 {
9507   GList *list;
9508
9509   if (tree_view->priv->is_list)
9510     return FALSE;
9511
9512   if (tree_view->priv->expander_column != NULL)
9513     {
9514       if (tree_view->priv->expander_column == column)
9515         return TRUE;
9516       return FALSE;
9517     }
9518   else
9519     {
9520       for (list = tree_view->priv->columns;
9521            list;
9522            list = list->next)
9523         if (gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (list->data)))
9524           break;
9525       if (list && list->data == column)
9526         return TRUE;
9527     }
9528   return FALSE;
9529 }
9530
9531 static inline gboolean
9532 gtk_tree_view_draw_expanders (GtkTreeView *tree_view)
9533 {
9534   if (!tree_view->priv->is_list && tree_view->priv->show_expanders)
9535     return TRUE;
9536   /* else */
9537   return FALSE;
9538 }
9539
9540 static void
9541 gtk_tree_view_add_move_binding (GtkBindingSet  *binding_set,
9542                                 guint           keyval,
9543                                 guint           modmask,
9544                                 gboolean        add_shifted_binding,
9545                                 GtkMovementStep step,
9546                                 gint            count)
9547 {
9548   
9549   gtk_binding_entry_add_signal (binding_set, keyval, modmask,
9550                                 "move-cursor", 2,
9551                                 G_TYPE_ENUM, step,
9552                                 G_TYPE_INT, count);
9553
9554   if (add_shifted_binding)
9555     gtk_binding_entry_add_signal (binding_set, keyval, GDK_SHIFT_MASK,
9556                                   "move-cursor", 2,
9557                                   G_TYPE_ENUM, step,
9558                                   G_TYPE_INT, count);
9559
9560   if ((modmask & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
9561    return;
9562
9563   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK | GDK_SHIFT_MASK,
9564                                 "move-cursor", 2,
9565                                 G_TYPE_ENUM, step,
9566                                 G_TYPE_INT, count);
9567
9568   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK,
9569                                 "move-cursor", 2,
9570                                 G_TYPE_ENUM, step,
9571                                 G_TYPE_INT, count);
9572 }
9573
9574 static gint
9575 gtk_tree_view_unref_tree_helper (GtkTreeModel *model,
9576                                  GtkTreeIter  *iter,
9577                                  GtkRBTree    *tree,
9578                                  GtkRBNode    *node)
9579 {
9580   gint retval = FALSE;
9581   do
9582     {
9583       g_return_val_if_fail (node != NULL, FALSE);
9584
9585       if (node->children)
9586         {
9587           GtkTreeIter child;
9588           GtkRBTree *new_tree;
9589           GtkRBNode *new_node;
9590
9591           new_tree = node->children;
9592           new_node = new_tree->root;
9593
9594           while (new_node && new_node->left != new_tree->nil)
9595             new_node = new_node->left;
9596
9597           if (!gtk_tree_model_iter_children (model, &child, iter))
9598             return FALSE;
9599
9600           retval = retval || gtk_tree_view_unref_tree_helper (model, &child, new_tree, new_node);
9601         }
9602
9603       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
9604         retval = TRUE;
9605       gtk_tree_model_unref_node (model, iter);
9606       node = _gtk_rbtree_next (tree, node);
9607     }
9608   while (gtk_tree_model_iter_next (model, iter));
9609
9610   return retval;
9611 }
9612
9613 static gint
9614 gtk_tree_view_unref_and_check_selection_tree (GtkTreeView *tree_view,
9615                                               GtkRBTree   *tree)
9616 {
9617   GtkTreeIter iter;
9618   GtkTreePath *path;
9619   GtkRBNode *node;
9620   gint retval;
9621
9622   if (!tree)
9623     return FALSE;
9624
9625   node = tree->root;
9626   while (node && node->left != tree->nil)
9627     node = node->left;
9628
9629   g_return_val_if_fail (node != NULL, FALSE);
9630   path = _gtk_tree_view_find_path (tree_view, tree, node);
9631   gtk_tree_model_get_iter (GTK_TREE_MODEL (tree_view->priv->model),
9632                            &iter, path);
9633   retval = gtk_tree_view_unref_tree_helper (GTK_TREE_MODEL (tree_view->priv->model), &iter, tree, node);
9634   gtk_tree_path_free (path);
9635
9636   return retval;
9637 }
9638
9639 static void
9640 gtk_tree_view_set_column_drag_info (GtkTreeView       *tree_view,
9641                                     GtkTreeViewColumn *column)
9642 {
9643   GtkTreeViewColumn *left_column;
9644   GtkTreeViewColumn *cur_column = NULL;
9645   GtkTreeViewColumnReorder *reorder;
9646   gboolean rtl;
9647   GList *tmp_list;
9648   gint left;
9649
9650   /* We want to precalculate the motion list such that we know what column slots
9651    * are available.
9652    */
9653   left_column = NULL;
9654   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
9655
9656   /* First, identify all possible drop spots */
9657   if (rtl)
9658     tmp_list = g_list_last (tree_view->priv->columns);
9659   else
9660     tmp_list = g_list_first (tree_view->priv->columns);
9661
9662   while (tmp_list)
9663     {
9664       cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
9665       tmp_list = rtl?g_list_previous (tmp_list):g_list_next (tmp_list);
9666
9667       if (gtk_tree_view_column_get_visible (cur_column) == FALSE)
9668         continue;
9669
9670       /* If it's not the column moving and func tells us to skip over the column, we continue. */
9671       if (left_column != column && cur_column != column &&
9672           tree_view->priv->column_drop_func &&
9673           ! tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
9674         {
9675           left_column = cur_column;
9676           continue;
9677         }
9678       reorder = g_slice_new0 (GtkTreeViewColumnReorder);
9679       reorder->left_column = left_column;
9680       left_column = reorder->right_column = cur_column;
9681
9682       tree_view->priv->column_drag_info = g_list_append (tree_view->priv->column_drag_info, reorder);
9683     }
9684
9685   /* Add the last one */
9686   if (tree_view->priv->column_drop_func == NULL ||
9687       ((left_column != column) &&
9688        tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data)))
9689     {
9690       reorder = g_slice_new0 (GtkTreeViewColumnReorder);
9691       reorder->left_column = left_column;
9692       reorder->right_column = NULL;
9693       tree_view->priv->column_drag_info = g_list_append (tree_view->priv->column_drag_info, reorder);
9694     }
9695
9696   /* We quickly check to see if it even makes sense to reorder columns. */
9697   /* If there is nothing that can be moved, then we return */
9698
9699   if (tree_view->priv->column_drag_info == NULL)
9700     return;
9701
9702   /* We know there are always 2 slots possbile, as you can always return column. */
9703   /* If that's all there is, return */
9704   if (tree_view->priv->column_drag_info->next == NULL || 
9705       (tree_view->priv->column_drag_info->next->next == NULL &&
9706        ((GtkTreeViewColumnReorder *)tree_view->priv->column_drag_info->data)->right_column == column &&
9707        ((GtkTreeViewColumnReorder *)tree_view->priv->column_drag_info->next->data)->left_column == column))
9708     {
9709       for (tmp_list = tree_view->priv->column_drag_info; tmp_list; tmp_list = tmp_list->next)
9710         g_slice_free (GtkTreeViewColumnReorder, tmp_list->data);
9711       g_list_free (tree_view->priv->column_drag_info);
9712       tree_view->priv->column_drag_info = NULL;
9713       return;
9714     }
9715   /* We fill in the ranges for the columns, now that we've isolated them */
9716   left = - TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER (tree_view);
9717
9718   for (tmp_list = tree_view->priv->column_drag_info; tmp_list; tmp_list = tmp_list->next)
9719     {
9720       reorder = (GtkTreeViewColumnReorder *) tmp_list->data;
9721
9722       reorder->left_align = left;
9723       if (tmp_list->next != NULL)
9724         {
9725           GtkAllocation right_allocation, left_allocation;
9726           GtkWidget    *left_button, *right_button;
9727
9728           g_assert (tmp_list->next->data);
9729
9730           right_button = gtk_tree_view_column_get_button (reorder->right_column);
9731           left_button  = gtk_tree_view_column_get_button
9732             (((GtkTreeViewColumnReorder *)tmp_list->next->data)->left_column);
9733
9734           gtk_widget_get_allocation (right_button, &right_allocation);
9735           gtk_widget_get_allocation (left_button, &left_allocation);
9736           left = reorder->right_align = (right_allocation.x + right_allocation.width + left_allocation.x) / 2;
9737         }
9738       else
9739         {
9740           reorder->right_align = gdk_window_get_width (tree_view->priv->header_window)
9741                                  + TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER (tree_view);
9742         }
9743     }
9744 }
9745
9746 void
9747 _gtk_tree_view_column_start_drag (GtkTreeView       *tree_view,
9748                                   GtkTreeViewColumn *column,
9749                                   GdkDevice         *device)
9750 {
9751   GdkEvent *send_event;
9752   GtkAllocation allocation;
9753   GtkAllocation button_allocation;
9754   GdkScreen *screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
9755   GtkWidget *button;
9756   GdkDevice *pointer, *keyboard;
9757
9758   g_return_if_fail (tree_view->priv->column_drag_info == NULL);
9759   g_return_if_fail (tree_view->priv->cur_reorder == NULL);
9760
9761   gtk_tree_view_set_column_drag_info (tree_view, column);
9762
9763   if (tree_view->priv->column_drag_info == NULL)
9764     return;
9765
9766   button = gtk_tree_view_column_get_button (column);
9767
9768   if (tree_view->priv->drag_window == NULL)
9769     {
9770       GdkWindowAttr attributes;
9771       guint attributes_mask;
9772
9773       gtk_widget_get_allocation (button, &button_allocation);
9774
9775       attributes.window_type = GDK_WINDOW_CHILD;
9776       attributes.wclass = GDK_INPUT_OUTPUT;
9777       attributes.x = button_allocation.x;
9778       attributes.y = 0;
9779       attributes.width = button_allocation.width;
9780       attributes.height = button_allocation.height;
9781       attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
9782       attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
9783       attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
9784
9785       tree_view->priv->drag_window = gdk_window_new (tree_view->priv->bin_window,
9786                                                      &attributes,
9787                                                      attributes_mask);
9788       gdk_window_set_user_data (tree_view->priv->drag_window, GTK_WIDGET (tree_view));
9789     }
9790
9791   if (gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD)
9792     {
9793       keyboard = device;
9794       pointer = gdk_device_get_associated_device (device);
9795     }
9796   else
9797     {
9798       pointer = device;
9799       keyboard = gdk_device_get_associated_device (device);
9800     }
9801
9802   gdk_device_ungrab (pointer, GDK_CURRENT_TIME);
9803   gdk_device_ungrab (keyboard, GDK_CURRENT_TIME);
9804
9805   gtk_grab_remove (button);
9806
9807   send_event = gdk_event_new (GDK_LEAVE_NOTIFY);
9808   send_event->crossing.send_event = TRUE;
9809   send_event->crossing.window = g_object_ref (gtk_button_get_event_window (GTK_BUTTON (button)));
9810   send_event->crossing.subwindow = NULL;
9811   send_event->crossing.detail = GDK_NOTIFY_ANCESTOR;
9812   send_event->crossing.time = GDK_CURRENT_TIME;
9813   gdk_event_set_device (send_event, device);
9814
9815   gtk_propagate_event (button, send_event);
9816   gdk_event_free (send_event);
9817
9818   send_event = gdk_event_new (GDK_BUTTON_RELEASE);
9819   send_event->button.window = g_object_ref (gdk_screen_get_root_window (screen));
9820   send_event->button.send_event = TRUE;
9821   send_event->button.time = GDK_CURRENT_TIME;
9822   send_event->button.x = -1;
9823   send_event->button.y = -1;
9824   send_event->button.axes = NULL;
9825   send_event->button.state = 0;
9826   send_event->button.button = 1;
9827   send_event->button.x_root = 0;
9828   send_event->button.y_root = 0;
9829   gdk_event_set_device (send_event, device);
9830
9831   gtk_propagate_event (button, send_event);
9832   gdk_event_free (send_event);
9833
9834   /* Kids, don't try this at home */
9835   g_object_ref (button);
9836   gtk_container_remove (GTK_CONTAINER (tree_view), button);
9837   gtk_widget_set_parent_window (button, tree_view->priv->drag_window);
9838   gtk_widget_set_parent (button, GTK_WIDGET (tree_view));
9839   g_object_unref (button);
9840
9841   gtk_widget_get_allocation (button, &button_allocation);
9842   tree_view->priv->drag_column_x = button_allocation.x;
9843   allocation = button_allocation;
9844   allocation.x = 0;
9845   gtk_widget_size_allocate (button, &allocation);
9846   gtk_widget_set_parent_window (button, tree_view->priv->drag_window);
9847
9848   tree_view->priv->drag_column = column;
9849   gdk_window_show (tree_view->priv->drag_window);
9850
9851   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
9852   while (gtk_events_pending ())
9853     gtk_main_iteration ();
9854
9855   tree_view->priv->in_column_drag = TRUE;
9856
9857   gdk_device_grab (pointer,
9858                    tree_view->priv->drag_window,
9859                    GDK_OWNERSHIP_NONE,
9860                    FALSE,
9861                    GDK_POINTER_MOTION_MASK|GDK_BUTTON_RELEASE_MASK,
9862                    NULL,
9863                    GDK_CURRENT_TIME);
9864   gdk_device_grab (keyboard,
9865                    tree_view->priv->drag_window,
9866                    GDK_OWNERSHIP_NONE,
9867                    FALSE,
9868                    GDK_KEY_PRESS_MASK|GDK_KEY_RELEASE_MASK,
9869                    NULL,
9870                    GDK_CURRENT_TIME);
9871 }
9872
9873 static void
9874 gtk_tree_view_queue_draw_arrow (GtkTreeView        *tree_view,
9875                                 GtkRBTree          *tree,
9876                                 GtkRBNode          *node)
9877 {
9878   GtkAllocation allocation;
9879   GdkRectangle rect;
9880
9881   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
9882     return;
9883
9884   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
9885   rect.x = 0;
9886   rect.width = MAX (tree_view->priv->expander_size, MAX (tree_view->priv->width, allocation.width));
9887
9888   rect.y = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
9889   rect.height = gtk_tree_view_get_row_height (tree_view, node);
9890
9891   gdk_window_invalidate_rect (tree_view->priv->bin_window, &rect, TRUE);
9892 }
9893
9894 void
9895 _gtk_tree_view_queue_draw_node (GtkTreeView        *tree_view,
9896                                 GtkRBTree          *tree,
9897                                 GtkRBNode          *node,
9898                                 const GdkRectangle *clip_rect)
9899 {
9900   GtkAllocation allocation;
9901   GdkRectangle rect;
9902
9903   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
9904     return;
9905
9906   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
9907   rect.x = 0;
9908   rect.width = MAX (tree_view->priv->width, allocation.width);
9909
9910   rect.y = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
9911   rect.height = gtk_tree_view_get_row_height (tree_view, node);
9912
9913   if (clip_rect)
9914     {
9915       GdkRectangle new_rect;
9916
9917       gdk_rectangle_intersect (clip_rect, &rect, &new_rect);
9918
9919       gdk_window_invalidate_rect (tree_view->priv->bin_window, &new_rect, TRUE);
9920     }
9921   else
9922     {
9923       gdk_window_invalidate_rect (tree_view->priv->bin_window, &rect, TRUE);
9924     }
9925 }
9926
9927 static inline gint
9928 gtk_tree_view_get_effective_header_height (GtkTreeView *tree_view)
9929 {
9930   if (tree_view->priv->headers_visible)
9931     return tree_view->priv->header_height;
9932   /* else */
9933   return 0;
9934 }
9935
9936 gint
9937 _gtk_tree_view_get_header_height (GtkTreeView *tree_view)
9938 {
9939   return tree_view->priv->header_height;
9940 }
9941
9942 void
9943 _gtk_tree_view_get_row_separator_func (GtkTreeView                 *tree_view,
9944                                        GtkTreeViewRowSeparatorFunc *func,
9945                                        gpointer                    *data)
9946 {
9947   *func = tree_view->priv->row_separator_func;
9948   *data = tree_view->priv->row_separator_data;
9949 }
9950
9951 GtkTreePath *
9952 _gtk_tree_view_get_anchor_path (GtkTreeView *tree_view)
9953 {
9954   if (tree_view->priv->anchor)
9955     return gtk_tree_row_reference_get_path (tree_view->priv->anchor);
9956
9957   return NULL;
9958 }
9959
9960 void
9961 _gtk_tree_view_set_anchor_path (GtkTreeView *tree_view,
9962                                 GtkTreePath *anchor_path)
9963 {
9964   if (tree_view->priv->anchor)
9965     {
9966       gtk_tree_row_reference_free (tree_view->priv->anchor);
9967       tree_view->priv->anchor = NULL;
9968     }
9969
9970   if (anchor_path && tree_view->priv->model)
9971     tree_view->priv->anchor =
9972       gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), 
9973                                         tree_view->priv->model, anchor_path);
9974 }
9975
9976 GtkRBTree *
9977 _gtk_tree_view_get_rbtree (GtkTreeView *tree_view)
9978 {
9979   return tree_view->priv->tree;
9980 }
9981
9982 GdkWindow *
9983 _gtk_tree_view_get_header_window (GtkTreeView *tree_view)
9984 {
9985   return tree_view->priv->header_window;
9986 }
9987
9988 void
9989 _gtk_tree_view_set_focus_column (GtkTreeView       *tree_view,
9990                                  GtkTreeViewColumn *column)
9991 {
9992   tree_view->priv->focus_column = column;
9993 }
9994
9995
9996 static void
9997 gtk_tree_view_queue_draw_path (GtkTreeView        *tree_view,
9998                                GtkTreePath        *path,
9999                                const GdkRectangle *clip_rect)
10000 {
10001   GtkRBTree *tree = NULL;
10002   GtkRBNode *node = NULL;
10003
10004   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
10005
10006   if (tree)
10007     _gtk_tree_view_queue_draw_node (tree_view, tree, node, clip_rect);
10008 }
10009
10010 /* x and y are the mouse position
10011  */
10012 static void
10013 gtk_tree_view_draw_arrow (GtkTreeView *tree_view,
10014                           cairo_t     *cr,
10015                           GtkRBTree   *tree,
10016                           GtkRBNode   *node,
10017                           /* in bin_window coordinates */
10018                           gint         x,
10019                           gint         y)
10020 {
10021   GdkRectangle area;
10022   GtkStateFlags state = 0;
10023   GtkStyleContext *context;
10024   GtkWidget *widget;
10025   gint x_offset = 0;
10026   gint x2;
10027   gint vertical_separator;
10028   gint expander_size;
10029   GtkCellRendererState flags;
10030
10031   widget = GTK_WIDGET (tree_view);
10032   context = gtk_widget_get_style_context (widget);
10033
10034   gtk_widget_style_get (widget,
10035                         "vertical-separator", &vertical_separator,
10036                         NULL);
10037   expander_size = tree_view->priv->expander_size - EXPANDER_EXTRA_PADDING;
10038
10039   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
10040     return;
10041
10042   gtk_tree_view_get_arrow_xrange (tree_view, tree, &x_offset, &x2);
10043
10044   area.x = x_offset;
10045   area.y = gtk_tree_view_get_cell_area_y_offset (tree_view, tree, node,
10046                                                  vertical_separator);
10047   area.width = expander_size + 2;
10048   area.height = gtk_tree_view_get_cell_area_height (tree_view, node,
10049                                                     vertical_separator);
10050
10051   if (!gtk_widget_get_sensitive (widget))
10052     state |= GTK_STATE_FLAG_INSENSITIVE;
10053   else
10054     {
10055       flags = 0;
10056
10057       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
10058         flags |= GTK_CELL_RENDERER_SELECTED;
10059
10060       state = gtk_cell_renderer_get_state (NULL, widget, flags);
10061
10062       if (node == tree_view->priv->button_pressed_node &&
10063           x >= area.x && x <= (area.x + area.width) &&
10064           y >= area.y && y <= (area.y + area.height))
10065         state |= GTK_STATE_FLAG_FOCUSED;
10066
10067       if (node == tree_view->priv->prelight_node &&
10068           tree_view->priv->arrow_prelit)
10069         state |= GTK_STATE_FLAG_PRELIGHT;
10070     }
10071
10072   if (node->children != NULL)
10073     state |= GTK_STATE_FLAG_ACTIVE;
10074
10075   gtk_style_context_save (context);
10076
10077   gtk_style_context_set_state (context, state);
10078   gtk_style_context_add_class (context, GTK_STYLE_CLASS_EXPANDER);
10079
10080   gtk_style_context_push_animatable_region (context, node);
10081
10082   gtk_render_expander (context, cr,
10083                        area.x, area.y,
10084                        area.width, area.height);
10085
10086   gtk_style_context_pop_animatable_region (context);
10087   gtk_style_context_restore (context);
10088 }
10089
10090 static void
10091 gtk_tree_view_focus_to_cursor (GtkTreeView *tree_view)
10092
10093 {
10094   GtkTreePath *cursor_path;
10095
10096   if ((tree_view->priv->tree == NULL) ||
10097       (! gtk_widget_get_realized (GTK_WIDGET (tree_view))))
10098     return;
10099
10100   cursor_path = NULL;
10101   if (tree_view->priv->cursor)
10102     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10103
10104   if (cursor_path == NULL)
10105     {
10106       /* Consult the selection before defaulting to the
10107        * first focusable element
10108        */
10109       GList *selected_rows;
10110       GtkTreeModel *model;
10111       GtkTreeSelection *selection;
10112
10113       selection = gtk_tree_view_get_selection (tree_view);
10114       selected_rows = gtk_tree_selection_get_selected_rows (selection, &model);
10115
10116       if (selected_rows)
10117         {
10118           cursor_path = gtk_tree_path_copy((const GtkTreePath *)(selected_rows->data));
10119           g_list_foreach (selected_rows, (GFunc)gtk_tree_path_free, NULL);
10120           g_list_free (selected_rows);
10121         }
10122       else
10123         {
10124           cursor_path = gtk_tree_path_new_first ();
10125           search_first_focusable_path (tree_view, &cursor_path,
10126                                        TRUE, NULL, NULL);
10127         }
10128
10129       gtk_tree_row_reference_free (tree_view->priv->cursor);
10130       tree_view->priv->cursor = NULL;
10131
10132       if (cursor_path)
10133         {
10134           if (gtk_tree_selection_get_mode (tree_view->priv->selection) == GTK_SELECTION_MULTIPLE)
10135             gtk_tree_view_real_set_cursor (tree_view, cursor_path, FALSE, FALSE);
10136           else
10137             gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE);
10138         }
10139     }
10140
10141   if (cursor_path)
10142     {
10143       tree_view->priv->draw_keyfocus = TRUE;
10144
10145       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10146       gtk_tree_path_free (cursor_path);
10147
10148       if (tree_view->priv->focus_column == NULL)
10149         {
10150           GList *list;
10151           for (list = tree_view->priv->columns; list; list = list->next)
10152             {
10153               if (gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (list->data)))
10154                 {
10155                   GtkCellArea *cell_area;
10156
10157                   tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (list->data);
10158
10159                   /* This happens when the treeview initially grabs focus and there
10160                    * is no column in focus, here we explicitly focus into the first cell */
10161                   cell_area = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (tree_view->priv->focus_column));
10162                   if (!gtk_cell_area_get_focus_cell (cell_area))
10163                     {
10164                       gboolean rtl;
10165
10166                       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
10167                       gtk_cell_area_focus (cell_area,
10168                                            rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT);
10169                     }
10170
10171                   break;
10172                 }
10173             }
10174         }
10175     }
10176 }
10177
10178 static void
10179 gtk_tree_view_move_cursor_up_down (GtkTreeView *tree_view,
10180                                    gint         count)
10181 {
10182   gint selection_count;
10183   GtkRBTree *cursor_tree = NULL;
10184   GtkRBNode *cursor_node = NULL;
10185   GtkRBTree *new_cursor_tree = NULL;
10186   GtkRBNode *new_cursor_node = NULL;
10187   GtkTreePath *cursor_path = NULL;
10188   gboolean grab_focus = TRUE;
10189   gboolean selectable;
10190   GtkDirectionType direction;
10191   GtkCellArea *cell_area = NULL;
10192   GtkCellRenderer *last_focus_cell = NULL;
10193   GtkTreeIter iter;
10194
10195   if (! gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10196     return;
10197
10198   cursor_path = NULL;
10199   if (!gtk_tree_row_reference_valid (tree_view->priv->cursor))
10200     /* FIXME: we lost the cursor; should we get the first? */
10201     return;
10202
10203   cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10204   _gtk_tree_view_find_node (tree_view, cursor_path,
10205                             &cursor_tree, &cursor_node);
10206
10207   if (cursor_tree == NULL)
10208     /* FIXME: we lost the cursor; should we get the first? */
10209     return;
10210
10211   direction = count < 0 ? GTK_DIR_UP : GTK_DIR_DOWN;
10212
10213   if (tree_view->priv->focus_column)
10214     cell_area = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (tree_view->priv->focus_column));
10215
10216   /* If focus stays in the area for this row, then just return for this round */
10217   if (cell_area && (count == -1 || count == 1) &&
10218       gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path))
10219     {
10220       gtk_tree_view_column_cell_set_cell_data (tree_view->priv->focus_column,
10221                                                tree_view->priv->model,
10222                                                &iter,
10223                                                GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_PARENT),
10224                                                cursor_node->children?TRUE:FALSE);
10225
10226       /* Save the last cell that had focus, if we hit the end of the view we'll give
10227        * focus back to it. */
10228       last_focus_cell = gtk_cell_area_get_focus_cell (cell_area);
10229
10230       /* If focus stays in the area, no need to change the cursor row */
10231       if (gtk_cell_area_focus (cell_area, direction))
10232         return;
10233     }
10234
10235   selection_count = gtk_tree_selection_count_selected_rows (tree_view->priv->selection);
10236   selectable = _gtk_tree_selection_row_is_selectable (tree_view->priv->selection,
10237                                                       cursor_node,
10238                                                       cursor_path);
10239
10240   if (selection_count == 0
10241       && gtk_tree_selection_get_mode (tree_view->priv->selection) != GTK_SELECTION_NONE
10242       && !tree_view->priv->ctrl_pressed
10243       && selectable)
10244     {
10245       /* Don't move the cursor, but just select the current node */
10246       new_cursor_tree = cursor_tree;
10247       new_cursor_node = cursor_node;
10248     }
10249   else
10250     {
10251       if (count == -1)
10252         _gtk_rbtree_prev_full (cursor_tree, cursor_node,
10253                                &new_cursor_tree, &new_cursor_node);
10254       else
10255         _gtk_rbtree_next_full (cursor_tree, cursor_node,
10256                                &new_cursor_tree, &new_cursor_node);
10257     }
10258
10259   gtk_tree_path_free (cursor_path);
10260
10261   if (new_cursor_node)
10262     {
10263       cursor_path = _gtk_tree_view_find_path (tree_view,
10264                                               new_cursor_tree, new_cursor_node);
10265
10266       search_first_focusable_path (tree_view, &cursor_path,
10267                                    (count != -1),
10268                                    &new_cursor_tree,
10269                                    &new_cursor_node);
10270
10271       if (cursor_path)
10272         gtk_tree_path_free (cursor_path);
10273     }
10274
10275   /*
10276    * If the list has only one item and multi-selection is set then select
10277    * the row (if not yet selected).
10278    */
10279   if (gtk_tree_selection_get_mode (tree_view->priv->selection) == GTK_SELECTION_MULTIPLE &&
10280       new_cursor_node == NULL)
10281     {
10282       if (count == -1)
10283         _gtk_rbtree_next_full (cursor_tree, cursor_node,
10284                                &new_cursor_tree, &new_cursor_node);
10285       else
10286         _gtk_rbtree_prev_full (cursor_tree, cursor_node,
10287                                &new_cursor_tree, &new_cursor_node);
10288
10289       if (new_cursor_node == NULL
10290           && !GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_SELECTED))
10291         {
10292           new_cursor_node = cursor_node;
10293           new_cursor_tree = cursor_tree;
10294         }
10295       else
10296         {
10297           new_cursor_node = NULL;
10298         }
10299     }
10300
10301   if (new_cursor_node)
10302     {
10303       cursor_path = _gtk_tree_view_find_path (tree_view, new_cursor_tree, new_cursor_node);
10304       gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, TRUE);
10305       gtk_tree_path_free (cursor_path);
10306
10307       /* Give focus to the area in the new row */
10308       if (cell_area)
10309         gtk_cell_area_focus (cell_area, direction);
10310     }
10311   else
10312     {
10313       gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10314
10315       if (!tree_view->priv->shift_pressed)
10316         {
10317           if (! gtk_widget_keynav_failed (GTK_WIDGET (tree_view),
10318                                           count < 0 ?
10319                                           GTK_DIR_UP : GTK_DIR_DOWN))
10320             {
10321               GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (tree_view));
10322
10323               if (toplevel)
10324                 gtk_widget_child_focus (toplevel,
10325                                         count < 0 ?
10326                                         GTK_DIR_TAB_BACKWARD :
10327                                         GTK_DIR_TAB_FORWARD);
10328
10329               grab_focus = FALSE;
10330             }
10331         }
10332       else
10333         {
10334           gtk_widget_error_bell (GTK_WIDGET (tree_view));
10335         }
10336
10337       if (cell_area)
10338         gtk_cell_area_set_focus_cell (cell_area, last_focus_cell);
10339     }
10340
10341   if (grab_focus)
10342     gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10343 }
10344
10345 static void
10346 gtk_tree_view_move_cursor_page_up_down (GtkTreeView *tree_view,
10347                                         gint         count)
10348 {
10349   GtkRBTree *cursor_tree = NULL;
10350   GtkRBNode *cursor_node = NULL;
10351   GtkTreePath *old_cursor_path = NULL;
10352   GtkTreePath *cursor_path = NULL;
10353   GtkRBTree *start_cursor_tree = NULL;
10354   GtkRBNode *start_cursor_node = NULL;
10355   gint y;
10356   gint window_y;
10357   gint vertical_separator;
10358
10359   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10360     return;
10361
10362   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
10363     old_cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10364   else
10365     /* This is sorta weird.  Focus in should give us a cursor */
10366     return;
10367
10368   gtk_widget_style_get (GTK_WIDGET (tree_view), "vertical-separator", &vertical_separator, NULL);
10369   _gtk_tree_view_find_node (tree_view, old_cursor_path,
10370                             &cursor_tree, &cursor_node);
10371
10372   if (cursor_tree == NULL)
10373     {
10374       /* FIXME: we lost the cursor.  Should we try to get one? */
10375       gtk_tree_path_free (old_cursor_path);
10376       return;
10377     }
10378   g_return_if_fail (cursor_node != NULL);
10379
10380   y = _gtk_rbtree_node_find_offset (cursor_tree, cursor_node);
10381   window_y = RBTREE_Y_TO_TREE_WINDOW_Y (tree_view, y);
10382   y += tree_view->priv->cursor_offset;
10383   y += count * (int)gtk_adjustment_get_page_increment (tree_view->priv->vadjustment);
10384   y = CLAMP (y, (gint)gtk_adjustment_get_lower (tree_view->priv->vadjustment),  (gint)gtk_adjustment_get_upper (tree_view->priv->vadjustment) - vertical_separator);
10385
10386   if (y >= tree_view->priv->height)
10387     y = tree_view->priv->height - 1;
10388
10389   tree_view->priv->cursor_offset =
10390     _gtk_rbtree_find_offset (tree_view->priv->tree, y,
10391                              &cursor_tree, &cursor_node);
10392
10393   if (cursor_tree == NULL)
10394     {
10395       /* FIXME: we lost the cursor.  Should we try to get one? */
10396       gtk_tree_path_free (old_cursor_path);
10397       return;
10398     }
10399
10400   if (tree_view->priv->cursor_offset
10401       > gtk_tree_view_get_row_height (tree_view, cursor_node))
10402     {
10403       _gtk_rbtree_next_full (cursor_tree, cursor_node,
10404                              &cursor_tree, &cursor_node);
10405       tree_view->priv->cursor_offset -= gtk_tree_view_get_row_height (tree_view, cursor_node);
10406     }
10407
10408   y -= tree_view->priv->cursor_offset;
10409   cursor_path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
10410
10411   start_cursor_tree = cursor_tree;
10412   start_cursor_node = cursor_node;
10413
10414   if (! search_first_focusable_path (tree_view, &cursor_path,
10415                                      (count != -1),
10416                                      &cursor_tree, &cursor_node))
10417     {
10418       /* It looks like we reached the end of the view without finding
10419        * a focusable row.  We will step backwards to find the last
10420        * focusable row.
10421        */
10422       cursor_tree = start_cursor_tree;
10423       cursor_node = start_cursor_node;
10424       cursor_path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
10425
10426       search_first_focusable_path (tree_view, &cursor_path,
10427                                    (count == -1),
10428                                    &cursor_tree, &cursor_node);
10429     }
10430
10431   if (!cursor_path)
10432     goto cleanup;
10433
10434   /* update y */
10435   y = _gtk_rbtree_node_find_offset (cursor_tree, cursor_node);
10436
10437   gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE);
10438
10439   y -= window_y;
10440   gtk_tree_view_scroll_to_point (tree_view, -1, y);
10441   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10442   _gtk_tree_view_queue_draw_node (tree_view, cursor_tree, cursor_node, NULL);
10443
10444   if (!gtk_tree_path_compare (old_cursor_path, cursor_path))
10445     gtk_widget_error_bell (GTK_WIDGET (tree_view));
10446
10447   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10448
10449 cleanup:
10450   gtk_tree_path_free (old_cursor_path);
10451   gtk_tree_path_free (cursor_path);
10452 }
10453
10454 static void
10455 gtk_tree_view_move_cursor_left_right (GtkTreeView *tree_view,
10456                                       gint         count)
10457 {
10458   GtkRBTree *cursor_tree = NULL;
10459   GtkRBNode *cursor_node = NULL;
10460   GtkTreePath *cursor_path = NULL;
10461   GtkTreeViewColumn *column;
10462   GtkTreeIter iter;
10463   GList *list;
10464   gboolean found_column = FALSE;
10465   gboolean rtl;
10466   GtkDirectionType direction;
10467   GtkCellArea     *cell_area;
10468   GtkCellRenderer *last_focus_cell = NULL;
10469   GtkCellArea     *last_focus_area = NULL;
10470
10471   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
10472
10473   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10474     return;
10475
10476   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
10477     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10478   else
10479     return;
10480
10481   _gtk_tree_view_find_node (tree_view, cursor_path, &cursor_tree, &cursor_node);
10482   if (cursor_tree == NULL)
10483     return;
10484   if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path) == FALSE)
10485     {
10486       gtk_tree_path_free (cursor_path);
10487       return;
10488     }
10489   gtk_tree_path_free (cursor_path);
10490
10491   list = rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns);
10492   if (tree_view->priv->focus_column)
10493     {
10494       /* Save the cell/area we are moving focus from, if moving the cursor
10495        * by one step hits the end we'll set focus back here */
10496       last_focus_area = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (tree_view->priv->focus_column));
10497       last_focus_cell = gtk_cell_area_get_focus_cell (last_focus_area);
10498
10499       for (; list; list = (rtl ? list->prev : list->next))
10500         {
10501           if (list->data == tree_view->priv->focus_column)
10502             break;
10503         }
10504     }
10505
10506   direction = count > 0 ? GTK_DIR_RIGHT : GTK_DIR_LEFT;
10507
10508   while (list)
10509     {
10510       column = list->data;
10511       if (gtk_tree_view_column_get_visible (column) == FALSE)
10512         goto loop_end;
10513
10514       gtk_tree_view_column_cell_set_cell_data (column,
10515                                                tree_view->priv->model,
10516                                                &iter,
10517                                                GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_PARENT),
10518                                                cursor_node->children?TRUE:FALSE);
10519
10520       cell_area = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (column));
10521       if (gtk_cell_area_focus (cell_area, direction))
10522         {
10523           tree_view->priv->focus_column = column;
10524           found_column = TRUE;
10525           break;
10526         }
10527
10528     loop_end:
10529       if (count == 1)
10530         list = rtl ? list->prev : list->next;
10531       else
10532         list = rtl ? list->next : list->prev;
10533     }
10534
10535   if (found_column)
10536     {
10537       if (!gtk_tree_view_has_can_focus_cell (tree_view))
10538         _gtk_tree_view_queue_draw_node (tree_view,
10539                                         cursor_tree,
10540                                         cursor_node,
10541                                         NULL);
10542       g_signal_emit (tree_view, tree_view_signals[CURSOR_CHANGED], 0);
10543       gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10544     }
10545   else
10546     {
10547       gtk_widget_error_bell (GTK_WIDGET (tree_view));
10548
10549       if (last_focus_area)
10550         gtk_cell_area_set_focus_cell (last_focus_area, last_focus_cell);
10551     }
10552
10553   gtk_tree_view_clamp_column_visible (tree_view,
10554                                       tree_view->priv->focus_column, TRUE);
10555 }
10556
10557 static void
10558 gtk_tree_view_move_cursor_start_end (GtkTreeView *tree_view,
10559                                      gint         count)
10560 {
10561   GtkRBTree *cursor_tree;
10562   GtkRBNode *cursor_node;
10563   GtkTreePath *path;
10564   GtkTreePath *old_path;
10565
10566   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10567     return;
10568
10569   g_return_if_fail (tree_view->priv->tree != NULL);
10570
10571   gtk_tree_view_get_cursor (tree_view, &old_path, NULL);
10572
10573   cursor_tree = tree_view->priv->tree;
10574   cursor_node = cursor_tree->root;
10575
10576   if (count == -1)
10577     {
10578       while (cursor_node && cursor_node->left != cursor_tree->nil)
10579         cursor_node = cursor_node->left;
10580
10581       /* Now go forward to find the first focusable row. */
10582       path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
10583       search_first_focusable_path (tree_view, &path,
10584                                    TRUE, &cursor_tree, &cursor_node);
10585     }
10586   else
10587     {
10588       do
10589         {
10590           while (cursor_node && cursor_node->right != cursor_tree->nil)
10591             cursor_node = cursor_node->right;
10592           if (cursor_node->children == NULL)
10593             break;
10594
10595           cursor_tree = cursor_node->children;
10596           cursor_node = cursor_tree->root;
10597         }
10598       while (1);
10599
10600       /* Now go backwards to find last focusable row. */
10601       path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
10602       search_first_focusable_path (tree_view, &path,
10603                                    FALSE, &cursor_tree, &cursor_node);
10604     }
10605
10606   if (!path)
10607     goto cleanup;
10608
10609   if (gtk_tree_path_compare (old_path, path))
10610     {
10611       gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
10612       gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10613     }
10614   else
10615     {
10616       gtk_widget_error_bell (GTK_WIDGET (tree_view));
10617     }
10618
10619 cleanup:
10620   gtk_tree_path_free (old_path);
10621   gtk_tree_path_free (path);
10622 }
10623
10624 static gboolean
10625 gtk_tree_view_real_select_all (GtkTreeView *tree_view)
10626 {
10627   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10628     return FALSE;
10629
10630   if (gtk_tree_selection_get_mode (tree_view->priv->selection) != GTK_SELECTION_MULTIPLE)
10631     return FALSE;
10632
10633   gtk_tree_selection_select_all (tree_view->priv->selection);
10634
10635   return TRUE;
10636 }
10637
10638 static gboolean
10639 gtk_tree_view_real_unselect_all (GtkTreeView *tree_view)
10640 {
10641   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10642     return FALSE;
10643
10644   if (gtk_tree_selection_get_mode (tree_view->priv->selection) != GTK_SELECTION_MULTIPLE)
10645     return FALSE;
10646
10647   gtk_tree_selection_unselect_all (tree_view->priv->selection);
10648
10649   return TRUE;
10650 }
10651
10652 static gboolean
10653 gtk_tree_view_real_select_cursor_row (GtkTreeView *tree_view,
10654                                       gboolean     start_editing)
10655 {
10656   GtkRBTree *new_tree = NULL;
10657   GtkRBNode *new_node = NULL;
10658   GtkRBTree *cursor_tree = NULL;
10659   GtkRBNode *cursor_node = NULL;
10660   GtkTreePath *cursor_path = NULL;
10661   GtkTreeSelectMode mode = 0;
10662
10663   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10664     return FALSE;
10665
10666   if (tree_view->priv->cursor)
10667     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10668
10669   if (cursor_path == NULL)
10670     return FALSE;
10671
10672   _gtk_tree_view_find_node (tree_view, cursor_path,
10673                             &cursor_tree, &cursor_node);
10674
10675   if (cursor_tree == NULL)
10676     {
10677       gtk_tree_path_free (cursor_path);
10678       return FALSE;
10679     }
10680
10681   if (!tree_view->priv->shift_pressed && start_editing &&
10682       tree_view->priv->focus_column)
10683     {
10684       if (gtk_tree_view_start_editing (tree_view, cursor_path, FALSE))
10685         {
10686           gtk_tree_path_free (cursor_path);
10687           return TRUE;
10688         }
10689     }
10690
10691   if (tree_view->priv->ctrl_pressed)
10692     mode |= GTK_TREE_SELECT_MODE_TOGGLE;
10693   if (tree_view->priv->shift_pressed)
10694     mode |= GTK_TREE_SELECT_MODE_EXTEND;
10695
10696   _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
10697                                             cursor_node,
10698                                             cursor_tree,
10699                                             cursor_path,
10700                                             mode,
10701                                             FALSE);
10702
10703   /* We bail out if the original (tree, node) don't exist anymore after
10704    * handling the selection-changed callback.  We do return TRUE because
10705    * the key press has been handled at this point.
10706    */
10707   _gtk_tree_view_find_node (tree_view, cursor_path, &new_tree, &new_node);
10708
10709   if (cursor_tree != new_tree || cursor_node != new_node)
10710     return FALSE;
10711
10712   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10713
10714   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10715   _gtk_tree_view_queue_draw_node (tree_view, cursor_tree, cursor_node, NULL);
10716
10717   if (!tree_view->priv->shift_pressed)
10718     gtk_tree_view_row_activated (tree_view, cursor_path,
10719                                  tree_view->priv->focus_column);
10720     
10721   gtk_tree_path_free (cursor_path);
10722
10723   return TRUE;
10724 }
10725
10726 static gboolean
10727 gtk_tree_view_real_toggle_cursor_row (GtkTreeView *tree_view)
10728 {
10729   GtkRBTree *new_tree = NULL;
10730   GtkRBNode *new_node = NULL;
10731   GtkRBTree *cursor_tree = NULL;
10732   GtkRBNode *cursor_node = NULL;
10733   GtkTreePath *cursor_path = NULL;
10734
10735   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10736     return FALSE;
10737
10738   cursor_path = NULL;
10739   if (tree_view->priv->cursor)
10740     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10741
10742   if (cursor_path == NULL)
10743     return FALSE;
10744
10745   _gtk_tree_view_find_node (tree_view, cursor_path,
10746                             &cursor_tree, &cursor_node);
10747   if (cursor_tree == NULL)
10748     {
10749       gtk_tree_path_free (cursor_path);
10750       return FALSE;
10751     }
10752
10753   _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
10754                                             cursor_node,
10755                                             cursor_tree,
10756                                             cursor_path,
10757                                             GTK_TREE_SELECT_MODE_TOGGLE,
10758                                             FALSE);
10759
10760   /* We bail out if the original (tree, node) don't exist anymore after
10761    * handling the selection-changed callback.  We do return TRUE because
10762    * the key press has been handled at this point.
10763    */
10764   _gtk_tree_view_find_node (tree_view, cursor_path, &new_tree, &new_node);
10765
10766   if (cursor_tree != new_tree || cursor_node != new_node)
10767     return FALSE;
10768
10769   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10770
10771   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10772   gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10773   gtk_tree_path_free (cursor_path);
10774
10775   return TRUE;
10776 }
10777
10778 static gboolean
10779 gtk_tree_view_real_expand_collapse_cursor_row (GtkTreeView *tree_view,
10780                                                gboolean     logical,
10781                                                gboolean     expand,
10782                                                gboolean     open_all)
10783 {
10784   GtkTreePath *cursor_path = NULL;
10785   GtkRBTree *tree;
10786   GtkRBNode *node;
10787
10788   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10789     return FALSE;
10790
10791   cursor_path = NULL;
10792   if (tree_view->priv->cursor)
10793     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10794
10795   if (cursor_path == NULL)
10796     return FALSE;
10797
10798   if (_gtk_tree_view_find_node (tree_view, cursor_path, &tree, &node))
10799     return FALSE;
10800
10801   /* Don't handle the event if we aren't an expander */
10802   if (!((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT))
10803     return FALSE;
10804
10805   if (!logical
10806       && gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL)
10807     expand = !expand;
10808
10809   if (expand)
10810     gtk_tree_view_real_expand_row (tree_view, cursor_path, tree, node, open_all, TRUE);
10811   else
10812     gtk_tree_view_real_collapse_row (tree_view, cursor_path, tree, node, TRUE);
10813
10814   gtk_tree_path_free (cursor_path);
10815
10816   return TRUE;
10817 }
10818
10819 static gboolean
10820 gtk_tree_view_real_select_cursor_parent (GtkTreeView *tree_view)
10821 {
10822   GtkRBTree *cursor_tree = NULL;
10823   GtkRBNode *cursor_node = NULL;
10824   GtkTreePath *cursor_path = NULL;
10825   GdkModifierType state;
10826
10827   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10828     goto out;
10829
10830   cursor_path = NULL;
10831   if (tree_view->priv->cursor)
10832     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10833
10834   if (cursor_path == NULL)
10835     goto out;
10836
10837   _gtk_tree_view_find_node (tree_view, cursor_path,
10838                             &cursor_tree, &cursor_node);
10839   if (cursor_tree == NULL)
10840     {
10841       gtk_tree_path_free (cursor_path);
10842       goto out;
10843     }
10844
10845   if (cursor_tree->parent_node)
10846     {
10847       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10848       cursor_node = cursor_tree->parent_node;
10849       cursor_tree = cursor_tree->parent_tree;
10850
10851       gtk_tree_path_up (cursor_path);
10852
10853       if (gtk_get_current_event_state (&state))
10854         {
10855           if ((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
10856             tree_view->priv->ctrl_pressed = TRUE;
10857         }
10858
10859       gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE);
10860       gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10861
10862       gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10863       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10864       gtk_tree_path_free (cursor_path);
10865
10866       tree_view->priv->ctrl_pressed = FALSE;
10867
10868       return TRUE;
10869     }
10870
10871  out:
10872
10873   tree_view->priv->search_entry_avoid_unhandled_binding = TRUE;
10874   return FALSE;
10875 }
10876
10877 static gboolean
10878 gtk_tree_view_search_entry_flush_timeout (GtkTreeView *tree_view)
10879 {
10880   gtk_tree_view_search_dialog_hide (tree_view->priv->search_window, tree_view, NULL);
10881   tree_view->priv->typeselect_flush_timeout = 0;
10882
10883   return FALSE;
10884 }
10885
10886 /* Cut and paste from gtkwindow.c */
10887 static void
10888 send_focus_change (GtkWidget *widget,
10889                    GdkDevice *device,
10890                    gboolean   in)
10891 {
10892   GdkDeviceManager *device_manager;
10893   GList *devices, *d;
10894
10895   device_manager = gdk_display_get_device_manager (gtk_widget_get_display (widget));
10896   devices = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER);
10897   devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_SLAVE));
10898   devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_FLOATING));
10899
10900   for (d = devices; d; d = d->next)
10901     {
10902       GdkDevice *dev = d->data;
10903       GdkEvent *fevent;
10904       GdkWindow *window;
10905
10906       if (gdk_device_get_source (dev) != GDK_SOURCE_KEYBOARD)
10907         continue;
10908
10909       window = gtk_widget_get_window (widget);
10910
10911       /* Skip non-master keyboards that haven't
10912        * selected for events from this window
10913        */
10914       if (gdk_device_get_device_type (dev) != GDK_DEVICE_TYPE_MASTER &&
10915           !gdk_window_get_device_events (window, dev))
10916         continue;
10917
10918       fevent = gdk_event_new (GDK_FOCUS_CHANGE);
10919
10920       fevent->focus_change.type = GDK_FOCUS_CHANGE;
10921       fevent->focus_change.window = g_object_ref (window);
10922       fevent->focus_change.in = in;
10923       gdk_event_set_device (fevent, device);
10924
10925       gtk_widget_send_focus_change (widget, fevent);
10926
10927       gdk_event_free (fevent);
10928     }
10929 }
10930
10931 static void
10932 gtk_tree_view_ensure_interactive_directory (GtkTreeView *tree_view)
10933 {
10934   GtkWidget *frame, *vbox, *toplevel;
10935   GdkScreen *screen;
10936
10937   if (tree_view->priv->search_custom_entry_set)
10938     return;
10939
10940   toplevel = gtk_widget_get_toplevel (GTK_WIDGET (tree_view));
10941   screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
10942
10943    if (tree_view->priv->search_window != NULL)
10944      {
10945        if (gtk_window_has_group (GTK_WINDOW (toplevel)))
10946          gtk_window_group_add_window (gtk_window_get_group (GTK_WINDOW (toplevel)),
10947                                       GTK_WINDOW (tree_view->priv->search_window));
10948        else if (gtk_window_has_group (GTK_WINDOW (tree_view->priv->search_window)))
10949          gtk_window_group_remove_window (gtk_window_get_group (GTK_WINDOW (tree_view->priv->search_window)),
10950                                          GTK_WINDOW (tree_view->priv->search_window));
10951
10952        gtk_window_set_screen (GTK_WINDOW (tree_view->priv->search_window), screen);
10953
10954        return;
10955      }
10956    
10957   tree_view->priv->search_window = gtk_window_new (GTK_WINDOW_POPUP);
10958   gtk_window_set_screen (GTK_WINDOW (tree_view->priv->search_window), screen);
10959
10960   if (gtk_window_has_group (GTK_WINDOW (toplevel)))
10961     gtk_window_group_add_window (gtk_window_get_group (GTK_WINDOW (toplevel)),
10962                                  GTK_WINDOW (tree_view->priv->search_window));
10963
10964   gtk_window_set_type_hint (GTK_WINDOW (tree_view->priv->search_window),
10965                             GDK_WINDOW_TYPE_HINT_UTILITY);
10966   gtk_window_set_modal (GTK_WINDOW (tree_view->priv->search_window), TRUE);
10967   g_signal_connect (tree_view->priv->search_window, "delete-event",
10968                     G_CALLBACK (gtk_tree_view_search_delete_event),
10969                     tree_view);
10970   g_signal_connect (tree_view->priv->search_window, "key-press-event",
10971                     G_CALLBACK (gtk_tree_view_search_key_press_event),
10972                     tree_view);
10973   g_signal_connect (tree_view->priv->search_window, "button-press-event",
10974                     G_CALLBACK (gtk_tree_view_search_button_press_event),
10975                     tree_view);
10976   g_signal_connect (tree_view->priv->search_window, "scroll-event",
10977                     G_CALLBACK (gtk_tree_view_search_scroll_event),
10978                     tree_view);
10979
10980   frame = gtk_frame_new (NULL);
10981   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
10982   gtk_widget_show (frame);
10983   gtk_container_add (GTK_CONTAINER (tree_view->priv->search_window), frame);
10984
10985   vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
10986   gtk_widget_show (vbox);
10987   gtk_container_add (GTK_CONTAINER (frame), vbox);
10988   gtk_container_set_border_width (GTK_CONTAINER (vbox), 3);
10989
10990   /* add entry */
10991   tree_view->priv->search_entry = gtk_entry_new ();
10992   gtk_widget_show (tree_view->priv->search_entry);
10993   g_signal_connect (tree_view->priv->search_entry, "populate-popup",
10994                     G_CALLBACK (gtk_tree_view_search_disable_popdown),
10995                     tree_view);
10996   g_signal_connect (tree_view->priv->search_entry,
10997                     "activate", G_CALLBACK (gtk_tree_view_search_activate),
10998                     tree_view);
10999
11000   g_signal_connect (_gtk_entry_get_im_context (GTK_ENTRY (tree_view->priv->search_entry)),
11001                     "preedit-changed",
11002                     G_CALLBACK (gtk_tree_view_search_preedit_changed),
11003                     tree_view);
11004
11005   gtk_container_add (GTK_CONTAINER (vbox),
11006                      tree_view->priv->search_entry);
11007
11008   gtk_widget_realize (tree_view->priv->search_entry);
11009 }
11010
11011 /* Pops up the interactive search entry.  If keybinding is TRUE then the user
11012  * started this by typing the start_interactive_search keybinding.  Otherwise, it came from 
11013  */
11014 static gboolean
11015 gtk_tree_view_real_start_interactive_search (GtkTreeView *tree_view,
11016                                              GdkDevice   *device,
11017                                              gboolean     keybinding)
11018 {
11019   /* We only start interactive search if we have focus or the columns
11020    * have focus.  If one of our children have focus, we don't want to
11021    * start the search.
11022    */
11023   GList *list;
11024   gboolean found_focus = FALSE;
11025   GtkWidgetClass *entry_parent_class;
11026   
11027   if (!tree_view->priv->enable_search && !keybinding)
11028     return FALSE;
11029
11030   if (tree_view->priv->search_custom_entry_set)
11031     return FALSE;
11032
11033   if (tree_view->priv->search_window != NULL &&
11034       gtk_widget_get_visible (tree_view->priv->search_window))
11035     return TRUE;
11036
11037   for (list = tree_view->priv->columns; list; list = list->next)
11038     {
11039       GtkTreeViewColumn *column;
11040       GtkWidget         *button;
11041
11042       column = list->data;
11043       if (!gtk_tree_view_column_get_visible (column))
11044         continue;
11045
11046       button = gtk_tree_view_column_get_button (column);
11047       if (gtk_widget_has_focus (button))
11048         {
11049           found_focus = TRUE;
11050           break;
11051         }
11052     }
11053   
11054   if (gtk_widget_has_focus (GTK_WIDGET (tree_view)))
11055     found_focus = TRUE;
11056
11057   if (!found_focus)
11058     return FALSE;
11059
11060   if (tree_view->priv->search_column < 0)
11061     return FALSE;
11062
11063   gtk_tree_view_ensure_interactive_directory (tree_view);
11064
11065   if (keybinding)
11066     gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
11067
11068   /* done, show it */
11069   tree_view->priv->search_position_func (tree_view, tree_view->priv->search_window, tree_view->priv->search_position_user_data);
11070   gtk_widget_show (tree_view->priv->search_window);
11071   if (tree_view->priv->search_entry_changed_id == 0)
11072     {
11073       tree_view->priv->search_entry_changed_id =
11074         g_signal_connect (tree_view->priv->search_entry, "changed",
11075                           G_CALLBACK (gtk_tree_view_search_init),
11076                           tree_view);
11077     }
11078
11079   tree_view->priv->typeselect_flush_timeout =
11080     gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
11081                    (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
11082                    tree_view);
11083
11084   /* Grab focus will select all the text.  We don't want that to happen, so we
11085    * call the parent instance and bypass the selection change.  This is probably
11086    * really non-kosher. */
11087   entry_parent_class = g_type_class_peek_parent (GTK_ENTRY_GET_CLASS (tree_view->priv->search_entry));
11088   (entry_parent_class->grab_focus) (tree_view->priv->search_entry);
11089
11090   /* send focus-in event */
11091   send_focus_change (tree_view->priv->search_entry, device, TRUE);
11092
11093   /* search first matching iter */
11094   gtk_tree_view_search_init (tree_view->priv->search_entry, tree_view);
11095
11096   return TRUE;
11097 }
11098
11099 static gboolean
11100 gtk_tree_view_start_interactive_search (GtkTreeView *tree_view)
11101 {
11102   return gtk_tree_view_real_start_interactive_search (tree_view,
11103                                                       gtk_get_current_event_device (),
11104                                                       TRUE);
11105 }
11106
11107 /* this function returns the new width of the column being resized given
11108  * the column and x position of the cursor; the x cursor position is passed
11109  * in as a pointer and automagicly corrected if it's beyond min/max limits
11110  */
11111 static gint
11112 gtk_tree_view_new_column_width (GtkTreeView *tree_view,
11113                                 gint       i,
11114                                 gint      *x)
11115 {
11116   GtkAllocation allocation;
11117   GtkTreeViewColumn *column;
11118   GtkRequisition button_req;
11119   gint max_width, min_width;
11120   gint width;
11121   gboolean rtl;
11122
11123   /* first translate the x position from widget->window
11124    * to clist->clist_window
11125    */
11126   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
11127   column = g_list_nth (tree_view->priv->columns, i)->data;
11128   gtk_widget_get_allocation (gtk_tree_view_column_get_button (column), &allocation);
11129   width = rtl ? (allocation.x + allocation.width - *x) : (*x - allocation.x);
11130
11131   /* Clamp down the value */
11132   min_width = gtk_tree_view_column_get_min_width (column);
11133   if (min_width == -1)
11134     {
11135       gtk_widget_get_preferred_size (gtk_tree_view_column_get_button (column), &button_req, NULL);
11136       width = MAX (button_req.width, width);
11137     }
11138   else
11139     width = MAX (min_width, width);
11140
11141   max_width = gtk_tree_view_column_get_max_width (column);
11142   if (max_width != -1)
11143     width = MIN (width, max_width);
11144
11145   *x = rtl ? (allocation.x + allocation.width - width) : (allocation.x + width);
11146
11147   return width;
11148 }
11149
11150
11151 /* FIXME this adjust_allocation is a big cut-and-paste from
11152  * GtkCList, needs to be some "official" way to do this
11153  * factored out.
11154  */
11155 typedef struct
11156 {
11157   GdkWindow *window;
11158   int dx;
11159   int dy;
11160 } ScrollData;
11161
11162 /* The window to which widget->window is relative */
11163 #define ALLOCATION_WINDOW(widget)               \
11164    (!gtk_widget_get_has_window (widget) ?                   \
11165     gtk_widget_get_window (widget) :                        \
11166     gdk_window_get_parent (gtk_widget_get_window (widget)))
11167
11168 static void
11169 adjust_allocation_recurse (GtkWidget *widget,
11170                            gpointer   data)
11171 {
11172   GtkAllocation allocation;
11173   ScrollData *scroll_data = data;
11174
11175   /* Need to really size allocate instead of just poking
11176    * into widget->allocation if the widget is not realized.
11177    * FIXME someone figure out why this was.
11178    */
11179   gtk_widget_get_allocation (widget, &allocation);
11180   if (!gtk_widget_get_realized (widget))
11181     {
11182       if (gtk_widget_get_visible (widget))
11183         {
11184           GdkRectangle tmp_rectangle = allocation;
11185           tmp_rectangle.x += scroll_data->dx;
11186           tmp_rectangle.y += scroll_data->dy;
11187           
11188           gtk_widget_size_allocate (widget, &tmp_rectangle);
11189         }
11190     }
11191   else
11192     {
11193       if (ALLOCATION_WINDOW (widget) == scroll_data->window)
11194         {
11195           allocation.x += scroll_data->dx;
11196           allocation.y += scroll_data->dy;
11197           gtk_widget_set_allocation (widget, &allocation);
11198
11199           if (GTK_IS_CONTAINER (widget))
11200             gtk_container_forall (GTK_CONTAINER (widget),
11201                                   adjust_allocation_recurse,
11202                                   data);
11203         }
11204     }
11205 }
11206
11207 static void
11208 adjust_allocation (GtkWidget *widget,
11209                    int        dx,
11210                    int        dy)
11211 {
11212   ScrollData scroll_data;
11213
11214   if (gtk_widget_get_realized (widget))
11215     scroll_data.window = ALLOCATION_WINDOW (widget);
11216   else
11217     scroll_data.window = NULL;
11218     
11219   scroll_data.dx = dx;
11220   scroll_data.dy = dy;
11221   
11222   adjust_allocation_recurse (widget, &scroll_data);
11223 }
11224
11225 /* Callbacks */
11226 static void
11227 gtk_tree_view_adjustment_changed (GtkAdjustment *adjustment,
11228                                   GtkTreeView   *tree_view)
11229 {
11230   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11231     {
11232       GtkStyleContext *context;
11233       gint dy;
11234         
11235       gdk_window_move (tree_view->priv->bin_window,
11236                        - gtk_adjustment_get_value (tree_view->priv->hadjustment),
11237                        gtk_tree_view_get_effective_header_height (tree_view));
11238       gdk_window_move (tree_view->priv->header_window,
11239                        - gtk_adjustment_get_value (tree_view->priv->hadjustment),
11240                        0);
11241       dy = tree_view->priv->dy - (int) gtk_adjustment_get_value (tree_view->priv->vadjustment);
11242       if (dy)
11243         {
11244           update_prelight (tree_view,
11245                            tree_view->priv->event_last_x,
11246                            tree_view->priv->event_last_y - dy);
11247
11248           if (tree_view->priv->edited_column)
11249             {
11250               GList *list;
11251               GtkTreeViewChild *child = NULL;
11252               GtkCellEditable *edit_widget;
11253               GtkCellArea *area;
11254
11255               area        = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (tree_view->priv->edited_column));
11256               edit_widget = gtk_cell_area_get_edit_widget (area);
11257               if (GTK_IS_WIDGET (edit_widget))
11258                 {
11259                   adjust_allocation (GTK_WIDGET (edit_widget), 0, dy);
11260
11261                   for (list = tree_view->priv->children; list; list = list->next)
11262                     {
11263                       child = (GtkTreeViewChild *)list->data;
11264                       if (child->widget == GTK_WIDGET (edit_widget))
11265                         {
11266                           child->y += dy;
11267                           break;
11268                         }
11269                     }
11270                 }
11271             }
11272         }
11273       gdk_window_scroll (tree_view->priv->bin_window, 0, dy);
11274
11275       context = gtk_widget_get_style_context (GTK_WIDGET (tree_view));
11276       gtk_style_context_scroll_animations (context, tree_view->priv->bin_window, 0, dy);
11277
11278       if (tree_view->priv->dy != (int) gtk_adjustment_get_value (tree_view->priv->vadjustment))
11279         {
11280           /* update our dy and top_row */
11281           tree_view->priv->dy = (int) gtk_adjustment_get_value (tree_view->priv->vadjustment);
11282
11283           if (!tree_view->priv->in_top_row_to_dy)
11284             gtk_tree_view_dy_to_top_row (tree_view);
11285         }
11286
11287       gdk_window_process_updates (tree_view->priv->header_window, TRUE);
11288       gtk_tree_view_bin_process_updates (tree_view);
11289     }
11290 }
11291
11292 \f
11293
11294 /* Public methods
11295  */
11296
11297 /**
11298  * gtk_tree_view_new:
11299  *
11300  * Creates a new #GtkTreeView widget.
11301  *
11302  * Return value: A newly created #GtkTreeView widget.
11303  **/
11304 GtkWidget *
11305 gtk_tree_view_new (void)
11306 {
11307   return g_object_new (GTK_TYPE_TREE_VIEW, NULL);
11308 }
11309
11310 /**
11311  * gtk_tree_view_new_with_model:
11312  * @model: the model.
11313  *
11314  * Creates a new #GtkTreeView widget with the model initialized to @model.
11315  *
11316  * Return value: A newly created #GtkTreeView widget.
11317  **/
11318 GtkWidget *
11319 gtk_tree_view_new_with_model (GtkTreeModel *model)
11320 {
11321   return g_object_new (GTK_TYPE_TREE_VIEW, "model", model, NULL);
11322 }
11323
11324 /* Public Accessors
11325  */
11326
11327 /**
11328  * gtk_tree_view_get_model:
11329  * @tree_view: a #GtkTreeView
11330  *
11331  * Returns the model the #GtkTreeView is based on.  Returns %NULL if the
11332  * model is unset.
11333  *
11334  * Return value: (transfer none): A #GtkTreeModel, or %NULL if none is currently being used.
11335  **/
11336 GtkTreeModel *
11337 gtk_tree_view_get_model (GtkTreeView *tree_view)
11338 {
11339   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11340
11341   return tree_view->priv->model;
11342 }
11343
11344 /**
11345  * gtk_tree_view_set_model:
11346  * @tree_view: A #GtkTreeNode.
11347  * @model: (allow-none): The model.
11348  *
11349  * Sets the model for a #GtkTreeView.  If the @tree_view already has a model
11350  * set, it will remove it before setting the new model.  If @model is %NULL,
11351  * then it will unset the old model.
11352  **/
11353 void
11354 gtk_tree_view_set_model (GtkTreeView  *tree_view,
11355                          GtkTreeModel *model)
11356 {
11357   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11358   g_return_if_fail (model == NULL || GTK_IS_TREE_MODEL (model));
11359
11360   if (model == tree_view->priv->model)
11361     return;
11362
11363   if (tree_view->priv->scroll_to_path)
11364     {
11365       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
11366       tree_view->priv->scroll_to_path = NULL;
11367     }
11368
11369   if (tree_view->priv->model)
11370     {
11371       GList *tmplist = tree_view->priv->columns;
11372       GtkStyleContext *context;
11373
11374       gtk_tree_view_unref_and_check_selection_tree (tree_view, tree_view->priv->tree);
11375       gtk_tree_view_stop_editing (tree_view, TRUE);
11376
11377       context = gtk_widget_get_style_context (GTK_WIDGET (tree_view));
11378       gtk_style_context_cancel_animations (context, NULL);
11379
11380       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
11381                                             gtk_tree_view_row_changed,
11382                                             tree_view);
11383       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
11384                                             gtk_tree_view_row_inserted,
11385                                             tree_view);
11386       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
11387                                             gtk_tree_view_row_has_child_toggled,
11388                                             tree_view);
11389       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
11390                                             gtk_tree_view_row_deleted,
11391                                             tree_view);
11392       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
11393                                             gtk_tree_view_rows_reordered,
11394                                             tree_view);
11395
11396       for (; tmplist; tmplist = tmplist->next)
11397         _gtk_tree_view_column_unset_model (tmplist->data,
11398                                            tree_view->priv->model);
11399
11400       if (tree_view->priv->tree)
11401         gtk_tree_view_free_rbtree (tree_view);
11402
11403       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
11404       tree_view->priv->drag_dest_row = NULL;
11405       gtk_tree_row_reference_free (tree_view->priv->cursor);
11406       tree_view->priv->cursor = NULL;
11407       gtk_tree_row_reference_free (tree_view->priv->anchor);
11408       tree_view->priv->anchor = NULL;
11409       gtk_tree_row_reference_free (tree_view->priv->top_row);
11410       tree_view->priv->top_row = NULL;
11411       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
11412       tree_view->priv->scroll_to_path = NULL;
11413
11414       tree_view->priv->scroll_to_column = NULL;
11415
11416       g_object_unref (tree_view->priv->model);
11417
11418       tree_view->priv->search_column = -1;
11419       tree_view->priv->fixed_height_check = 0;
11420       tree_view->priv->fixed_height = -1;
11421       tree_view->priv->dy = tree_view->priv->top_row_dy = 0;
11422       tree_view->priv->last_button_x = -1;
11423       tree_view->priv->last_button_y = -1;
11424     }
11425
11426   tree_view->priv->model = model;
11427
11428   if (tree_view->priv->model)
11429     {
11430       gint i;
11431       GtkTreePath *path;
11432       GtkTreeIter iter;
11433       GtkTreeModelFlags flags;
11434
11435       if (tree_view->priv->search_column == -1)
11436         {
11437           for (i = 0; i < gtk_tree_model_get_n_columns (model); i++)
11438             {
11439               GType type = gtk_tree_model_get_column_type (model, i);
11440
11441               if (g_value_type_transformable (type, G_TYPE_STRING))
11442                 {
11443                   tree_view->priv->search_column = i;
11444                   break;
11445                 }
11446             }
11447         }
11448
11449       g_object_ref (tree_view->priv->model);
11450       g_signal_connect (tree_view->priv->model,
11451                         "row-changed",
11452                         G_CALLBACK (gtk_tree_view_row_changed),
11453                         tree_view);
11454       g_signal_connect (tree_view->priv->model,
11455                         "row-inserted",
11456                         G_CALLBACK (gtk_tree_view_row_inserted),
11457                         tree_view);
11458       g_signal_connect (tree_view->priv->model,
11459                         "row-has-child-toggled",
11460                         G_CALLBACK (gtk_tree_view_row_has_child_toggled),
11461                         tree_view);
11462       g_signal_connect (tree_view->priv->model,
11463                         "row-deleted",
11464                         G_CALLBACK (gtk_tree_view_row_deleted),
11465                         tree_view);
11466       g_signal_connect (tree_view->priv->model,
11467                         "rows-reordered",
11468                         G_CALLBACK (gtk_tree_view_rows_reordered),
11469                         tree_view);
11470
11471       flags = gtk_tree_model_get_flags (tree_view->priv->model);
11472       if ((flags & GTK_TREE_MODEL_LIST_ONLY) == GTK_TREE_MODEL_LIST_ONLY)
11473         tree_view->priv->is_list = TRUE;
11474       else
11475         tree_view->priv->is_list = FALSE;
11476
11477       path = gtk_tree_path_new_first ();
11478       if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, path))
11479         {
11480           tree_view->priv->tree = _gtk_rbtree_new ();
11481           gtk_tree_view_build_tree (tree_view, tree_view->priv->tree, &iter, 1, FALSE);
11482         }
11483       gtk_tree_path_free (path);
11484
11485       /*  FIXME: do I need to do this? gtk_tree_view_create_buttons (tree_view); */
11486       install_presize_handler (tree_view);
11487     }
11488
11489   g_object_notify (G_OBJECT (tree_view), "model");
11490
11491   if (tree_view->priv->selection)
11492   _gtk_tree_selection_emit_changed (tree_view->priv->selection);
11493
11494   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11495     gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11496 }
11497
11498 /**
11499  * gtk_tree_view_get_selection:
11500  * @tree_view: A #GtkTreeView.
11501  *
11502  * Gets the #GtkTreeSelection associated with @tree_view.
11503  *
11504  * Return value: (transfer none): A #GtkTreeSelection object.
11505  **/
11506 GtkTreeSelection *
11507 gtk_tree_view_get_selection (GtkTreeView *tree_view)
11508 {
11509   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11510
11511   return tree_view->priv->selection;
11512 }
11513
11514 /**
11515  * gtk_tree_view_get_hadjustment:
11516  * @tree_view: A #GtkTreeView
11517  *
11518  * Gets the #GtkAdjustment currently being used for the horizontal aspect.
11519  *
11520  * Return value: (transfer none): A #GtkAdjustment object, or %NULL
11521  *     if none is currently being used.
11522  *
11523  * Deprecated: 3.0: Use gtk_scrollable_get_hadjustment()
11524  **/
11525 GtkAdjustment *
11526 gtk_tree_view_get_hadjustment (GtkTreeView *tree_view)
11527 {
11528   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11529
11530   return tree_view->priv->hadjustment;
11531 }
11532
11533 /**
11534  * gtk_tree_view_set_hadjustment:
11535  * @tree_view: A #GtkTreeView
11536  * @adjustment: (allow-none): The #GtkAdjustment to set, or %NULL
11537  *
11538  * Sets the #GtkAdjustment for the current horizontal aspect.
11539  *
11540  * Deprecated: 3.0: Use gtk_scrollable_set_hadjustment()
11541  **/
11542 void
11543 gtk_tree_view_set_hadjustment (GtkTreeView   *tree_view,
11544                                GtkAdjustment *adjustment)
11545 {
11546   GtkTreeViewPrivate *priv = tree_view->priv;
11547
11548   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11549   g_return_if_fail (adjustment == NULL || GTK_IS_ADJUSTMENT (adjustment));
11550
11551   if (adjustment && priv->hadjustment == adjustment)
11552     return;
11553
11554   if (priv->hadjustment != NULL)
11555     {
11556       g_signal_handlers_disconnect_by_func (priv->hadjustment,
11557                                             gtk_tree_view_adjustment_changed,
11558                                             tree_view);
11559       g_object_unref (priv->hadjustment);
11560     }
11561
11562   if (adjustment == NULL)
11563     adjustment = gtk_adjustment_new (0.0, 0.0, 0.0,
11564                                      0.0, 0.0, 0.0);
11565
11566   g_signal_connect (adjustment, "value-changed",
11567                     G_CALLBACK (gtk_tree_view_adjustment_changed), tree_view);
11568   priv->hadjustment = g_object_ref_sink (adjustment);
11569   /* FIXME: Adjustment should probably be populated here with fresh values, but
11570    * internal details are too complicated for me to decipher right now.
11571    */
11572   gtk_tree_view_adjustment_changed (NULL, tree_view);
11573
11574   g_object_notify (G_OBJECT (tree_view), "hadjustment");
11575 }
11576
11577 /**
11578  * gtk_tree_view_get_vadjustment:
11579  * @tree_view: A #GtkTreeView
11580  *
11581  * Gets the #GtkAdjustment currently being used for the vertical aspect.
11582  *
11583  * Return value: (transfer none): A #GtkAdjustment object, or %NULL
11584  *     if none is currently being used.
11585  *
11586  * Deprecated: 3.0: Use gtk_scrollable_get_vadjustment()
11587  **/
11588 GtkAdjustment *
11589 gtk_tree_view_get_vadjustment (GtkTreeView *tree_view)
11590 {
11591   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11592
11593   return tree_view->priv->vadjustment;
11594 }
11595
11596 /**
11597  * gtk_tree_view_set_vadjustment:
11598  * @tree_view: A #GtkTreeView
11599  * @adjustment: (allow-none): The #GtkAdjustment to set, or %NULL
11600  *
11601  * Sets the #GtkAdjustment for the current vertical aspect.
11602  *
11603  * Deprecated: 3.0: Use gtk_scrollable_set_vadjustment()
11604  **/
11605 void
11606 gtk_tree_view_set_vadjustment (GtkTreeView   *tree_view,
11607                                GtkAdjustment *adjustment)
11608 {
11609   GtkTreeViewPrivate *priv = tree_view->priv;
11610
11611   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11612   g_return_if_fail (adjustment == NULL || GTK_IS_ADJUSTMENT (adjustment));
11613
11614   if (adjustment && priv->vadjustment == adjustment)
11615     return;
11616
11617   if (priv->vadjustment != NULL)
11618     {
11619       g_signal_handlers_disconnect_by_func (priv->vadjustment,
11620                                             gtk_tree_view_adjustment_changed,
11621                                             tree_view);
11622       g_object_unref (priv->vadjustment);
11623     }
11624
11625   if (adjustment == NULL)
11626     adjustment = gtk_adjustment_new (0.0, 0.0, 0.0,
11627                                      0.0, 0.0, 0.0);
11628
11629   g_signal_connect (adjustment, "value-changed",
11630                     G_CALLBACK (gtk_tree_view_adjustment_changed), tree_view);
11631   priv->vadjustment = g_object_ref_sink (adjustment);
11632   /* FIXME: Adjustment should probably be populated here with fresh values, but
11633    * internal details are too complicated for me to decipher right now.
11634    */
11635   gtk_tree_view_adjustment_changed (NULL, tree_view);
11636   g_object_notify (G_OBJECT (tree_view), "vadjustment");
11637 }
11638
11639 /* Column and header operations */
11640
11641 /**
11642  * gtk_tree_view_get_headers_visible:
11643  * @tree_view: A #GtkTreeView.
11644  *
11645  * Returns %TRUE if the headers on the @tree_view are visible.
11646  *
11647  * Return value: Whether the headers are visible or not.
11648  **/
11649 gboolean
11650 gtk_tree_view_get_headers_visible (GtkTreeView *tree_view)
11651 {
11652   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
11653
11654   return tree_view->priv->headers_visible;
11655 }
11656
11657 /**
11658  * gtk_tree_view_set_headers_visible:
11659  * @tree_view: A #GtkTreeView.
11660  * @headers_visible: %TRUE if the headers are visible
11661  *
11662  * Sets the visibility state of the headers.
11663  **/
11664 void
11665 gtk_tree_view_set_headers_visible (GtkTreeView *tree_view,
11666                                    gboolean     headers_visible)
11667 {
11668   gint x, y;
11669   GList *list;
11670   GtkTreeViewColumn *column;
11671   GtkAllocation allocation;
11672   GtkWidget *button;
11673
11674   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11675
11676   headers_visible = !! headers_visible;
11677
11678   if (tree_view->priv->headers_visible == headers_visible)
11679     return;
11680
11681   tree_view->priv->headers_visible = headers_visible == TRUE;
11682
11683   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11684     {
11685       gdk_window_get_position (tree_view->priv->bin_window, &x, &y);
11686       if (headers_visible)
11687         {
11688           gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
11689           gdk_window_move_resize (tree_view->priv->bin_window,
11690                                   x, y  + gtk_tree_view_get_effective_header_height (tree_view),
11691                                   tree_view->priv->width, allocation.height -  + gtk_tree_view_get_effective_header_height (tree_view));
11692
11693           if (gtk_widget_get_mapped (GTK_WIDGET (tree_view)))
11694             gtk_tree_view_map_buttons (tree_view);
11695         }
11696       else
11697         {
11698           gdk_window_move_resize (tree_view->priv->bin_window, x, y, tree_view->priv->width, tree_view->priv->height);
11699
11700           for (list = tree_view->priv->columns; list; list = list->next)
11701             {
11702               column = list->data;
11703               button = gtk_tree_view_column_get_button (column);
11704
11705               gtk_widget_hide (button);
11706               gtk_widget_unmap (button);
11707             }
11708           gdk_window_hide (tree_view->priv->header_window);
11709         }
11710     }
11711
11712   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
11713   gtk_adjustment_configure (tree_view->priv->vadjustment,
11714                             gtk_adjustment_get_value (tree_view->priv->vadjustment),
11715                             0,
11716                             tree_view->priv->height,
11717                             gtk_adjustment_get_step_increment (tree_view->priv->vadjustment),
11718                             (allocation.height - gtk_tree_view_get_effective_header_height (tree_view)) / 2,
11719                             allocation.height - gtk_tree_view_get_effective_header_height (tree_view));
11720
11721   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11722
11723   g_object_notify (G_OBJECT (tree_view), "headers-visible");
11724 }
11725
11726 /**
11727  * gtk_tree_view_columns_autosize:
11728  * @tree_view: A #GtkTreeView.
11729  *
11730  * Resizes all columns to their optimal width. Only works after the
11731  * treeview has been realized.
11732  **/
11733 void
11734 gtk_tree_view_columns_autosize (GtkTreeView *tree_view)
11735 {
11736   gboolean dirty = FALSE;
11737   GList *list;
11738   GtkTreeViewColumn *column;
11739
11740   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11741
11742   for (list = tree_view->priv->columns; list; list = list->next)
11743     {
11744       column = list->data;
11745       if (gtk_tree_view_column_get_sizing (column) == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
11746         continue;
11747       _gtk_tree_view_column_cell_set_dirty (column, TRUE);
11748       dirty = TRUE;
11749     }
11750
11751   if (dirty)
11752     gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11753 }
11754
11755 /**
11756  * gtk_tree_view_set_headers_clickable:
11757  * @tree_view: A #GtkTreeView.
11758  * @setting: %TRUE if the columns are clickable.
11759  *
11760  * Allow the column title buttons to be clicked.
11761  **/
11762 void
11763 gtk_tree_view_set_headers_clickable (GtkTreeView *tree_view,
11764                                      gboolean   setting)
11765 {
11766   GList *list;
11767
11768   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11769
11770   for (list = tree_view->priv->columns; list; list = list->next)
11771     gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (list->data), setting);
11772
11773   g_object_notify (G_OBJECT (tree_view), "headers-clickable");
11774 }
11775
11776
11777 /**
11778  * gtk_tree_view_get_headers_clickable:
11779  * @tree_view: A #GtkTreeView.
11780  *
11781  * Returns whether all header columns are clickable.
11782  *
11783  * Return value: %TRUE if all header columns are clickable, otherwise %FALSE
11784  *
11785  * Since: 2.10
11786  **/
11787 gboolean 
11788 gtk_tree_view_get_headers_clickable (GtkTreeView *tree_view)
11789 {
11790   GList *list;
11791   
11792   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
11793
11794   for (list = tree_view->priv->columns; list; list = list->next)
11795     if (!gtk_tree_view_column_get_clickable (GTK_TREE_VIEW_COLUMN (list->data)))
11796       return FALSE;
11797
11798   return TRUE;
11799 }
11800
11801 /**
11802  * gtk_tree_view_set_rules_hint
11803  * @tree_view: a #GtkTreeView
11804  * @setting: %TRUE if the tree requires reading across rows
11805  *
11806  * This function tells GTK+ that the user interface for your
11807  * application requires users to read across tree rows and associate
11808  * cells with one another. By default, GTK+ will then render the tree
11809  * with alternating row colors. Do <emphasis>not</emphasis> use it
11810  * just because you prefer the appearance of the ruled tree; that's a
11811  * question for the theme. Some themes will draw tree rows in
11812  * alternating colors even when rules are turned off, and users who
11813  * prefer that appearance all the time can choose those themes. You
11814  * should call this function only as a <emphasis>semantic</emphasis>
11815  * hint to the theme engine that your tree makes alternating colors
11816  * useful from a functional standpoint (since it has lots of columns,
11817  * generally).
11818  *
11819  **/
11820 void
11821 gtk_tree_view_set_rules_hint (GtkTreeView  *tree_view,
11822                               gboolean      setting)
11823 {
11824   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11825
11826   setting = setting != FALSE;
11827
11828   if (tree_view->priv->has_rules != setting)
11829     {
11830       tree_view->priv->has_rules = setting;
11831       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
11832     }
11833
11834   g_object_notify (G_OBJECT (tree_view), "rules-hint");
11835 }
11836
11837 /**
11838  * gtk_tree_view_get_rules_hint
11839  * @tree_view: a #GtkTreeView
11840  *
11841  * Gets the setting set by gtk_tree_view_set_rules_hint().
11842  *
11843  * Return value: %TRUE if rules are useful for the user of this tree
11844  **/
11845 gboolean
11846 gtk_tree_view_get_rules_hint (GtkTreeView  *tree_view)
11847 {
11848   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
11849
11850   return tree_view->priv->has_rules;
11851 }
11852
11853 /* Public Column functions
11854  */
11855
11856 /**
11857  * gtk_tree_view_append_column:
11858  * @tree_view: A #GtkTreeView.
11859  * @column: The #GtkTreeViewColumn to add.
11860  *
11861  * Appends @column to the list of columns. If @tree_view has "fixed_height"
11862  * mode enabled, then @column must have its "sizing" property set to be
11863  * GTK_TREE_VIEW_COLUMN_FIXED.
11864  *
11865  * Return value: The number of columns in @tree_view after appending.
11866  **/
11867 gint
11868 gtk_tree_view_append_column (GtkTreeView       *tree_view,
11869                              GtkTreeViewColumn *column)
11870 {
11871   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11872   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
11873   g_return_val_if_fail (gtk_tree_view_column_get_tree_view (column) == NULL, -1);
11874
11875   return gtk_tree_view_insert_column (tree_view, column, -1);
11876 }
11877
11878 void
11879 _gtk_tree_view_reset_header_styles (GtkTreeView *tree_view)
11880 {
11881   GList *columns;
11882
11883   for (columns = tree_view->priv->columns; columns; columns = columns->next)
11884     {
11885       GtkTreeViewColumn *column = columns->data;
11886       GtkWidget *header_widget;
11887
11888       if (gtk_tree_view_column_get_visible (column))
11889         continue;
11890
11891       header_widget = gtk_tree_view_column_get_widget (column);
11892
11893       if (!header_widget)
11894         header_widget = gtk_tree_view_column_get_button (column);
11895
11896       gtk_widget_reset_style (header_widget);
11897     }
11898 }
11899
11900
11901 /**
11902  * gtk_tree_view_remove_column:
11903  * @tree_view: A #GtkTreeView.
11904  * @column: The #GtkTreeViewColumn to remove.
11905  *
11906  * Removes @column from @tree_view.
11907  *
11908  * Return value: The number of columns in @tree_view after removing.
11909  **/
11910 gint
11911 gtk_tree_view_remove_column (GtkTreeView       *tree_view,
11912                              GtkTreeViewColumn *column)
11913 {
11914   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11915   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
11916   g_return_val_if_fail (gtk_tree_view_column_get_tree_view (column) == GTK_WIDGET (tree_view), -1);
11917
11918   if (tree_view->priv->focus_column == column)
11919     tree_view->priv->focus_column = NULL;
11920
11921   if (tree_view->priv->edited_column == column)
11922     {
11923       gtk_tree_view_stop_editing (tree_view, TRUE);
11924
11925       /* no need to, but just to be sure ... */
11926       tree_view->priv->edited_column = NULL;
11927     }
11928
11929   if (tree_view->priv->expander_column == column)
11930     tree_view->priv->expander_column = NULL;
11931
11932   g_signal_handlers_disconnect_by_func (column,
11933                                         G_CALLBACK (column_sizing_notify),
11934                                         tree_view);
11935
11936   _gtk_tree_view_column_unset_tree_view (column);
11937
11938   tree_view->priv->columns = g_list_remove (tree_view->priv->columns, column);
11939   tree_view->priv->n_columns--;
11940
11941   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11942     {
11943       GList *list;
11944
11945       _gtk_tree_view_column_unrealize_button (column);
11946       for (list = tree_view->priv->columns; list; list = list->next)
11947         {
11948           GtkTreeViewColumn *tmp_column;
11949
11950           tmp_column = GTK_TREE_VIEW_COLUMN (list->data);
11951           if (gtk_tree_view_column_get_visible (tmp_column))
11952             _gtk_tree_view_column_cell_set_dirty (tmp_column, TRUE);
11953         }
11954
11955       if (tree_view->priv->n_columns == 0 &&
11956           gtk_tree_view_get_headers_visible (tree_view))
11957         gdk_window_hide (tree_view->priv->header_window);
11958
11959       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11960     }
11961
11962   _gtk_tree_view_reset_header_styles (tree_view);
11963
11964   g_object_unref (column);
11965   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
11966
11967   return tree_view->priv->n_columns;
11968 }
11969
11970 /**
11971  * gtk_tree_view_insert_column:
11972  * @tree_view: A #GtkTreeView.
11973  * @column: The #GtkTreeViewColumn to be inserted.
11974  * @position: The position to insert @column in.
11975  *
11976  * This inserts the @column into the @tree_view at @position.  If @position is
11977  * -1, then the column is inserted at the end. If @tree_view has
11978  * "fixed_height" mode enabled, then @column must have its "sizing" property
11979  * set to be GTK_TREE_VIEW_COLUMN_FIXED.
11980  *
11981  * Return value: The number of columns in @tree_view after insertion.
11982  **/
11983 gint
11984 gtk_tree_view_insert_column (GtkTreeView       *tree_view,
11985                              GtkTreeViewColumn *column,
11986                              gint               position)
11987 {
11988   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11989   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
11990   g_return_val_if_fail (gtk_tree_view_column_get_tree_view (column) == NULL, -1);
11991
11992   if (tree_view->priv->fixed_height_mode)
11993     g_return_val_if_fail (gtk_tree_view_column_get_sizing (column)
11994                           == GTK_TREE_VIEW_COLUMN_FIXED, -1);
11995
11996   g_object_ref_sink (column);
11997
11998   if (tree_view->priv->n_columns == 0 &&
11999       gtk_widget_get_realized (GTK_WIDGET (tree_view)) &&
12000       gtk_tree_view_get_headers_visible (tree_view))
12001     {
12002       gdk_window_show (tree_view->priv->header_window);
12003     }
12004
12005   g_signal_connect (column, "notify::sizing",
12006                     G_CALLBACK (column_sizing_notify), tree_view);
12007
12008   tree_view->priv->columns = g_list_insert (tree_view->priv->columns,
12009                                             column, position);
12010   tree_view->priv->n_columns++;
12011
12012   _gtk_tree_view_column_set_tree_view (column, tree_view);
12013
12014   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
12015     {
12016       GList *list;
12017
12018       _gtk_tree_view_column_realize_button (column);
12019
12020       for (list = tree_view->priv->columns; list; list = list->next)
12021         {
12022           column = GTK_TREE_VIEW_COLUMN (list->data);
12023           if (gtk_tree_view_column_get_visible (column))
12024             _gtk_tree_view_column_cell_set_dirty (column, TRUE);
12025         }
12026       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
12027     }
12028
12029   _gtk_tree_view_reset_header_styles (tree_view);
12030   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
12031
12032   return tree_view->priv->n_columns;
12033 }
12034
12035 /**
12036  * gtk_tree_view_insert_column_with_attributes:
12037  * @tree_view: A #GtkTreeView
12038  * @position: The position to insert the new column in.
12039  * @title: The title to set the header to.
12040  * @cell: The #GtkCellRenderer.
12041  * @Varargs: A %NULL-terminated list of attributes.
12042  *
12043  * Creates a new #GtkTreeViewColumn and inserts it into the @tree_view at
12044  * @position.  If @position is -1, then the newly created column is inserted at
12045  * the end.  The column is initialized with the attributes given. If @tree_view
12046  * has "fixed_height" mode enabled, then the new column will have its sizing
12047  * property set to be GTK_TREE_VIEW_COLUMN_FIXED.
12048  *
12049  * Return value: The number of columns in @tree_view after insertion.
12050  **/
12051 gint
12052 gtk_tree_view_insert_column_with_attributes (GtkTreeView     *tree_view,
12053                                              gint             position,
12054                                              const gchar     *title,
12055                                              GtkCellRenderer *cell,
12056                                              ...)
12057 {
12058   GtkTreeViewColumn *column;
12059   gchar *attribute;
12060   va_list args;
12061   gint column_id;
12062
12063   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
12064
12065   column = gtk_tree_view_column_new ();
12066   if (tree_view->priv->fixed_height_mode)
12067     gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
12068
12069   gtk_tree_view_column_set_title (column, title);
12070   gtk_tree_view_column_pack_start (column, cell, TRUE);
12071
12072   va_start (args, cell);
12073
12074   attribute = va_arg (args, gchar *);
12075
12076   while (attribute != NULL)
12077     {
12078       column_id = va_arg (args, gint);
12079       gtk_tree_view_column_add_attribute (column, cell, attribute, column_id);
12080       attribute = va_arg (args, gchar *);
12081     }
12082
12083   va_end (args);
12084
12085   gtk_tree_view_insert_column (tree_view, column, position);
12086
12087   return tree_view->priv->n_columns;
12088 }
12089
12090 /**
12091  * gtk_tree_view_insert_column_with_data_func:
12092  * @tree_view: a #GtkTreeView
12093  * @position: Position to insert, -1 for append
12094  * @title: column title
12095  * @cell: cell renderer for column
12096  * @func: function to set attributes of cell renderer
12097  * @data: data for @func
12098  * @dnotify: destroy notifier for @data
12099  *
12100  * Convenience function that inserts a new column into the #GtkTreeView
12101  * with the given cell renderer and a #GtkCellDataFunc to set cell renderer
12102  * attributes (normally using data from the model). See also
12103  * gtk_tree_view_column_set_cell_data_func(), gtk_tree_view_column_pack_start().
12104  * If @tree_view has "fixed_height" mode enabled, then the new column will have its
12105  * "sizing" property set to be GTK_TREE_VIEW_COLUMN_FIXED.
12106  *
12107  * Return value: number of columns in the tree view post-insert
12108  **/
12109 gint
12110 gtk_tree_view_insert_column_with_data_func  (GtkTreeView               *tree_view,
12111                                              gint                       position,
12112                                              const gchar               *title,
12113                                              GtkCellRenderer           *cell,
12114                                              GtkTreeCellDataFunc        func,
12115                                              gpointer                   data,
12116                                              GDestroyNotify             dnotify)
12117 {
12118   GtkTreeViewColumn *column;
12119
12120   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
12121
12122   column = gtk_tree_view_column_new ();
12123   if (tree_view->priv->fixed_height_mode)
12124     gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
12125
12126   gtk_tree_view_column_set_title (column, title);
12127   gtk_tree_view_column_pack_start (column, cell, TRUE);
12128   gtk_tree_view_column_set_cell_data_func (column, cell, func, data, dnotify);
12129
12130   gtk_tree_view_insert_column (tree_view, column, position);
12131
12132   return tree_view->priv->n_columns;
12133 }
12134
12135 /**
12136  * gtk_tree_view_get_column:
12137  * @tree_view: A #GtkTreeView.
12138  * @n: The position of the column, counting from 0.
12139  *
12140  * Gets the #GtkTreeViewColumn at the given position in the #tree_view.
12141  *
12142  * Return value: (transfer none): The #GtkTreeViewColumn, or %NULL if the
12143  *     position is outside the range of columns.
12144  **/
12145 GtkTreeViewColumn *
12146 gtk_tree_view_get_column (GtkTreeView *tree_view,
12147                           gint         n)
12148 {
12149   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
12150
12151   if (n < 0 || n >= tree_view->priv->n_columns)
12152     return NULL;
12153
12154   if (tree_view->priv->columns == NULL)
12155     return NULL;
12156
12157   return GTK_TREE_VIEW_COLUMN (g_list_nth (tree_view->priv->columns, n)->data);
12158 }
12159
12160 /**
12161  * gtk_tree_view_get_columns:
12162  * @tree_view: A #GtkTreeView
12163  *
12164  * Returns a #GList of all the #GtkTreeViewColumn s currently in @tree_view.
12165  * The returned list must be freed with g_list_free ().
12166  *
12167  * Return value: (element-type GtkTreeViewColumn) (transfer container): A list of #GtkTreeViewColumn s
12168  **/
12169 GList *
12170 gtk_tree_view_get_columns (GtkTreeView *tree_view)
12171 {
12172   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
12173
12174   return g_list_copy (tree_view->priv->columns);
12175 }
12176
12177 /**
12178  * gtk_tree_view_move_column_after:
12179  * @tree_view: A #GtkTreeView
12180  * @column: The #GtkTreeViewColumn to be moved.
12181  * @base_column: (allow-none): The #GtkTreeViewColumn to be moved relative to, or %NULL.
12182  *
12183  * Moves @column to be after to @base_column.  If @base_column is %NULL, then
12184  * @column is placed in the first position.
12185  **/
12186 void
12187 gtk_tree_view_move_column_after (GtkTreeView       *tree_view,
12188                                  GtkTreeViewColumn *column,
12189                                  GtkTreeViewColumn *base_column)
12190 {
12191   GList *column_list_el, *base_el = NULL;
12192
12193   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12194
12195   column_list_el = g_list_find (tree_view->priv->columns, column);
12196   g_return_if_fail (column_list_el != NULL);
12197
12198   if (base_column)
12199     {
12200       base_el = g_list_find (tree_view->priv->columns, base_column);
12201       g_return_if_fail (base_el != NULL);
12202     }
12203
12204   if (column_list_el->prev == base_el)
12205     return;
12206
12207   tree_view->priv->columns = g_list_remove_link (tree_view->priv->columns, column_list_el);
12208   if (base_el == NULL)
12209     {
12210       column_list_el->prev = NULL;
12211       column_list_el->next = tree_view->priv->columns;
12212       if (column_list_el->next)
12213         column_list_el->next->prev = column_list_el;
12214       tree_view->priv->columns = column_list_el;
12215     }
12216   else
12217     {
12218       column_list_el->prev = base_el;
12219       column_list_el->next = base_el->next;
12220       if (column_list_el->next)
12221         column_list_el->next->prev = column_list_el;
12222       base_el->next = column_list_el;
12223     }
12224
12225   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
12226     {
12227       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
12228       gtk_tree_view_size_allocate_columns (GTK_WIDGET (tree_view), NULL);
12229     }
12230
12231   _gtk_tree_view_reset_header_styles (tree_view);
12232   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
12233 }
12234
12235 /**
12236  * gtk_tree_view_set_expander_column:
12237  * @tree_view: A #GtkTreeView
12238  * @column: %NULL, or the column to draw the expander arrow at.
12239  *
12240  * Sets the column to draw the expander arrow at. It must be in @tree_view.  
12241  * If @column is %NULL, then the expander arrow is always at the first 
12242  * visible column.
12243  *
12244  * If you do not want expander arrow to appear in your tree, set the 
12245  * expander column to a hidden column.
12246  **/
12247 void
12248 gtk_tree_view_set_expander_column (GtkTreeView       *tree_view,
12249                                    GtkTreeViewColumn *column)
12250 {
12251   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12252   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
12253
12254   if (tree_view->priv->expander_column != column)
12255     {
12256       GList *list;
12257
12258       if (column)
12259         {
12260           /* Confirm that column is in tree_view */
12261           for (list = tree_view->priv->columns; list; list = list->next)
12262             if (list->data == column)
12263               break;
12264           g_return_if_fail (list != NULL);
12265         }
12266
12267       tree_view->priv->expander_column = column;
12268       g_object_notify (G_OBJECT (tree_view), "expander-column");
12269     }
12270 }
12271
12272 /**
12273  * gtk_tree_view_get_expander_column:
12274  * @tree_view: A #GtkTreeView
12275  *
12276  * Returns the column that is the current expander column.
12277  * This column has the expander arrow drawn next to it.
12278  *
12279  * Return value: (transfer none): The expander column.
12280  **/
12281 GtkTreeViewColumn *
12282 gtk_tree_view_get_expander_column (GtkTreeView *tree_view)
12283 {
12284   GList *list;
12285
12286   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
12287
12288   for (list = tree_view->priv->columns; list; list = list->next)
12289     if (gtk_tree_view_is_expander_column (tree_view, GTK_TREE_VIEW_COLUMN (list->data)))
12290       return (GtkTreeViewColumn *) list->data;
12291   return NULL;
12292 }
12293
12294
12295 /**
12296  * gtk_tree_view_set_column_drag_function:
12297  * @tree_view: A #GtkTreeView.
12298  * @func: (allow-none): A function to determine which columns are reorderable, or %NULL.
12299  * @user_data: (allow-none): User data to be passed to @func, or %NULL
12300  * @destroy: (allow-none): Destroy notifier for @user_data, or %NULL
12301  *
12302  * Sets a user function for determining where a column may be dropped when
12303  * dragged.  This function is called on every column pair in turn at the
12304  * beginning of a column drag to determine where a drop can take place.  The
12305  * arguments passed to @func are: the @tree_view, the #GtkTreeViewColumn being
12306  * dragged, the two #GtkTreeViewColumn s determining the drop spot, and
12307  * @user_data.  If either of the #GtkTreeViewColumn arguments for the drop spot
12308  * are %NULL, then they indicate an edge.  If @func is set to be %NULL, then
12309  * @tree_view reverts to the default behavior of allowing all columns to be
12310  * dropped everywhere.
12311  **/
12312 void
12313 gtk_tree_view_set_column_drag_function (GtkTreeView               *tree_view,
12314                                         GtkTreeViewColumnDropFunc  func,
12315                                         gpointer                   user_data,
12316                                         GDestroyNotify             destroy)
12317 {
12318   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12319
12320   if (tree_view->priv->column_drop_func_data_destroy)
12321     tree_view->priv->column_drop_func_data_destroy (tree_view->priv->column_drop_func_data);
12322
12323   tree_view->priv->column_drop_func = func;
12324   tree_view->priv->column_drop_func_data = user_data;
12325   tree_view->priv->column_drop_func_data_destroy = destroy;
12326 }
12327
12328 /**
12329  * gtk_tree_view_scroll_to_point:
12330  * @tree_view: a #GtkTreeView
12331  * @tree_x: X coordinate of new top-left pixel of visible area, or -1
12332  * @tree_y: Y coordinate of new top-left pixel of visible area, or -1
12333  *
12334  * Scrolls the tree view such that the top-left corner of the visible
12335  * area is @tree_x, @tree_y, where @tree_x and @tree_y are specified
12336  * in tree coordinates.  The @tree_view must be realized before
12337  * this function is called.  If it isn't, you probably want to be
12338  * using gtk_tree_view_scroll_to_cell().
12339  *
12340  * If either @tree_x or @tree_y are -1, then that direction isn't scrolled.
12341  **/
12342 void
12343 gtk_tree_view_scroll_to_point (GtkTreeView *tree_view,
12344                                gint         tree_x,
12345                                gint         tree_y)
12346 {
12347   GtkAdjustment *hadj;
12348   GtkAdjustment *vadj;
12349
12350   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12351   g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (tree_view)));
12352
12353   hadj = tree_view->priv->hadjustment;
12354   vadj = tree_view->priv->vadjustment;
12355
12356   if (tree_x != -1)
12357     gtk_adjustment_set_value (hadj, tree_x);
12358   if (tree_y != -1)
12359     gtk_adjustment_set_value (vadj, tree_y);
12360 }
12361
12362 /**
12363  * gtk_tree_view_scroll_to_cell:
12364  * @tree_view: A #GtkTreeView.
12365  * @path: (allow-none): The path of the row to move to, or %NULL.
12366  * @column: (allow-none): The #GtkTreeViewColumn to move horizontally to, or %NULL.
12367  * @use_align: whether to use alignment arguments, or %FALSE.
12368  * @row_align: The vertical alignment of the row specified by @path.
12369  * @col_align: The horizontal alignment of the column specified by @column.
12370  *
12371  * Moves the alignments of @tree_view to the position specified by @column and
12372  * @path.  If @column is %NULL, then no horizontal scrolling occurs.  Likewise,
12373  * if @path is %NULL no vertical scrolling occurs.  At a minimum, one of @column
12374  * or @path need to be non-%NULL.  @row_align determines where the row is
12375  * placed, and @col_align determines where @column is placed.  Both are expected
12376  * to be between 0.0 and 1.0. 0.0 means left/top alignment, 1.0 means
12377  * right/bottom alignment, 0.5 means center.
12378  *
12379  * If @use_align is %FALSE, then the alignment arguments are ignored, and the
12380  * tree does the minimum amount of work to scroll the cell onto the screen.
12381  * This means that the cell will be scrolled to the edge closest to its current
12382  * position.  If the cell is currently visible on the screen, nothing is done.
12383  *
12384  * This function only works if the model is set, and @path is a valid row on the
12385  * model.  If the model changes before the @tree_view is realized, the centered
12386  * path will be modified to reflect this change.
12387  **/
12388 void
12389 gtk_tree_view_scroll_to_cell (GtkTreeView       *tree_view,
12390                               GtkTreePath       *path,
12391                               GtkTreeViewColumn *column,
12392                               gboolean           use_align,
12393                               gfloat             row_align,
12394                               gfloat             col_align)
12395 {
12396   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12397   g_return_if_fail (tree_view->priv->model != NULL);
12398   g_return_if_fail (tree_view->priv->tree != NULL);
12399   g_return_if_fail (row_align >= 0.0 && row_align <= 1.0);
12400   g_return_if_fail (col_align >= 0.0 && col_align <= 1.0);
12401   g_return_if_fail (path != NULL || column != NULL);
12402
12403 #if 0
12404   g_print ("gtk_tree_view_scroll_to_cell:\npath: %s\ncolumn: %s\nuse_align: %d\nrow_align: %f\ncol_align: %f\n",
12405            gtk_tree_path_to_string (path), column?"non-null":"null", use_align, row_align, col_align);
12406 #endif
12407   row_align = CLAMP (row_align, 0.0, 1.0);
12408   col_align = CLAMP (col_align, 0.0, 1.0);
12409
12410
12411   /* Note: Despite the benefits that come from having one code path for the
12412    * scrolling code, we short-circuit validate_visible_area's immplementation as
12413    * it is much slower than just going to the point.
12414    */
12415   if (!gtk_widget_get_visible (GTK_WIDGET (tree_view)) ||
12416       !gtk_widget_get_realized (GTK_WIDGET (tree_view)) ||
12417       _gtk_widget_get_alloc_needed (GTK_WIDGET (tree_view)) ||
12418       GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID))
12419     {
12420       if (tree_view->priv->scroll_to_path)
12421         gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
12422
12423       tree_view->priv->scroll_to_path = NULL;
12424       tree_view->priv->scroll_to_column = NULL;
12425
12426       if (path)
12427         tree_view->priv->scroll_to_path = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
12428       if (column)
12429         tree_view->priv->scroll_to_column = column;
12430       tree_view->priv->scroll_to_use_align = use_align;
12431       tree_view->priv->scroll_to_row_align = row_align;
12432       tree_view->priv->scroll_to_col_align = col_align;
12433
12434       install_presize_handler (tree_view);
12435     }
12436   else
12437     {
12438       GdkRectangle cell_rect;
12439       GdkRectangle vis_rect;
12440       gint dest_x, dest_y;
12441
12442       gtk_tree_view_get_background_area (tree_view, path, column, &cell_rect);
12443       gtk_tree_view_get_visible_rect (tree_view, &vis_rect);
12444
12445       cell_rect.y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, cell_rect.y);
12446
12447       dest_x = vis_rect.x;
12448       dest_y = vis_rect.y;
12449
12450       if (column)
12451         {
12452           if (use_align)
12453             {
12454               dest_x = cell_rect.x - ((vis_rect.width - cell_rect.width) * col_align);
12455             }
12456           else
12457             {
12458               if (cell_rect.x < vis_rect.x)
12459                 dest_x = cell_rect.x;
12460               if (cell_rect.x + cell_rect.width > vis_rect.x + vis_rect.width)
12461                 dest_x = cell_rect.x + cell_rect.width - vis_rect.width;
12462             }
12463         }
12464
12465       if (path)
12466         {
12467           if (use_align)
12468             {
12469               dest_y = cell_rect.y - ((vis_rect.height - cell_rect.height) * row_align);
12470               dest_y = MAX (dest_y, 0);
12471             }
12472           else
12473             {
12474               if (cell_rect.y < vis_rect.y)
12475                 dest_y = cell_rect.y;
12476               if (cell_rect.y + cell_rect.height > vis_rect.y + vis_rect.height)
12477                 dest_y = cell_rect.y + cell_rect.height - vis_rect.height;
12478             }
12479         }
12480
12481       gtk_tree_view_scroll_to_point (tree_view, dest_x, dest_y);
12482     }
12483 }
12484
12485 /**
12486  * gtk_tree_view_row_activated:
12487  * @tree_view: A #GtkTreeView
12488  * @path: The #GtkTreePath to be activated.
12489  * @column: The #GtkTreeViewColumn to be activated.
12490  *
12491  * Activates the cell determined by @path and @column.
12492  **/
12493 void
12494 gtk_tree_view_row_activated (GtkTreeView       *tree_view,
12495                              GtkTreePath       *path,
12496                              GtkTreeViewColumn *column)
12497 {
12498   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12499
12500   g_signal_emit (tree_view, tree_view_signals[ROW_ACTIVATED], 0, path, column);
12501 }
12502
12503
12504 static void
12505 gtk_tree_view_expand_all_emission_helper (GtkRBTree *tree,
12506                                           GtkRBNode *node,
12507                                           gpointer   data)
12508 {
12509   GtkTreeView *tree_view = data;
12510
12511   if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT &&
12512       node->children)
12513     {
12514       GtkTreePath *path;
12515       GtkTreeIter iter;
12516
12517       path = _gtk_tree_view_find_path (tree_view, tree, node);
12518       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
12519
12520       g_signal_emit (tree_view, tree_view_signals[ROW_EXPANDED], 0, &iter, path);
12521
12522       gtk_tree_path_free (path);
12523     }
12524
12525   if (node->children)
12526     _gtk_rbtree_traverse (node->children,
12527                           node->children->root,
12528                           G_PRE_ORDER,
12529                           gtk_tree_view_expand_all_emission_helper,
12530                           tree_view);
12531 }
12532
12533 /**
12534  * gtk_tree_view_expand_all:
12535  * @tree_view: A #GtkTreeView.
12536  *
12537  * Recursively expands all nodes in the @tree_view.
12538  **/
12539 void
12540 gtk_tree_view_expand_all (GtkTreeView *tree_view)
12541 {
12542   GtkTreePath *path;
12543   GtkRBTree *tree;
12544   GtkRBNode *node;
12545
12546   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12547
12548   if (tree_view->priv->tree == NULL)
12549     return;
12550
12551   path = gtk_tree_path_new_first ();
12552   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
12553
12554   while (node)
12555     {
12556       gtk_tree_view_real_expand_row (tree_view, path, tree, node, TRUE, FALSE);
12557       node = _gtk_rbtree_next (tree, node);
12558       gtk_tree_path_next (path);
12559   }
12560
12561   gtk_tree_path_free (path);
12562 }
12563
12564 /**
12565  * gtk_tree_view_collapse_all:
12566  * @tree_view: A #GtkTreeView.
12567  *
12568  * Recursively collapses all visible, expanded nodes in @tree_view.
12569  **/
12570 void
12571 gtk_tree_view_collapse_all (GtkTreeView *tree_view)
12572 {
12573   GtkRBTree *tree;
12574   GtkRBNode *node;
12575   GtkTreePath *path;
12576   gint *indices;
12577
12578   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12579
12580   if (tree_view->priv->tree == NULL)
12581     return;
12582
12583   path = gtk_tree_path_new ();
12584   gtk_tree_path_down (path);
12585   indices = gtk_tree_path_get_indices (path);
12586
12587   tree = tree_view->priv->tree;
12588   node = tree->root;
12589   while (node && node->left != tree->nil)
12590     node = node->left;
12591
12592   while (node)
12593     {
12594       if (node->children)
12595         gtk_tree_view_real_collapse_row (tree_view, path, tree, node, FALSE);
12596       indices[0]++;
12597       node = _gtk_rbtree_next (tree, node);
12598     }
12599
12600   gtk_tree_path_free (path);
12601 }
12602
12603 /**
12604  * gtk_tree_view_expand_to_path:
12605  * @tree_view: A #GtkTreeView.
12606  * @path: path to a row.
12607  *
12608  * Expands the row at @path. This will also expand all parent rows of
12609  * @path as necessary.
12610  *
12611  * Since: 2.2
12612  **/
12613 void
12614 gtk_tree_view_expand_to_path (GtkTreeView *tree_view,
12615                               GtkTreePath *path)
12616 {
12617   gint i, depth;
12618   gint *indices;
12619   GtkTreePath *tmp;
12620
12621   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12622   g_return_if_fail (path != NULL);
12623
12624   depth = gtk_tree_path_get_depth (path);
12625   indices = gtk_tree_path_get_indices (path);
12626
12627   tmp = gtk_tree_path_new ();
12628   g_return_if_fail (tmp != NULL);
12629
12630   for (i = 0; i < depth; i++)
12631     {
12632       gtk_tree_path_append_index (tmp, indices[i]);
12633       gtk_tree_view_expand_row (tree_view, tmp, FALSE);
12634     }
12635
12636   gtk_tree_path_free (tmp);
12637 }
12638
12639 /* FIXME the bool return values for expand_row and collapse_row are
12640  * not analagous; they should be TRUE if the row had children and
12641  * was not already in the requested state.
12642  */
12643
12644
12645 static gboolean
12646 gtk_tree_view_real_expand_row (GtkTreeView *tree_view,
12647                                GtkTreePath *path,
12648                                GtkRBTree   *tree,
12649                                GtkRBNode   *node,
12650                                gboolean     open_all,
12651                                gboolean     animate)
12652 {
12653   GtkTreeIter iter;
12654   GtkTreeIter temp;
12655   gboolean expand;
12656
12657   if (animate)
12658     g_object_get (gtk_widget_get_settings (GTK_WIDGET (tree_view)),
12659                   "gtk-enable-animations", &animate,
12660                   NULL);
12661
12662   remove_auto_expand_timeout (tree_view);
12663
12664   if (node->children && !open_all)
12665     return FALSE;
12666
12667   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
12668     return FALSE;
12669
12670   gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
12671   if (! gtk_tree_model_iter_has_child (tree_view->priv->model, &iter))
12672     return FALSE;
12673
12674
12675    if (node->children && open_all)
12676     {
12677       gboolean retval = FALSE;
12678       GtkTreePath *tmp_path = gtk_tree_path_copy (path);
12679
12680       gtk_tree_path_append_index (tmp_path, 0);
12681       tree = node->children;
12682       node = tree->root;
12683       while (node->left != tree->nil)
12684         node = node->left;
12685       /* try to expand the children */
12686       do
12687         {
12688          gboolean t;
12689          t = gtk_tree_view_real_expand_row (tree_view, tmp_path, tree, node,
12690                                             TRUE, animate);
12691          if (t)
12692            retval = TRUE;
12693
12694          gtk_tree_path_next (tmp_path);
12695          node = _gtk_rbtree_next (tree, node);
12696        }
12697       while (node != NULL);
12698
12699       gtk_tree_path_free (tmp_path);
12700
12701       return retval;
12702     }
12703
12704   g_signal_emit (tree_view, tree_view_signals[TEST_EXPAND_ROW], 0, &iter, path, &expand);
12705
12706   if (!gtk_tree_model_iter_has_child (tree_view->priv->model, &iter))
12707     return FALSE;
12708
12709   if (expand)
12710     return FALSE;
12711
12712   node->children = _gtk_rbtree_new ();
12713   node->children->parent_tree = tree;
12714   node->children->parent_node = node;
12715
12716   gtk_tree_model_iter_children (tree_view->priv->model, &temp, &iter);
12717
12718   gtk_tree_view_build_tree (tree_view,
12719                             node->children,
12720                             &temp,
12721                             gtk_tree_path_get_depth (path) + 1,
12722                             open_all);
12723
12724   if (animate)
12725     {
12726       GtkStyleContext *context;
12727
12728       context = gtk_widget_get_style_context (GTK_WIDGET (tree_view));
12729
12730       gtk_style_context_save (context);
12731       gtk_style_context_add_class (context, GTK_STYLE_CLASS_EXPANDER);
12732
12733       gtk_style_context_notify_state_change (context, tree_view->priv->bin_window,
12734                                              node, GTK_STATE_ACTIVE, TRUE);
12735
12736       _gtk_style_context_invalidate_animation_areas (context);
12737       gtk_style_context_restore (context);
12738     }
12739
12740   install_presize_handler (tree_view);
12741
12742   g_signal_emit (tree_view, tree_view_signals[ROW_EXPANDED], 0, &iter, path);
12743   if (open_all && node->children)
12744     {
12745       _gtk_rbtree_traverse (node->children,
12746                             node->children->root,
12747                             G_PRE_ORDER,
12748                             gtk_tree_view_expand_all_emission_helper,
12749                             tree_view);
12750     }
12751   return TRUE;
12752 }
12753
12754
12755 /**
12756  * gtk_tree_view_expand_row:
12757  * @tree_view: a #GtkTreeView
12758  * @path: path to a row
12759  * @open_all: whether to recursively expand, or just expand immediate children
12760  *
12761  * Opens the row so its children are visible.
12762  *
12763  * Return value: %TRUE if the row existed and had children
12764  **/
12765 gboolean
12766 gtk_tree_view_expand_row (GtkTreeView *tree_view,
12767                           GtkTreePath *path,
12768                           gboolean     open_all)
12769 {
12770   GtkRBTree *tree;
12771   GtkRBNode *node;
12772
12773   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12774   g_return_val_if_fail (tree_view->priv->model != NULL, FALSE);
12775   g_return_val_if_fail (path != NULL, FALSE);
12776
12777   if (_gtk_tree_view_find_node (tree_view,
12778                                 path,
12779                                 &tree,
12780                                 &node))
12781     return FALSE;
12782
12783   if (tree != NULL)
12784     return gtk_tree_view_real_expand_row (tree_view, path, tree, node, open_all, FALSE);
12785   else
12786     return FALSE;
12787 }
12788
12789 static gboolean
12790 gtk_tree_view_real_collapse_row (GtkTreeView *tree_view,
12791                                  GtkTreePath *path,
12792                                  GtkRBTree   *tree,
12793                                  GtkRBNode   *node,
12794                                  gboolean     animate)
12795 {
12796   GtkTreeIter iter;
12797   GtkTreeIter children;
12798   gboolean collapse;
12799   gint x, y;
12800   GList *list;
12801   GdkWindow *child, *parent;
12802
12803   if (animate)
12804     g_object_get (gtk_widget_get_settings (GTK_WIDGET (tree_view)),
12805                   "gtk-enable-animations", &animate,
12806                   NULL);
12807
12808   remove_auto_expand_timeout (tree_view);
12809
12810   if (node->children == NULL)
12811     return FALSE;
12812   gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
12813
12814   g_signal_emit (tree_view, tree_view_signals[TEST_COLLAPSE_ROW], 0, &iter, path, &collapse);
12815
12816   if (collapse)
12817     return FALSE;
12818
12819   /* if the prelighted node is a child of us, we want to unprelight it.  We have
12820    * a chance to prelight the correct node below */
12821
12822   if (tree_view->priv->prelight_tree)
12823     {
12824       GtkRBTree *parent_tree;
12825       GtkRBNode *parent_node;
12826
12827       parent_tree = tree_view->priv->prelight_tree->parent_tree;
12828       parent_node = tree_view->priv->prelight_tree->parent_node;
12829       while (parent_tree)
12830         {
12831           if (parent_tree == tree && parent_node == node)
12832             {
12833               ensure_unprelighted (tree_view);
12834               break;
12835             }
12836           parent_node = parent_tree->parent_node;
12837           parent_tree = parent_tree->parent_tree;
12838         }
12839     }
12840
12841   TREE_VIEW_INTERNAL_ASSERT (gtk_tree_model_iter_children (tree_view->priv->model, &children, &iter), FALSE);
12842
12843   for (list = tree_view->priv->columns; list; list = list->next)
12844     {
12845       GtkTreeViewColumn *column = list->data;
12846
12847       if (gtk_tree_view_column_get_visible (column) == FALSE)
12848         continue;
12849       if (gtk_tree_view_column_get_sizing (column) == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
12850         _gtk_tree_view_column_cell_set_dirty (column, TRUE);
12851     }
12852
12853   if (tree_view->priv->destroy_count_func)
12854     {
12855       GtkTreePath *child_path;
12856       gint child_count = 0;
12857       child_path = gtk_tree_path_copy (path);
12858       gtk_tree_path_down (child_path);
12859       if (node->children)
12860         _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, &child_count);
12861       tree_view->priv->destroy_count_func (tree_view, child_path, child_count, tree_view->priv->destroy_count_data);
12862       gtk_tree_path_free (child_path);
12863     }
12864
12865   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
12866     {
12867       GtkTreePath *cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
12868
12869       if (gtk_tree_path_is_ancestor (path, cursor_path))
12870         {
12871           gtk_tree_row_reference_free (tree_view->priv->cursor);
12872           tree_view->priv->cursor = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
12873                                                                       tree_view->priv->model,
12874                                                                       path);
12875         }
12876       gtk_tree_path_free (cursor_path);
12877     }
12878
12879   if (gtk_tree_row_reference_valid (tree_view->priv->anchor))
12880     {
12881       GtkTreePath *anchor_path = gtk_tree_row_reference_get_path (tree_view->priv->anchor);
12882       if (gtk_tree_path_is_ancestor (path, anchor_path))
12883         {
12884           gtk_tree_row_reference_free (tree_view->priv->anchor);
12885           tree_view->priv->anchor = NULL;
12886         }
12887       gtk_tree_path_free (anchor_path);
12888     }
12889
12890   /* Stop a pending double click */
12891   tree_view->priv->last_button_x = -1;
12892   tree_view->priv->last_button_y = -1;
12893
12894   if (gtk_tree_view_unref_and_check_selection_tree (tree_view, node->children))
12895     {
12896       _gtk_rbtree_remove (node->children);
12897       g_signal_emit_by_name (tree_view->priv->selection, "changed");
12898     }
12899   else
12900     _gtk_rbtree_remove (node->children);
12901
12902   if (animate)
12903     {
12904       GtkStyleContext *context;
12905
12906       context = gtk_widget_get_style_context (GTK_WIDGET (tree_view));
12907
12908       gtk_style_context_save (context);
12909       gtk_style_context_add_class (context, GTK_STYLE_CLASS_EXPANDER);
12910
12911       gtk_style_context_notify_state_change (context, tree_view->priv->bin_window,
12912                                              node, GTK_STATE_ACTIVE, FALSE);
12913
12914       _gtk_style_context_invalidate_animation_areas (context);
12915       gtk_style_context_restore (context);
12916     }
12917
12918   if (gtk_widget_get_mapped (GTK_WIDGET (tree_view)))
12919     {
12920       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
12921     }
12922
12923   g_signal_emit (tree_view, tree_view_signals[ROW_COLLAPSED], 0, &iter, path);
12924   
12925   if (gtk_widget_get_mapped (GTK_WIDGET (tree_view)))
12926     {
12927       /* now that we've collapsed all rows, we want to try to set the prelight
12928        * again. To do this, we fake a motion event and send it to ourselves. */
12929
12930       child = tree_view->priv->bin_window;
12931       parent = gdk_window_get_parent (child);
12932
12933       if (gdk_window_get_pointer (parent, &x, &y, NULL) == child)
12934         {
12935           GdkEventMotion event;
12936           gint child_x, child_y;
12937
12938           gdk_window_get_position (child, &child_x, &child_y);
12939
12940           event.window = tree_view->priv->bin_window;
12941           event.x = x - child_x;
12942           event.y = y - child_y;
12943
12944           /* despite the fact this isn't a real event, I'm almost positive it will
12945            * never trigger a drag event.  maybe_drag is the only function that uses
12946            * more than just event.x and event.y. */
12947           gtk_tree_view_motion_bin_window (GTK_WIDGET (tree_view), &event);
12948         }
12949     }
12950
12951   return TRUE;
12952 }
12953
12954 /**
12955  * gtk_tree_view_collapse_row:
12956  * @tree_view: a #GtkTreeView
12957  * @path: path to a row in the @tree_view
12958  *
12959  * Collapses a row (hides its child rows, if they exist).
12960  *
12961  * Return value: %TRUE if the row was collapsed.
12962  **/
12963 gboolean
12964 gtk_tree_view_collapse_row (GtkTreeView *tree_view,
12965                             GtkTreePath *path)
12966 {
12967   GtkRBTree *tree;
12968   GtkRBNode *node;
12969
12970   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12971   g_return_val_if_fail (tree_view->priv->tree != NULL, FALSE);
12972   g_return_val_if_fail (path != NULL, FALSE);
12973
12974   if (_gtk_tree_view_find_node (tree_view,
12975                                 path,
12976                                 &tree,
12977                                 &node))
12978     return FALSE;
12979
12980   if (tree == NULL || node->children == NULL)
12981     return FALSE;
12982
12983   return gtk_tree_view_real_collapse_row (tree_view, path, tree, node, FALSE);
12984 }
12985
12986 static void
12987 gtk_tree_view_map_expanded_rows_helper (GtkTreeView            *tree_view,
12988                                         GtkRBTree              *tree,
12989                                         GtkTreePath            *path,
12990                                         GtkTreeViewMappingFunc  func,
12991                                         gpointer                user_data)
12992 {
12993   GtkRBNode *node;
12994
12995   if (tree == NULL || tree->root == NULL)
12996     return;
12997
12998   node = tree->root;
12999
13000   while (node && node->left != tree->nil)
13001     node = node->left;
13002
13003   while (node)
13004     {
13005       if (node->children)
13006         {
13007           (* func) (tree_view, path, user_data);
13008           gtk_tree_path_down (path);
13009           gtk_tree_view_map_expanded_rows_helper (tree_view, node->children, path, func, user_data);
13010           gtk_tree_path_up (path);
13011         }
13012       gtk_tree_path_next (path);
13013       node = _gtk_rbtree_next (tree, node);
13014     }
13015 }
13016
13017 /**
13018  * gtk_tree_view_map_expanded_rows:
13019  * @tree_view: A #GtkTreeView
13020  * @func: (scope call): A function to be called
13021  * @data: User data to be passed to the function.
13022  *
13023  * Calls @func on all expanded rows.
13024  **/
13025 void
13026 gtk_tree_view_map_expanded_rows (GtkTreeView            *tree_view,
13027                                  GtkTreeViewMappingFunc  func,
13028                                  gpointer                user_data)
13029 {
13030   GtkTreePath *path;
13031
13032   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13033   g_return_if_fail (func != NULL);
13034
13035   path = gtk_tree_path_new_first ();
13036
13037   gtk_tree_view_map_expanded_rows_helper (tree_view,
13038                                           tree_view->priv->tree,
13039                                           path, func, user_data);
13040
13041   gtk_tree_path_free (path);
13042 }
13043
13044 /**
13045  * gtk_tree_view_row_expanded:
13046  * @tree_view: A #GtkTreeView.
13047  * @path: A #GtkTreePath to test expansion state.
13048  *
13049  * Returns %TRUE if the node pointed to by @path is expanded in @tree_view.
13050  *
13051  * Return value: %TRUE if #path is expanded.
13052  **/
13053 gboolean
13054 gtk_tree_view_row_expanded (GtkTreeView *tree_view,
13055                             GtkTreePath *path)
13056 {
13057   GtkRBTree *tree;
13058   GtkRBNode *node;
13059
13060   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
13061   g_return_val_if_fail (path != NULL, FALSE);
13062
13063   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
13064
13065   if (node == NULL)
13066     return FALSE;
13067
13068   return (node->children != NULL);
13069 }
13070
13071 /**
13072  * gtk_tree_view_get_reorderable:
13073  * @tree_view: a #GtkTreeView
13074  *
13075  * Retrieves whether the user can reorder the tree via drag-and-drop. See
13076  * gtk_tree_view_set_reorderable().
13077  *
13078  * Return value: %TRUE if the tree can be reordered.
13079  **/
13080 gboolean
13081 gtk_tree_view_get_reorderable (GtkTreeView *tree_view)
13082 {
13083   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
13084
13085   return tree_view->priv->reorderable;
13086 }
13087
13088 /**
13089  * gtk_tree_view_set_reorderable:
13090  * @tree_view: A #GtkTreeView.
13091  * @reorderable: %TRUE, if the tree can be reordered.
13092  *
13093  * This function is a convenience function to allow you to reorder
13094  * models that support the #GtkDragSourceIface and the
13095  * #GtkDragDestIface.  Both #GtkTreeStore and #GtkListStore support
13096  * these.  If @reorderable is %TRUE, then the user can reorder the
13097  * model by dragging and dropping rows. The developer can listen to
13098  * these changes by connecting to the model's row_inserted and
13099  * row_deleted signals. The reordering is implemented by setting up
13100  * the tree view as a drag source and destination. Therefore, drag and
13101  * drop can not be used in a reorderable view for any other purpose.
13102  *
13103  * This function does not give you any degree of control over the order -- any
13104  * reordering is allowed.  If more control is needed, you should probably
13105  * handle drag and drop manually.
13106  **/
13107 void
13108 gtk_tree_view_set_reorderable (GtkTreeView *tree_view,
13109                                gboolean     reorderable)
13110 {
13111   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13112
13113   reorderable = reorderable != FALSE;
13114
13115   if (tree_view->priv->reorderable == reorderable)
13116     return;
13117
13118   if (reorderable)
13119     {
13120       const GtkTargetEntry row_targets[] = {
13121         { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, 0 }
13122       };
13123
13124       gtk_tree_view_enable_model_drag_source (tree_view,
13125                                               GDK_BUTTON1_MASK,
13126                                               row_targets,
13127                                               G_N_ELEMENTS (row_targets),
13128                                               GDK_ACTION_MOVE);
13129       gtk_tree_view_enable_model_drag_dest (tree_view,
13130                                             row_targets,
13131                                             G_N_ELEMENTS (row_targets),
13132                                             GDK_ACTION_MOVE);
13133     }
13134   else
13135     {
13136       gtk_tree_view_unset_rows_drag_source (tree_view);
13137       gtk_tree_view_unset_rows_drag_dest (tree_view);
13138     }
13139
13140   tree_view->priv->reorderable = reorderable;
13141
13142   g_object_notify (G_OBJECT (tree_view), "reorderable");
13143 }
13144
13145 static void
13146 gtk_tree_view_real_set_cursor (GtkTreeView     *tree_view,
13147                                GtkTreePath     *path,
13148                                gboolean         clear_and_select,
13149                                gboolean         clamp_node)
13150 {
13151   GtkRBTree *tree = NULL;
13152   GtkRBNode *node = NULL;
13153
13154   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
13155     {
13156       GtkTreePath *cursor_path;
13157       cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
13158       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
13159       gtk_tree_path_free (cursor_path);
13160     }
13161
13162   gtk_tree_row_reference_free (tree_view->priv->cursor);
13163   tree_view->priv->cursor = NULL;
13164
13165   /* One cannot set the cursor on a separator.   Also, if
13166    * _gtk_tree_view_find_node returns TRUE, it ran out of tree
13167    * before finding the tree and node belonging to path.  The
13168    * path maps to a non-existing path and we will silently bail out.
13169    * We unset tree and node to avoid further processing.
13170    */
13171   if (!row_is_separator (tree_view, NULL, path)
13172       && _gtk_tree_view_find_node (tree_view, path, &tree, &node) == FALSE)
13173     {
13174       tree_view->priv->cursor =
13175           gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
13176                                             tree_view->priv->model,
13177                                             path);
13178     }
13179   else
13180     {
13181       tree = NULL;
13182       node = NULL;
13183     }
13184
13185   if (tree != NULL)
13186     {
13187       GtkRBTree *new_tree = NULL;
13188       GtkRBNode *new_node = NULL;
13189
13190       if (clear_and_select && !tree_view->priv->ctrl_pressed)
13191         {
13192           GtkTreeSelectMode mode = 0;
13193
13194           if (tree_view->priv->ctrl_pressed)
13195             mode |= GTK_TREE_SELECT_MODE_TOGGLE;
13196           if (tree_view->priv->shift_pressed)
13197             mode |= GTK_TREE_SELECT_MODE_EXTEND;
13198
13199           _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
13200                                                     node, tree, path, mode,
13201                                                     FALSE);
13202         }
13203
13204       /* We have to re-find tree and node here again, somebody might have
13205        * cleared the node or the whole tree in the GtkTreeSelection::changed
13206        * callback. If the nodes differ we bail out here.
13207        */
13208       _gtk_tree_view_find_node (tree_view, path, &new_tree, &new_node);
13209
13210       if (tree != new_tree || node != new_node)
13211         return;
13212
13213       if (clamp_node)
13214         {
13215           gtk_tree_view_clamp_node_visible (tree_view, tree, node);
13216           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
13217         }
13218     }
13219
13220   g_signal_emit (tree_view, tree_view_signals[CURSOR_CHANGED], 0);
13221 }
13222
13223 /**
13224  * gtk_tree_view_get_cursor:
13225  * @tree_view: A #GtkTreeView
13226  * @path: (out) (transfer full) (allow-none): A pointer to be filled with the current cursor path, or %NULL
13227  * @focus_column: (out) (transfer none) (allow-none): A pointer to be filled with the current focus column, or %NULL
13228  *
13229  * Fills in @path and @focus_column with the current path and focus column.  If
13230  * the cursor isn't currently set, then *@path will be %NULL.  If no column
13231  * currently has focus, then *@focus_column will be %NULL.
13232  *
13233  * The returned #GtkTreePath must be freed with gtk_tree_path_free() when
13234  * you are done with it.
13235  **/
13236 void
13237 gtk_tree_view_get_cursor (GtkTreeView        *tree_view,
13238                           GtkTreePath       **path,
13239                           GtkTreeViewColumn **focus_column)
13240 {
13241   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13242
13243   if (path)
13244     {
13245       if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
13246         *path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
13247       else
13248         *path = NULL;
13249     }
13250
13251   if (focus_column)
13252     {
13253       *focus_column = tree_view->priv->focus_column;
13254     }
13255 }
13256
13257 /**
13258  * gtk_tree_view_set_cursor:
13259  * @tree_view: A #GtkTreeView
13260  * @path: A #GtkTreePath
13261  * @focus_column: (allow-none): A #GtkTreeViewColumn, or %NULL
13262  * @start_editing: %TRUE if the specified cell should start being edited.
13263  *
13264  * Sets the current keyboard focus to be at @path, and selects it.  This is
13265  * useful when you want to focus the user's attention on a particular row.  If
13266  * @focus_column is not %NULL, then focus is given to the column specified by 
13267  * it. Additionally, if @focus_column is specified, and @start_editing is 
13268  * %TRUE, then editing should be started in the specified cell.  
13269  * This function is often followed by @gtk_widget_grab_focus (@tree_view) 
13270  * in order to give keyboard focus to the widget.  Please note that editing 
13271  * can only happen when the widget is realized.
13272  *
13273  * If @path is invalid for @model, the current cursor (if any) will be unset
13274  * and the function will return without failing.
13275  **/
13276 void
13277 gtk_tree_view_set_cursor (GtkTreeView       *tree_view,
13278                           GtkTreePath       *path,
13279                           GtkTreeViewColumn *focus_column,
13280                           gboolean           start_editing)
13281 {
13282   gtk_tree_view_set_cursor_on_cell (tree_view, path, focus_column,
13283                                     NULL, start_editing);
13284 }
13285
13286 /**
13287  * gtk_tree_view_set_cursor_on_cell:
13288  * @tree_view: A #GtkTreeView
13289  * @path: A #GtkTreePath
13290  * @focus_column: (allow-none): A #GtkTreeViewColumn, or %NULL
13291  * @focus_cell: (allow-none): A #GtkCellRenderer, or %NULL
13292  * @start_editing: %TRUE if the specified cell should start being edited.
13293  *
13294  * Sets the current keyboard focus to be at @path, and selects it.  This is
13295  * useful when you want to focus the user's attention on a particular row.  If
13296  * @focus_column is not %NULL, then focus is given to the column specified by
13297  * it. If @focus_column and @focus_cell are not %NULL, and @focus_column
13298  * contains 2 or more editable or activatable cells, then focus is given to
13299  * the cell specified by @focus_cell. Additionally, if @focus_column is
13300  * specified, and @start_editing is %TRUE, then editing should be started in
13301  * the specified cell.  This function is often followed by
13302  * @gtk_widget_grab_focus (@tree_view) in order to give keyboard focus to the
13303  * widget.  Please note that editing can only happen when the widget is
13304  * realized.
13305  *
13306  * If @path is invalid for @model, the current cursor (if any) will be unset
13307  * and the function will return without failing.
13308  *
13309  * Since: 2.2
13310  **/
13311 void
13312 gtk_tree_view_set_cursor_on_cell (GtkTreeView       *tree_view,
13313                                   GtkTreePath       *path,
13314                                   GtkTreeViewColumn *focus_column,
13315                                   GtkCellRenderer   *focus_cell,
13316                                   gboolean           start_editing)
13317 {
13318   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13319   g_return_if_fail (path != NULL);
13320   g_return_if_fail (focus_column == NULL || GTK_IS_TREE_VIEW_COLUMN (focus_column));
13321
13322   if (!tree_view->priv->model)
13323     return;
13324
13325   if (focus_cell)
13326     {
13327       g_return_if_fail (focus_column);
13328       g_return_if_fail (GTK_IS_CELL_RENDERER (focus_cell));
13329     }
13330
13331   /* cancel the current editing, if it exists */
13332   if (tree_view->priv->edited_column &&
13333       gtk_cell_area_get_edit_widget
13334       (gtk_cell_layout_get_area (GTK_CELL_LAYOUT (tree_view->priv->edited_column))))
13335     gtk_tree_view_stop_editing (tree_view, TRUE);
13336
13337   gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
13338
13339   if (focus_column &&
13340       gtk_tree_view_column_get_visible (focus_column))
13341     {
13342       GList *list;
13343       gboolean column_in_tree = FALSE;
13344
13345       for (list = tree_view->priv->columns; list; list = list->next)
13346         if (list->data == focus_column)
13347           {
13348             column_in_tree = TRUE;
13349             break;
13350           }
13351       g_return_if_fail (column_in_tree);
13352       tree_view->priv->focus_column = focus_column;
13353       if (focus_cell)
13354         gtk_tree_view_column_focus_cell (focus_column, focus_cell);
13355       if (start_editing)
13356         gtk_tree_view_start_editing (tree_view, path, TRUE);
13357     }
13358 }
13359
13360 /**
13361  * gtk_tree_view_get_bin_window:
13362  * @tree_view: A #GtkTreeView
13363  *
13364  * Returns the window that @tree_view renders to.
13365  * This is used primarily to compare to <literal>event->window</literal>
13366  * to confirm that the event on @tree_view is on the right window.
13367  *
13368  * Return value: (transfer none): A #GdkWindow, or %NULL when @tree_view
13369  *     hasn't been realized yet
13370  **/
13371 GdkWindow *
13372 gtk_tree_view_get_bin_window (GtkTreeView *tree_view)
13373 {
13374   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
13375
13376   return tree_view->priv->bin_window;
13377 }
13378
13379 /**
13380  * gtk_tree_view_get_path_at_pos:
13381  * @tree_view: A #GtkTreeView.
13382  * @x: The x position to be identified (relative to bin_window).
13383  * @y: The y position to be identified (relative to bin_window).
13384  * @path: (out) (allow-none): A pointer to a #GtkTreePath pointer to be filled in, or %NULL
13385  * @column: (out) (transfer none) (allow-none): A pointer to a #GtkTreeViewColumn pointer to be filled in, or %NULL
13386  * @cell_x: (out) (allow-none): A pointer where the X coordinate relative to the cell can be placed, or %NULL
13387  * @cell_y: (out) (allow-none): A pointer where the Y coordinate relative to the cell can be placed, or %NULL
13388  *
13389  * Finds the path at the point (@x, @y), relative to bin_window coordinates
13390  * (please see gtk_tree_view_get_bin_window()).
13391  * That is, @x and @y are relative to an events coordinates. @x and @y must
13392  * come from an event on the @tree_view only where <literal>event->window ==
13393  * gtk_tree_view_get_bin_window (<!-- -->)</literal>. It is primarily for
13394  * things like popup menus. If @path is non-%NULL, then it will be filled
13395  * with the #GtkTreePath at that point.  This path should be freed with
13396  * gtk_tree_path_free().  If @column is non-%NULL, then it will be filled
13397  * with the column at that point.  @cell_x and @cell_y return the coordinates
13398  * relative to the cell background (i.e. the @background_area passed to
13399  * gtk_cell_renderer_render()).  This function is only meaningful if
13400  * @tree_view is realized.  Therefore this function will always return %FALSE
13401  * if @tree_view is not realized or does not have a model.
13402  *
13403  * For converting widget coordinates (eg. the ones you get from
13404  * GtkWidget::query-tooltip), please see
13405  * gtk_tree_view_convert_widget_to_bin_window_coords().
13406  *
13407  * Return value: %TRUE if a row exists at that coordinate.
13408  **/
13409 gboolean
13410 gtk_tree_view_get_path_at_pos (GtkTreeView        *tree_view,
13411                                gint                x,
13412                                gint                y,
13413                                GtkTreePath       **path,
13414                                GtkTreeViewColumn **column,
13415                                gint               *cell_x,
13416                                gint               *cell_y)
13417 {
13418   GtkRBTree *tree;
13419   GtkRBNode *node;
13420   gint y_offset;
13421
13422   g_return_val_if_fail (tree_view != NULL, FALSE);
13423
13424   if (path)
13425     *path = NULL;
13426   if (column)
13427     *column = NULL;
13428
13429   if (tree_view->priv->bin_window == NULL)
13430     return FALSE;
13431
13432   if (tree_view->priv->tree == NULL)
13433     return FALSE;
13434
13435   if (x > gtk_adjustment_get_upper (tree_view->priv->hadjustment))
13436     return FALSE;
13437
13438   if (x < 0 || y < 0)
13439     return FALSE;
13440
13441   if (column || cell_x)
13442     {
13443       GtkTreeViewColumn *tmp_column;
13444       GtkTreeViewColumn *last_column = NULL;
13445       GList *list;
13446       gint remaining_x = x;
13447       gboolean found = FALSE;
13448       gboolean rtl;
13449       gint width;
13450
13451       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
13452       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
13453            list;
13454            list = (rtl ? list->prev : list->next))
13455         {
13456           tmp_column = list->data;
13457
13458           if (gtk_tree_view_column_get_visible (tmp_column) == FALSE)
13459             continue;
13460
13461           last_column = tmp_column;
13462           width = gtk_tree_view_column_get_width (tmp_column);
13463           if (remaining_x <= width)
13464             {
13465               found = TRUE;
13466
13467               if (column)
13468                 *column = tmp_column;
13469
13470               if (cell_x)
13471                 *cell_x = remaining_x;
13472
13473               break;
13474             }
13475           remaining_x -= width;
13476         }
13477
13478       /* If found is FALSE and there is a last_column, then it the remainder
13479        * space is in that area
13480        */
13481       if (!found)
13482         {
13483           if (last_column)
13484             {
13485               if (column)
13486                 *column = last_column;
13487               
13488               if (cell_x)
13489                 *cell_x = gtk_tree_view_column_get_width (last_column) + remaining_x;
13490             }
13491           else
13492             {
13493               return FALSE;
13494             }
13495         }
13496     }
13497
13498   y_offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
13499                                       TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, y),
13500                                       &tree, &node);
13501
13502   if (tree == NULL)
13503     return FALSE;
13504
13505   if (cell_y)
13506     *cell_y = y_offset;
13507
13508   if (path)
13509     *path = _gtk_tree_view_find_path (tree_view, tree, node);
13510
13511   return TRUE;
13512 }
13513
13514
13515 static inline gint
13516 gtk_tree_view_get_cell_area_height (GtkTreeView *tree_view,
13517                                     GtkRBNode   *node,
13518                                     gint         vertical_separator)
13519 {
13520   int height;
13521
13522   /* The "cell" areas are the cell_area passed in to gtk_cell_renderer_render(),
13523    * i.e. just the cells, no spacing.
13524    *
13525    * The cell area height is at least expander_size - vertical_separator.
13526    * For regular nodes, the height is then at least expander_size. We should
13527    * be able to enforce the expander_size minimum here, because this
13528    * function will not be called for irregular (e.g. separator) rows.
13529    */
13530   height = gtk_tree_view_get_row_height (tree_view, node);
13531   if (height < tree_view->priv->expander_size)
13532     height = tree_view->priv->expander_size;
13533
13534   return height - vertical_separator;
13535 }
13536
13537 static inline gint
13538 gtk_tree_view_get_cell_area_y_offset (GtkTreeView *tree_view,
13539                                       GtkRBTree   *tree,
13540                                       GtkRBNode   *node,
13541                                       gint         vertical_separator)
13542 {
13543   int offset;
13544
13545   offset = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
13546   offset += vertical_separator / 2;
13547
13548   return offset;
13549 }
13550
13551 /**
13552  * gtk_tree_view_get_cell_area:
13553  * @tree_view: a #GtkTreeView
13554  * @path: (allow-none): a #GtkTreePath for the row, or %NULL to get only horizontal coordinates
13555  * @column: (allow-none): a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordinates
13556  * @rect: (out): rectangle to fill with cell rect
13557  *
13558  * Fills the bounding rectangle in bin_window coordinates for the cell at the
13559  * row specified by @path and the column specified by @column.  If @path is
13560  * %NULL, or points to a path not currently displayed, the @y and @height fields
13561  * of the rectangle will be filled with 0. If @column is %NULL, the @x and @width
13562  * fields will be filled with 0.  The sum of all cell rects does not cover the
13563  * entire tree; there are extra pixels in between rows, for example. The
13564  * returned rectangle is equivalent to the @cell_area passed to
13565  * gtk_cell_renderer_render().  This function is only valid if @tree_view is
13566  * realized.
13567  **/
13568 void
13569 gtk_tree_view_get_cell_area (GtkTreeView        *tree_view,
13570                              GtkTreePath        *path,
13571                              GtkTreeViewColumn  *column,
13572                              GdkRectangle       *rect)
13573 {
13574   GtkAllocation allocation;
13575   GtkRBTree *tree = NULL;
13576   GtkRBNode *node = NULL;
13577   gint vertical_separator;
13578   gint horizontal_separator;
13579
13580   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13581   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
13582   g_return_if_fail (rect != NULL);
13583   g_return_if_fail (!column || gtk_tree_view_column_get_tree_view (column) == (GtkWidget *) tree_view);
13584   g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (tree_view)));
13585
13586   gtk_widget_style_get (GTK_WIDGET (tree_view),
13587                         "vertical-separator", &vertical_separator,
13588                         "horizontal-separator", &horizontal_separator,
13589                         NULL);
13590
13591   rect->x = 0;
13592   rect->y = 0;
13593   rect->width = 0;
13594   rect->height = 0;
13595
13596   if (column)
13597     {
13598       gtk_widget_get_allocation (gtk_tree_view_column_get_button (column), &allocation);
13599       rect->x = allocation.x + horizontal_separator/2;
13600       rect->width = allocation.width - horizontal_separator;
13601     }
13602
13603   if (path)
13604     {
13605       gboolean ret = _gtk_tree_view_find_node (tree_view, path, &tree, &node);
13606
13607       /* Get vertical coords */
13608       if ((!ret && tree == NULL) || ret)
13609         return;
13610
13611       if (row_is_separator (tree_view, NULL, path))
13612         {
13613           /* There isn't really a "cell area" for separator, so we
13614            * return the y, height values for background area instead.
13615            */
13616           rect->y = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
13617           rect->height = gtk_tree_view_get_row_height (tree_view, node);
13618         }
13619       else
13620         {
13621           rect->y = gtk_tree_view_get_cell_area_y_offset (tree_view, tree, node,
13622                                                           vertical_separator);
13623           rect->height = gtk_tree_view_get_cell_area_height (tree_view, node,
13624                                                              vertical_separator);
13625         }
13626
13627       if (column &&
13628           gtk_tree_view_is_expander_column (tree_view, column))
13629         {
13630           gint depth = gtk_tree_path_get_depth (path);
13631           gboolean rtl;
13632
13633           rtl = gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL;
13634
13635           if (!rtl)
13636             rect->x += (depth - 1) * tree_view->priv->level_indentation;
13637           rect->width -= (depth - 1) * tree_view->priv->level_indentation;
13638
13639           if (gtk_tree_view_draw_expanders (tree_view))
13640             {
13641               if (!rtl)
13642                 rect->x += depth * tree_view->priv->expander_size;
13643               rect->width -= depth * tree_view->priv->expander_size;
13644             }
13645
13646           rect->width = MAX (rect->width, 0);
13647         }
13648     }
13649 }
13650
13651 static inline gint
13652 gtk_tree_view_get_row_height (GtkTreeView *tree_view,
13653                               GtkRBNode   *node)
13654 {
13655   int height;
13656
13657   /* The "background" areas of all rows/cells add up to cover the entire tree.
13658    * The background includes all inter-row and inter-cell spacing.
13659    *
13660    * If the row pointed at by node does not have a height set, we default
13661    * to expander_size, which is the minimum height for regular nodes.
13662    * Non-regular nodes (e.g. separators) can have a height set smaller
13663    * than expander_size and should not be overruled here.
13664    */
13665   height = GTK_RBNODE_GET_HEIGHT (node);
13666   if (height <= 0)
13667     height = tree_view->priv->expander_size;
13668
13669   return height;
13670 }
13671
13672 static inline gint
13673 gtk_tree_view_get_row_y_offset (GtkTreeView *tree_view,
13674                                 GtkRBTree   *tree,
13675                                 GtkRBNode   *node)
13676 {
13677   int offset;
13678
13679   offset = _gtk_rbtree_node_find_offset (tree, node);
13680
13681   return RBTREE_Y_TO_TREE_WINDOW_Y (tree_view, offset);
13682 }
13683
13684 /**
13685  * gtk_tree_view_get_background_area:
13686  * @tree_view: a #GtkTreeView
13687  * @path: (allow-none): a #GtkTreePath for the row, or %NULL to get only horizontal coordinates
13688  * @column: (allow-none): a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordiantes
13689  * @rect: (out): rectangle to fill with cell background rect
13690  *
13691  * Fills the bounding rectangle in bin_window coordinates for the cell at the
13692  * row specified by @path and the column specified by @column.  If @path is
13693  * %NULL, or points to a node not found in the tree, the @y and @height fields of
13694  * the rectangle will be filled with 0. If @column is %NULL, the @x and @width
13695  * fields will be filled with 0.  The returned rectangle is equivalent to the
13696  * @background_area passed to gtk_cell_renderer_render().  These background
13697  * areas tile to cover the entire bin window.  Contrast with the @cell_area,
13698  * returned by gtk_tree_view_get_cell_area(), which returns only the cell
13699  * itself, excluding surrounding borders and the tree expander area.
13700  *
13701  **/
13702 void
13703 gtk_tree_view_get_background_area (GtkTreeView        *tree_view,
13704                                    GtkTreePath        *path,
13705                                    GtkTreeViewColumn  *column,
13706                                    GdkRectangle       *rect)
13707 {
13708   GtkRBTree *tree = NULL;
13709   GtkRBNode *node = NULL;
13710
13711   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13712   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
13713   g_return_if_fail (rect != NULL);
13714
13715   rect->x = 0;
13716   rect->y = 0;
13717   rect->width = 0;
13718   rect->height = 0;
13719
13720   if (path)
13721     {
13722       /* Get vertical coords */
13723
13724       if (!_gtk_tree_view_find_node (tree_view, path, &tree, &node) &&
13725           tree == NULL)
13726         return;
13727
13728       rect->y = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
13729       rect->height = gtk_tree_view_get_row_height (tree_view, node);
13730     }
13731
13732   if (column)
13733     {
13734       gint x2 = 0;
13735
13736       gtk_tree_view_get_background_xrange (tree_view, tree, column, &rect->x, &x2);
13737       rect->width = x2 - rect->x;
13738     }
13739 }
13740
13741 /**
13742  * gtk_tree_view_get_visible_rect:
13743  * @tree_view: a #GtkTreeView
13744  * @visible_rect: (out): rectangle to fill
13745  *
13746  * Fills @visible_rect with the currently-visible region of the
13747  * buffer, in tree coordinates. Convert to bin_window coordinates with
13748  * gtk_tree_view_convert_tree_to_bin_window_coords().
13749  * Tree coordinates start at 0,0 for row 0 of the tree, and cover the entire
13750  * scrollable area of the tree.
13751  **/
13752 void
13753 gtk_tree_view_get_visible_rect (GtkTreeView  *tree_view,
13754                                 GdkRectangle *visible_rect)
13755 {
13756   GtkAllocation allocation;
13757   GtkWidget *widget;
13758
13759   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13760
13761   widget = GTK_WIDGET (tree_view);
13762
13763   if (visible_rect)
13764     {
13765       gtk_widget_get_allocation (widget, &allocation);
13766       visible_rect->x = gtk_adjustment_get_value (tree_view->priv->hadjustment);
13767       visible_rect->y = gtk_adjustment_get_value (tree_view->priv->vadjustment);
13768       visible_rect->width = allocation.width;
13769       visible_rect->height = allocation.height - gtk_tree_view_get_effective_header_height (tree_view);
13770     }
13771 }
13772
13773 /**
13774  * gtk_tree_view_convert_widget_to_tree_coords:
13775  * @tree_view: a #GtkTreeView
13776  * @wx: X coordinate relative to the widget
13777  * @wy: Y coordinate relative to the widget
13778  * @tx: (out): return location for tree X coordinate
13779  * @ty: (out): return location for tree Y coordinate
13780  *
13781  * Converts widget coordinates to coordinates for the
13782  * tree (the full scrollable area of the tree).
13783  *
13784  * Since: 2.12
13785  **/
13786 void
13787 gtk_tree_view_convert_widget_to_tree_coords (GtkTreeView *tree_view,
13788                                              gint         wx,
13789                                              gint         wy,
13790                                              gint        *tx,
13791                                              gint        *ty)
13792 {
13793   gint x, y;
13794
13795   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13796
13797   gtk_tree_view_convert_widget_to_bin_window_coords (tree_view,
13798                                                      wx, wy,
13799                                                      &x, &y);
13800   gtk_tree_view_convert_bin_window_to_tree_coords (tree_view,
13801                                                    x, y,
13802                                                    tx, ty);
13803 }
13804
13805 /**
13806  * gtk_tree_view_convert_tree_to_widget_coords:
13807  * @tree_view: a #GtkTreeView
13808  * @tx: X coordinate relative to the tree
13809  * @ty: Y coordinate relative to the tree
13810  * @wx: (out): return location for widget X coordinate
13811  * @wy: (out): return location for widget Y coordinate
13812  *
13813  * Converts tree coordinates (coordinates in full scrollable area of the tree)
13814  * to widget coordinates.
13815  *
13816  * Since: 2.12
13817  **/
13818 void
13819 gtk_tree_view_convert_tree_to_widget_coords (GtkTreeView *tree_view,
13820                                              gint         tx,
13821                                              gint         ty,
13822                                              gint        *wx,
13823                                              gint        *wy)
13824 {
13825   gint x, y;
13826
13827   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13828
13829   gtk_tree_view_convert_tree_to_bin_window_coords (tree_view,
13830                                                    tx, ty,
13831                                                    &x, &y);
13832   gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
13833                                                      x, y,
13834                                                      wx, wy);
13835 }
13836
13837 /**
13838  * gtk_tree_view_convert_widget_to_bin_window_coords:
13839  * @tree_view: a #GtkTreeView
13840  * @wx: X coordinate relative to the widget
13841  * @wy: Y coordinate relative to the widget
13842  * @bx: (out): return location for bin_window X coordinate
13843  * @by: (out): return location for bin_window Y coordinate
13844  *
13845  * Converts widget coordinates to coordinates for the bin_window
13846  * (see gtk_tree_view_get_bin_window()).
13847  *
13848  * Since: 2.12
13849  **/
13850 void
13851 gtk_tree_view_convert_widget_to_bin_window_coords (GtkTreeView *tree_view,
13852                                                    gint         wx,
13853                                                    gint         wy,
13854                                                    gint        *bx,
13855                                                    gint        *by)
13856 {
13857   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13858
13859   if (bx)
13860     *bx = wx + gtk_adjustment_get_value (tree_view->priv->hadjustment);
13861   if (by)
13862     *by = wy - gtk_tree_view_get_effective_header_height (tree_view);
13863 }
13864
13865 /**
13866  * gtk_tree_view_convert_bin_window_to_widget_coords:
13867  * @tree_view: a #GtkTreeView
13868  * @bx: bin_window X coordinate
13869  * @by: bin_window Y coordinate
13870  * @wx: (out): return location for widget X coordinate
13871  * @wy: (out): return location for widget Y coordinate
13872  *
13873  * Converts bin_window coordinates (see gtk_tree_view_get_bin_window())
13874  * to widget relative coordinates.
13875  *
13876  * Since: 2.12
13877  **/
13878 void
13879 gtk_tree_view_convert_bin_window_to_widget_coords (GtkTreeView *tree_view,
13880                                                    gint         bx,
13881                                                    gint         by,
13882                                                    gint        *wx,
13883                                                    gint        *wy)
13884 {
13885   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13886
13887   if (wx)
13888     *wx = bx - gtk_adjustment_get_value (tree_view->priv->hadjustment);
13889   if (wy)
13890     *wy = by + gtk_tree_view_get_effective_header_height (tree_view);
13891 }
13892
13893 /**
13894  * gtk_tree_view_convert_tree_to_bin_window_coords:
13895  * @tree_view: a #GtkTreeView
13896  * @tx: tree X coordinate
13897  * @ty: tree Y coordinate
13898  * @bx: (out): return location for X coordinate relative to bin_window
13899  * @by: (out): return location for Y coordinate relative to bin_window
13900  *
13901  * Converts tree coordinates (coordinates in full scrollable area of the tree)
13902  * to bin_window coordinates.
13903  *
13904  * Since: 2.12
13905  **/
13906 void
13907 gtk_tree_view_convert_tree_to_bin_window_coords (GtkTreeView *tree_view,
13908                                                  gint         tx,
13909                                                  gint         ty,
13910                                                  gint        *bx,
13911                                                  gint        *by)
13912 {
13913   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13914
13915   if (bx)
13916     *bx = tx;
13917   if (by)
13918     *by = ty - tree_view->priv->dy;
13919 }
13920
13921 /**
13922  * gtk_tree_view_convert_bin_window_to_tree_coords:
13923  * @tree_view: a #GtkTreeView
13924  * @bx: X coordinate relative to bin_window
13925  * @by: Y coordinate relative to bin_window
13926  * @tx: (out): return location for tree X coordinate
13927  * @ty: (out): return location for tree Y coordinate
13928  *
13929  * Converts bin_window coordinates to coordinates for the
13930  * tree (the full scrollable area of the tree).
13931  *
13932  * Since: 2.12
13933  **/
13934 void
13935 gtk_tree_view_convert_bin_window_to_tree_coords (GtkTreeView *tree_view,
13936                                                  gint         bx,
13937                                                  gint         by,
13938                                                  gint        *tx,
13939                                                  gint        *ty)
13940 {
13941   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13942
13943   if (tx)
13944     *tx = bx;
13945   if (ty)
13946     *ty = by + tree_view->priv->dy;
13947 }
13948
13949
13950
13951 /**
13952  * gtk_tree_view_get_visible_range:
13953  * @tree_view: A #GtkTreeView
13954  * @start_path: (out) (allow-none): Return location for start of region,
13955  *              or %NULL.
13956  * @end_path: (out) (allow-none): Return location for end of region, or %NULL.
13957  *
13958  * Sets @start_path and @end_path to be the first and last visible path.
13959  * Note that there may be invisible paths in between.
13960  *
13961  * The paths should be freed with gtk_tree_path_free() after use.
13962  *
13963  * Returns: %TRUE, if valid paths were placed in @start_path and @end_path.
13964  *
13965  * Since: 2.8
13966  **/
13967 gboolean
13968 gtk_tree_view_get_visible_range (GtkTreeView  *tree_view,
13969                                  GtkTreePath **start_path,
13970                                  GtkTreePath **end_path)
13971 {
13972   GtkRBTree *tree;
13973   GtkRBNode *node;
13974   gboolean retval;
13975   
13976   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
13977
13978   if (!tree_view->priv->tree)
13979     return FALSE;
13980
13981   retval = TRUE;
13982
13983   if (start_path)
13984     {
13985       _gtk_rbtree_find_offset (tree_view->priv->tree,
13986                                TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, 0),
13987                                &tree, &node);
13988       if (node)
13989         *start_path = _gtk_tree_view_find_path (tree_view, tree, node);
13990       else
13991         retval = FALSE;
13992     }
13993
13994   if (end_path)
13995     {
13996       gint y;
13997
13998       if (tree_view->priv->height < gtk_adjustment_get_page_size (tree_view->priv->vadjustment))
13999         y = tree_view->priv->height - 1;
14000       else
14001         y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, gtk_adjustment_get_page_size (tree_view->priv->vadjustment)) - 1;
14002
14003       _gtk_rbtree_find_offset (tree_view->priv->tree, y, &tree, &node);
14004       if (node)
14005         *end_path = _gtk_tree_view_find_path (tree_view, tree, node);
14006       else
14007         retval = FALSE;
14008     }
14009
14010   return retval;
14011 }
14012
14013 /**
14014  * gtk_tree_view_is_blank_at_pos:
14015  * @tree_view: A #GtkTreeView
14016  * @x: The x position to be identified (relative to bin_window)
14017  * @y: The y position to be identified (relative to bin_window)
14018  * @path: (out) (allow-none): A pointer to a #GtkTreePath pointer to be filled in, or %NULL
14019  * @column: (out) (allow-none): A pointer to a #GtkTreeViewColumn pointer to be filled in, or %NULL
14020  * @cell_x: (out) (allow-none): A pointer where the X coordinate relative to the cell can be placed, or %NULL
14021  * @cell_y: (out) (allow-none): A pointer where the Y coordinate relative to the cell can be placed, or %NULL
14022  *
14023  * Determine whether the point (@x, @y) in @tree_view is blank, that is no
14024  * cell content nor an expander arrow is drawn at the location. If so, the
14025  * location can be considered as the background. You might wish to take
14026  * special action on clicks on the background, such as clearing a current
14027  * selection, having a custom context menu or starting rubber banding.
14028  *
14029  * The @x and @y coordinate that are provided must be relative to bin_window
14030  * coordinates.  That is, @x and @y must come from an event on @tree_view
14031  * where <literal>event->window == gtk_tree_view_get_bin_window (<!-- -->)</literal>.
14032  *
14033  * For converting widget coordinates (eg. the ones you get from
14034  * GtkWidget::query-tooltip), please see
14035  * gtk_tree_view_convert_widget_to_bin_window_coords().
14036  *
14037  * The @path, @column, @cell_x and @cell_y arguments will be filled in
14038  * likewise as for gtk_tree_view_get_path_at_pos().  Please see
14039  * gtk_tree_view_get_path_at_pos() for more information.
14040  *
14041  * Return value: %TRUE if the area at the given coordinates is blank,
14042  * %FALSE otherwise.
14043  *
14044  * Since: 3.0
14045  */
14046 gboolean
14047 gtk_tree_view_is_blank_at_pos (GtkTreeView       *tree_view,
14048                                gint                x,
14049                                gint                y,
14050                                GtkTreePath       **path,
14051                                GtkTreeViewColumn **column,
14052                                gint               *cell_x,
14053                                gint               *cell_y)
14054 {
14055   GtkRBTree *tree;
14056   GtkRBNode *node;
14057   GtkTreeIter iter;
14058   GtkTreePath *real_path;
14059   GtkTreeViewColumn *real_column;
14060   GdkRectangle cell_area, background_area;
14061
14062   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
14063
14064   if (!gtk_tree_view_get_path_at_pos (tree_view, x, y,
14065                                       &real_path, &real_column,
14066                                       cell_x, cell_y))
14067     /* If there's no path here, it is blank */
14068     return TRUE;
14069
14070   if (path)
14071     *path = real_path;
14072
14073   if (column)
14074     *column = real_column;
14075
14076   gtk_tree_model_get_iter (tree_view->priv->model, &iter, real_path);
14077   _gtk_tree_view_find_node (tree_view, real_path, &tree, &node);
14078
14079   /* Check if there's an expander arrow at (x, y) */
14080   if (real_column == tree_view->priv->expander_column
14081       && gtk_tree_view_draw_expanders (tree_view))
14082     {
14083       gboolean over_arrow;
14084
14085       over_arrow = coords_are_over_arrow (tree_view, tree, node, x, y);
14086
14087       if (over_arrow)
14088         {
14089           if (!path)
14090             gtk_tree_path_free (real_path);
14091           return FALSE;
14092         }
14093     }
14094
14095   /* Otherwise, have the column see if there's a cell at (x, y) */
14096   gtk_tree_view_column_cell_set_cell_data (real_column,
14097                                            tree_view->priv->model,
14098                                            &iter,
14099                                            GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
14100                                            node->children ? TRUE : FALSE);
14101
14102   gtk_tree_view_get_background_area (tree_view, real_path, real_column,
14103                                      &background_area);
14104   gtk_tree_view_get_cell_area (tree_view, real_path, real_column,
14105                                &cell_area);
14106
14107   if (!path)
14108     gtk_tree_path_free (real_path);
14109
14110   return _gtk_tree_view_column_is_blank_at_pos (real_column,
14111                                                 &cell_area,
14112                                                 &background_area,
14113                                                 x, y);
14114 }
14115
14116 static void
14117 unset_reorderable (GtkTreeView *tree_view)
14118 {
14119   if (tree_view->priv->reorderable)
14120     {
14121       tree_view->priv->reorderable = FALSE;
14122       g_object_notify (G_OBJECT (tree_view), "reorderable");
14123     }
14124 }
14125
14126 /**
14127  * gtk_tree_view_enable_model_drag_source:
14128  * @tree_view: a #GtkTreeView
14129  * @start_button_mask: Mask of allowed buttons to start drag
14130  * @targets: (array): the table of targets that the drag will support
14131  * @n_targets: the number of items in @targets
14132  * @actions: the bitmask of possible actions for a drag from this
14133  *    widget
14134  *
14135  * Turns @tree_view into a drag source for automatic DND. Calling this
14136  * method sets #GtkTreeView:reorderable to %FALSE.
14137  **/
14138 void
14139 gtk_tree_view_enable_model_drag_source (GtkTreeView              *tree_view,
14140                                         GdkModifierType           start_button_mask,
14141                                         const GtkTargetEntry     *targets,
14142                                         gint                      n_targets,
14143                                         GdkDragAction             actions)
14144 {
14145   TreeViewDragInfo *di;
14146
14147   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14148
14149   gtk_drag_source_set (GTK_WIDGET (tree_view),
14150                        0,
14151                        targets,
14152                        n_targets,
14153                        actions);
14154
14155   di = ensure_info (tree_view);
14156
14157   di->start_button_mask = start_button_mask;
14158   di->source_actions = actions;
14159   di->source_set = TRUE;
14160
14161   unset_reorderable (tree_view);
14162 }
14163
14164 /**
14165  * gtk_tree_view_enable_model_drag_dest:
14166  * @tree_view: a #GtkTreeView
14167  * @targets: (array length=n_targets): the table of targets that
14168  *           the drag will support
14169  * @n_targets: the number of items in @targets
14170  * @actions: the bitmask of possible actions for a drag from this
14171  *    widget
14172  * 
14173  * Turns @tree_view into a drop destination for automatic DND. Calling
14174  * this method sets #GtkTreeView:reorderable to %FALSE.
14175  **/
14176 void
14177 gtk_tree_view_enable_model_drag_dest (GtkTreeView              *tree_view,
14178                                       const GtkTargetEntry     *targets,
14179                                       gint                      n_targets,
14180                                       GdkDragAction             actions)
14181 {
14182   TreeViewDragInfo *di;
14183
14184   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14185
14186   gtk_drag_dest_set (GTK_WIDGET (tree_view),
14187                      0,
14188                      targets,
14189                      n_targets,
14190                      actions);
14191
14192   di = ensure_info (tree_view);
14193   di->dest_set = TRUE;
14194
14195   unset_reorderable (tree_view);
14196 }
14197
14198 /**
14199  * gtk_tree_view_unset_rows_drag_source:
14200  * @tree_view: a #GtkTreeView
14201  *
14202  * Undoes the effect of
14203  * gtk_tree_view_enable_model_drag_source(). Calling this method sets
14204  * #GtkTreeView:reorderable to %FALSE.
14205  **/
14206 void
14207 gtk_tree_view_unset_rows_drag_source (GtkTreeView *tree_view)
14208 {
14209   TreeViewDragInfo *di;
14210
14211   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14212
14213   di = get_info (tree_view);
14214
14215   if (di)
14216     {
14217       if (di->source_set)
14218         {
14219           gtk_drag_source_unset (GTK_WIDGET (tree_view));
14220           di->source_set = FALSE;
14221         }
14222
14223       if (!di->dest_set && !di->source_set)
14224         remove_info (tree_view);
14225     }
14226   
14227   unset_reorderable (tree_view);
14228 }
14229
14230 /**
14231  * gtk_tree_view_unset_rows_drag_dest:
14232  * @tree_view: a #GtkTreeView
14233  *
14234  * Undoes the effect of
14235  * gtk_tree_view_enable_model_drag_dest(). Calling this method sets
14236  * #GtkTreeView:reorderable to %FALSE.
14237  **/
14238 void
14239 gtk_tree_view_unset_rows_drag_dest (GtkTreeView *tree_view)
14240 {
14241   TreeViewDragInfo *di;
14242
14243   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14244
14245   di = get_info (tree_view);
14246
14247   if (di)
14248     {
14249       if (di->dest_set)
14250         {
14251           gtk_drag_dest_unset (GTK_WIDGET (tree_view));
14252           di->dest_set = FALSE;
14253         }
14254
14255       if (!di->dest_set && !di->source_set)
14256         remove_info (tree_view);
14257     }
14258
14259   unset_reorderable (tree_view);
14260 }
14261
14262 /**
14263  * gtk_tree_view_set_drag_dest_row:
14264  * @tree_view: a #GtkTreeView
14265  * @path: (allow-none): The path of the row to highlight, or %NULL.
14266  * @pos: Specifies whether to drop before, after or into the row
14267  * 
14268  * Sets the row that is highlighted for feedback.
14269  **/
14270 void
14271 gtk_tree_view_set_drag_dest_row (GtkTreeView            *tree_view,
14272                                  GtkTreePath            *path,
14273                                  GtkTreeViewDropPosition pos)
14274 {
14275   GtkTreePath *current_dest;
14276
14277   /* Note; this function is exported to allow a custom DND
14278    * implementation, so it can't touch TreeViewDragInfo
14279    */
14280
14281   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14282
14283   current_dest = NULL;
14284
14285   if (tree_view->priv->drag_dest_row)
14286     {
14287       current_dest = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
14288       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
14289     }
14290
14291   /* special case a drop on an empty model */
14292   tree_view->priv->empty_view_drop = 0;
14293
14294   if (pos == GTK_TREE_VIEW_DROP_BEFORE && path
14295       && gtk_tree_path_get_depth (path) == 1
14296       && gtk_tree_path_get_indices (path)[0] == 0)
14297     {
14298       gint n_children;
14299
14300       n_children = gtk_tree_model_iter_n_children (tree_view->priv->model,
14301                                                    NULL);
14302
14303       if (!n_children)
14304         tree_view->priv->empty_view_drop = 1;
14305     }
14306
14307   tree_view->priv->drag_dest_pos = pos;
14308
14309   if (path)
14310     {
14311       tree_view->priv->drag_dest_row =
14312         gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
14313       gtk_tree_view_queue_draw_path (tree_view, path, NULL);
14314     }
14315   else
14316     tree_view->priv->drag_dest_row = NULL;
14317
14318   if (current_dest)
14319     {
14320       GtkRBTree *tree, *new_tree;
14321       GtkRBNode *node, *new_node;
14322
14323       _gtk_tree_view_find_node (tree_view, current_dest, &tree, &node);
14324       _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
14325
14326       if (tree && node)
14327         {
14328           _gtk_rbtree_next_full (tree, node, &new_tree, &new_node);
14329           if (new_tree && new_node)
14330             _gtk_tree_view_queue_draw_node (tree_view, new_tree, new_node, NULL);
14331
14332           _gtk_rbtree_prev_full (tree, node, &new_tree, &new_node);
14333           if (new_tree && new_node)
14334             _gtk_tree_view_queue_draw_node (tree_view, new_tree, new_node, NULL);
14335         }
14336       gtk_tree_path_free (current_dest);
14337     }
14338 }
14339
14340 /**
14341  * gtk_tree_view_get_drag_dest_row:
14342  * @tree_view: a #GtkTreeView
14343  * @path: (out) (allow-none): Return location for the path of the highlighted row, or %NULL.
14344  * @pos: (out) (allow-none): Return location for the drop position, or %NULL
14345  * 
14346  * Gets information about the row that is highlighted for feedback.
14347  **/
14348 void
14349 gtk_tree_view_get_drag_dest_row (GtkTreeView              *tree_view,
14350                                  GtkTreePath             **path,
14351                                  GtkTreeViewDropPosition  *pos)
14352 {
14353   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14354
14355   if (path)
14356     {
14357       if (tree_view->priv->drag_dest_row)
14358         *path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
14359       else
14360         {
14361           if (tree_view->priv->empty_view_drop)
14362             *path = gtk_tree_path_new_from_indices (0, -1);
14363           else
14364             *path = NULL;
14365         }
14366     }
14367
14368   if (pos)
14369     *pos = tree_view->priv->drag_dest_pos;
14370 }
14371
14372 /**
14373  * gtk_tree_view_get_dest_row_at_pos:
14374  * @tree_view: a #GtkTreeView
14375  * @drag_x: the position to determine the destination row for
14376  * @drag_y: the position to determine the destination row for
14377  * @path: (out) (allow-none): Return location for the path of the highlighted row, or %NULL.
14378  * @pos: (out) (allow-none): Return location for the drop position, or %NULL
14379  * 
14380  * Determines the destination row for a given position.  @drag_x and
14381  * @drag_y are expected to be in widget coordinates.  This function is only
14382  * meaningful if @tree_view is realized.  Therefore this function will always
14383  * return %FALSE if @tree_view is not realized or does not have a model.
14384  * 
14385  * Return value: whether there is a row at the given position, %TRUE if this
14386  * is indeed the case.
14387  **/
14388 gboolean
14389 gtk_tree_view_get_dest_row_at_pos (GtkTreeView             *tree_view,
14390                                    gint                     drag_x,
14391                                    gint                     drag_y,
14392                                    GtkTreePath            **path,
14393                                    GtkTreeViewDropPosition *pos)
14394 {
14395   gint cell_y;
14396   gint bin_x, bin_y;
14397   gdouble offset_into_row;
14398   gdouble third;
14399   GdkRectangle cell;
14400   GtkTreeViewColumn *column = NULL;
14401   GtkTreePath *tmp_path = NULL;
14402
14403   /* Note; this function is exported to allow a custom DND
14404    * implementation, so it can't touch TreeViewDragInfo
14405    */
14406
14407   g_return_val_if_fail (tree_view != NULL, FALSE);
14408   g_return_val_if_fail (drag_x >= 0, FALSE);
14409   g_return_val_if_fail (drag_y >= 0, FALSE);
14410
14411   if (path)
14412     *path = NULL;
14413
14414   if (tree_view->priv->bin_window == NULL)
14415     return FALSE;
14416
14417   if (tree_view->priv->tree == NULL)
14418     return FALSE;
14419
14420   /* If in the top third of a row, we drop before that row; if
14421    * in the bottom third, drop after that row; if in the middle,
14422    * and the row has children, drop into the row.
14423    */
14424   gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, drag_x, drag_y,
14425                                                      &bin_x, &bin_y);
14426
14427   if (!gtk_tree_view_get_path_at_pos (tree_view,
14428                                       bin_x,
14429                                       bin_y,
14430                                       &tmp_path,
14431                                       &column,
14432                                       NULL,
14433                                       &cell_y))
14434     return FALSE;
14435
14436   gtk_tree_view_get_background_area (tree_view, tmp_path, column,
14437                                      &cell);
14438
14439   offset_into_row = cell_y;
14440
14441   if (path)
14442     *path = tmp_path;
14443   else
14444     gtk_tree_path_free (tmp_path);
14445
14446   tmp_path = NULL;
14447
14448   third = cell.height / 3.0;
14449
14450   if (pos)
14451     {
14452       if (offset_into_row < third)
14453         {
14454           *pos = GTK_TREE_VIEW_DROP_BEFORE;
14455         }
14456       else if (offset_into_row < (cell.height / 2.0))
14457         {
14458           *pos = GTK_TREE_VIEW_DROP_INTO_OR_BEFORE;
14459         }
14460       else if (offset_into_row < third * 2.0)
14461         {
14462           *pos = GTK_TREE_VIEW_DROP_INTO_OR_AFTER;
14463         }
14464       else
14465         {
14466           *pos = GTK_TREE_VIEW_DROP_AFTER;
14467         }
14468     }
14469
14470   return TRUE;
14471 }
14472
14473
14474
14475 /* KEEP IN SYNC WITH GTK_TREE_VIEW_BIN_EXPOSE */
14476 /**
14477  * gtk_tree_view_create_row_drag_icon:
14478  * @tree_view: a #GtkTreeView
14479  * @path: a #GtkTreePath in @tree_view
14480  *
14481  * Creates a #cairo_surface_t representation of the row at @path.  
14482  * This image is used for a drag icon.
14483  *
14484  * Return value: (transfer full): a newly-allocated surface of the drag icon.
14485  **/
14486 cairo_surface_t *
14487 gtk_tree_view_create_row_drag_icon (GtkTreeView  *tree_view,
14488                                     GtkTreePath  *path)
14489 {
14490   GtkTreeIter   iter;
14491   GtkRBTree    *tree;
14492   GtkRBNode    *node;
14493   GtkStyleContext *context;
14494   GtkStateFlags state;
14495   gint cell_offset;
14496   GList *list;
14497   GdkRectangle background_area;
14498   GtkWidget *widget;
14499   gint depth;
14500   /* start drawing inside the black outline */
14501   gint x = 1, y = 1;
14502   cairo_surface_t *surface;
14503   gint bin_window_width;
14504   gboolean is_separator = FALSE;
14505   gboolean rtl, allow_rules;
14506   cairo_t *cr;
14507
14508   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14509   g_return_val_if_fail (path != NULL, NULL);
14510
14511   widget = GTK_WIDGET (tree_view);
14512
14513   if (!gtk_widget_get_realized (widget))
14514     return NULL;
14515
14516   depth = gtk_tree_path_get_depth (path);
14517
14518   _gtk_tree_view_find_node (tree_view,
14519                             path,
14520                             &tree,
14521                             &node);
14522
14523   if (tree == NULL)
14524     return NULL;
14525
14526   if (!gtk_tree_model_get_iter (tree_view->priv->model,
14527                                 &iter,
14528                                 path))
14529     return NULL;
14530
14531   context = gtk_widget_get_style_context (widget);
14532
14533   gtk_style_context_save (context);
14534
14535   state = gtk_widget_get_state_flags (widget);
14536   gtk_style_context_set_state (context, state);
14537
14538   gtk_style_context_add_class (context, GTK_STYLE_CLASS_VIEW);
14539   gtk_style_context_add_region (context, GTK_STYLE_REGION_COLUMN, 0);
14540
14541   gtk_widget_style_get (widget,
14542                         "allow-rules", &allow_rules,
14543                         NULL);
14544
14545   if (allow_rules && tree_view->priv->has_rules)
14546     {
14547       GtkRegionFlags row_flags;
14548
14549       if (_gtk_rbtree_node_find_parity (tree, node))
14550         row_flags = GTK_REGION_ODD;
14551       else
14552         row_flags = GTK_REGION_EVEN;
14553
14554       gtk_style_context_add_region (context, GTK_STYLE_REGION_ROW, row_flags);
14555     }
14556
14557   is_separator = row_is_separator (tree_view, &iter, NULL);
14558
14559   cell_offset = x;
14560
14561   background_area.y = y;
14562   background_area.height = gtk_tree_view_get_row_height (tree_view, node);
14563
14564   bin_window_width = gdk_window_get_width (tree_view->priv->bin_window);
14565
14566   surface = gdk_window_create_similar_surface (tree_view->priv->bin_window,
14567                                                CAIRO_CONTENT_COLOR,
14568                                                bin_window_width + 2,
14569                                                background_area.height + 2);
14570
14571   cr = cairo_create (surface);
14572
14573   gtk_render_background (context, cr, 0, 0,
14574                          bin_window_width + 2,
14575                          background_area.height + 2);
14576
14577   rtl = gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL;
14578
14579   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
14580       list;
14581       list = (rtl ? list->prev : list->next))
14582     {
14583       GtkTreeViewColumn *column = list->data;
14584       GdkRectangle cell_area;
14585       gint vertical_separator;
14586
14587       if (!gtk_tree_view_column_get_visible (column))
14588         continue;
14589
14590       gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, &iter,
14591                                                GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
14592                                                node->children?TRUE:FALSE);
14593
14594       background_area.x = cell_offset;
14595       background_area.width = gtk_tree_view_column_get_width (column);
14596
14597       gtk_widget_style_get (widget,
14598                             "vertical-separator", &vertical_separator,
14599                             NULL);
14600
14601       cell_area = background_area;
14602
14603       cell_area.y += vertical_separator / 2;
14604       cell_area.height -= vertical_separator;
14605
14606       if (gtk_tree_view_is_expander_column (tree_view, column))
14607         {
14608           if (!rtl)
14609             cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
14610           cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
14611
14612           if (gtk_tree_view_draw_expanders (tree_view))
14613             {
14614               if (!rtl)
14615                 cell_area.x += depth * tree_view->priv->expander_size;
14616               cell_area.width -= depth * tree_view->priv->expander_size;
14617             }
14618         }
14619
14620       if (gtk_tree_view_column_cell_is_visible (column))
14621         {
14622           if (is_separator)
14623             gtk_render_line (context, cr,
14624                              cell_area.x,
14625                              cell_area.y + cell_area.height / 2,
14626                              cell_area.x + cell_area.width,
14627                              cell_area.y + cell_area.height / 2);
14628           else
14629             _gtk_tree_view_column_cell_render (column,
14630                                                cr,
14631                                                &background_area,
14632                                                &cell_area,
14633                                                0, FALSE);
14634         }
14635       cell_offset += gtk_tree_view_column_get_width (column);
14636     }
14637
14638   cairo_set_source_rgb (cr, 0, 0, 0);
14639   cairo_rectangle (cr, 
14640                    0.5, 0.5, 
14641                    bin_window_width + 1,
14642                    background_area.height + 1);
14643   cairo_set_line_width (cr, 1.0);
14644   cairo_stroke (cr);
14645
14646   cairo_destroy (cr);
14647
14648   cairo_surface_set_device_offset (surface, 2, 2);
14649
14650   gtk_style_context_restore (context);
14651
14652   return surface;
14653 }
14654
14655
14656 /**
14657  * gtk_tree_view_set_destroy_count_func:
14658  * @tree_view: A #GtkTreeView
14659  * @func: (allow-none): Function to be called when a view row is destroyed, or %NULL
14660  * @data: (allow-none): User data to be passed to @func, or %NULL
14661  * @destroy: (allow-none): Destroy notifier for @data, or %NULL
14662  *
14663  * This function should almost never be used.  It is meant for private use by
14664  * ATK for determining the number of visible children that are removed when the
14665  * user collapses a row, or a row is deleted.
14666  **/
14667 void
14668 gtk_tree_view_set_destroy_count_func (GtkTreeView             *tree_view,
14669                                       GtkTreeDestroyCountFunc  func,
14670                                       gpointer                 data,
14671                                       GDestroyNotify           destroy)
14672 {
14673   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14674
14675   if (tree_view->priv->destroy_count_destroy)
14676     tree_view->priv->destroy_count_destroy (tree_view->priv->destroy_count_data);
14677
14678   tree_view->priv->destroy_count_func = func;
14679   tree_view->priv->destroy_count_data = data;
14680   tree_view->priv->destroy_count_destroy = destroy;
14681 }
14682
14683
14684 /*
14685  * Interactive search
14686  */
14687
14688 /**
14689  * gtk_tree_view_set_enable_search:
14690  * @tree_view: A #GtkTreeView
14691  * @enable_search: %TRUE, if the user can search interactively
14692  *
14693  * If @enable_search is set, then the user can type in text to search through
14694  * the tree interactively (this is sometimes called "typeahead find").
14695  * 
14696  * Note that even if this is %FALSE, the user can still initiate a search 
14697  * using the "start-interactive-search" key binding.
14698  */
14699 void
14700 gtk_tree_view_set_enable_search (GtkTreeView *tree_view,
14701                                  gboolean     enable_search)
14702 {
14703   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14704
14705   enable_search = !!enable_search;
14706   
14707   if (tree_view->priv->enable_search != enable_search)
14708     {
14709        tree_view->priv->enable_search = enable_search;
14710        g_object_notify (G_OBJECT (tree_view), "enable-search");
14711     }
14712 }
14713
14714 /**
14715  * gtk_tree_view_get_enable_search:
14716  * @tree_view: A #GtkTreeView
14717  *
14718  * Returns whether or not the tree allows to start interactive searching 
14719  * by typing in text.
14720  *
14721  * Return value: whether or not to let the user search interactively
14722  */
14723 gboolean
14724 gtk_tree_view_get_enable_search (GtkTreeView *tree_view)
14725 {
14726   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
14727
14728   return tree_view->priv->enable_search;
14729 }
14730
14731
14732 /**
14733  * gtk_tree_view_get_search_column:
14734  * @tree_view: A #GtkTreeView
14735  *
14736  * Gets the column searched on by the interactive search code.
14737  *
14738  * Return value: the column the interactive search code searches in.
14739  */
14740 gint
14741 gtk_tree_view_get_search_column (GtkTreeView *tree_view)
14742 {
14743   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
14744
14745   return (tree_view->priv->search_column);
14746 }
14747
14748 /**
14749  * gtk_tree_view_set_search_column:
14750  * @tree_view: A #GtkTreeView
14751  * @column: the column of the model to search in, or -1 to disable searching
14752  *
14753  * Sets @column as the column where the interactive search code should
14754  * search in for the current model. 
14755  * 
14756  * If the search column is set, users can use the "start-interactive-search"
14757  * key binding to bring up search popup. The enable-search property controls
14758  * whether simply typing text will also start an interactive search.
14759  *
14760  * Note that @column refers to a column of the current model. The search 
14761  * column is reset to -1 when the model is changed.
14762  */
14763 void
14764 gtk_tree_view_set_search_column (GtkTreeView *tree_view,
14765                                  gint         column)
14766 {
14767   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14768   g_return_if_fail (column >= -1);
14769
14770   if (tree_view->priv->search_column == column)
14771     return;
14772
14773   tree_view->priv->search_column = column;
14774   g_object_notify (G_OBJECT (tree_view), "search-column");
14775 }
14776
14777 /**
14778  * gtk_tree_view_get_search_equal_func: (skip)
14779  * @tree_view: A #GtkTreeView
14780  *
14781  * Returns the compare function currently in use.
14782  *
14783  * Return value: the currently used compare function for the search code.
14784  */
14785
14786 GtkTreeViewSearchEqualFunc
14787 gtk_tree_view_get_search_equal_func (GtkTreeView *tree_view)
14788 {
14789   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14790
14791   return tree_view->priv->search_equal_func;
14792 }
14793
14794 /**
14795  * gtk_tree_view_set_search_equal_func:
14796  * @tree_view: A #GtkTreeView
14797  * @search_equal_func: the compare function to use during the search
14798  * @search_user_data: (allow-none): user data to pass to @search_equal_func, or %NULL
14799  * @search_destroy: (allow-none): Destroy notifier for @search_user_data, or %NULL
14800  *
14801  * Sets the compare function for the interactive search capabilities; note
14802  * that somewhat like strcmp() returning 0 for equality
14803  * #GtkTreeViewSearchEqualFunc returns %FALSE on matches.
14804  **/
14805 void
14806 gtk_tree_view_set_search_equal_func (GtkTreeView                *tree_view,
14807                                      GtkTreeViewSearchEqualFunc  search_equal_func,
14808                                      gpointer                    search_user_data,
14809                                      GDestroyNotify              search_destroy)
14810 {
14811   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14812   g_return_if_fail (search_equal_func != NULL);
14813
14814   if (tree_view->priv->search_destroy)
14815     tree_view->priv->search_destroy (tree_view->priv->search_user_data);
14816
14817   tree_view->priv->search_equal_func = search_equal_func;
14818   tree_view->priv->search_user_data = search_user_data;
14819   tree_view->priv->search_destroy = search_destroy;
14820   if (tree_view->priv->search_equal_func == NULL)
14821     tree_view->priv->search_equal_func = gtk_tree_view_search_equal_func;
14822 }
14823
14824 /**
14825  * gtk_tree_view_get_search_entry:
14826  * @tree_view: A #GtkTreeView
14827  *
14828  * Returns the #GtkEntry which is currently in use as interactive search
14829  * entry for @tree_view.  In case the built-in entry is being used, %NULL
14830  * will be returned.
14831  *
14832  * Return value: (transfer none): the entry currently in use as search entry.
14833  *
14834  * Since: 2.10
14835  */
14836 GtkEntry *
14837 gtk_tree_view_get_search_entry (GtkTreeView *tree_view)
14838 {
14839   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14840
14841   if (tree_view->priv->search_custom_entry_set)
14842     return GTK_ENTRY (tree_view->priv->search_entry);
14843
14844   return NULL;
14845 }
14846
14847 /**
14848  * gtk_tree_view_set_search_entry:
14849  * @tree_view: A #GtkTreeView
14850  * @entry: (allow-none): the entry the interactive search code of @tree_view should use or %NULL
14851  *
14852  * Sets the entry which the interactive search code will use for this
14853  * @tree_view.  This is useful when you want to provide a search entry
14854  * in our interface at all time at a fixed position.  Passing %NULL for
14855  * @entry will make the interactive search code use the built-in popup
14856  * entry again.
14857  *
14858  * Since: 2.10
14859  */
14860 void
14861 gtk_tree_view_set_search_entry (GtkTreeView *tree_view,
14862                                 GtkEntry    *entry)
14863 {
14864   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14865   g_return_if_fail (entry == NULL || GTK_IS_ENTRY (entry));
14866
14867   if (tree_view->priv->search_custom_entry_set)
14868     {
14869       if (tree_view->priv->search_entry_changed_id)
14870         {
14871           g_signal_handler_disconnect (tree_view->priv->search_entry,
14872                                        tree_view->priv->search_entry_changed_id);
14873           tree_view->priv->search_entry_changed_id = 0;
14874         }
14875       g_signal_handlers_disconnect_by_func (tree_view->priv->search_entry,
14876                                             G_CALLBACK (gtk_tree_view_search_key_press_event),
14877                                             tree_view);
14878
14879       g_object_unref (tree_view->priv->search_entry);
14880     }
14881   else if (tree_view->priv->search_window)
14882     {
14883       gtk_widget_destroy (tree_view->priv->search_window);
14884
14885       tree_view->priv->search_window = NULL;
14886     }
14887
14888   if (entry)
14889     {
14890       tree_view->priv->search_entry = g_object_ref (entry);
14891       tree_view->priv->search_custom_entry_set = TRUE;
14892
14893       if (tree_view->priv->search_entry_changed_id == 0)
14894         {
14895           tree_view->priv->search_entry_changed_id =
14896             g_signal_connect (tree_view->priv->search_entry, "changed",
14897                               G_CALLBACK (gtk_tree_view_search_init),
14898                               tree_view);
14899         }
14900       
14901         g_signal_connect (tree_view->priv->search_entry, "key-press-event",
14902                           G_CALLBACK (gtk_tree_view_search_key_press_event),
14903                           tree_view);
14904
14905         gtk_tree_view_search_init (tree_view->priv->search_entry, tree_view);
14906     }
14907   else
14908     {
14909       tree_view->priv->search_entry = NULL;
14910       tree_view->priv->search_custom_entry_set = FALSE;
14911     }
14912 }
14913
14914 /**
14915  * gtk_tree_view_set_search_position_func:
14916  * @tree_view: A #GtkTreeView
14917  * @func: (allow-none): the function to use to position the search dialog, or %NULL
14918  *    to use the default search position function
14919  * @data: (allow-none): user data to pass to @func, or %NULL
14920  * @destroy: (allow-none): Destroy notifier for @data, or %NULL
14921  *
14922  * Sets the function to use when positioning the search dialog.
14923  *
14924  * Since: 2.10
14925  **/
14926 void
14927 gtk_tree_view_set_search_position_func (GtkTreeView                   *tree_view,
14928                                         GtkTreeViewSearchPositionFunc  func,
14929                                         gpointer                       user_data,
14930                                         GDestroyNotify                 destroy)
14931 {
14932   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14933
14934   if (tree_view->priv->search_position_destroy)
14935     tree_view->priv->search_position_destroy (tree_view->priv->search_position_user_data);
14936
14937   tree_view->priv->search_position_func = func;
14938   tree_view->priv->search_position_user_data = user_data;
14939   tree_view->priv->search_position_destroy = destroy;
14940   if (tree_view->priv->search_position_func == NULL)
14941     tree_view->priv->search_position_func = gtk_tree_view_search_position_func;
14942 }
14943
14944 /**
14945  * gtk_tree_view_get_search_position_func: (skip)
14946  * @tree_view: A #GtkTreeView
14947  *
14948  * Returns the positioning function currently in use.
14949  *
14950  * Return value: the currently used function for positioning the search dialog.
14951  *
14952  * Since: 2.10
14953  */
14954 GtkTreeViewSearchPositionFunc
14955 gtk_tree_view_get_search_position_func (GtkTreeView *tree_view)
14956 {
14957   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14958
14959   return tree_view->priv->search_position_func;
14960 }
14961
14962
14963 static void
14964 gtk_tree_view_search_dialog_hide (GtkWidget   *search_dialog,
14965                                   GtkTreeView *tree_view,
14966                                   GdkDevice   *device)
14967 {
14968   if (tree_view->priv->disable_popdown)
14969     return;
14970
14971   if (tree_view->priv->search_entry_changed_id)
14972     {
14973       g_signal_handler_disconnect (tree_view->priv->search_entry,
14974                                    tree_view->priv->search_entry_changed_id);
14975       tree_view->priv->search_entry_changed_id = 0;
14976     }
14977   if (tree_view->priv->typeselect_flush_timeout)
14978     {
14979       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14980       tree_view->priv->typeselect_flush_timeout = 0;
14981     }
14982         
14983   if (gtk_widget_get_visible (search_dialog))
14984     {
14985       /* send focus-in event */
14986       send_focus_change (GTK_WIDGET (tree_view->priv->search_entry), device, FALSE);
14987       gtk_widget_hide (search_dialog);
14988       gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
14989       send_focus_change (GTK_WIDGET (tree_view), device, TRUE);
14990     }
14991 }
14992
14993 static void
14994 gtk_tree_view_search_position_func (GtkTreeView *tree_view,
14995                                     GtkWidget   *search_dialog,
14996                                     gpointer     user_data)
14997 {
14998   gint x, y;
14999   gint tree_x, tree_y;
15000   gint tree_width, tree_height;
15001   GdkWindow *tree_window = gtk_widget_get_window (GTK_WIDGET (tree_view));
15002   GdkScreen *screen = gdk_window_get_screen (tree_window);
15003   GtkRequisition requisition;
15004   gint monitor_num;
15005   GdkRectangle monitor;
15006
15007   monitor_num = gdk_screen_get_monitor_at_window (screen, tree_window);
15008   gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
15009
15010   gtk_widget_realize (search_dialog);
15011
15012   gdk_window_get_origin (tree_window, &tree_x, &tree_y);
15013   tree_width = gdk_window_get_width (tree_window);
15014   tree_height = gdk_window_get_height (tree_window);
15015   gtk_widget_get_preferred_size (search_dialog, &requisition, NULL);
15016
15017   if (tree_x + tree_width > gdk_screen_get_width (screen))
15018     x = gdk_screen_get_width (screen) - requisition.width;
15019   else if (tree_x + tree_width - requisition.width < 0)
15020     x = 0;
15021   else
15022     x = tree_x + tree_width - requisition.width;
15023
15024   if (tree_y + tree_height + requisition.height > gdk_screen_get_height (screen))
15025     y = gdk_screen_get_height (screen) - requisition.height;
15026   else if (tree_y + tree_height < 0) /* isn't really possible ... */
15027     y = 0;
15028   else
15029     y = tree_y + tree_height;
15030
15031   gtk_window_move (GTK_WINDOW (search_dialog), x, y);
15032 }
15033
15034 static void
15035 gtk_tree_view_search_disable_popdown (GtkEntry *entry,
15036                                       GtkMenu  *menu,
15037                                       gpointer  data)
15038 {
15039   GtkTreeView *tree_view = (GtkTreeView *)data;
15040
15041   tree_view->priv->disable_popdown = 1;
15042   g_signal_connect (menu, "hide",
15043                     G_CALLBACK (gtk_tree_view_search_enable_popdown), data);
15044 }
15045
15046 /* Because we're visible but offscreen, we just set a flag in the preedit
15047  * callback.
15048  */
15049 static void
15050 gtk_tree_view_search_preedit_changed (GtkIMContext *im_context,
15051                                       GtkTreeView  *tree_view)
15052 {
15053   tree_view->priv->imcontext_changed = 1;
15054   if (tree_view->priv->typeselect_flush_timeout)
15055     {
15056       g_source_remove (tree_view->priv->typeselect_flush_timeout);
15057       tree_view->priv->typeselect_flush_timeout =
15058         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
15059                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
15060                        tree_view);
15061     }
15062
15063 }
15064
15065 static void
15066 gtk_tree_view_search_activate (GtkEntry    *entry,
15067                                GtkTreeView *tree_view)
15068 {
15069   GtkTreePath *path;
15070   GtkRBNode *node;
15071   GtkRBTree *tree;
15072
15073   gtk_tree_view_search_dialog_hide (tree_view->priv->search_window,
15074                                     tree_view,
15075                                     gtk_get_current_event_device ());
15076
15077   /* If we have a row selected and it's the cursor row, we activate
15078    * the row XXX */
15079   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
15080     {
15081       path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
15082       
15083       _gtk_tree_view_find_node (tree_view, path, &tree, &node);
15084       
15085       if (node && GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
15086         gtk_tree_view_row_activated (tree_view, path, tree_view->priv->focus_column);
15087       
15088       gtk_tree_path_free (path);
15089     }
15090 }
15091
15092 static gboolean
15093 gtk_tree_view_real_search_enable_popdown (gpointer data)
15094 {
15095   GtkTreeView *tree_view = (GtkTreeView *)data;
15096
15097   tree_view->priv->disable_popdown = 0;
15098
15099   return FALSE;
15100 }
15101
15102 static void
15103 gtk_tree_view_search_enable_popdown (GtkWidget *widget,
15104                                      gpointer   data)
15105 {
15106   gdk_threads_add_timeout_full (G_PRIORITY_HIGH, 200, gtk_tree_view_real_search_enable_popdown, g_object_ref (data), g_object_unref);
15107 }
15108
15109 static gboolean
15110 gtk_tree_view_search_delete_event (GtkWidget *widget,
15111                                    GdkEventAny *event,
15112                                    GtkTreeView *tree_view)
15113 {
15114   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
15115
15116   gtk_tree_view_search_dialog_hide (widget, tree_view, NULL);
15117
15118   return TRUE;
15119 }
15120
15121 static gboolean
15122 gtk_tree_view_search_button_press_event (GtkWidget *widget,
15123                                          GdkEventButton *event,
15124                                          GtkTreeView *tree_view)
15125 {
15126   GdkDevice *keyb_device;
15127
15128   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
15129
15130   keyb_device = gdk_device_get_associated_device (event->device);
15131   gtk_tree_view_search_dialog_hide (widget, tree_view, keyb_device);
15132
15133   if (event->window == tree_view->priv->bin_window)
15134     gtk_tree_view_button_press (GTK_WIDGET (tree_view), event);
15135
15136   return TRUE;
15137 }
15138
15139 static gboolean
15140 gtk_tree_view_search_scroll_event (GtkWidget *widget,
15141                                    GdkEventScroll *event,
15142                                    GtkTreeView *tree_view)
15143 {
15144   gboolean retval = FALSE;
15145
15146   if (event->direction == GDK_SCROLL_UP)
15147     {
15148       gtk_tree_view_search_move (widget, tree_view, TRUE);
15149       retval = TRUE;
15150     }
15151   else if (event->direction == GDK_SCROLL_DOWN)
15152     {
15153       gtk_tree_view_search_move (widget, tree_view, FALSE);
15154       retval = TRUE;
15155     }
15156
15157   /* renew the flush timeout */
15158   if (retval && tree_view->priv->typeselect_flush_timeout
15159       && !tree_view->priv->search_custom_entry_set)
15160     {
15161       g_source_remove (tree_view->priv->typeselect_flush_timeout);
15162       tree_view->priv->typeselect_flush_timeout =
15163         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
15164                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
15165                        tree_view);
15166     }
15167
15168   return retval;
15169 }
15170
15171 static gboolean
15172 gtk_tree_view_search_key_press_event (GtkWidget *widget,
15173                                       GdkEventKey *event,
15174                                       GtkTreeView *tree_view)
15175 {
15176   gboolean retval = FALSE;
15177
15178   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
15179   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15180
15181   /* close window and cancel the search */
15182   if (!tree_view->priv->search_custom_entry_set
15183       && (event->keyval == GDK_KEY_Escape ||
15184           event->keyval == GDK_KEY_Tab ||
15185             event->keyval == GDK_KEY_KP_Tab ||
15186             event->keyval == GDK_KEY_ISO_Left_Tab))
15187     {
15188       gtk_tree_view_search_dialog_hide (widget, tree_view,
15189                                         gdk_event_get_device ((GdkEvent *) event));
15190       return TRUE;
15191     }
15192
15193   /* select previous matching iter */
15194   if (event->keyval == GDK_KEY_Up || event->keyval == GDK_KEY_KP_Up)
15195     {
15196       if (!gtk_tree_view_search_move (widget, tree_view, TRUE))
15197         gtk_widget_error_bell (widget);
15198
15199       retval = TRUE;
15200     }
15201
15202   if (((event->state & (GTK_DEFAULT_ACCEL_MOD_MASK | GDK_SHIFT_MASK)) == (GTK_DEFAULT_ACCEL_MOD_MASK | GDK_SHIFT_MASK))
15203       && (event->keyval == GDK_KEY_g || event->keyval == GDK_KEY_G))
15204     {
15205       if (!gtk_tree_view_search_move (widget, tree_view, TRUE))
15206         gtk_widget_error_bell (widget);
15207
15208       retval = TRUE;
15209     }
15210
15211   /* select next matching iter */
15212   if (event->keyval == GDK_KEY_Down || event->keyval == GDK_KEY_KP_Down)
15213     {
15214       if (!gtk_tree_view_search_move (widget, tree_view, FALSE))
15215         gtk_widget_error_bell (widget);
15216
15217       retval = TRUE;
15218     }
15219
15220   if (((event->state & (GTK_DEFAULT_ACCEL_MOD_MASK | GDK_SHIFT_MASK)) == GTK_DEFAULT_ACCEL_MOD_MASK)
15221       && (event->keyval == GDK_KEY_g || event->keyval == GDK_KEY_G))
15222     {
15223       if (!gtk_tree_view_search_move (widget, tree_view, FALSE))
15224         gtk_widget_error_bell (widget);
15225
15226       retval = TRUE;
15227     }
15228
15229   /* renew the flush timeout */
15230   if (retval && tree_view->priv->typeselect_flush_timeout
15231       && !tree_view->priv->search_custom_entry_set)
15232     {
15233       g_source_remove (tree_view->priv->typeselect_flush_timeout);
15234       tree_view->priv->typeselect_flush_timeout =
15235         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
15236                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
15237                        tree_view);
15238     }
15239
15240   return retval;
15241 }
15242
15243 /*  this function returns FALSE if there is a search string but
15244  *  nothing was found, and TRUE otherwise.
15245  */
15246 static gboolean
15247 gtk_tree_view_search_move (GtkWidget   *window,
15248                            GtkTreeView *tree_view,
15249                            gboolean     up)
15250 {
15251   gboolean ret;
15252   gint len;
15253   gint count = 0;
15254   const gchar *text;
15255   GtkTreeIter iter;
15256   GtkTreeModel *model;
15257   GtkTreeSelection *selection;
15258
15259   text = gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry));
15260
15261   g_return_val_if_fail (text != NULL, FALSE);
15262
15263   len = strlen (text);
15264
15265   if (up && tree_view->priv->selected_iter == 1)
15266     return strlen (text) < 1;
15267
15268   len = strlen (text);
15269
15270   if (len < 1)
15271     return TRUE;
15272
15273   model = gtk_tree_view_get_model (tree_view);
15274   selection = gtk_tree_view_get_selection (tree_view);
15275
15276   /* search */
15277   gtk_tree_selection_unselect_all (selection);
15278   if (!gtk_tree_model_get_iter_first (model, &iter))
15279     return TRUE;
15280
15281   ret = gtk_tree_view_search_iter (model, selection, &iter, text,
15282                                    &count, up?((tree_view->priv->selected_iter) - 1):((tree_view->priv->selected_iter + 1)));
15283
15284   if (ret)
15285     {
15286       /* found */
15287       tree_view->priv->selected_iter += up?(-1):(1);
15288       return TRUE;
15289     }
15290   else
15291     {
15292       /* return to old iter */
15293       count = 0;
15294       gtk_tree_model_get_iter_first (model, &iter);
15295       gtk_tree_view_search_iter (model, selection,
15296                                  &iter, text,
15297                                  &count, tree_view->priv->selected_iter);
15298       return FALSE;
15299     }
15300 }
15301
15302 static gboolean
15303 gtk_tree_view_search_equal_func (GtkTreeModel *model,
15304                                  gint          column,
15305                                  const gchar  *key,
15306                                  GtkTreeIter  *iter,
15307                                  gpointer      search_data)
15308 {
15309   gboolean retval = TRUE;
15310   const gchar *str;
15311   gchar *normalized_string;
15312   gchar *normalized_key;
15313   gchar *case_normalized_string = NULL;
15314   gchar *case_normalized_key = NULL;
15315   GValue value = {0,};
15316   GValue transformed = {0,};
15317
15318   gtk_tree_model_get_value (model, iter, column, &value);
15319
15320   g_value_init (&transformed, G_TYPE_STRING);
15321
15322   if (!g_value_transform (&value, &transformed))
15323     {
15324       g_value_unset (&value);
15325       return TRUE;
15326     }
15327
15328   g_value_unset (&value);
15329
15330   str = g_value_get_string (&transformed);
15331   if (!str)
15332     {
15333       g_value_unset (&transformed);
15334       return TRUE;
15335     }
15336
15337   normalized_string = g_utf8_normalize (str, -1, G_NORMALIZE_ALL);
15338   normalized_key = g_utf8_normalize (key, -1, G_NORMALIZE_ALL);
15339
15340   if (normalized_string && normalized_key)
15341     {
15342       case_normalized_string = g_utf8_casefold (normalized_string, -1);
15343       case_normalized_key = g_utf8_casefold (normalized_key, -1);
15344
15345       if (strncmp (case_normalized_key, case_normalized_string, strlen (case_normalized_key)) == 0)
15346         retval = FALSE;
15347     }
15348
15349   g_value_unset (&transformed);
15350   g_free (normalized_key);
15351   g_free (normalized_string);
15352   g_free (case_normalized_key);
15353   g_free (case_normalized_string);
15354
15355   return retval;
15356 }
15357
15358 static gboolean
15359 gtk_tree_view_search_iter (GtkTreeModel     *model,
15360                            GtkTreeSelection *selection,
15361                            GtkTreeIter      *iter,
15362                            const gchar      *text,
15363                            gint             *count,
15364                            gint              n)
15365 {
15366   GtkRBTree *tree = NULL;
15367   GtkRBNode *node = NULL;
15368   GtkTreePath *path;
15369
15370   GtkTreeView *tree_view = gtk_tree_selection_get_tree_view (selection);
15371
15372   path = gtk_tree_model_get_path (model, iter);
15373   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
15374
15375   do
15376     {
15377       if (! tree_view->priv->search_equal_func (model, tree_view->priv->search_column, text, iter, tree_view->priv->search_user_data))
15378         {
15379           (*count)++;
15380           if (*count == n)
15381             {
15382               gtk_tree_view_scroll_to_cell (tree_view, path, NULL,
15383                                             TRUE, 0.5, 0.0);
15384               gtk_tree_selection_select_iter (selection, iter);
15385               gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
15386
15387               if (path)
15388                 gtk_tree_path_free (path);
15389
15390               return TRUE;
15391             }
15392         }
15393
15394       if (node->children)
15395         {
15396           gboolean has_child;
15397           GtkTreeIter tmp;
15398
15399           tree = node->children;
15400           node = tree->root;
15401
15402           while (node->left != tree->nil)
15403             node = node->left;
15404
15405           tmp = *iter;
15406           has_child = gtk_tree_model_iter_children (model, iter, &tmp);
15407           gtk_tree_path_down (path);
15408
15409           /* sanity check */
15410           TREE_VIEW_INTERNAL_ASSERT (has_child, FALSE);
15411         }
15412       else
15413         {
15414           gboolean done = FALSE;
15415
15416           do
15417             {
15418               node = _gtk_rbtree_next (tree, node);
15419
15420               if (node)
15421                 {
15422                   gboolean has_next;
15423
15424                   has_next = gtk_tree_model_iter_next (model, iter);
15425
15426                   done = TRUE;
15427                   gtk_tree_path_next (path);
15428
15429                   /* sanity check */
15430                   TREE_VIEW_INTERNAL_ASSERT (has_next, FALSE);
15431                 }
15432               else
15433                 {
15434                   gboolean has_parent;
15435                   GtkTreeIter tmp_iter = *iter;
15436
15437                   node = tree->parent_node;
15438                   tree = tree->parent_tree;
15439
15440                   if (!tree)
15441                     {
15442                       if (path)
15443                         gtk_tree_path_free (path);
15444
15445                       /* we've run out of tree, done with this func */
15446                       return FALSE;
15447                     }
15448
15449                   has_parent = gtk_tree_model_iter_parent (model,
15450                                                            iter,
15451                                                            &tmp_iter);
15452                   gtk_tree_path_up (path);
15453
15454                   /* sanity check */
15455                   TREE_VIEW_INTERNAL_ASSERT (has_parent, FALSE);
15456                 }
15457             }
15458           while (!done);
15459         }
15460     }
15461   while (1);
15462
15463   return FALSE;
15464 }
15465
15466 static void
15467 gtk_tree_view_search_init (GtkWidget   *entry,
15468                            GtkTreeView *tree_view)
15469 {
15470   gint ret;
15471   gint count = 0;
15472   const gchar *text;
15473   GtkTreeIter iter;
15474   GtkTreeModel *model;
15475   GtkTreeSelection *selection;
15476
15477   g_return_if_fail (GTK_IS_ENTRY (entry));
15478   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15479
15480   text = gtk_entry_get_text (GTK_ENTRY (entry));
15481
15482   model = gtk_tree_view_get_model (tree_view);
15483   selection = gtk_tree_view_get_selection (tree_view);
15484
15485   /* search */
15486   gtk_tree_selection_unselect_all (selection);
15487   if (tree_view->priv->typeselect_flush_timeout
15488       && !tree_view->priv->search_custom_entry_set)
15489     {
15490       g_source_remove (tree_view->priv->typeselect_flush_timeout);
15491       tree_view->priv->typeselect_flush_timeout =
15492         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
15493                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
15494                        tree_view);
15495     }
15496
15497   if (*text == '\0')
15498     return;
15499
15500   if (!gtk_tree_model_get_iter_first (model, &iter))
15501     return;
15502
15503   ret = gtk_tree_view_search_iter (model, selection,
15504                                    &iter, text,
15505                                    &count, 1);
15506
15507   if (ret)
15508     tree_view->priv->selected_iter = 1;
15509 }
15510
15511 void
15512 _gtk_tree_view_remove_editable (GtkTreeView       *tree_view,
15513                                 GtkTreeViewColumn *column,
15514                                 GtkCellEditable   *cell_editable)
15515 {
15516   if (tree_view->priv->edited_column == NULL)
15517     return;
15518
15519   g_return_if_fail (column == tree_view->priv->edited_column);
15520
15521   tree_view->priv->edited_column = NULL;
15522
15523   if (gtk_widget_has_focus (GTK_WIDGET (cell_editable)))
15524     gtk_widget_grab_focus (GTK_WIDGET (tree_view));
15525
15526   gtk_container_remove (GTK_CONTAINER (tree_view),
15527                         GTK_WIDGET (cell_editable));
15528
15529   /* FIXME should only redraw a single node */
15530   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15531 }
15532
15533 static gboolean
15534 gtk_tree_view_start_editing (GtkTreeView *tree_view,
15535                              GtkTreePath *cursor_path,
15536                              gboolean     edit_only)
15537 {
15538   GtkTreeIter iter;
15539   GdkRectangle cell_area;
15540   GtkTreeViewColumn *focus_column;
15541   guint flags = 0; /* can be 0, as the flags are primarily for rendering */
15542   gint retval = FALSE;
15543   GtkRBTree *cursor_tree;
15544   GtkRBNode *cursor_node;
15545
15546   g_assert (tree_view->priv->focus_column);
15547   focus_column = tree_view->priv->focus_column;
15548
15549   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
15550     return FALSE;
15551
15552   if (_gtk_tree_view_find_node (tree_view, cursor_path, &cursor_tree, &cursor_node) ||
15553       cursor_node == NULL)
15554     return FALSE;
15555
15556   gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path);
15557
15558   validate_row (tree_view, cursor_tree, cursor_node, &iter, cursor_path);
15559
15560   gtk_tree_view_column_cell_set_cell_data (focus_column,
15561                                            tree_view->priv->model,
15562                                            &iter,
15563                                            GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_PARENT),
15564                                            cursor_node->children ? TRUE : FALSE);
15565   gtk_tree_view_get_cell_area (tree_view,
15566                                cursor_path,
15567                                focus_column,
15568                                &cell_area);
15569
15570   if (gtk_cell_area_activate (gtk_cell_layout_get_area (GTK_CELL_LAYOUT (focus_column)),
15571                               _gtk_tree_view_column_get_context (focus_column),
15572                               GTK_WIDGET (tree_view),
15573                               &cell_area,
15574                               flags, edit_only))
15575     retval = TRUE;
15576
15577   return retval;
15578 }
15579
15580 void
15581 _gtk_tree_view_add_editable (GtkTreeView       *tree_view,
15582                              GtkTreeViewColumn *column,
15583                              GtkTreePath       *path,
15584                              GtkCellEditable   *cell_editable,
15585                              GdkRectangle      *cell_area)
15586 {
15587   gint pre_val = gtk_adjustment_get_value (tree_view->priv->vadjustment);
15588   GtkRequisition requisition;
15589
15590   tree_view->priv->edited_column = column;
15591
15592   gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
15593   cell_area->y += pre_val - (int)gtk_adjustment_get_value (tree_view->priv->vadjustment);
15594
15595   gtk_widget_get_preferred_size (GTK_WIDGET (cell_editable),
15596                                  &requisition, NULL);
15597
15598   tree_view->priv->draw_keyfocus = TRUE;
15599
15600   if (requisition.height < cell_area->height)
15601     {
15602       gint diff = cell_area->height - requisition.height;
15603       gtk_tree_view_put (tree_view,
15604                          GTK_WIDGET (cell_editable),
15605                          cell_area->x, cell_area->y + diff/2,
15606                          cell_area->width, requisition.height);
15607     }
15608   else
15609     {
15610       gtk_tree_view_put (tree_view,
15611                          GTK_WIDGET (cell_editable),
15612                          cell_area->x, cell_area->y,
15613                          cell_area->width, cell_area->height);
15614     }
15615 }
15616
15617 static void
15618 gtk_tree_view_stop_editing (GtkTreeView *tree_view,
15619                             gboolean     cancel_editing)
15620 {
15621   GtkTreeViewColumn *column;
15622
15623   if (tree_view->priv->edited_column == NULL)
15624     return;
15625
15626   /*
15627    * This is very evil. We need to do this, because
15628    * gtk_cell_editable_editing_done may trigger gtk_tree_view_row_changed
15629    * later on. If gtk_tree_view_row_changed notices
15630    * tree_view->priv->edited_column != NULL, it'll call
15631    * gtk_tree_view_stop_editing again. Bad things will happen then.
15632    *
15633    * Please read that again if you intend to modify anything here.
15634    */
15635
15636   column = tree_view->priv->edited_column;
15637   gtk_cell_area_stop_editing (gtk_cell_layout_get_area (GTK_CELL_LAYOUT (column)), cancel_editing);
15638   tree_view->priv->edited_column = NULL;
15639 }
15640
15641
15642 /**
15643  * gtk_tree_view_set_hover_selection:
15644  * @tree_view: a #GtkTreeView
15645  * @hover: %TRUE to enable hover selection mode
15646  *
15647  * Enables of disables the hover selection mode of @tree_view.
15648  * Hover selection makes the selected row follow the pointer.
15649  * Currently, this works only for the selection modes 
15650  * %GTK_SELECTION_SINGLE and %GTK_SELECTION_BROWSE.
15651  * 
15652  * Since: 2.6
15653  **/
15654 void     
15655 gtk_tree_view_set_hover_selection (GtkTreeView *tree_view,
15656                                    gboolean     hover)
15657 {
15658   hover = hover != FALSE;
15659
15660   if (hover != tree_view->priv->hover_selection)
15661     {
15662       tree_view->priv->hover_selection = hover;
15663
15664       g_object_notify (G_OBJECT (tree_view), "hover-selection");
15665     }
15666 }
15667
15668 /**
15669  * gtk_tree_view_get_hover_selection:
15670  * @tree_view: a #GtkTreeView
15671  * 
15672  * Returns whether hover selection mode is turned on for @tree_view.
15673  * 
15674  * Return value: %TRUE if @tree_view is in hover selection mode
15675  *
15676  * Since: 2.6 
15677  **/
15678 gboolean 
15679 gtk_tree_view_get_hover_selection (GtkTreeView *tree_view)
15680 {
15681   return tree_view->priv->hover_selection;
15682 }
15683
15684 /**
15685  * gtk_tree_view_set_hover_expand:
15686  * @tree_view: a #GtkTreeView
15687  * @expand: %TRUE to enable hover selection mode
15688  *
15689  * Enables of disables the hover expansion mode of @tree_view.
15690  * Hover expansion makes rows expand or collapse if the pointer 
15691  * moves over them.
15692  * 
15693  * Since: 2.6
15694  **/
15695 void     
15696 gtk_tree_view_set_hover_expand (GtkTreeView *tree_view,
15697                                 gboolean     expand)
15698 {
15699   expand = expand != FALSE;
15700
15701   if (expand != tree_view->priv->hover_expand)
15702     {
15703       tree_view->priv->hover_expand = expand;
15704
15705       g_object_notify (G_OBJECT (tree_view), "hover-expand");
15706     }
15707 }
15708
15709 /**
15710  * gtk_tree_view_get_hover_expand:
15711  * @tree_view: a #GtkTreeView
15712  * 
15713  * Returns whether hover expansion mode is turned on for @tree_view.
15714  * 
15715  * Return value: %TRUE if @tree_view is in hover expansion mode
15716  *
15717  * Since: 2.6 
15718  **/
15719 gboolean 
15720 gtk_tree_view_get_hover_expand (GtkTreeView *tree_view)
15721 {
15722   return tree_view->priv->hover_expand;
15723 }
15724
15725 /**
15726  * gtk_tree_view_set_rubber_banding:
15727  * @tree_view: a #GtkTreeView
15728  * @enable: %TRUE to enable rubber banding
15729  *
15730  * Enables or disables rubber banding in @tree_view.  If the selection mode
15731  * is #GTK_SELECTION_MULTIPLE, rubber banding will allow the user to select
15732  * multiple rows by dragging the mouse.
15733  * 
15734  * Since: 2.10
15735  **/
15736 void
15737 gtk_tree_view_set_rubber_banding (GtkTreeView *tree_view,
15738                                   gboolean     enable)
15739 {
15740   enable = enable != FALSE;
15741
15742   if (enable != tree_view->priv->rubber_banding_enable)
15743     {
15744       tree_view->priv->rubber_banding_enable = enable;
15745
15746       g_object_notify (G_OBJECT (tree_view), "rubber-banding");
15747     }
15748 }
15749
15750 /**
15751  * gtk_tree_view_get_rubber_banding:
15752  * @tree_view: a #GtkTreeView
15753  * 
15754  * Returns whether rubber banding is turned on for @tree_view.  If the
15755  * selection mode is #GTK_SELECTION_MULTIPLE, rubber banding will allow the
15756  * user to select multiple rows by dragging the mouse.
15757  * 
15758  * Return value: %TRUE if rubber banding in @tree_view is enabled.
15759  *
15760  * Since: 2.10
15761  **/
15762 gboolean
15763 gtk_tree_view_get_rubber_banding (GtkTreeView *tree_view)
15764 {
15765   return tree_view->priv->rubber_banding_enable;
15766 }
15767
15768 /**
15769  * gtk_tree_view_is_rubber_banding_active:
15770  * @tree_view: a #GtkTreeView
15771  * 
15772  * Returns whether a rubber banding operation is currently being done
15773  * in @tree_view.
15774  *
15775  * Return value: %TRUE if a rubber banding operation is currently being
15776  * done in @tree_view.
15777  *
15778  * Since: 2.12
15779  **/
15780 gboolean
15781 gtk_tree_view_is_rubber_banding_active (GtkTreeView *tree_view)
15782 {
15783   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15784
15785   if (tree_view->priv->rubber_banding_enable
15786       && tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
15787     return TRUE;
15788
15789   return FALSE;
15790 }
15791
15792 /**
15793  * gtk_tree_view_get_row_separator_func: (skip)
15794  * @tree_view: a #GtkTreeView
15795  * 
15796  * Returns the current row separator function.
15797  * 
15798  * Return value: the current row separator function.
15799  *
15800  * Since: 2.6
15801  **/
15802 GtkTreeViewRowSeparatorFunc 
15803 gtk_tree_view_get_row_separator_func (GtkTreeView *tree_view)
15804 {
15805   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
15806
15807   return tree_view->priv->row_separator_func;
15808 }
15809
15810 /**
15811  * gtk_tree_view_set_row_separator_func:
15812  * @tree_view: a #GtkTreeView
15813  * @func: (allow-none): a #GtkTreeViewRowSeparatorFunc
15814  * @data: (allow-none): user data to pass to @func, or %NULL
15815  * @destroy: (allow-none): destroy notifier for @data, or %NULL
15816  * 
15817  * Sets the row separator function, which is used to determine
15818  * whether a row should be drawn as a separator. If the row separator
15819  * function is %NULL, no separators are drawn. This is the default value.
15820  *
15821  * Since: 2.6
15822  **/
15823 void
15824 gtk_tree_view_set_row_separator_func (GtkTreeView                 *tree_view,
15825                                       GtkTreeViewRowSeparatorFunc  func,
15826                                       gpointer                     data,
15827                                       GDestroyNotify               destroy)
15828 {
15829   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15830
15831   if (tree_view->priv->row_separator_destroy)
15832     tree_view->priv->row_separator_destroy (tree_view->priv->row_separator_data);
15833
15834   tree_view->priv->row_separator_func = func;
15835   tree_view->priv->row_separator_data = data;
15836   tree_view->priv->row_separator_destroy = destroy;
15837
15838   /* Have the tree recalculate heights */
15839   _gtk_rbtree_mark_invalid (tree_view->priv->tree);
15840   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
15841 }
15842
15843   
15844 static void
15845 gtk_tree_view_grab_notify (GtkWidget *widget,
15846                            gboolean   was_grabbed)
15847 {
15848   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
15849
15850   tree_view->priv->in_grab = !was_grabbed;
15851
15852   if (!was_grabbed)
15853     {
15854       tree_view->priv->pressed_button = -1;
15855
15856       if (tree_view->priv->rubber_band_status)
15857         gtk_tree_view_stop_rubber_band (tree_view);
15858     }
15859 }
15860
15861 static void
15862 gtk_tree_view_state_flags_changed (GtkWidget     *widget,
15863                                    GtkStateFlags  previous_state)
15864 {
15865   if (gtk_widget_get_realized (widget))
15866     {
15867       GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
15868       GtkStyleContext *context;
15869
15870       context = gtk_widget_get_style_context (widget);
15871       gtk_style_context_set_background (context, tree_view->priv->bin_window);
15872     }
15873
15874   gtk_widget_queue_draw (widget);
15875 }
15876
15877 /**
15878  * gtk_tree_view_get_grid_lines:
15879  * @tree_view: a #GtkTreeView
15880  *
15881  * Returns which grid lines are enabled in @tree_view.
15882  *
15883  * Return value: a #GtkTreeViewGridLines value indicating which grid lines
15884  * are enabled.
15885  *
15886  * Since: 2.10
15887  */
15888 GtkTreeViewGridLines
15889 gtk_tree_view_get_grid_lines (GtkTreeView *tree_view)
15890 {
15891   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
15892
15893   return tree_view->priv->grid_lines;
15894 }
15895
15896 /**
15897  * gtk_tree_view_set_grid_lines:
15898  * @tree_view: a #GtkTreeView
15899  * @grid_lines: a #GtkTreeViewGridLines value indicating which grid lines to
15900  * enable.
15901  *
15902  * Sets which grid lines to draw in @tree_view.
15903  *
15904  * Since: 2.10
15905  */
15906 void
15907 gtk_tree_view_set_grid_lines (GtkTreeView           *tree_view,
15908                               GtkTreeViewGridLines   grid_lines)
15909 {
15910   GtkTreeViewPrivate *priv;
15911   GtkWidget *widget;
15912   GtkTreeViewGridLines old_grid_lines;
15913
15914   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15915
15916   priv = tree_view->priv;
15917   widget = GTK_WIDGET (tree_view);
15918
15919   old_grid_lines = priv->grid_lines;
15920   priv->grid_lines = grid_lines;
15921   
15922   if (gtk_widget_get_realized (widget))
15923     {
15924       if (grid_lines == GTK_TREE_VIEW_GRID_LINES_NONE &&
15925           priv->grid_line_width)
15926         {
15927           priv->grid_line_width = 0;
15928         }
15929       
15930       if (grid_lines != GTK_TREE_VIEW_GRID_LINES_NONE && 
15931           !priv->grid_line_width)
15932         {
15933           gint8 *dash_list;
15934
15935           gtk_widget_style_get (widget,
15936                                 "grid-line-width", &priv->grid_line_width,
15937                                 "grid-line-pattern", (gchar *)&dash_list,
15938                                 NULL);
15939       
15940           if (dash_list)
15941             {
15942               priv->grid_line_dashes[0] = dash_list[0];
15943               if (dash_list[0])
15944                 priv->grid_line_dashes[1] = dash_list[1];
15945               
15946               g_free (dash_list);
15947             }
15948           else
15949             {
15950               priv->grid_line_dashes[0] = 1;
15951               priv->grid_line_dashes[1] = 1;
15952             }
15953         }      
15954     }
15955
15956   if (old_grid_lines != grid_lines)
15957     {
15958       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15959       
15960       g_object_notify (G_OBJECT (tree_view), "enable-grid-lines");
15961     }
15962 }
15963
15964 /**
15965  * gtk_tree_view_get_enable_tree_lines:
15966  * @tree_view: a #GtkTreeView.
15967  *
15968  * Returns whether or not tree lines are drawn in @tree_view.
15969  *
15970  * Return value: %TRUE if tree lines are drawn in @tree_view, %FALSE
15971  * otherwise.
15972  *
15973  * Since: 2.10
15974  */
15975 gboolean
15976 gtk_tree_view_get_enable_tree_lines (GtkTreeView *tree_view)
15977 {
15978   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15979
15980   return tree_view->priv->tree_lines_enabled;
15981 }
15982
15983 /**
15984  * gtk_tree_view_set_enable_tree_lines:
15985  * @tree_view: a #GtkTreeView
15986  * @enabled: %TRUE to enable tree line drawing, %FALSE otherwise.
15987  *
15988  * Sets whether to draw lines interconnecting the expanders in @tree_view.
15989  * This does not have any visible effects for lists.
15990  *
15991  * Since: 2.10
15992  */
15993 void
15994 gtk_tree_view_set_enable_tree_lines (GtkTreeView *tree_view,
15995                                      gboolean     enabled)
15996 {
15997   GtkTreeViewPrivate *priv;
15998   GtkWidget *widget;
15999   gboolean was_enabled;
16000
16001   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
16002
16003   enabled = enabled != FALSE;
16004
16005   priv = tree_view->priv;
16006   widget = GTK_WIDGET (tree_view);
16007
16008   was_enabled = priv->tree_lines_enabled;
16009
16010   priv->tree_lines_enabled = enabled;
16011
16012   if (gtk_widget_get_realized (widget))
16013     {
16014       if (!enabled && priv->tree_line_width)
16015         {
16016           priv->tree_line_width = 0;
16017         }
16018       
16019       if (enabled && !priv->tree_line_width)
16020         {
16021           gint8 *dash_list;
16022           gtk_widget_style_get (widget,
16023                                 "tree-line-width", &priv->tree_line_width,
16024                                 "tree-line-pattern", (gchar *)&dash_list,
16025                                 NULL);
16026           
16027           if (dash_list)
16028             {
16029               priv->tree_line_dashes[0] = dash_list[0];
16030               if (dash_list[0])
16031                 priv->tree_line_dashes[1] = dash_list[1];
16032               
16033               g_free (dash_list);
16034             }
16035           else
16036             {
16037               priv->tree_line_dashes[0] = 1;
16038               priv->tree_line_dashes[1] = 1;
16039             }
16040         }
16041     }
16042
16043   if (was_enabled != enabled)
16044     {
16045       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
16046
16047       g_object_notify (G_OBJECT (tree_view), "enable-tree-lines");
16048     }
16049 }
16050
16051
16052 /**
16053  * gtk_tree_view_set_show_expanders:
16054  * @tree_view: a #GtkTreeView
16055  * @enabled: %TRUE to enable expander drawing, %FALSE otherwise.
16056  *
16057  * Sets whether to draw and enable expanders and indent child rows in
16058  * @tree_view.  When disabled there will be no expanders visible in trees
16059  * and there will be no way to expand and collapse rows by default.  Also
16060  * note that hiding the expanders will disable the default indentation.  You
16061  * can set a custom indentation in this case using
16062  * gtk_tree_view_set_level_indentation().
16063  * This does not have any visible effects for lists.
16064  *
16065  * Since: 2.12
16066  */
16067 void
16068 gtk_tree_view_set_show_expanders (GtkTreeView *tree_view,
16069                                   gboolean     enabled)
16070 {
16071   gboolean was_enabled;
16072
16073   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
16074
16075   enabled = enabled != FALSE;
16076   was_enabled = tree_view->priv->show_expanders;
16077
16078   tree_view->priv->show_expanders = enabled == TRUE;
16079
16080   if (enabled != was_enabled)
16081     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
16082 }
16083
16084 /**
16085  * gtk_tree_view_get_show_expanders:
16086  * @tree_view: a #GtkTreeView.
16087  *
16088  * Returns whether or not expanders are drawn in @tree_view.
16089  *
16090  * Return value: %TRUE if expanders are drawn in @tree_view, %FALSE
16091  * otherwise.
16092  *
16093  * Since: 2.12
16094  */
16095 gboolean
16096 gtk_tree_view_get_show_expanders (GtkTreeView *tree_view)
16097 {
16098   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
16099
16100   return tree_view->priv->show_expanders;
16101 }
16102
16103 /**
16104  * gtk_tree_view_set_level_indentation:
16105  * @tree_view: a #GtkTreeView
16106  * @indentation: the amount, in pixels, of extra indentation in @tree_view.
16107  *
16108  * Sets the amount of extra indentation for child levels to use in @tree_view
16109  * in addition to the default indentation.  The value should be specified in
16110  * pixels, a value of 0 disables this feature and in this case only the default
16111  * indentation will be used.
16112  * This does not have any visible effects for lists.
16113  *
16114  * Since: 2.12
16115  */
16116 void
16117 gtk_tree_view_set_level_indentation (GtkTreeView *tree_view,
16118                                      gint         indentation)
16119 {
16120   tree_view->priv->level_indentation = indentation;
16121
16122   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
16123 }
16124
16125 /**
16126  * gtk_tree_view_get_level_indentation:
16127  * @tree_view: a #GtkTreeView.
16128  *
16129  * Returns the amount, in pixels, of extra indentation for child levels
16130  * in @tree_view.
16131  *
16132  * Return value: the amount of extra indentation for child levels in
16133  * @tree_view.  A return value of 0 means that this feature is disabled.
16134  *
16135  * Since: 2.12
16136  */
16137 gint
16138 gtk_tree_view_get_level_indentation (GtkTreeView *tree_view)
16139 {
16140   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
16141
16142   return tree_view->priv->level_indentation;
16143 }
16144
16145 /**
16146  * gtk_tree_view_set_tooltip_row:
16147  * @tree_view: a #GtkTreeView
16148  * @tooltip: a #GtkTooltip
16149  * @path: a #GtkTreePath
16150  *
16151  * Sets the tip area of @tooltip to be the area covered by the row at @path.
16152  * See also gtk_tree_view_set_tooltip_column() for a simpler alternative.
16153  * See also gtk_tooltip_set_tip_area().
16154  *
16155  * Since: 2.12
16156  */
16157 void
16158 gtk_tree_view_set_tooltip_row (GtkTreeView *tree_view,
16159                                GtkTooltip  *tooltip,
16160                                GtkTreePath *path)
16161 {
16162   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
16163   g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
16164
16165   gtk_tree_view_set_tooltip_cell (tree_view, tooltip, path, NULL, NULL);
16166 }
16167
16168 /**
16169  * gtk_tree_view_set_tooltip_cell:
16170  * @tree_view: a #GtkTreeView
16171  * @tooltip: a #GtkTooltip
16172  * @path: (allow-none): a #GtkTreePath or %NULL
16173  * @column: (allow-none): a #GtkTreeViewColumn or %NULL
16174  * @cell: (allow-none): a #GtkCellRenderer or %NULL
16175  *
16176  * Sets the tip area of @tooltip to the area @path, @column and @cell have
16177  * in common.  For example if @path is %NULL and @column is set, the tip
16178  * area will be set to the full area covered by @column.  See also
16179  * gtk_tooltip_set_tip_area().
16180  *
16181  * Note that if @path is not specified and @cell is set and part of a column
16182  * containing the expander, the tooltip might not show and hide at the correct
16183  * position.  In such cases @path must be set to the current node under the
16184  * mouse cursor for this function to operate correctly.
16185  *
16186  * See also gtk_tree_view_set_tooltip_column() for a simpler alternative.
16187  *
16188  * Since: 2.12
16189  */
16190 void
16191 gtk_tree_view_set_tooltip_cell (GtkTreeView       *tree_view,
16192                                 GtkTooltip        *tooltip,
16193                                 GtkTreePath       *path,
16194                                 GtkTreeViewColumn *column,
16195                                 GtkCellRenderer   *cell)
16196 {
16197   GtkAllocation allocation;
16198   GdkRectangle rect;
16199
16200   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
16201   g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
16202   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
16203   g_return_if_fail (cell == NULL || GTK_IS_CELL_RENDERER (cell));
16204
16205   /* Determine x values. */
16206   if (column && cell)
16207     {
16208       GdkRectangle tmp;
16209       gint start, width;
16210
16211       /* We always pass in path here, whether it is NULL or not.
16212        * For cells in expander columns path must be specified so that
16213        * we can correctly account for the indentation.  This also means
16214        * that the tooltip is constrained vertically by the "Determine y
16215        * values" code below; this is not a real problem since cells actually
16216        * don't stretch vertically in constrast to columns.
16217        */
16218       gtk_tree_view_get_cell_area (tree_view, path, column, &tmp);
16219       gtk_tree_view_column_cell_get_position (column, cell, &start, &width);
16220
16221       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
16222                                                          tmp.x + start, 0,
16223                                                          &rect.x, NULL);
16224       rect.width = width;
16225     }
16226   else if (column)
16227     {
16228       GdkRectangle tmp;
16229
16230       gtk_tree_view_get_background_area (tree_view, NULL, column, &tmp);
16231       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
16232                                                          tmp.x, 0,
16233                                                          &rect.x, NULL);
16234       rect.width = tmp.width;
16235     }
16236   else
16237     {
16238       gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
16239       rect.x = 0;
16240       rect.width = allocation.width;
16241     }
16242
16243   /* Determine y values. */
16244   if (path)
16245     {
16246       GdkRectangle tmp;
16247
16248       gtk_tree_view_get_background_area (tree_view, path, NULL, &tmp);
16249       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
16250                                                          0, tmp.y,
16251                                                          NULL, &rect.y);
16252       rect.height = tmp.height;
16253     }
16254   else
16255     {
16256       rect.y = 0;
16257       rect.height = gtk_adjustment_get_page_size (tree_view->priv->vadjustment);
16258     }
16259
16260   gtk_tooltip_set_tip_area (tooltip, &rect);
16261 }
16262
16263 /**
16264  * gtk_tree_view_get_tooltip_context:
16265  * @tree_view: a #GtkTreeView
16266  * @x: (inout): the x coordinate (relative to widget coordinates)
16267  * @y: (inout): the y coordinate (relative to widget coordinates)
16268  * @keyboard_tip: whether this is a keyboard tooltip or not
16269  * @model: (out) (allow-none): a pointer to receive a #GtkTreeModel or %NULL
16270  * @path: (out) (allow-none): a pointer to receive a #GtkTreePath or %NULL
16271  * @iter: (out) (allow-none): a pointer to receive a #GtkTreeIter or %NULL
16272  *
16273  * This function is supposed to be used in a #GtkWidget::query-tooltip
16274  * signal handler for #GtkTreeView.  The @x, @y and @keyboard_tip values
16275  * which are received in the signal handler, should be passed to this
16276  * function without modification.
16277  *
16278  * The return value indicates whether there is a tree view row at the given
16279  * coordinates (%TRUE) or not (%FALSE) for mouse tooltips.  For keyboard
16280  * tooltips the row returned will be the cursor row.  When %TRUE, then any of
16281  * @model, @path and @iter which have been provided will be set to point to
16282  * that row and the corresponding model.  @x and @y will always be converted
16283  * to be relative to @tree_view's bin_window if @keyboard_tooltip is %FALSE.
16284  *
16285  * Return value: whether or not the given tooltip context points to a row.
16286  *
16287  * Since: 2.12
16288  */
16289 gboolean
16290 gtk_tree_view_get_tooltip_context (GtkTreeView   *tree_view,
16291                                    gint          *x,
16292                                    gint          *y,
16293                                    gboolean       keyboard_tip,
16294                                    GtkTreeModel **model,
16295                                    GtkTreePath  **path,
16296                                    GtkTreeIter   *iter)
16297 {
16298   GtkTreePath *tmppath = NULL;
16299
16300   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
16301   g_return_val_if_fail (x != NULL, FALSE);
16302   g_return_val_if_fail (y != NULL, FALSE);
16303
16304   if (keyboard_tip)
16305     {
16306       gtk_tree_view_get_cursor (tree_view, &tmppath, NULL);
16307
16308       if (!tmppath)
16309         return FALSE;
16310     }
16311   else
16312     {
16313       gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, *x, *y,
16314                                                          x, y);
16315
16316       if (!gtk_tree_view_get_path_at_pos (tree_view, *x, *y,
16317                                           &tmppath, NULL, NULL, NULL))
16318         return FALSE;
16319     }
16320
16321   if (model)
16322     *model = gtk_tree_view_get_model (tree_view);
16323
16324   if (iter)
16325     gtk_tree_model_get_iter (gtk_tree_view_get_model (tree_view),
16326                              iter, tmppath);
16327
16328   if (path)
16329     *path = tmppath;
16330   else
16331     gtk_tree_path_free (tmppath);
16332
16333   return TRUE;
16334 }
16335
16336 static gboolean
16337 gtk_tree_view_set_tooltip_query_cb (GtkWidget  *widget,
16338                                     gint        x,
16339                                     gint        y,
16340                                     gboolean    keyboard_tip,
16341                                     GtkTooltip *tooltip,
16342                                     gpointer    data)
16343 {
16344   GValue value = { 0, };
16345   GValue transformed = { 0, };
16346   GtkTreeIter iter;
16347   GtkTreePath *path;
16348   GtkTreeModel *model;
16349   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
16350
16351   if (!gtk_tree_view_get_tooltip_context (GTK_TREE_VIEW (widget),
16352                                           &x, &y,
16353                                           keyboard_tip,
16354                                           &model, &path, &iter))
16355     return FALSE;
16356
16357   gtk_tree_model_get_value (model, &iter,
16358                             tree_view->priv->tooltip_column, &value);
16359
16360   g_value_init (&transformed, G_TYPE_STRING);
16361
16362   if (!g_value_transform (&value, &transformed))
16363     {
16364       g_value_unset (&value);
16365       gtk_tree_path_free (path);
16366
16367       return FALSE;
16368     }
16369
16370   g_value_unset (&value);
16371
16372   if (!g_value_get_string (&transformed))
16373     {
16374       g_value_unset (&transformed);
16375       gtk_tree_path_free (path);
16376
16377       return FALSE;
16378     }
16379
16380   gtk_tooltip_set_markup (tooltip, g_value_get_string (&transformed));
16381   gtk_tree_view_set_tooltip_row (tree_view, tooltip, path);
16382
16383   gtk_tree_path_free (path);
16384   g_value_unset (&transformed);
16385
16386   return TRUE;
16387 }
16388
16389 /**
16390  * gtk_tree_view_set_tooltip_column:
16391  * @tree_view: a #GtkTreeView
16392  * @column: an integer, which is a valid column number for @tree_view's model
16393  *
16394  * If you only plan to have simple (text-only) tooltips on full rows, you
16395  * can use this function to have #GtkTreeView handle these automatically
16396  * for you. @column should be set to the column in @tree_view's model
16397  * containing the tooltip texts, or -1 to disable this feature.
16398  *
16399  * When enabled, #GtkWidget::has-tooltip will be set to %TRUE and
16400  * @tree_view will connect a #GtkWidget::query-tooltip signal handler.
16401  *
16402  * Note that the signal handler sets the text with gtk_tooltip_set_markup(),
16403  * so &amp;, &lt;, etc have to be escaped in the text.
16404  *
16405  * Since: 2.12
16406  */
16407 void
16408 gtk_tree_view_set_tooltip_column (GtkTreeView *tree_view,
16409                                   gint         column)
16410 {
16411   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
16412
16413   if (column == tree_view->priv->tooltip_column)
16414     return;
16415
16416   if (column == -1)
16417     {
16418       g_signal_handlers_disconnect_by_func (tree_view,
16419                                             gtk_tree_view_set_tooltip_query_cb,
16420                                             NULL);
16421       gtk_widget_set_has_tooltip (GTK_WIDGET (tree_view), FALSE);
16422     }
16423   else
16424     {
16425       if (tree_view->priv->tooltip_column == -1)
16426         {
16427           g_signal_connect (tree_view, "query-tooltip",
16428                             G_CALLBACK (gtk_tree_view_set_tooltip_query_cb), NULL);
16429           gtk_widget_set_has_tooltip (GTK_WIDGET (tree_view), TRUE);
16430         }
16431     }
16432
16433   tree_view->priv->tooltip_column = column;
16434   g_object_notify (G_OBJECT (tree_view), "tooltip-column");
16435 }
16436
16437 /**
16438  * gtk_tree_view_get_tooltip_column:
16439  * @tree_view: a #GtkTreeView
16440  *
16441  * Returns the column of @tree_view's model which is being used for
16442  * displaying tooltips on @tree_view's rows.
16443  *
16444  * Return value: the index of the tooltip column that is currently being
16445  * used, or -1 if this is disabled.
16446  *
16447  * Since: 2.12
16448  */
16449 gint
16450 gtk_tree_view_get_tooltip_column (GtkTreeView *tree_view)
16451 {
16452   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
16453
16454   return tree_view->priv->tooltip_column;
16455 }