]> Pileus Git - ~andy/gtk/blob - gtk/gtktreeview.c
Kill gtk_tree_view_size_request
[~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, see <http://www.gnu.org/licenses/>.
16  */
17
18
19 #include "config.h"
20
21 #include <math.h>
22 #include <string.h>
23
24 #include "gtktreeview.h"
25
26 #include "gtkadjustment.h"
27 #include "gtkrbtree.h"
28 #include "gtktreednd.h"
29 #include "gtktreeprivate.h"
30 #include "gtkcellrenderer.h"
31 #include "gtkmarshalers.h"
32 #include "gtkbuildable.h"
33 #include "gtkbutton.h"
34 #include "gtklabel.h"
35 #include "gtkbox.h"
36 #include "gtkarrow.h"
37 #include "gtkintl.h"
38 #include "gtkbindings.h"
39 #include "gtkcontainer.h"
40 #include "gtkentry.h"
41 #include "gtkframe.h"
42 #include "gtkmain.h"
43 #include "gtktreemodelsort.h"
44 #include "gtktooltip.h"
45 #include "gtkscrollable.h"
46 #include "gtkcelllayout.h"
47 #include "gtkprivate.h"
48 #include "gtkwidgetprivate.h"
49 #include "gtkentryprivate.h"
50 #include "gtkstylecontextprivate.h"
51 #include "gtkcssstylepropertyprivate.h"
52 #include "gtktypebuiltins.h"
53 #include "gtkmain.h"
54 #include "gtksettings.h"
55 #include "gtkwidgetpath.h"
56 #include "a11y/gtktreeviewaccessibleprivate.h"
57
58
59 /**
60  * SECTION:gtktreeview
61  * @Short_description: A widget for displaying both trees and lists
62  * @Title: GtkTreeView
63  * @See_also: #GtkTreeViewColumn, #GtkTreeSelection, #GtkTreeDnd, #GtkTreeMode,
64  *   #GtkTreeSortable, #GtkTreeModelSort, #GtkListStore, #GtkTreeStore,
65  *   #GtkCellRenderer, #GtkCellEditable, #GtkCellRendererPixbuf,
66  *   #GtkCellRendererText, #GtkCellRendererToggle
67  *
68  * Widget that displays any object that implements the #GtkTreeModel interface.
69  *
70  * Please refer to the <link linkend="TreeWidget">tree widget conceptual
71  * overview</link> for an overview of all the objects and data types related
72  * to the tree widget and how they work together.
73  *
74  * Several different coordinate systems are exposed in the GtkTreeView API.
75  * These are:
76  *
77  * <inlinegraphic fileref="tree-view-coordinates.png" format="PNG"></inlinegraphic>
78  * <variablelist><title>Coordinate systems in GtkTreeView API</title>
79  * <varlistentry><term>Widget coordinates</term>
80  * <listitem>
81  * <para>
82  * Coordinates relative to the widget (usually <literal>widget->window</literal>).
83  * </para>
84  * </listitem>
85  * </varlistentry>
86  * <varlistentry><term>Bin window coordinates</term>
87  * <listitem>
88  * <para>
89  * Coordinates relative to the window that GtkTreeView renders to.
90  * </para>
91  * </listitem>
92  * </varlistentry>
93  * <varlistentry><term>Tree coordinates</term>
94  * <listitem>
95  * <para>
96  * Coordinates relative to the entire scrollable area of GtkTreeView. These
97  * coordinates start at (0, 0) for row 0 of the tree.
98  * </para>
99  * </listitem>
100  * </varlistentry>
101  * </variablelist>
102  *
103  * Several functions are available for converting between the different
104  * coordinate systems.  The most common translations are between widget and bin
105  * window coordinates and between bin window and tree coordinates. For the
106  * former you can use gtk_tree_view_convert_widget_to_bin_window_coords()
107  * (and vice versa), for the latter gtk_tree_view_convert_bin_window_to_tree_coords()
108  * (and vice versa).
109  *
110  * <refsect2 id="GtkTreeView-BUILDER-UI">
111  * <title>GtkTreeView as GtkBuildable</title>
112  * The GtkTreeView implementation of the GtkBuildable interface accepts
113  * #GtkTreeViewColumn objects as &lt;child&gt; elements and exposes the
114  * internal #GtkTreeSelection in UI definitions.
115  * <example>
116  * <title>A UI definition fragment with GtkTreeView</title>
117  * <programlisting><![CDATA[
118  * <object class="GtkTreeView" id="treeview">
119  *   <property name="model">liststore1</property>
120  *   <child>
121  *     <object class="GtkTreeViewColumn" id="test-column">
122  *       <property name="title">Test</property>
123  *       <child>
124  *         <object class="GtkCellRendererText" id="test-renderer"/>
125  *         <attributes>
126  *           <attribute name="text">1</attribute>
127  *         </attributes>
128  *       </child>
129  *     </object>
130  *   </child>
131  *   <child internal-child="selection">
132  *     <object class="GtkTreeSelection" id="selection">
133  *       <signal name="changed" handler="on_treeview_selection_changed"/>
134  *     </object>
135  *   </child>
136  * </object>
137  * ]]></programlisting>
138  * </example>
139  * </refsect2>
140  */
141
142 enum
143 {
144   DRAG_COLUMN_WINDOW_STATE_UNSET = 0,
145   DRAG_COLUMN_WINDOW_STATE_ORIGINAL = 1,
146   DRAG_COLUMN_WINDOW_STATE_ARROW = 2,
147   DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT = 3,
148   DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT = 4
149 };
150
151 enum
152 {
153   RUBBER_BAND_OFF = 0,
154   RUBBER_BAND_MAYBE_START = 1,
155   RUBBER_BAND_ACTIVE = 2
156 };
157
158 typedef enum {
159   CLEAR_AND_SELECT = (1 << 0),
160   CLAMP_NODE       = (1 << 1),
161   CURSOR_INVALID   = (1 << 2)
162 } SetCursorFlags;
163
164  /* This lovely little value is used to determine how far away from the title bar
165   * you can move the mouse and still have a column drag work.
166   */
167 #define TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER(tree_view) (10*gtk_tree_view_get_effective_header_height(tree_view))
168
169 #ifdef __GNUC__
170
171 #define TREE_VIEW_INTERNAL_ASSERT(expr, ret)     G_STMT_START{          \
172      if (!(expr))                                                       \
173        {                                                                \
174          g_log (G_LOG_DOMAIN,                                           \
175                 G_LOG_LEVEL_CRITICAL,                                   \
176                 "%s (%s): assertion `%s' failed.\n"                     \
177                 "There is a disparity between the internal view of the GtkTreeView,\n"    \
178                 "and the GtkTreeModel.  This generally means that the model has changed\n"\
179                 "without letting the view know.  Any display from now on is likely to\n"  \
180                 "be incorrect.\n",                                                        \
181                 G_STRLOC,                                               \
182                 G_STRFUNC,                                              \
183                 #expr);                                                 \
184          return ret;                                                    \
185        };                               }G_STMT_END
186
187 #define TREE_VIEW_INTERNAL_ASSERT_VOID(expr)     G_STMT_START{          \
188      if (!(expr))                                                       \
189        {                                                                \
190          g_log (G_LOG_DOMAIN,                                           \
191                 G_LOG_LEVEL_CRITICAL,                                   \
192                 "%s (%s): assertion `%s' failed.\n"                     \
193                 "There is a disparity between the internal view of the GtkTreeView,\n"    \
194                 "and the GtkTreeModel.  This generally means that the model has changed\n"\
195                 "without letting the view know.  Any display from now on is likely to\n"  \
196                 "be incorrect.\n",                                                        \
197                 G_STRLOC,                                               \
198                 G_STRFUNC,                                              \
199                 #expr);                                                 \
200          return;                                                        \
201        };                               }G_STMT_END
202
203 #else
204
205 #define TREE_VIEW_INTERNAL_ASSERT(expr, ret)     G_STMT_START{          \
206      if (!(expr))                                                       \
207        {                                                                \
208          g_log (G_LOG_DOMAIN,                                           \
209                 G_LOG_LEVEL_CRITICAL,                                   \
210                 "file %s: line %d: assertion `%s' failed.\n"       \
211                 "There is a disparity between the internal view of the GtkTreeView,\n"    \
212                 "and the GtkTreeModel.  This generally means that the model has changed\n"\
213                 "without letting the view know.  Any display from now on is likely to\n"  \
214                 "be incorrect.\n",                                                        \
215                 __FILE__,                                               \
216                 __LINE__,                                               \
217                 #expr);                                                 \
218          return ret;                                                    \
219        };                               }G_STMT_END
220
221 #define TREE_VIEW_INTERNAL_ASSERT_VOID(expr)     G_STMT_START{          \
222      if (!(expr))                                                       \
223        {                                                                \
224          g_log (G_LOG_DOMAIN,                                           \
225                 G_LOG_LEVEL_CRITICAL,                                   \
226                 "file %s: line %d: assertion '%s' failed.\n"            \
227                 "There is a disparity between the internal view of the GtkTreeView,\n"    \
228                 "and the GtkTreeModel.  This generally means that the model has changed\n"\
229                 "without letting the view know.  Any display from now on is likely to\n"  \
230                 "be incorrect.\n",                                                        \
231                 __FILE__,                                               \
232                 __LINE__,                                               \
233                 #expr);                                                 \
234          return;                                                        \
235        };                               }G_STMT_END
236 #endif
237
238 #define GTK_TREE_VIEW_PRIORITY_VALIDATE (GDK_PRIORITY_REDRAW + 5)
239 #define GTK_TREE_VIEW_PRIORITY_SCROLL_SYNC (GTK_TREE_VIEW_PRIORITY_VALIDATE + 2)
240 #define GTK_TREE_VIEW_TIME_MS_PER_IDLE 30
241 #define SCROLL_EDGE_SIZE 15
242 #define EXPANDER_EXTRA_PADDING 4
243 #define GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT 5000
244 #define AUTO_EXPAND_TIMEOUT 500
245
246 /* Translate from bin_window coordinates to rbtree (tree coordinates) and
247  * vice versa.
248  */
249 #define TREE_WINDOW_Y_TO_RBTREE_Y(tree_view,y) ((y) + tree_view->priv->dy)
250 #define RBTREE_Y_TO_TREE_WINDOW_Y(tree_view,y) ((y) - tree_view->priv->dy)
251
252 typedef struct _GtkTreeViewColumnReorder GtkTreeViewColumnReorder;
253 struct _GtkTreeViewColumnReorder
254 {
255   gint left_align;
256   gint right_align;
257   GtkTreeViewColumn *left_column;
258   GtkTreeViewColumn *right_column;
259 };
260
261 typedef struct _GtkTreeViewChild GtkTreeViewChild;
262 struct _GtkTreeViewChild
263 {
264   GtkWidget *widget;
265   gint x;
266   gint y;
267   gint width;
268   gint height;
269 };
270
271
272 typedef struct _TreeViewDragInfo TreeViewDragInfo;
273 struct _TreeViewDragInfo
274 {
275   GdkModifierType start_button_mask;
276   GtkTargetList *_unused_source_target_list;
277   GdkDragAction source_actions;
278
279   GtkTargetList *_unused_dest_target_list;
280
281   guint source_set : 1;
282   guint dest_set : 1;
283 };
284
285
286 struct _GtkTreeViewPrivate
287 {
288   GtkTreeModel *model;
289
290   /* tree information */
291   GtkRBTree *tree;
292
293   /* Container info */
294   GList *children;
295   gint width;
296   gint height;
297
298   /* Adjustments */
299   GtkAdjustment *hadjustment;
300   GtkAdjustment *vadjustment;
301   gint           min_display_width;
302   gint           min_display_height;
303
304   /* Sub windows */
305   GdkWindow *bin_window;
306   GdkWindow *header_window;
307
308   /* Scroll position state keeping */
309   GtkTreeRowReference *top_row;
310   gint top_row_dy;
311   /* dy == y pos of top_row + top_row_dy */
312   /* we cache it for simplicity of the code */
313   gint dy;
314
315   guint presize_handler_timer;
316   guint validate_rows_timer;
317   guint scroll_sync_timer;
318
319   /* Indentation and expander layout */
320   GtkTreeViewColumn *expander_column;
321
322   gint level_indentation;
323
324   /* Key navigation (focus), selection */
325   gint cursor_offset;
326
327   GtkTreeRowReference *anchor;
328   GtkRBNode *cursor_node;
329   GtkRBTree *cursor_tree;
330
331   GtkTreeViewColumn *focus_column;
332
333   /* Current pressed node, previously pressed, prelight */
334   GtkRBNode *button_pressed_node;
335   GtkRBTree *button_pressed_tree;
336
337   gint pressed_button;
338   gint press_start_x;
339   gint press_start_y;
340
341   gint event_last_x;
342   gint event_last_y;
343
344   guint last_button_time;
345   gint last_button_x;
346   gint last_button_y;
347
348   GtkRBNode *prelight_node;
349   GtkRBTree *prelight_tree;
350
351   /* Cell Editing */
352   GtkTreeViewColumn *edited_column;
353
354   /* The node that's currently being collapsed or expanded */
355   GtkRBNode *expanded_collapsed_node;
356   GtkRBTree *expanded_collapsed_tree;
357   guint expand_collapse_timeout;
358
359   /* Auto expand/collapse timeout in hover mode */
360   guint auto_expand_timeout;
361
362   /* Selection information */
363   GtkTreeSelection *selection;
364
365   /* Header information */
366   gint n_columns;
367   GList *columns;
368   gint header_height;
369
370   GtkTreeViewColumnDropFunc column_drop_func;
371   gpointer column_drop_func_data;
372   GDestroyNotify column_drop_func_data_destroy;
373   GList *column_drag_info;
374   GtkTreeViewColumnReorder *cur_reorder;
375
376   gint prev_width_before_expander;
377
378   /* Interactive Header reordering */
379   GdkWindow *drag_window;
380   GdkWindow *drag_highlight_window;
381   GtkTreeViewColumn *drag_column;
382   gint drag_column_x;
383
384   /* Interactive Header Resizing */
385   gint drag_pos;
386   gint x_drag;
387
388   /* Non-interactive Header Resizing, expand flag support */
389   gint last_extra_space;
390   gint last_extra_space_per_column;
391   gint last_number_of_expand_columns;
392
393   /* ATK Hack */
394   GtkTreeDestroyCountFunc destroy_count_func;
395   gpointer destroy_count_data;
396   GDestroyNotify destroy_count_destroy;
397
398   /* Scroll timeout (e.g. during dnd, rubber banding) */
399   guint scroll_timeout;
400
401   /* Row drag-and-drop */
402   GtkTreeRowReference *drag_dest_row;
403   GtkTreeViewDropPosition drag_dest_pos;
404   guint open_dest_timeout;
405
406   /* Rubber banding */
407   gint rubber_band_status;
408   gint rubber_band_x;
409   gint rubber_band_y;
410   gint rubber_band_extend;
411   gint rubber_band_modify;
412
413   GtkRBNode *rubber_band_start_node;
414   GtkRBTree *rubber_band_start_tree;
415
416   GtkRBNode *rubber_band_end_node;
417   GtkRBTree *rubber_band_end_tree;
418
419   /* fixed height */
420   gint fixed_height;
421
422   /* Scroll-to functionality when unrealized */
423   GtkTreeRowReference *scroll_to_path;
424   GtkTreeViewColumn *scroll_to_column;
425   gfloat scroll_to_row_align;
426   gfloat scroll_to_col_align;
427
428   /* Interactive search */
429   gint selected_iter;
430   gint search_column;
431   GtkTreeViewSearchPositionFunc search_position_func;
432   GtkTreeViewSearchEqualFunc search_equal_func;
433   gpointer search_user_data;
434   GDestroyNotify search_destroy;
435   gpointer search_position_user_data;
436   GDestroyNotify search_position_destroy;
437   GtkWidget *search_window;
438   GtkWidget *search_entry;
439   gulong search_entry_changed_id;
440   guint typeselect_flush_timeout;
441
442   /* Grid and tree lines */
443   GtkTreeViewGridLines grid_lines;
444   double grid_line_dashes[2];
445   int grid_line_width;
446
447   gboolean tree_lines_enabled;
448   double tree_line_dashes[2];
449   int tree_line_width;
450
451   /* Row separators */
452   GtkTreeViewRowSeparatorFunc row_separator_func;
453   gpointer row_separator_data;
454   GDestroyNotify row_separator_destroy;
455
456   /* Tooltip support */
457   gint tooltip_column;
458
459   /* Here comes the bitfield */
460   guint scroll_to_use_align : 1;
461
462   guint fixed_height_mode : 1;
463   guint fixed_height_check : 1;
464
465   guint reorderable : 1;
466   guint header_has_focus : 1;
467   guint drag_column_window_state : 3;
468   /* hint to display rows in alternating colors */
469   guint has_rules : 1;
470   guint mark_rows_col_dirty : 1;
471
472   /* for DnD */
473   guint empty_view_drop : 1;
474
475   guint modify_selection_pressed : 1;
476   guint extend_selection_pressed : 1;
477
478   guint init_hadjust_value : 1;
479
480   guint in_top_row_to_dy : 1;
481
482   /* interactive search */
483   guint enable_search : 1;
484   guint disable_popdown : 1;
485   guint search_custom_entry_set : 1;
486   
487   guint hover_selection : 1;
488   guint hover_expand : 1;
489   guint imcontext_changed : 1;
490
491   guint rubber_banding_enable : 1;
492
493   guint in_grab : 1;
494
495   guint post_validation_flag : 1;
496
497   /* Whether our key press handler is to avoid sending an unhandled binding to the search entry */
498   guint search_entry_avoid_unhandled_binding : 1;
499
500   /* GtkScrollablePolicy needs to be checked when
501    * driving the scrollable adjustment values */
502   guint hscroll_policy : 1;
503   guint vscroll_policy : 1;
504
505   /* GtkTreeView flags */
506   guint is_list : 1;
507   guint show_expanders : 1;
508   guint in_column_resize : 1;
509   guint arrow_prelit : 1;
510   guint headers_visible : 1;
511   guint draw_keyfocus : 1;
512   guint model_setup : 1;
513   guint in_column_drag : 1;
514 };
515
516
517 /* Signals */
518 enum
519 {
520   ROW_ACTIVATED,
521   TEST_EXPAND_ROW,
522   TEST_COLLAPSE_ROW,
523   ROW_EXPANDED,
524   ROW_COLLAPSED,
525   COLUMNS_CHANGED,
526   CURSOR_CHANGED,
527   MOVE_CURSOR,
528   SELECT_ALL,
529   UNSELECT_ALL,
530   SELECT_CURSOR_ROW,
531   TOGGLE_CURSOR_ROW,
532   EXPAND_COLLAPSE_CURSOR_ROW,
533   SELECT_CURSOR_PARENT,
534   START_INTERACTIVE_SEARCH,
535   LAST_SIGNAL
536 };
537
538 /* Properties */
539 enum {
540   PROP_0,
541   PROP_MODEL,
542   PROP_HADJUSTMENT,
543   PROP_VADJUSTMENT,
544   PROP_HSCROLL_POLICY,
545   PROP_VSCROLL_POLICY,
546   PROP_HEADERS_VISIBLE,
547   PROP_HEADERS_CLICKABLE,
548   PROP_EXPANDER_COLUMN,
549   PROP_REORDERABLE,
550   PROP_RULES_HINT,
551   PROP_ENABLE_SEARCH,
552   PROP_SEARCH_COLUMN,
553   PROP_FIXED_HEIGHT_MODE,
554   PROP_HOVER_SELECTION,
555   PROP_HOVER_EXPAND,
556   PROP_SHOW_EXPANDERS,
557   PROP_LEVEL_INDENTATION,
558   PROP_RUBBER_BANDING,
559   PROP_ENABLE_GRID_LINES,
560   PROP_ENABLE_TREE_LINES,
561   PROP_TOOLTIP_COLUMN
562 };
563
564 /* object signals */
565 static void     gtk_tree_view_finalize             (GObject          *object);
566 static void     gtk_tree_view_set_property         (GObject         *object,
567                                                     guint            prop_id,
568                                                     const GValue    *value,
569                                                     GParamSpec      *pspec);
570 static void     gtk_tree_view_get_property         (GObject         *object,
571                                                     guint            prop_id,
572                                                     GValue          *value,
573                                                     GParamSpec      *pspec);
574
575 /* gtkwidget signals */
576 static void     gtk_tree_view_destroy              (GtkWidget        *widget);
577 static void     gtk_tree_view_realize              (GtkWidget        *widget);
578 static void     gtk_tree_view_unrealize            (GtkWidget        *widget);
579 static void     gtk_tree_view_map                  (GtkWidget        *widget);
580 static void     gtk_tree_view_get_preferred_width  (GtkWidget        *widget,
581                                                     gint             *minimum,
582                                                     gint             *natural);
583 static void     gtk_tree_view_get_preferred_height (GtkWidget        *widget,
584                                                     gint             *minimum,
585                                                     gint             *natural);
586 static void     gtk_tree_view_size_allocate        (GtkWidget        *widget,
587                                                     GtkAllocation    *allocation);
588 static gboolean gtk_tree_view_draw                 (GtkWidget        *widget,
589                                                     cairo_t          *cr);
590 static gboolean gtk_tree_view_key_press            (GtkWidget        *widget,
591                                                     GdkEventKey      *event);
592 static gboolean gtk_tree_view_key_release          (GtkWidget        *widget,
593                                                     GdkEventKey      *event);
594 static gboolean gtk_tree_view_motion               (GtkWidget        *widget,
595                                                     GdkEventMotion   *event);
596 static gboolean gtk_tree_view_enter_notify         (GtkWidget        *widget,
597                                                     GdkEventCrossing *event);
598 static gboolean gtk_tree_view_leave_notify         (GtkWidget        *widget,
599                                                     GdkEventCrossing *event);
600 static gboolean gtk_tree_view_button_press         (GtkWidget        *widget,
601                                                     GdkEventButton   *event);
602 static gboolean gtk_tree_view_button_release       (GtkWidget        *widget,
603                                                     GdkEventButton   *event);
604 static gboolean gtk_tree_view_grab_broken          (GtkWidget          *widget,
605                                                     GdkEventGrabBroken *event);
606 #if 0
607 static gboolean gtk_tree_view_configure            (GtkWidget         *widget,
608                                                     GdkEventConfigure *event);
609 #endif
610
611 static GtkWidgetPath * gtk_tree_view_get_path_for_child (GtkContainer *container,
612                                                          GtkWidget    *child);
613
614 static void     gtk_tree_view_set_focus_child      (GtkContainer     *container,
615                                                     GtkWidget        *child);
616 static gint     gtk_tree_view_focus_out            (GtkWidget        *widget,
617                                                     GdkEventFocus    *event);
618 static gint     gtk_tree_view_focus                (GtkWidget        *widget,
619                                                     GtkDirectionType  direction);
620 static void     gtk_tree_view_grab_focus           (GtkWidget        *widget);
621 static void     gtk_tree_view_style_updated        (GtkWidget        *widget);
622 static void     gtk_tree_view_grab_notify          (GtkWidget        *widget,
623                                                     gboolean          was_grabbed);
624 static void     gtk_tree_view_state_flags_changed  (GtkWidget        *widget,
625                                                     GtkStateFlags     previous_state);
626
627 /* container signals */
628 static void     gtk_tree_view_remove               (GtkContainer     *container,
629                                                     GtkWidget        *widget);
630 static void     gtk_tree_view_forall               (GtkContainer     *container,
631                                                     gboolean          include_internals,
632                                                     GtkCallback       callback,
633                                                     gpointer          callback_data);
634
635 /* Source side drag signals */
636 static void gtk_tree_view_drag_begin       (GtkWidget        *widget,
637                                             GdkDragContext   *context);
638 static void gtk_tree_view_drag_end         (GtkWidget        *widget,
639                                             GdkDragContext   *context);
640 static void gtk_tree_view_drag_data_get    (GtkWidget        *widget,
641                                             GdkDragContext   *context,
642                                             GtkSelectionData *selection_data,
643                                             guint             info,
644                                             guint             time);
645 static void gtk_tree_view_drag_data_delete (GtkWidget        *widget,
646                                             GdkDragContext   *context);
647
648 /* Target side drag signals */
649 static void     gtk_tree_view_drag_leave         (GtkWidget        *widget,
650                                                   GdkDragContext   *context,
651                                                   guint             time);
652 static gboolean gtk_tree_view_drag_motion        (GtkWidget        *widget,
653                                                   GdkDragContext   *context,
654                                                   gint              x,
655                                                   gint              y,
656                                                   guint             time);
657 static gboolean gtk_tree_view_drag_drop          (GtkWidget        *widget,
658                                                   GdkDragContext   *context,
659                                                   gint              x,
660                                                   gint              y,
661                                                   guint             time);
662 static void     gtk_tree_view_drag_data_received (GtkWidget        *widget,
663                                                   GdkDragContext   *context,
664                                                   gint              x,
665                                                   gint              y,
666                                                   GtkSelectionData *selection_data,
667                                                   guint             info,
668                                                   guint             time);
669
670 /* tree_model signals */
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     queue_resize);
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 static void     gtk_tree_view_get_arrow_xrange               (GtkTreeView        *tree_view,
749                                                               GtkRBTree          *tree,
750                                                               gint               *x1,
751                                                               gint               *x2);
752 static gint     gtk_tree_view_new_column_width               (GtkTreeView        *tree_view,
753                                                               gint                i,
754                                                               gint               *x);
755 static void     gtk_tree_view_adjustment_changed             (GtkAdjustment      *adjustment,
756                                                               GtkTreeView        *tree_view);
757 static void     gtk_tree_view_build_tree                     (GtkTreeView        *tree_view,
758                                                               GtkRBTree          *tree,
759                                                               GtkTreeIter        *iter,
760                                                               gint                depth,
761                                                               gboolean            recurse);
762 static void     gtk_tree_view_clamp_node_visible             (GtkTreeView        *tree_view,
763                                                               GtkRBTree          *tree,
764                                                               GtkRBNode          *node);
765 static void     gtk_tree_view_clamp_column_visible           (GtkTreeView        *tree_view,
766                                                               GtkTreeViewColumn  *column,
767                                                               gboolean            focus_to_cell);
768 static gboolean gtk_tree_view_maybe_begin_dragging_row       (GtkTreeView        *tree_view,
769                                                               GdkEventMotion     *event);
770 static void     gtk_tree_view_focus_to_cursor                (GtkTreeView        *tree_view);
771 static void     gtk_tree_view_move_cursor_up_down            (GtkTreeView        *tree_view,
772                                                               gint                count);
773 static void     gtk_tree_view_move_cursor_page_up_down       (GtkTreeView        *tree_view,
774                                                               gint                count);
775 static void     gtk_tree_view_move_cursor_left_right         (GtkTreeView        *tree_view,
776                                                               gint                count);
777 static void     gtk_tree_view_move_cursor_start_end          (GtkTreeView        *tree_view,
778                                                               gint                count);
779 static gboolean gtk_tree_view_real_collapse_row              (GtkTreeView        *tree_view,
780                                                               GtkTreePath        *path,
781                                                               GtkRBTree          *tree,
782                                                               GtkRBNode          *node,
783                                                               gboolean            animate);
784 static gboolean gtk_tree_view_real_expand_row                (GtkTreeView        *tree_view,
785                                                               GtkTreePath        *path,
786                                                               GtkRBTree          *tree,
787                                                               GtkRBNode          *node,
788                                                               gboolean            open_all,
789                                                               gboolean            animate);
790 static void     gtk_tree_view_real_set_cursor                (GtkTreeView        *tree_view,
791                                                               GtkTreePath        *path,
792                                                               SetCursorFlags      flags);
793 static gboolean gtk_tree_view_has_can_focus_cell             (GtkTreeView        *tree_view);
794 static void     column_sizing_notify                         (GObject            *object,
795                                                               GParamSpec         *pspec,
796                                                               gpointer            data);
797 static void     gtk_tree_view_stop_rubber_band               (GtkTreeView        *tree_view);
798 static void     update_prelight                              (GtkTreeView        *tree_view,
799                                                               int                 x,
800                                                               int                 y);
801
802 static inline gint gtk_tree_view_get_effective_header_height (GtkTreeView *tree_view);
803
804 static inline gint gtk_tree_view_get_cell_area_y_offset      (GtkTreeView *tree_view,
805                                                               GtkRBTree   *tree,
806                                                               GtkRBNode   *node,
807                                                               gint         vertical_separator);
808 static inline gint gtk_tree_view_get_cell_area_height        (GtkTreeView *tree_view,
809                                                               GtkRBNode   *node,
810                                                               gint         vertical_separator);
811
812 static inline gint gtk_tree_view_get_row_y_offset            (GtkTreeView *tree_view,
813                                                               GtkRBTree   *tree,
814                                                               GtkRBNode   *node);
815 static inline gint gtk_tree_view_get_row_height              (GtkTreeView *tree_view,
816                                                               GtkRBNode   *node);
817
818 /* interactive search */
819 static void     gtk_tree_view_ensure_interactive_directory (GtkTreeView *tree_view);
820 static void     gtk_tree_view_search_dialog_hide        (GtkWidget        *search_dialog,
821                                                          GtkTreeView      *tree_view,
822                                                          GdkDevice        *device);
823 static void     gtk_tree_view_search_position_func      (GtkTreeView      *tree_view,
824                                                          GtkWidget        *search_dialog,
825                                                          gpointer          user_data);
826 static void     gtk_tree_view_search_disable_popdown    (GtkEntry         *entry,
827                                                          GtkMenu          *menu,
828                                                          gpointer          data);
829 static void     gtk_tree_view_search_preedit_changed    (GtkIMContext     *im_context,
830                                                          GtkTreeView      *tree_view);
831 static void     gtk_tree_view_search_activate           (GtkEntry         *entry,
832                                                          GtkTreeView      *tree_view);
833 static gboolean gtk_tree_view_real_search_enable_popdown(gpointer          data);
834 static void     gtk_tree_view_search_enable_popdown     (GtkWidget        *widget,
835                                                          gpointer          data);
836 static gboolean gtk_tree_view_search_delete_event       (GtkWidget        *widget,
837                                                          GdkEventAny      *event,
838                                                          GtkTreeView      *tree_view);
839 static gboolean gtk_tree_view_search_button_press_event (GtkWidget        *widget,
840                                                          GdkEventButton   *event,
841                                                          GtkTreeView      *tree_view);
842 static gboolean gtk_tree_view_search_scroll_event       (GtkWidget        *entry,
843                                                          GdkEventScroll   *event,
844                                                          GtkTreeView      *tree_view);
845 static gboolean gtk_tree_view_search_key_press_event    (GtkWidget        *entry,
846                                                          GdkEventKey      *event,
847                                                          GtkTreeView      *tree_view);
848 static gboolean gtk_tree_view_search_move               (GtkWidget        *window,
849                                                          GtkTreeView      *tree_view,
850                                                          gboolean          up);
851 static gboolean gtk_tree_view_search_equal_func         (GtkTreeModel     *model,
852                                                          gint              column,
853                                                          const gchar      *key,
854                                                          GtkTreeIter      *iter,
855                                                          gpointer          search_data);
856 static gboolean gtk_tree_view_search_iter               (GtkTreeModel     *model,
857                                                          GtkTreeSelection *selection,
858                                                          GtkTreeIter      *iter,
859                                                          const gchar      *text,
860                                                          gint             *count,
861                                                          gint              n);
862 static void     gtk_tree_view_search_init               (GtkWidget        *entry,
863                                                          GtkTreeView      *tree_view);
864 static void     gtk_tree_view_put                       (GtkTreeView      *tree_view,
865                                                          GtkWidget        *child_widget,
866                                                          gint              x,
867                                                          gint              y,
868                                                          gint              width,
869                                                          gint              height);
870 static gboolean gtk_tree_view_start_editing             (GtkTreeView      *tree_view,
871                                                          GtkTreePath      *cursor_path,
872                                                          gboolean          edit_only);
873 static void gtk_tree_view_stop_editing                  (GtkTreeView *tree_view,
874                                                          gboolean     cancel_editing);
875 static gboolean gtk_tree_view_real_start_interactive_search (GtkTreeView *tree_view,
876                                                              GdkDevice   *device,
877                                                              gboolean     keybinding);
878 static gboolean gtk_tree_view_start_interactive_search      (GtkTreeView *tree_view);
879 static GtkTreeViewColumn *gtk_tree_view_get_drop_column (GtkTreeView       *tree_view,
880                                                          GtkTreeViewColumn *column,
881                                                          gint               drop_position);
882
883 /* GtkBuildable */
884 static void     gtk_tree_view_buildable_add_child          (GtkBuildable      *tree_view,
885                                                             GtkBuilder        *builder,
886                                                             GObject           *child,
887                                                             const gchar       *type);
888 static GObject *gtk_tree_view_buildable_get_internal_child (GtkBuildable      *buildable,
889                                                             GtkBuilder        *builder,
890                                                             const gchar       *childname);
891 static void     gtk_tree_view_buildable_init               (GtkBuildableIface *iface);
892
893 static GtkAdjustment *gtk_tree_view_do_get_hadjustment (GtkTreeView   *tree_view);
894 static void           gtk_tree_view_do_set_hadjustment (GtkTreeView   *tree_view,
895                                                         GtkAdjustment *adjustment);
896 static GtkAdjustment *gtk_tree_view_do_get_vadjustment (GtkTreeView   *tree_view);
897 static void           gtk_tree_view_do_set_vadjustment (GtkTreeView   *tree_view,
898                                                         GtkAdjustment *adjustment);
899
900 static gboolean scroll_row_timeout                   (gpointer     data);
901 static void     add_scroll_timeout                   (GtkTreeView *tree_view);
902 static void     remove_scroll_timeout                (GtkTreeView *tree_view);
903
904 static guint tree_view_signals [LAST_SIGNAL] = { 0 };
905
906 \f
907
908 /* GType Methods
909  */
910
911 G_DEFINE_TYPE_WITH_CODE (GtkTreeView, gtk_tree_view, GTK_TYPE_CONTAINER,
912                          G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
913                                                 gtk_tree_view_buildable_init)
914                          G_IMPLEMENT_INTERFACE (GTK_TYPE_SCROLLABLE, NULL))
915
916 static void
917 gtk_tree_view_class_init (GtkTreeViewClass *class)
918 {
919   GObjectClass *o_class;
920   GtkWidgetClass *widget_class;
921   GtkContainerClass *container_class;
922   GtkBindingSet *binding_set;
923
924   binding_set = gtk_binding_set_by_class (class);
925
926   o_class = (GObjectClass *) class;
927   widget_class = (GtkWidgetClass *) class;
928   container_class = (GtkContainerClass *) class;
929
930   /* GObject signals */
931   o_class->set_property = gtk_tree_view_set_property;
932   o_class->get_property = gtk_tree_view_get_property;
933   o_class->finalize = gtk_tree_view_finalize;
934
935   /* GtkWidget signals */
936   widget_class->destroy = gtk_tree_view_destroy;
937   widget_class->map = gtk_tree_view_map;
938   widget_class->realize = gtk_tree_view_realize;
939   widget_class->unrealize = gtk_tree_view_unrealize;
940   widget_class->get_preferred_width = gtk_tree_view_get_preferred_width;
941   widget_class->get_preferred_height = gtk_tree_view_get_preferred_height;
942   widget_class->size_allocate = gtk_tree_view_size_allocate;
943   widget_class->button_press_event = gtk_tree_view_button_press;
944   widget_class->button_release_event = gtk_tree_view_button_release;
945   widget_class->grab_broken_event = gtk_tree_view_grab_broken;
946   /*widget_class->configure_event = gtk_tree_view_configure;*/
947   widget_class->motion_notify_event = gtk_tree_view_motion;
948   widget_class->draw = gtk_tree_view_draw;
949   widget_class->key_press_event = gtk_tree_view_key_press;
950   widget_class->key_release_event = gtk_tree_view_key_release;
951   widget_class->enter_notify_event = gtk_tree_view_enter_notify;
952   widget_class->leave_notify_event = gtk_tree_view_leave_notify;
953   widget_class->focus_out_event = gtk_tree_view_focus_out;
954   widget_class->drag_begin = gtk_tree_view_drag_begin;
955   widget_class->drag_end = gtk_tree_view_drag_end;
956   widget_class->drag_data_get = gtk_tree_view_drag_data_get;
957   widget_class->drag_data_delete = gtk_tree_view_drag_data_delete;
958   widget_class->drag_leave = gtk_tree_view_drag_leave;
959   widget_class->drag_motion = gtk_tree_view_drag_motion;
960   widget_class->drag_drop = gtk_tree_view_drag_drop;
961   widget_class->drag_data_received = gtk_tree_view_drag_data_received;
962   widget_class->focus = gtk_tree_view_focus;
963   widget_class->grab_focus = gtk_tree_view_grab_focus;
964   widget_class->style_updated = gtk_tree_view_style_updated;
965   widget_class->grab_notify = gtk_tree_view_grab_notify;
966   widget_class->state_flags_changed = gtk_tree_view_state_flags_changed;
967
968   /* GtkContainer signals */
969   container_class->remove = gtk_tree_view_remove;
970   container_class->forall = gtk_tree_view_forall;
971   container_class->set_focus_child = gtk_tree_view_set_focus_child;
972   container_class->get_path_for_child = gtk_tree_view_get_path_for_child;
973
974   class->move_cursor = gtk_tree_view_real_move_cursor;
975   class->select_all = gtk_tree_view_real_select_all;
976   class->unselect_all = gtk_tree_view_real_unselect_all;
977   class->select_cursor_row = gtk_tree_view_real_select_cursor_row;
978   class->toggle_cursor_row = gtk_tree_view_real_toggle_cursor_row;
979   class->expand_collapse_cursor_row = gtk_tree_view_real_expand_collapse_cursor_row;
980   class->select_cursor_parent = gtk_tree_view_real_select_cursor_parent;
981   class->start_interactive_search = gtk_tree_view_start_interactive_search;
982
983   /* Properties */
984
985   g_object_class_install_property (o_class,
986                                    PROP_MODEL,
987                                    g_param_spec_object ("model",
988                                                         P_("TreeView Model"),
989                                                         P_("The model for the tree view"),
990                                                         GTK_TYPE_TREE_MODEL,
991                                                         GTK_PARAM_READWRITE));
992
993   g_object_class_override_property (o_class, PROP_HADJUSTMENT,    "hadjustment");
994   g_object_class_override_property (o_class, PROP_VADJUSTMENT,    "vadjustment");
995   g_object_class_override_property (o_class, PROP_HSCROLL_POLICY, "hscroll-policy");
996   g_object_class_override_property (o_class, PROP_VSCROLL_POLICY, "vscroll-policy");
997
998   g_object_class_install_property (o_class,
999                                    PROP_HEADERS_VISIBLE,
1000                                    g_param_spec_boolean ("headers-visible",
1001                                                          P_("Headers Visible"),
1002                                                          P_("Show the column header buttons"),
1003                                                          TRUE,
1004                                                          GTK_PARAM_READWRITE));
1005
1006   g_object_class_install_property (o_class,
1007                                    PROP_HEADERS_CLICKABLE,
1008                                    g_param_spec_boolean ("headers-clickable",
1009                                                          P_("Headers Clickable"),
1010                                                          P_("Column headers respond to click events"),
1011                                                          TRUE,
1012                                                          GTK_PARAM_READWRITE));
1013
1014   g_object_class_install_property (o_class,
1015                                    PROP_EXPANDER_COLUMN,
1016                                    g_param_spec_object ("expander-column",
1017                                                         P_("Expander Column"),
1018                                                         P_("Set the column for the expander column"),
1019                                                         GTK_TYPE_TREE_VIEW_COLUMN,
1020                                                         GTK_PARAM_READWRITE));
1021
1022   g_object_class_install_property (o_class,
1023                                    PROP_REORDERABLE,
1024                                    g_param_spec_boolean ("reorderable",
1025                                                          P_("Reorderable"),
1026                                                          P_("View is reorderable"),
1027                                                          FALSE,
1028                                                          GTK_PARAM_READWRITE));
1029
1030   g_object_class_install_property (o_class,
1031                                    PROP_RULES_HINT,
1032                                    g_param_spec_boolean ("rules-hint",
1033                                                          P_("Rules Hint"),
1034                                                          P_("Set a hint to the theme engine to draw rows in alternating colors"),
1035                                                          FALSE,
1036                                                          GTK_PARAM_READWRITE));
1037
1038     g_object_class_install_property (o_class,
1039                                      PROP_ENABLE_SEARCH,
1040                                      g_param_spec_boolean ("enable-search",
1041                                                            P_("Enable Search"),
1042                                                            P_("View allows user to search through columns interactively"),
1043                                                            TRUE,
1044                                                            GTK_PARAM_READWRITE));
1045
1046     g_object_class_install_property (o_class,
1047                                      PROP_SEARCH_COLUMN,
1048                                      g_param_spec_int ("search-column",
1049                                                        P_("Search Column"),
1050                                                        P_("Model column to search through during interactive search"),
1051                                                        -1,
1052                                                        G_MAXINT,
1053                                                        -1,
1054                                                        GTK_PARAM_READWRITE));
1055
1056     /**
1057      * GtkTreeView:fixed-height-mode:
1058      *
1059      * Setting the ::fixed-height-mode property to %TRUE speeds up 
1060      * #GtkTreeView by assuming that all rows have the same height. 
1061      * Only enable this option if all rows are the same height.  
1062      * Please see gtk_tree_view_set_fixed_height_mode() for more 
1063      * information on this option.
1064      *
1065      * Since: 2.4
1066      **/
1067     g_object_class_install_property (o_class,
1068                                      PROP_FIXED_HEIGHT_MODE,
1069                                      g_param_spec_boolean ("fixed-height-mode",
1070                                                            P_("Fixed Height Mode"),
1071                                                            P_("Speeds up GtkTreeView by assuming that all rows have the same height"),
1072                                                            FALSE,
1073                                                            GTK_PARAM_READWRITE));
1074     
1075     /**
1076      * GtkTreeView:hover-selection:
1077      * 
1078      * Enables or disables the hover selection mode of @tree_view.
1079      * Hover selection makes the selected row follow the pointer.
1080      * Currently, this works only for the selection modes 
1081      * %GTK_SELECTION_SINGLE and %GTK_SELECTION_BROWSE.
1082      *
1083      * This mode is primarily intended for treeviews in popups, e.g.
1084      * in #GtkComboBox or #GtkEntryCompletion.
1085      *
1086      * Since: 2.6
1087      */
1088     g_object_class_install_property (o_class,
1089                                      PROP_HOVER_SELECTION,
1090                                      g_param_spec_boolean ("hover-selection",
1091                                                            P_("Hover Selection"),
1092                                                            P_("Whether the selection should follow the pointer"),
1093                                                            FALSE,
1094                                                            GTK_PARAM_READWRITE));
1095
1096     /**
1097      * GtkTreeView:hover-expand:
1098      * 
1099      * Enables or disables the hover expansion mode of @tree_view.
1100      * Hover expansion makes rows expand or collapse if the pointer moves 
1101      * over them.
1102      *
1103      * This mode is primarily intended for treeviews in popups, e.g.
1104      * in #GtkComboBox or #GtkEntryCompletion.
1105      *
1106      * Since: 2.6
1107      */
1108     g_object_class_install_property (o_class,
1109                                      PROP_HOVER_EXPAND,
1110                                      g_param_spec_boolean ("hover-expand",
1111                                                            P_("Hover Expand"),
1112                                                            P_("Whether rows should be expanded/collapsed when the pointer moves over them"),
1113                                                            FALSE,
1114                                                            GTK_PARAM_READWRITE));
1115
1116     /**
1117      * GtkTreeView:show-expanders:
1118      *
1119      * %TRUE if the view has expanders.
1120      *
1121      * Since: 2.12
1122      */
1123     g_object_class_install_property (o_class,
1124                                      PROP_SHOW_EXPANDERS,
1125                                      g_param_spec_boolean ("show-expanders",
1126                                                            P_("Show Expanders"),
1127                                                            P_("View has expanders"),
1128                                                            TRUE,
1129                                                            GTK_PARAM_READWRITE));
1130
1131     /**
1132      * GtkTreeView:level-indentation:
1133      *
1134      * Extra indentation for each level.
1135      *
1136      * Since: 2.12
1137      */
1138     g_object_class_install_property (o_class,
1139                                      PROP_LEVEL_INDENTATION,
1140                                      g_param_spec_int ("level-indentation",
1141                                                        P_("Level Indentation"),
1142                                                        P_("Extra indentation for each level"),
1143                                                        0,
1144                                                        G_MAXINT,
1145                                                        0,
1146                                                        GTK_PARAM_READWRITE));
1147
1148     g_object_class_install_property (o_class,
1149                                      PROP_RUBBER_BANDING,
1150                                      g_param_spec_boolean ("rubber-banding",
1151                                                            P_("Rubber Banding"),
1152                                                            P_("Whether to enable selection of multiple items by dragging the mouse pointer"),
1153                                                            FALSE,
1154                                                            GTK_PARAM_READWRITE));
1155
1156     g_object_class_install_property (o_class,
1157                                      PROP_ENABLE_GRID_LINES,
1158                                      g_param_spec_enum ("enable-grid-lines",
1159                                                         P_("Enable Grid Lines"),
1160                                                         P_("Whether grid lines should be drawn in the tree view"),
1161                                                         GTK_TYPE_TREE_VIEW_GRID_LINES,
1162                                                         GTK_TREE_VIEW_GRID_LINES_NONE,
1163                                                         GTK_PARAM_READWRITE));
1164
1165     g_object_class_install_property (o_class,
1166                                      PROP_ENABLE_TREE_LINES,
1167                                      g_param_spec_boolean ("enable-tree-lines",
1168                                                            P_("Enable Tree Lines"),
1169                                                            P_("Whether tree lines should be drawn in the tree view"),
1170                                                            FALSE,
1171                                                            GTK_PARAM_READWRITE));
1172
1173     g_object_class_install_property (o_class,
1174                                      PROP_TOOLTIP_COLUMN,
1175                                      g_param_spec_int ("tooltip-column",
1176                                                        P_("Tooltip Column"),
1177                                                        P_("The column in the model containing the tooltip texts for the rows"),
1178                                                        -1,
1179                                                        G_MAXINT,
1180                                                        -1,
1181                                                        GTK_PARAM_READWRITE));
1182
1183   /* Style properties */
1184 #define _TREE_VIEW_EXPANDER_SIZE 14
1185 #define _TREE_VIEW_VERTICAL_SEPARATOR 2
1186 #define _TREE_VIEW_HORIZONTAL_SEPARATOR 2
1187
1188   gtk_widget_class_install_style_property (widget_class,
1189                                            g_param_spec_int ("expander-size",
1190                                                              P_("Expander Size"),
1191                                                              P_("Size of the expander arrow"),
1192                                                              0,
1193                                                              G_MAXINT,
1194                                                              _TREE_VIEW_EXPANDER_SIZE,
1195                                                              GTK_PARAM_READABLE));
1196
1197   gtk_widget_class_install_style_property (widget_class,
1198                                            g_param_spec_int ("vertical-separator",
1199                                                              P_("Vertical Separator Width"),
1200                                                              P_("Vertical space between cells.  Must be an even number"),
1201                                                              0,
1202                                                              G_MAXINT,
1203                                                              _TREE_VIEW_VERTICAL_SEPARATOR,
1204                                                              GTK_PARAM_READABLE));
1205
1206   gtk_widget_class_install_style_property (widget_class,
1207                                            g_param_spec_int ("horizontal-separator",
1208                                                              P_("Horizontal Separator Width"),
1209                                                              P_("Horizontal space between cells.  Must be an even number"),
1210                                                              0,
1211                                                              G_MAXINT,
1212                                                              _TREE_VIEW_HORIZONTAL_SEPARATOR,
1213                                                              GTK_PARAM_READABLE));
1214
1215   gtk_widget_class_install_style_property (widget_class,
1216                                            g_param_spec_boolean ("allow-rules",
1217                                                                  P_("Allow Rules"),
1218                                                                  P_("Allow drawing of alternating color rows"),
1219                                                                  TRUE,
1220                                                                  GTK_PARAM_READABLE));
1221
1222   gtk_widget_class_install_style_property (widget_class,
1223                                            g_param_spec_boolean ("indent-expanders",
1224                                                                  P_("Indent Expanders"),
1225                                                                  P_("Make the expanders indented"),
1226                                                                  TRUE,
1227                                                                  GTK_PARAM_READABLE));
1228
1229   gtk_widget_class_install_style_property (widget_class,
1230                                            g_param_spec_boxed ("even-row-color",
1231                                                                P_("Even Row Color"),
1232                                                                P_("Color to use for even rows"),
1233                                                                GDK_TYPE_COLOR,
1234                                                                GTK_PARAM_READABLE));
1235
1236   gtk_widget_class_install_style_property (widget_class,
1237                                            g_param_spec_boxed ("odd-row-color",
1238                                                                P_("Odd Row Color"),
1239                                                                P_("Color to use for odd rows"),
1240                                                                GDK_TYPE_COLOR,
1241                                                                GTK_PARAM_READABLE));
1242
1243   gtk_widget_class_install_style_property (widget_class,
1244                                            g_param_spec_int ("grid-line-width",
1245                                                              P_("Grid line width"),
1246                                                              P_("Width, in pixels, of the tree view grid lines"),
1247                                                              0, G_MAXINT, 1,
1248                                                              GTK_PARAM_READABLE));
1249
1250   gtk_widget_class_install_style_property (widget_class,
1251                                            g_param_spec_int ("tree-line-width",
1252                                                              P_("Tree line width"),
1253                                                              P_("Width, in pixels, of the tree view lines"),
1254                                                              0, G_MAXINT, 1,
1255                                                              GTK_PARAM_READABLE));
1256
1257   gtk_widget_class_install_style_property (widget_class,
1258                                            g_param_spec_string ("grid-line-pattern",
1259                                                                 P_("Grid line pattern"),
1260                                                                 P_("Dash pattern used to draw the tree view grid lines"),
1261                                                                 "\1\1",
1262                                                                 GTK_PARAM_READABLE));
1263
1264   gtk_widget_class_install_style_property (widget_class,
1265                                            g_param_spec_string ("tree-line-pattern",
1266                                                                 P_("Tree line pattern"),
1267                                                                 P_("Dash pattern used to draw the tree view lines"),
1268                                                                 "\1\1",
1269                                                                 GTK_PARAM_READABLE));
1270
1271   /* Signals */
1272   /**
1273    * GtkTreeView::row-activated:
1274    * @tree_view: the object on which the signal is emitted
1275    * @path: the #GtkTreePath for the activated row
1276    * @column: the #GtkTreeViewColumn in which the activation occurred
1277    *
1278    * The "row-activated" signal is emitted when the method
1279    * gtk_tree_view_row_activated() is called or the user double clicks 
1280    * a treeview row. It is also emitted when a non-editable row is 
1281    * selected and one of the keys: Space, Shift+Space, Return or 
1282    * Enter is pressed.
1283    * 
1284    * For selection handling refer to the <link linkend="TreeWidget">tree 
1285    * widget conceptual overview</link> as well as #GtkTreeSelection.
1286    */
1287   tree_view_signals[ROW_ACTIVATED] =
1288     g_signal_new (I_("row-activated"),
1289                   G_TYPE_FROM_CLASS (o_class),
1290                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1291                   G_STRUCT_OFFSET (GtkTreeViewClass, row_activated),
1292                   NULL, NULL,
1293                   _gtk_marshal_VOID__BOXED_OBJECT,
1294                   G_TYPE_NONE, 2,
1295                   GTK_TYPE_TREE_PATH,
1296                   GTK_TYPE_TREE_VIEW_COLUMN);
1297
1298   /**
1299    * GtkTreeView::test-expand-row:
1300    * @tree_view: the object on which the signal is emitted
1301    * @iter: the tree iter of the row to expand
1302    * @path: a tree path that points to the row 
1303    * 
1304    * The given row is about to be expanded (show its children nodes). Use this
1305    * signal if you need to control the expandability of individual rows.
1306    *
1307    * Returns: %FALSE to allow expansion, %TRUE to reject
1308    */
1309   tree_view_signals[TEST_EXPAND_ROW] =
1310     g_signal_new (I_("test-expand-row"),
1311                   G_TYPE_FROM_CLASS (o_class),
1312                   G_SIGNAL_RUN_LAST,
1313                   G_STRUCT_OFFSET (GtkTreeViewClass, test_expand_row),
1314                   _gtk_boolean_handled_accumulator, NULL,
1315                   _gtk_marshal_BOOLEAN__BOXED_BOXED,
1316                   G_TYPE_BOOLEAN, 2,
1317                   GTK_TYPE_TREE_ITER,
1318                   GTK_TYPE_TREE_PATH);
1319
1320   /**
1321    * GtkTreeView::test-collapse-row:
1322    * @tree_view: the object on which the signal is emitted
1323    * @iter: the tree iter of the row to collapse
1324    * @path: a tree path that points to the row 
1325    * 
1326    * The given row is about to be collapsed (hide its children nodes). Use this
1327    * signal if you need to control the collapsibility of individual rows.
1328    *
1329    * Returns: %FALSE to allow collapsing, %TRUE to reject
1330    */
1331   tree_view_signals[TEST_COLLAPSE_ROW] =
1332     g_signal_new (I_("test-collapse-row"),
1333                   G_TYPE_FROM_CLASS (o_class),
1334                   G_SIGNAL_RUN_LAST,
1335                   G_STRUCT_OFFSET (GtkTreeViewClass, test_collapse_row),
1336                   _gtk_boolean_handled_accumulator, NULL,
1337                   _gtk_marshal_BOOLEAN__BOXED_BOXED,
1338                   G_TYPE_BOOLEAN, 2,
1339                   GTK_TYPE_TREE_ITER,
1340                   GTK_TYPE_TREE_PATH);
1341
1342   /**
1343    * GtkTreeView::row-expanded:
1344    * @tree_view: the object on which the signal is emitted
1345    * @iter: the tree iter of the expanded row
1346    * @path: a tree path that points to the row 
1347    * 
1348    * The given row has been expanded (child nodes are shown).
1349    */
1350   tree_view_signals[ROW_EXPANDED] =
1351     g_signal_new (I_("row-expanded"),
1352                   G_TYPE_FROM_CLASS (o_class),
1353                   G_SIGNAL_RUN_LAST,
1354                   G_STRUCT_OFFSET (GtkTreeViewClass, row_expanded),
1355                   NULL, NULL,
1356                   _gtk_marshal_VOID__BOXED_BOXED,
1357                   G_TYPE_NONE, 2,
1358                   GTK_TYPE_TREE_ITER,
1359                   GTK_TYPE_TREE_PATH);
1360
1361   /**
1362    * GtkTreeView::row-collapsed:
1363    * @tree_view: the object on which the signal is emitted
1364    * @iter: the tree iter of the collapsed row
1365    * @path: a tree path that points to the row 
1366    * 
1367    * The given row has been collapsed (child nodes are hidden).
1368    */
1369   tree_view_signals[ROW_COLLAPSED] =
1370     g_signal_new (I_("row-collapsed"),
1371                   G_TYPE_FROM_CLASS (o_class),
1372                   G_SIGNAL_RUN_LAST,
1373                   G_STRUCT_OFFSET (GtkTreeViewClass, row_collapsed),
1374                   NULL, NULL,
1375                   _gtk_marshal_VOID__BOXED_BOXED,
1376                   G_TYPE_NONE, 2,
1377                   GTK_TYPE_TREE_ITER,
1378                   GTK_TYPE_TREE_PATH);
1379
1380   /**
1381    * GtkTreeView::columns-changed:
1382    * @tree_view: the object on which the signal is emitted 
1383    * 
1384    * The number of columns of the treeview has changed.
1385    */
1386   tree_view_signals[COLUMNS_CHANGED] =
1387     g_signal_new (I_("columns-changed"),
1388                   G_TYPE_FROM_CLASS (o_class),
1389                   G_SIGNAL_RUN_LAST,
1390                   G_STRUCT_OFFSET (GtkTreeViewClass, columns_changed),
1391                   NULL, NULL,
1392                   _gtk_marshal_VOID__VOID,
1393                   G_TYPE_NONE, 0);
1394
1395   /**
1396    * GtkTreeView::cursor-changed:
1397    * @tree_view: the object on which the signal is emitted
1398    * 
1399    * The position of the cursor (focused cell) has changed.
1400    */
1401   tree_view_signals[CURSOR_CHANGED] =
1402     g_signal_new (I_("cursor-changed"),
1403                   G_TYPE_FROM_CLASS (o_class),
1404                   G_SIGNAL_RUN_LAST,
1405                   G_STRUCT_OFFSET (GtkTreeViewClass, cursor_changed),
1406                   NULL, NULL,
1407                   _gtk_marshal_VOID__VOID,
1408                   G_TYPE_NONE, 0);
1409
1410   tree_view_signals[MOVE_CURSOR] =
1411     g_signal_new (I_("move-cursor"),
1412                   G_TYPE_FROM_CLASS (o_class),
1413                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1414                   G_STRUCT_OFFSET (GtkTreeViewClass, move_cursor),
1415                   NULL, NULL,
1416                   _gtk_marshal_BOOLEAN__ENUM_INT,
1417                   G_TYPE_BOOLEAN, 2,
1418                   GTK_TYPE_MOVEMENT_STEP,
1419                   G_TYPE_INT);
1420
1421   tree_view_signals[SELECT_ALL] =
1422     g_signal_new (I_("select-all"),
1423                   G_TYPE_FROM_CLASS (o_class),
1424                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1425                   G_STRUCT_OFFSET (GtkTreeViewClass, select_all),
1426                   NULL, NULL,
1427                   _gtk_marshal_BOOLEAN__VOID,
1428                   G_TYPE_BOOLEAN, 0);
1429
1430   tree_view_signals[UNSELECT_ALL] =
1431     g_signal_new (I_("unselect-all"),
1432                   G_TYPE_FROM_CLASS (o_class),
1433                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1434                   G_STRUCT_OFFSET (GtkTreeViewClass, unselect_all),
1435                   NULL, NULL,
1436                   _gtk_marshal_BOOLEAN__VOID,
1437                   G_TYPE_BOOLEAN, 0);
1438
1439   tree_view_signals[SELECT_CURSOR_ROW] =
1440     g_signal_new (I_("select-cursor-row"),
1441                   G_TYPE_FROM_CLASS (o_class),
1442                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1443                   G_STRUCT_OFFSET (GtkTreeViewClass, select_cursor_row),
1444                   NULL, NULL,
1445                   _gtk_marshal_BOOLEAN__BOOLEAN,
1446                   G_TYPE_BOOLEAN, 1,
1447                   G_TYPE_BOOLEAN);
1448
1449   tree_view_signals[TOGGLE_CURSOR_ROW] =
1450     g_signal_new (I_("toggle-cursor-row"),
1451                   G_TYPE_FROM_CLASS (o_class),
1452                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1453                   G_STRUCT_OFFSET (GtkTreeViewClass, toggle_cursor_row),
1454                   NULL, NULL,
1455                   _gtk_marshal_BOOLEAN__VOID,
1456                   G_TYPE_BOOLEAN, 0);
1457
1458   tree_view_signals[EXPAND_COLLAPSE_CURSOR_ROW] =
1459     g_signal_new (I_("expand-collapse-cursor-row"),
1460                   G_TYPE_FROM_CLASS (o_class),
1461                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1462                   G_STRUCT_OFFSET (GtkTreeViewClass, expand_collapse_cursor_row),
1463                   NULL, NULL,
1464                   _gtk_marshal_BOOLEAN__BOOLEAN_BOOLEAN_BOOLEAN,
1465                   G_TYPE_BOOLEAN, 3,
1466                   G_TYPE_BOOLEAN,
1467                   G_TYPE_BOOLEAN,
1468                   G_TYPE_BOOLEAN);
1469
1470   tree_view_signals[SELECT_CURSOR_PARENT] =
1471     g_signal_new (I_("select-cursor-parent"),
1472                   G_TYPE_FROM_CLASS (o_class),
1473                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1474                   G_STRUCT_OFFSET (GtkTreeViewClass, select_cursor_parent),
1475                   NULL, NULL,
1476                   _gtk_marshal_BOOLEAN__VOID,
1477                   G_TYPE_BOOLEAN, 0);
1478
1479   tree_view_signals[START_INTERACTIVE_SEARCH] =
1480     g_signal_new (I_("start-interactive-search"),
1481                   G_TYPE_FROM_CLASS (o_class),
1482                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1483                   G_STRUCT_OFFSET (GtkTreeViewClass, start_interactive_search),
1484                   NULL, NULL,
1485                   _gtk_marshal_BOOLEAN__VOID,
1486                   G_TYPE_BOOLEAN, 0);
1487
1488   /* Key bindings */
1489   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Up, 0, TRUE,
1490                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
1491   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Up, 0, TRUE,
1492                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
1493
1494   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Down, 0, TRUE,
1495                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
1496   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Down, 0, TRUE,
1497                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
1498
1499   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_p, GDK_CONTROL_MASK, FALSE,
1500                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
1501
1502   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_n, GDK_CONTROL_MASK, FALSE,
1503                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
1504
1505   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Home, 0, TRUE,
1506                                   GTK_MOVEMENT_BUFFER_ENDS, -1);
1507   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Home, 0, TRUE,
1508                                   GTK_MOVEMENT_BUFFER_ENDS, -1);
1509
1510   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_End, 0, TRUE,
1511                                   GTK_MOVEMENT_BUFFER_ENDS, 1);
1512   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_End, 0, TRUE,
1513                                   GTK_MOVEMENT_BUFFER_ENDS, 1);
1514
1515   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Page_Up, 0, TRUE,
1516                                   GTK_MOVEMENT_PAGES, -1);
1517   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Page_Up, 0, TRUE,
1518                                   GTK_MOVEMENT_PAGES, -1);
1519
1520   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Page_Down, 0, TRUE,
1521                                   GTK_MOVEMENT_PAGES, 1);
1522   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Page_Down, 0, TRUE,
1523                                   GTK_MOVEMENT_PAGES, 1);
1524
1525
1526   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Right, 0, "move-cursor", 2,
1527                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1528                                 G_TYPE_INT, 1);
1529
1530   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Left, 0, "move-cursor", 2,
1531                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1532                                 G_TYPE_INT, -1);
1533
1534   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Right, 0, "move-cursor", 2,
1535                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1536                                 G_TYPE_INT, 1);
1537
1538   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Left, 0, "move-cursor", 2,
1539                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1540                                 G_TYPE_INT, -1);
1541
1542   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Right, GDK_CONTROL_MASK,
1543                                 "move-cursor", 2,
1544                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1545                                 G_TYPE_INT, 1);
1546
1547   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Left, GDK_CONTROL_MASK,
1548                                 "move-cursor", 2,
1549                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1550                                 G_TYPE_INT, -1);
1551
1552   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Right, GDK_CONTROL_MASK,
1553                                 "move-cursor", 2,
1554                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1555                                 G_TYPE_INT, 1);
1556
1557   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Left, GDK_CONTROL_MASK,
1558                                 "move-cursor", 2,
1559                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1560                                 G_TYPE_INT, -1);
1561
1562   gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, GDK_CONTROL_MASK, "toggle-cursor-row", 0);
1563   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Space, GDK_CONTROL_MASK, "toggle-cursor-row", 0);
1564
1565   gtk_binding_entry_add_signal (binding_set, GDK_KEY_a, GDK_CONTROL_MASK, "select-all", 0);
1566   gtk_binding_entry_add_signal (binding_set, GDK_KEY_slash, GDK_CONTROL_MASK, "select-all", 0);
1567
1568   gtk_binding_entry_add_signal (binding_set, GDK_KEY_A, GDK_CONTROL_MASK | GDK_SHIFT_MASK, "unselect-all", 0);
1569   gtk_binding_entry_add_signal (binding_set, GDK_KEY_backslash, GDK_CONTROL_MASK, "unselect-all", 0);
1570
1571   gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, GDK_SHIFT_MASK, "select-cursor-row", 1,
1572                                 G_TYPE_BOOLEAN, TRUE);
1573   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Space, GDK_SHIFT_MASK, "select-cursor-row", 1,
1574                                 G_TYPE_BOOLEAN, TRUE);
1575
1576   gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, 0, "select-cursor-row", 1,
1577                                 G_TYPE_BOOLEAN, TRUE);
1578   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Space, 0, "select-cursor-row", 1,
1579                                 G_TYPE_BOOLEAN, TRUE);
1580   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Return, 0, "select-cursor-row", 1,
1581                                 G_TYPE_BOOLEAN, TRUE);
1582   gtk_binding_entry_add_signal (binding_set, GDK_KEY_ISO_Enter, 0, "select-cursor-row", 1,
1583                                 G_TYPE_BOOLEAN, TRUE);
1584   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Enter, 0, "select-cursor-row", 1,
1585                                 G_TYPE_BOOLEAN, TRUE);
1586
1587   /* expand and collapse rows */
1588   gtk_binding_entry_add_signal (binding_set, GDK_KEY_plus, 0, "expand-collapse-cursor-row", 3,
1589                                 G_TYPE_BOOLEAN, TRUE,
1590                                 G_TYPE_BOOLEAN, TRUE,
1591                                 G_TYPE_BOOLEAN, FALSE);
1592
1593   gtk_binding_entry_add_signal (binding_set, GDK_KEY_asterisk, 0,
1594                                 "expand-collapse-cursor-row", 3,
1595                                 G_TYPE_BOOLEAN, TRUE,
1596                                 G_TYPE_BOOLEAN, TRUE,
1597                                 G_TYPE_BOOLEAN, TRUE);
1598   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Multiply, 0,
1599                                 "expand-collapse-cursor-row", 3,
1600                                 G_TYPE_BOOLEAN, TRUE,
1601                                 G_TYPE_BOOLEAN, TRUE,
1602                                 G_TYPE_BOOLEAN, TRUE);
1603
1604   gtk_binding_entry_add_signal (binding_set, GDK_KEY_slash, 0,
1605                                 "expand-collapse-cursor-row", 3,
1606                                 G_TYPE_BOOLEAN, TRUE,
1607                                 G_TYPE_BOOLEAN, FALSE,
1608                                 G_TYPE_BOOLEAN, FALSE);
1609   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Divide, 0,
1610                                 "expand-collapse-cursor-row", 3,
1611                                 G_TYPE_BOOLEAN, TRUE,
1612                                 G_TYPE_BOOLEAN, FALSE,
1613                                 G_TYPE_BOOLEAN, FALSE);
1614
1615   /* Not doable on US keyboards */
1616   gtk_binding_entry_add_signal (binding_set, GDK_KEY_plus, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1617                                 G_TYPE_BOOLEAN, TRUE,
1618                                 G_TYPE_BOOLEAN, TRUE,
1619                                 G_TYPE_BOOLEAN, TRUE);
1620   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Add, 0, "expand-collapse-cursor-row", 3,
1621                                 G_TYPE_BOOLEAN, TRUE,
1622                                 G_TYPE_BOOLEAN, TRUE,
1623                                 G_TYPE_BOOLEAN, FALSE);
1624   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Add, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1625                                 G_TYPE_BOOLEAN, TRUE,
1626                                 G_TYPE_BOOLEAN, TRUE,
1627                                 G_TYPE_BOOLEAN, TRUE);
1628   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Add, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1629                                 G_TYPE_BOOLEAN, TRUE,
1630                                 G_TYPE_BOOLEAN, TRUE,
1631                                 G_TYPE_BOOLEAN, TRUE);
1632   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Right, GDK_SHIFT_MASK,
1633                                 "expand-collapse-cursor-row", 3,
1634                                 G_TYPE_BOOLEAN, FALSE,
1635                                 G_TYPE_BOOLEAN, TRUE,
1636                                 G_TYPE_BOOLEAN, TRUE);
1637   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Right, GDK_SHIFT_MASK,
1638                                 "expand-collapse-cursor-row", 3,
1639                                 G_TYPE_BOOLEAN, FALSE,
1640                                 G_TYPE_BOOLEAN, TRUE,
1641                                 G_TYPE_BOOLEAN, TRUE);
1642   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Right,
1643                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1644                                 "expand-collapse-cursor-row", 3,
1645                                 G_TYPE_BOOLEAN, FALSE,
1646                                 G_TYPE_BOOLEAN, TRUE,
1647                                 G_TYPE_BOOLEAN, TRUE);
1648   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Right,
1649                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1650                                 "expand-collapse-cursor-row", 3,
1651                                 G_TYPE_BOOLEAN, FALSE,
1652                                 G_TYPE_BOOLEAN, TRUE,
1653                                 G_TYPE_BOOLEAN, TRUE);
1654
1655   gtk_binding_entry_add_signal (binding_set, GDK_KEY_minus, 0, "expand-collapse-cursor-row", 3,
1656                                 G_TYPE_BOOLEAN, TRUE,
1657                                 G_TYPE_BOOLEAN, FALSE,
1658                                 G_TYPE_BOOLEAN, FALSE);
1659   gtk_binding_entry_add_signal (binding_set, GDK_KEY_minus, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1660                                 G_TYPE_BOOLEAN, TRUE,
1661                                 G_TYPE_BOOLEAN, FALSE,
1662                                 G_TYPE_BOOLEAN, TRUE);
1663   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Subtract, 0, "expand-collapse-cursor-row", 3,
1664                                 G_TYPE_BOOLEAN, TRUE,
1665                                 G_TYPE_BOOLEAN, FALSE,
1666                                 G_TYPE_BOOLEAN, FALSE);
1667   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Subtract, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1668                                 G_TYPE_BOOLEAN, TRUE,
1669                                 G_TYPE_BOOLEAN, FALSE,
1670                                 G_TYPE_BOOLEAN, TRUE);
1671   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Left, GDK_SHIFT_MASK,
1672                                 "expand-collapse-cursor-row", 3,
1673                                 G_TYPE_BOOLEAN, FALSE,
1674                                 G_TYPE_BOOLEAN, FALSE,
1675                                 G_TYPE_BOOLEAN, TRUE);
1676   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Left, GDK_SHIFT_MASK,
1677                                 "expand-collapse-cursor-row", 3,
1678                                 G_TYPE_BOOLEAN, FALSE,
1679                                 G_TYPE_BOOLEAN, FALSE,
1680                                 G_TYPE_BOOLEAN, TRUE);
1681   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Left,
1682                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1683                                 "expand-collapse-cursor-row", 3,
1684                                 G_TYPE_BOOLEAN, FALSE,
1685                                 G_TYPE_BOOLEAN, FALSE,
1686                                 G_TYPE_BOOLEAN, TRUE);
1687   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Left,
1688                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1689                                 "expand-collapse-cursor-row", 3,
1690                                 G_TYPE_BOOLEAN, FALSE,
1691                                 G_TYPE_BOOLEAN, FALSE,
1692                                 G_TYPE_BOOLEAN, TRUE);
1693
1694   gtk_binding_entry_add_signal (binding_set, GDK_KEY_BackSpace, 0, "select-cursor-parent", 0);
1695   gtk_binding_entry_add_signal (binding_set, GDK_KEY_BackSpace, GDK_CONTROL_MASK, "select-cursor-parent", 0);
1696
1697   gtk_binding_entry_add_signal (binding_set, GDK_KEY_f, GDK_CONTROL_MASK, "start-interactive-search", 0);
1698
1699   gtk_binding_entry_add_signal (binding_set, GDK_KEY_F, GDK_CONTROL_MASK, "start-interactive-search", 0);
1700
1701   g_type_class_add_private (o_class, sizeof (GtkTreeViewPrivate));
1702
1703   gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_TREE_VIEW_ACCESSIBLE);
1704 }
1705
1706 static void
1707 gtk_tree_view_init (GtkTreeView *tree_view)
1708 {
1709   tree_view->priv = G_TYPE_INSTANCE_GET_PRIVATE (tree_view, GTK_TYPE_TREE_VIEW, GtkTreeViewPrivate);
1710
1711   gtk_widget_set_can_focus (GTK_WIDGET (tree_view), TRUE);
1712   gtk_widget_set_redraw_on_allocate (GTK_WIDGET (tree_view), FALSE);
1713
1714   tree_view->priv->show_expanders = TRUE;
1715   tree_view->priv->draw_keyfocus = TRUE;
1716   tree_view->priv->headers_visible = TRUE;
1717
1718   /* We need some padding */
1719   tree_view->priv->dy = 0;
1720   tree_view->priv->cursor_offset = 0;
1721   tree_view->priv->n_columns = 0;
1722   tree_view->priv->header_height = 1;
1723   tree_view->priv->x_drag = 0;
1724   tree_view->priv->drag_pos = -1;
1725   tree_view->priv->header_has_focus = FALSE;
1726   tree_view->priv->pressed_button = -1;
1727   tree_view->priv->press_start_x = -1;
1728   tree_view->priv->press_start_y = -1;
1729   tree_view->priv->reorderable = FALSE;
1730   tree_view->priv->presize_handler_timer = 0;
1731   tree_view->priv->scroll_sync_timer = 0;
1732   tree_view->priv->fixed_height = -1;
1733   tree_view->priv->fixed_height_mode = FALSE;
1734   tree_view->priv->fixed_height_check = 0;
1735   tree_view->priv->selection = _gtk_tree_selection_new_with_tree_view (tree_view);
1736   tree_view->priv->enable_search = TRUE;
1737   tree_view->priv->search_column = -1;
1738   tree_view->priv->search_position_func = gtk_tree_view_search_position_func;
1739   tree_view->priv->search_equal_func = gtk_tree_view_search_equal_func;
1740   tree_view->priv->search_custom_entry_set = FALSE;
1741   tree_view->priv->typeselect_flush_timeout = 0;
1742   tree_view->priv->init_hadjust_value = TRUE;    
1743   tree_view->priv->width = 0;
1744           
1745   tree_view->priv->hover_selection = FALSE;
1746   tree_view->priv->hover_expand = FALSE;
1747
1748   tree_view->priv->level_indentation = 0;
1749
1750   tree_view->priv->rubber_banding_enable = FALSE;
1751
1752   tree_view->priv->grid_lines = GTK_TREE_VIEW_GRID_LINES_NONE;
1753   tree_view->priv->tree_lines_enabled = FALSE;
1754
1755   tree_view->priv->tooltip_column = -1;
1756
1757   tree_view->priv->post_validation_flag = FALSE;
1758
1759   tree_view->priv->last_button_x = -1;
1760   tree_view->priv->last_button_y = -1;
1761
1762   tree_view->priv->event_last_x = -10000;
1763   tree_view->priv->event_last_y = -10000;
1764
1765   gtk_tree_view_do_set_vadjustment (tree_view, NULL);
1766   gtk_tree_view_do_set_hadjustment (tree_view, NULL);
1767
1768   gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (tree_view)),
1769                                GTK_STYLE_CLASS_VIEW);
1770 }
1771
1772 \f
1773
1774 /* GObject Methods
1775  */
1776
1777 static void
1778 gtk_tree_view_set_property (GObject         *object,
1779                             guint            prop_id,
1780                             const GValue    *value,
1781                             GParamSpec      *pspec)
1782 {
1783   GtkTreeView *tree_view;
1784
1785   tree_view = GTK_TREE_VIEW (object);
1786
1787   switch (prop_id)
1788     {
1789     case PROP_MODEL:
1790       gtk_tree_view_set_model (tree_view, g_value_get_object (value));
1791       break;
1792     case PROP_HADJUSTMENT:
1793       gtk_tree_view_do_set_hadjustment (tree_view, g_value_get_object (value));
1794       break;
1795     case PROP_VADJUSTMENT:
1796       gtk_tree_view_do_set_vadjustment (tree_view, g_value_get_object (value));
1797       break;
1798     case PROP_HSCROLL_POLICY:
1799       tree_view->priv->hscroll_policy = g_value_get_enum (value);
1800       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
1801       break;
1802     case PROP_VSCROLL_POLICY:
1803       tree_view->priv->vscroll_policy = g_value_get_enum (value);
1804       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
1805       break;
1806     case PROP_HEADERS_VISIBLE:
1807       gtk_tree_view_set_headers_visible (tree_view, g_value_get_boolean (value));
1808       break;
1809     case PROP_HEADERS_CLICKABLE:
1810       gtk_tree_view_set_headers_clickable (tree_view, g_value_get_boolean (value));
1811       break;
1812     case PROP_EXPANDER_COLUMN:
1813       gtk_tree_view_set_expander_column (tree_view, g_value_get_object (value));
1814       break;
1815     case PROP_REORDERABLE:
1816       gtk_tree_view_set_reorderable (tree_view, g_value_get_boolean (value));
1817       break;
1818     case PROP_RULES_HINT:
1819       gtk_tree_view_set_rules_hint (tree_view, g_value_get_boolean (value));
1820       break;
1821     case PROP_ENABLE_SEARCH:
1822       gtk_tree_view_set_enable_search (tree_view, g_value_get_boolean (value));
1823       break;
1824     case PROP_SEARCH_COLUMN:
1825       gtk_tree_view_set_search_column (tree_view, g_value_get_int (value));
1826       break;
1827     case PROP_FIXED_HEIGHT_MODE:
1828       gtk_tree_view_set_fixed_height_mode (tree_view, g_value_get_boolean (value));
1829       break;
1830     case PROP_HOVER_SELECTION:
1831       tree_view->priv->hover_selection = g_value_get_boolean (value);
1832       break;
1833     case PROP_HOVER_EXPAND:
1834       tree_view->priv->hover_expand = g_value_get_boolean (value);
1835       break;
1836     case PROP_SHOW_EXPANDERS:
1837       gtk_tree_view_set_show_expanders (tree_view, g_value_get_boolean (value));
1838       break;
1839     case PROP_LEVEL_INDENTATION:
1840       tree_view->priv->level_indentation = g_value_get_int (value);
1841       break;
1842     case PROP_RUBBER_BANDING:
1843       tree_view->priv->rubber_banding_enable = g_value_get_boolean (value);
1844       break;
1845     case PROP_ENABLE_GRID_LINES:
1846       gtk_tree_view_set_grid_lines (tree_view, g_value_get_enum (value));
1847       break;
1848     case PROP_ENABLE_TREE_LINES:
1849       gtk_tree_view_set_enable_tree_lines (tree_view, g_value_get_boolean (value));
1850       break;
1851     case PROP_TOOLTIP_COLUMN:
1852       gtk_tree_view_set_tooltip_column (tree_view, g_value_get_int (value));
1853       break;
1854     default:
1855       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1856       break;
1857     }
1858 }
1859
1860 static void
1861 gtk_tree_view_get_property (GObject    *object,
1862                             guint       prop_id,
1863                             GValue     *value,
1864                             GParamSpec *pspec)
1865 {
1866   GtkTreeView *tree_view;
1867
1868   tree_view = GTK_TREE_VIEW (object);
1869
1870   switch (prop_id)
1871     {
1872     case PROP_MODEL:
1873       g_value_set_object (value, tree_view->priv->model);
1874       break;
1875     case PROP_HADJUSTMENT:
1876       g_value_set_object (value, tree_view->priv->hadjustment);
1877       break;
1878     case PROP_VADJUSTMENT:
1879       g_value_set_object (value, tree_view->priv->vadjustment);
1880       break;
1881     case PROP_HSCROLL_POLICY:
1882       g_value_set_enum (value, tree_view->priv->hscroll_policy);
1883       break;
1884     case PROP_VSCROLL_POLICY:
1885       g_value_set_enum (value, tree_view->priv->vscroll_policy);
1886       break;
1887     case PROP_HEADERS_VISIBLE:
1888       g_value_set_boolean (value, gtk_tree_view_get_headers_visible (tree_view));
1889       break;
1890     case PROP_HEADERS_CLICKABLE:
1891       g_value_set_boolean (value, gtk_tree_view_get_headers_clickable (tree_view));
1892       break;
1893     case PROP_EXPANDER_COLUMN:
1894       g_value_set_object (value, tree_view->priv->expander_column);
1895       break;
1896     case PROP_REORDERABLE:
1897       g_value_set_boolean (value, tree_view->priv->reorderable);
1898       break;
1899     case PROP_RULES_HINT:
1900       g_value_set_boolean (value, tree_view->priv->has_rules);
1901       break;
1902     case PROP_ENABLE_SEARCH:
1903       g_value_set_boolean (value, tree_view->priv->enable_search);
1904       break;
1905     case PROP_SEARCH_COLUMN:
1906       g_value_set_int (value, tree_view->priv->search_column);
1907       break;
1908     case PROP_FIXED_HEIGHT_MODE:
1909       g_value_set_boolean (value, tree_view->priv->fixed_height_mode);
1910       break;
1911     case PROP_HOVER_SELECTION:
1912       g_value_set_boolean (value, tree_view->priv->hover_selection);
1913       break;
1914     case PROP_HOVER_EXPAND:
1915       g_value_set_boolean (value, tree_view->priv->hover_expand);
1916       break;
1917     case PROP_SHOW_EXPANDERS:
1918       g_value_set_boolean (value, tree_view->priv->show_expanders);
1919       break;
1920     case PROP_LEVEL_INDENTATION:
1921       g_value_set_int (value, tree_view->priv->level_indentation);
1922       break;
1923     case PROP_RUBBER_BANDING:
1924       g_value_set_boolean (value, tree_view->priv->rubber_banding_enable);
1925       break;
1926     case PROP_ENABLE_GRID_LINES:
1927       g_value_set_enum (value, tree_view->priv->grid_lines);
1928       break;
1929     case PROP_ENABLE_TREE_LINES:
1930       g_value_set_boolean (value, tree_view->priv->tree_lines_enabled);
1931       break;
1932     case PROP_TOOLTIP_COLUMN:
1933       g_value_set_int (value, tree_view->priv->tooltip_column);
1934       break;
1935     default:
1936       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1937       break;
1938     }
1939 }
1940
1941 static void
1942 gtk_tree_view_finalize (GObject *object)
1943 {
1944   G_OBJECT_CLASS (gtk_tree_view_parent_class)->finalize (object);
1945 }
1946
1947
1948 static GtkBuildableIface *parent_buildable_iface;
1949
1950 static void
1951 gtk_tree_view_buildable_init (GtkBuildableIface *iface)
1952 {
1953   parent_buildable_iface = g_type_interface_peek_parent (iface);
1954   iface->add_child = gtk_tree_view_buildable_add_child;
1955   iface->get_internal_child = gtk_tree_view_buildable_get_internal_child;
1956 }
1957
1958 static void
1959 gtk_tree_view_buildable_add_child (GtkBuildable *tree_view,
1960                                    GtkBuilder  *builder,
1961                                    GObject     *child,
1962                                    const gchar *type)
1963 {
1964   gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), GTK_TREE_VIEW_COLUMN (child));
1965 }
1966
1967 static GObject *
1968 gtk_tree_view_buildable_get_internal_child (GtkBuildable      *buildable,
1969                                             GtkBuilder        *builder,
1970                                             const gchar       *childname)
1971 {
1972     if (strcmp (childname, "selection") == 0)
1973       return G_OBJECT (GTK_TREE_VIEW (buildable)->priv->selection);
1974     
1975     return parent_buildable_iface->get_internal_child (buildable,
1976                                                        builder,
1977                                                        childname);
1978 }
1979
1980 /* GtkWidget Methods
1981  */
1982
1983 static void
1984 gtk_tree_view_free_rbtree (GtkTreeView *tree_view)
1985 {
1986   _gtk_rbtree_free (tree_view->priv->tree);
1987   
1988   tree_view->priv->tree = NULL;
1989   tree_view->priv->button_pressed_node = NULL;
1990   tree_view->priv->button_pressed_tree = NULL;
1991   tree_view->priv->prelight_tree = NULL;
1992   tree_view->priv->prelight_node = NULL;
1993   tree_view->priv->expanded_collapsed_node = NULL;
1994   tree_view->priv->expanded_collapsed_tree = NULL;
1995 }
1996
1997 static void
1998 gtk_tree_view_destroy (GtkWidget *widget)
1999 {
2000   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2001   GList *list;
2002
2003   gtk_tree_view_stop_editing (tree_view, TRUE);
2004
2005   if (tree_view->priv->columns != NULL)
2006     {
2007       list = tree_view->priv->columns;
2008       while (list)
2009         {
2010           GtkTreeViewColumn *column;
2011           column = GTK_TREE_VIEW_COLUMN (list->data);
2012           list = list->next;
2013           gtk_tree_view_remove_column (tree_view, column);
2014         }
2015       tree_view->priv->columns = NULL;
2016     }
2017
2018   if (tree_view->priv->tree != NULL)
2019     {
2020       gtk_tree_view_unref_and_check_selection_tree (tree_view, tree_view->priv->tree);
2021
2022       gtk_tree_view_free_rbtree (tree_view);
2023     }
2024
2025   if (tree_view->priv->selection != NULL)
2026     {
2027       _gtk_tree_selection_set_tree_view (tree_view->priv->selection, NULL);
2028       g_object_unref (tree_view->priv->selection);
2029       tree_view->priv->selection = NULL;
2030     }
2031
2032   if (tree_view->priv->scroll_to_path != NULL)
2033     {
2034       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
2035       tree_view->priv->scroll_to_path = NULL;
2036     }
2037
2038   if (tree_view->priv->drag_dest_row != NULL)
2039     {
2040       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
2041       tree_view->priv->drag_dest_row = NULL;
2042     }
2043
2044   if (tree_view->priv->top_row != NULL)
2045     {
2046       gtk_tree_row_reference_free (tree_view->priv->top_row);
2047       tree_view->priv->top_row = NULL;
2048     }
2049
2050   if (tree_view->priv->column_drop_func_data &&
2051       tree_view->priv->column_drop_func_data_destroy)
2052     {
2053       tree_view->priv->column_drop_func_data_destroy (tree_view->priv->column_drop_func_data);
2054       tree_view->priv->column_drop_func_data = NULL;
2055     }
2056
2057   if (tree_view->priv->destroy_count_destroy &&
2058       tree_view->priv->destroy_count_data)
2059     {
2060       tree_view->priv->destroy_count_destroy (tree_view->priv->destroy_count_data);
2061       tree_view->priv->destroy_count_data = NULL;
2062     }
2063
2064   gtk_tree_row_reference_free (tree_view->priv->anchor);
2065   tree_view->priv->anchor = NULL;
2066
2067   /* destroy interactive search dialog */
2068   if (tree_view->priv->search_window)
2069     {
2070       gtk_widget_destroy (tree_view->priv->search_window);
2071       tree_view->priv->search_window = NULL;
2072       tree_view->priv->search_entry = NULL;
2073       if (tree_view->priv->typeselect_flush_timeout)
2074         {
2075           g_source_remove (tree_view->priv->typeselect_flush_timeout);
2076           tree_view->priv->typeselect_flush_timeout = 0;
2077         }
2078     }
2079
2080   if (tree_view->priv->search_destroy && tree_view->priv->search_user_data)
2081     {
2082       tree_view->priv->search_destroy (tree_view->priv->search_user_data);
2083       tree_view->priv->search_user_data = NULL;
2084     }
2085
2086   if (tree_view->priv->search_position_destroy && tree_view->priv->search_position_user_data)
2087     {
2088       tree_view->priv->search_position_destroy (tree_view->priv->search_position_user_data);
2089       tree_view->priv->search_position_user_data = NULL;
2090     }
2091
2092   if (tree_view->priv->row_separator_destroy && tree_view->priv->row_separator_data)
2093     {
2094       tree_view->priv->row_separator_destroy (tree_view->priv->row_separator_data);
2095       tree_view->priv->row_separator_data = NULL;
2096     }
2097   
2098   gtk_tree_view_set_model (tree_view, NULL);
2099
2100   if (tree_view->priv->hadjustment)
2101     {
2102       g_object_unref (tree_view->priv->hadjustment);
2103       tree_view->priv->hadjustment = NULL;
2104     }
2105   if (tree_view->priv->vadjustment)
2106     {
2107       g_object_unref (tree_view->priv->vadjustment);
2108       tree_view->priv->vadjustment = NULL;
2109     }
2110
2111   GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->destroy (widget);
2112 }
2113
2114 /* GtkWidget::map helper */
2115 static void
2116 gtk_tree_view_map_buttons (GtkTreeView *tree_view)
2117 {
2118   GList *list;
2119
2120   g_return_if_fail (gtk_widget_get_mapped (GTK_WIDGET (tree_view)));
2121
2122   if (tree_view->priv->headers_visible)
2123     {
2124       GtkTreeViewColumn *column;
2125       GtkWidget         *button;
2126       GdkWindow         *window;
2127
2128       for (list = tree_view->priv->columns; list; list = list->next)
2129         {
2130           column = list->data;
2131           button = gtk_tree_view_column_get_button (column);
2132
2133           if (gtk_tree_view_column_get_visible (column) && button)
2134             gtk_widget_show_now (button);
2135
2136           if (gtk_widget_get_visible (button) &&
2137               !gtk_widget_get_mapped (button))
2138             gtk_widget_map (button);
2139         }
2140       for (list = tree_view->priv->columns; list; list = list->next)
2141         {
2142           column = list->data;
2143           if (gtk_tree_view_column_get_visible (column) == FALSE)
2144             continue;
2145
2146           window = _gtk_tree_view_column_get_window (column);
2147           if (gtk_tree_view_column_get_resizable (column))
2148             {
2149               gdk_window_raise (window);
2150               gdk_window_show (window);
2151             }
2152           else
2153             gdk_window_hide (window);
2154         }
2155       gdk_window_show (tree_view->priv->header_window);
2156     }
2157 }
2158
2159 static void
2160 gtk_tree_view_map (GtkWidget *widget)
2161 {
2162   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2163   GList *tmp_list;
2164
2165   gtk_widget_set_mapped (widget, TRUE);
2166
2167   tmp_list = tree_view->priv->children;
2168   while (tmp_list)
2169     {
2170       GtkTreeViewChild *child = tmp_list->data;
2171       tmp_list = tmp_list->next;
2172
2173       if (gtk_widget_get_visible (child->widget))
2174         {
2175           if (!gtk_widget_get_mapped (child->widget))
2176             gtk_widget_map (child->widget);
2177         }
2178     }
2179   gdk_window_show (tree_view->priv->bin_window);
2180
2181   gtk_tree_view_map_buttons (tree_view);
2182
2183   gdk_window_show (gtk_widget_get_window (widget));
2184 }
2185
2186 static void
2187 gtk_tree_view_ensure_background (GtkTreeView *tree_view)
2188 {
2189   GtkStyleContext *context;
2190
2191   context = gtk_widget_get_style_context (GTK_WIDGET (tree_view));
2192   gtk_style_context_set_background (context, tree_view->priv->header_window);
2193 }
2194
2195 static void
2196 gtk_tree_view_realize (GtkWidget *widget)
2197 {
2198   GtkAllocation allocation;
2199   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2200   GdkWindow *window;
2201   GdkWindowAttr attributes;
2202   GList *tmp_list;
2203   gint attributes_mask;
2204
2205   gtk_widget_set_realized (widget, TRUE);
2206
2207   gtk_widget_get_allocation (widget, &allocation);
2208
2209   /* Make the main, clipping window */
2210   attributes.window_type = GDK_WINDOW_CHILD;
2211   attributes.x = allocation.x;
2212   attributes.y = allocation.y;
2213   attributes.width = allocation.width;
2214   attributes.height = allocation.height;
2215   attributes.wclass = GDK_INPUT_OUTPUT;
2216   attributes.visual = gtk_widget_get_visual (widget);
2217   attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK;
2218
2219   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
2220
2221   window = gdk_window_new (gtk_widget_get_parent_window (widget),
2222                            &attributes, attributes_mask);
2223   gtk_widget_set_window (widget, window);
2224   gdk_window_set_user_data (window, widget);
2225
2226   gtk_widget_get_allocation (widget, &allocation);
2227
2228   /* Make the window for the tree */
2229   attributes.x = 0;
2230   attributes.y = gtk_tree_view_get_effective_header_height (tree_view);
2231   attributes.width = MAX (tree_view->priv->width, allocation.width);
2232   attributes.height = allocation.height;
2233   attributes.event_mask = (GDK_EXPOSURE_MASK |
2234                            GDK_SCROLL_MASK |
2235                            GDK_SMOOTH_SCROLL_MASK |
2236                            GDK_POINTER_MOTION_MASK |
2237                            GDK_ENTER_NOTIFY_MASK |
2238                            GDK_LEAVE_NOTIFY_MASK |
2239                            GDK_BUTTON_PRESS_MASK |
2240                            GDK_BUTTON_RELEASE_MASK |
2241                            gtk_widget_get_events (widget));
2242
2243   tree_view->priv->bin_window = gdk_window_new (window,
2244                                                 &attributes, attributes_mask);
2245   gdk_window_set_user_data (tree_view->priv->bin_window, widget);
2246
2247   gtk_widget_get_allocation (widget, &allocation);
2248
2249   /* Make the column header window */
2250   attributes.x = 0;
2251   attributes.y = 0;
2252   attributes.width = MAX (tree_view->priv->width, allocation.width);
2253   attributes.height = tree_view->priv->header_height;
2254   attributes.event_mask = (GDK_EXPOSURE_MASK |
2255                            GDK_SCROLL_MASK |
2256                            GDK_ENTER_NOTIFY_MASK |
2257                            GDK_LEAVE_NOTIFY_MASK |
2258                            GDK_BUTTON_PRESS_MASK |
2259                            GDK_BUTTON_RELEASE_MASK |
2260                            GDK_KEY_PRESS_MASK |
2261                            GDK_KEY_RELEASE_MASK |
2262                            gtk_widget_get_events (widget));
2263
2264   tree_view->priv->header_window = gdk_window_new (window,
2265                                                    &attributes, attributes_mask);
2266   gdk_window_set_user_data (tree_view->priv->header_window, widget);
2267
2268   gtk_tree_view_ensure_background (tree_view);
2269
2270   tmp_list = tree_view->priv->children;
2271   while (tmp_list)
2272     {
2273       GtkTreeViewChild *child = tmp_list->data;
2274       tmp_list = tmp_list->next;
2275
2276       gtk_widget_set_parent_window (child->widget, tree_view->priv->bin_window);
2277     }
2278
2279   for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
2280     _gtk_tree_view_column_realize_button (GTK_TREE_VIEW_COLUMN (tmp_list->data));
2281
2282   /* Need to call those here, since they create GCs */
2283   gtk_tree_view_set_grid_lines (tree_view, tree_view->priv->grid_lines);
2284   gtk_tree_view_set_enable_tree_lines (tree_view, tree_view->priv->tree_lines_enabled);
2285
2286   install_presize_handler (tree_view); 
2287 }
2288
2289 static void
2290 gtk_tree_view_unrealize (GtkWidget *widget)
2291 {
2292   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2293   GtkTreeViewPrivate *priv = tree_view->priv;
2294   GList *list;
2295
2296   if (priv->scroll_timeout != 0)
2297     {
2298       g_source_remove (priv->scroll_timeout);
2299       priv->scroll_timeout = 0;
2300     }
2301
2302   if (priv->auto_expand_timeout != 0)
2303     {
2304       g_source_remove (priv->auto_expand_timeout);
2305       priv->auto_expand_timeout = 0;
2306     }
2307
2308   if (priv->open_dest_timeout != 0)
2309     {
2310       g_source_remove (priv->open_dest_timeout);
2311       priv->open_dest_timeout = 0;
2312     }
2313
2314   if (priv->presize_handler_timer != 0)
2315     {
2316       g_source_remove (priv->presize_handler_timer);
2317       priv->presize_handler_timer = 0;
2318     }
2319
2320   if (priv->validate_rows_timer != 0)
2321     {
2322       g_source_remove (priv->validate_rows_timer);
2323       priv->validate_rows_timer = 0;
2324     }
2325
2326   if (priv->scroll_sync_timer != 0)
2327     {
2328       g_source_remove (priv->scroll_sync_timer);
2329       priv->scroll_sync_timer = 0;
2330     }
2331
2332   if (priv->typeselect_flush_timeout)
2333     {
2334       g_source_remove (priv->typeselect_flush_timeout);
2335       priv->typeselect_flush_timeout = 0;
2336     }
2337   
2338   for (list = priv->columns; list; list = list->next)
2339     _gtk_tree_view_column_unrealize_button (GTK_TREE_VIEW_COLUMN (list->data));
2340
2341   gdk_window_set_user_data (priv->bin_window, NULL);
2342   gdk_window_destroy (priv->bin_window);
2343   priv->bin_window = NULL;
2344
2345   gdk_window_set_user_data (priv->header_window, NULL);
2346   gdk_window_destroy (priv->header_window);
2347   priv->header_window = NULL;
2348
2349   if (priv->drag_window)
2350     {
2351       gdk_window_set_user_data (priv->drag_window, NULL);
2352       gdk_window_destroy (priv->drag_window);
2353       priv->drag_window = NULL;
2354     }
2355
2356   if (priv->drag_highlight_window)
2357     {
2358       gdk_window_set_user_data (priv->drag_highlight_window, NULL);
2359       gdk_window_destroy (priv->drag_highlight_window);
2360       priv->drag_highlight_window = NULL;
2361     }
2362
2363   GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->unrealize (widget);
2364 }
2365
2366 /* GtkWidget::get_preferred_height helper */
2367 static void
2368 gtk_tree_view_update_height (GtkTreeView *tree_view)
2369 {
2370   GList *list;
2371
2372   tree_view->priv->header_height = 0;
2373
2374   for (list = tree_view->priv->columns; list; list = list->next)
2375     {
2376       GtkRequisition     requisition;
2377       GtkTreeViewColumn *column = list->data;
2378       GtkWidget         *button = gtk_tree_view_column_get_button (column);
2379
2380       if (button == NULL)
2381         continue;
2382
2383       gtk_widget_get_preferred_size (button, &requisition, NULL);
2384       tree_view->priv->header_height = MAX (tree_view->priv->header_height, requisition.height);
2385     }
2386
2387   if (tree_view->priv->tree == NULL)
2388     tree_view->priv->height = 0;
2389   else
2390     tree_view->priv->height = tree_view->priv->tree->root->offset;
2391 }
2392
2393 static void
2394 gtk_tree_view_get_preferred_width (GtkWidget *widget,
2395                                    gint      *minimum,
2396                                    gint      *natural)
2397 {
2398   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2399   GList *list;
2400   GtkTreeViewColumn *column;
2401   gint width = 0;
2402
2403   /* we validate some rows initially just to make sure we have some size.
2404    * In practice, with a lot of static lists, this should get a good width.
2405    */
2406   do_validate_rows (tree_view, FALSE);
2407
2408   /* keep this in sync with size_allocate below */
2409   for (list = tree_view->priv->columns; list; list = list->next)
2410     {
2411       column = list->data;
2412       if (!gtk_tree_view_column_get_visible (column))
2413         continue;
2414
2415       width += _gtk_tree_view_column_request_width (column);
2416     }
2417
2418   *minimum = *natural = width;
2419 }
2420
2421 static void
2422 gtk_tree_view_get_preferred_height (GtkWidget *widget,
2423                                     gint      *minimum,
2424                                     gint      *natural)
2425 {
2426   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2427   gint height;
2428
2429   gtk_tree_view_update_height (tree_view);
2430
2431   height = tree_view->priv->height + gtk_tree_view_get_effective_header_height (tree_view);
2432
2433   *minimum = *natural = height;
2434 }
2435
2436 static int
2437 gtk_tree_view_calculate_width_before_expander (GtkTreeView *tree_view)
2438 {
2439   int width = 0;
2440   GList *list;
2441   gboolean rtl;
2442
2443   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2444   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
2445        list->data != tree_view->priv->expander_column;
2446        list = (rtl ? list->prev : list->next))
2447     {
2448       GtkTreeViewColumn *column = list->data;
2449
2450       width += gtk_tree_view_column_get_width (column);
2451     }
2452
2453   return width;
2454 }
2455
2456 /* GtkWidget::size_allocate helper */
2457 static void
2458 gtk_tree_view_size_allocate_columns (GtkWidget *widget,
2459                                      gboolean  *width_changed)
2460 {
2461   GtkTreeView *tree_view;
2462   GList *list, *first_column, *last_column;
2463   GtkTreeViewColumn *column;
2464   GtkAllocation widget_allocation;
2465   gint width = 0;
2466   gint extra, extra_per_column, extra_for_last;
2467   gint full_requested_width = 0;
2468   gint number_of_expand_columns = 0;
2469   gboolean rtl;
2470   gboolean update_expand;
2471   
2472   tree_view = GTK_TREE_VIEW (widget);
2473
2474   for (last_column = g_list_last (tree_view->priv->columns);
2475        last_column &&
2476        !(gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (last_column->data)));
2477        last_column = last_column->prev)
2478     ;
2479   if (last_column == NULL)
2480     return;
2481
2482   for (first_column = g_list_first (tree_view->priv->columns);
2483        first_column &&
2484        !(gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (first_column->data)));
2485        first_column = first_column->next)
2486     ;
2487
2488   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
2489
2490   /* find out how many extra space and expandable columns we have */
2491   for (list = tree_view->priv->columns; list != last_column->next; list = list->next)
2492     {
2493       column = (GtkTreeViewColumn *)list->data;
2494
2495       if (!gtk_tree_view_column_get_visible (column))
2496         continue;
2497
2498       full_requested_width += _gtk_tree_view_column_request_width (column);
2499
2500       if (gtk_tree_view_column_get_expand (column))
2501         number_of_expand_columns++;
2502     }
2503
2504   /* Only update the expand value if the width of the widget has changed,
2505    * or the number of expand columns has changed, or if there are no expand
2506    * columns, or if we didn't have an size-allocation yet after the
2507    * last validated node.
2508    */
2509   update_expand = (width_changed && *width_changed == TRUE)
2510       || number_of_expand_columns != tree_view->priv->last_number_of_expand_columns
2511       || number_of_expand_columns == 0
2512       || tree_view->priv->post_validation_flag == TRUE;
2513
2514   tree_view->priv->post_validation_flag = FALSE;
2515
2516   gtk_widget_get_allocation (widget, &widget_allocation);
2517   if (!update_expand)
2518     {
2519       extra = tree_view->priv->last_extra_space;
2520       extra_for_last = MAX (widget_allocation.width - full_requested_width - extra, 0);
2521     }
2522   else
2523     {
2524       extra = MAX (widget_allocation.width - full_requested_width, 0);
2525       extra_for_last = 0;
2526
2527       tree_view->priv->last_extra_space = extra;
2528     }
2529
2530   if (number_of_expand_columns > 0)
2531     extra_per_column = extra/number_of_expand_columns;
2532   else
2533     extra_per_column = 0;
2534
2535   if (update_expand)
2536     {
2537       tree_view->priv->last_extra_space_per_column = extra_per_column;
2538       tree_view->priv->last_number_of_expand_columns = number_of_expand_columns;
2539     }
2540
2541   for (list = (rtl ? last_column : first_column); 
2542        list != (rtl ? first_column->prev : last_column->next);
2543        list = (rtl ? list->prev : list->next)) 
2544     {
2545       gint column_width;
2546
2547       column = list->data;
2548
2549       if (!gtk_tree_view_column_get_visible (column))
2550         continue;
2551
2552       /* We need to handle the dragged button specially.
2553        */
2554       if (column == tree_view->priv->drag_column)
2555         {
2556           GtkAllocation drag_allocation;
2557           GtkWidget    *button;
2558
2559           button = gtk_tree_view_column_get_button (tree_view->priv->drag_column);
2560
2561           drag_allocation.x = 0;
2562           drag_allocation.y = 0;
2563           drag_allocation.width = gdk_window_get_width (tree_view->priv->drag_window);
2564           drag_allocation.height = gdk_window_get_height (tree_view->priv->drag_window);
2565           gtk_widget_size_allocate (button, &drag_allocation);
2566           width += drag_allocation.width;
2567           continue;
2568         }
2569
2570       column_width = _gtk_tree_view_column_request_width (column);
2571
2572       if (gtk_tree_view_column_get_expand (column))
2573         {
2574           if (number_of_expand_columns == 1)
2575             {
2576               /* We add the remander to the last column as
2577                * */
2578               column_width += extra;
2579             }
2580           else
2581             {
2582               column_width += extra_per_column;
2583               extra -= extra_per_column;
2584               number_of_expand_columns --;
2585             }
2586         }
2587       else if (number_of_expand_columns == 0 &&
2588                list == last_column)
2589         {
2590           column_width += extra;
2591         }
2592
2593       /* In addition to expand, the last column can get even more
2594        * extra space so all available space is filled up.
2595        */
2596       if (extra_for_last > 0 && list == last_column)
2597         column_width += extra_for_last;
2598
2599       _gtk_tree_view_column_allocate (column, width, column_width);
2600
2601       width += column_width;
2602     }
2603
2604   /* We change the width here.  The user might have been resizing columns,
2605    * which changes the total width of the tree view.  This is of
2606    * importance for getting the horizontal scroll bar right.
2607    */
2608   if (tree_view->priv->width != width)
2609     {
2610       tree_view->priv->width = width;
2611       if (width_changed)
2612         *width_changed = TRUE;
2613     }
2614 }
2615
2616
2617 static void
2618 gtk_tree_view_size_allocate (GtkWidget     *widget,
2619                              GtkAllocation *allocation)
2620 {
2621   GtkAllocation widget_allocation;
2622   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2623   GList *tmp_list;
2624   gboolean width_changed = FALSE;
2625   gint old_width;
2626
2627   gtk_widget_get_allocation (widget, &widget_allocation);
2628   old_width = widget_allocation.width;
2629   if (allocation->width != widget_allocation.width)
2630     width_changed = TRUE;
2631
2632   gtk_widget_set_allocation (widget, allocation);
2633
2634   tmp_list = tree_view->priv->children;
2635
2636   while (tmp_list)
2637     {
2638       GtkAllocation allocation;
2639
2640       GtkTreeViewChild *child = tmp_list->data;
2641       tmp_list = tmp_list->next;
2642
2643       /* totally ignore our child's requisition */
2644       allocation.x = child->x;
2645       allocation.y = child->y;
2646       allocation.width = child->width;
2647       allocation.height = child->height;
2648       gtk_widget_size_allocate (child->widget, &allocation);
2649     }
2650
2651   /* We size-allocate the columns first because the width of the
2652    * tree view (used in updating the adjustments below) might change.
2653    */
2654   gtk_tree_view_size_allocate_columns (widget, &width_changed);
2655
2656   g_object_freeze_notify (G_OBJECT (tree_view->priv->hadjustment));
2657   gtk_adjustment_set_page_size (tree_view->priv->hadjustment,
2658                                 allocation->width);
2659   gtk_adjustment_set_page_increment (tree_view->priv->hadjustment,
2660                                      allocation->width * 0.9);
2661   gtk_adjustment_set_step_increment (tree_view->priv->hadjustment,
2662                                      allocation->width * 0.1);
2663   gtk_adjustment_set_lower (tree_view->priv->hadjustment, 0);
2664   gtk_adjustment_set_upper (tree_view->priv->hadjustment,
2665                             MAX (gtk_adjustment_get_page_size (tree_view->priv->hadjustment),
2666                                  tree_view->priv->width));
2667   g_object_thaw_notify (G_OBJECT (tree_view->priv->hadjustment));
2668
2669   if (gtk_widget_get_direction(widget) == GTK_TEXT_DIR_RTL)   
2670     {
2671       if (allocation->width < tree_view->priv->width)
2672         {
2673           if (tree_view->priv->init_hadjust_value)
2674             {
2675               gtk_adjustment_set_value (tree_view->priv->hadjustment,
2676                                         MAX (tree_view->priv->width -
2677                                              allocation->width, 0));
2678               tree_view->priv->init_hadjust_value = FALSE;
2679             }
2680           else if (allocation->width != old_width)
2681             {
2682               gtk_adjustment_set_value (tree_view->priv->hadjustment,
2683                                         CLAMP (gtk_adjustment_get_value (tree_view->priv->hadjustment) - allocation->width + old_width,
2684                                                0,
2685                                                tree_view->priv->width - allocation->width));
2686             }
2687         }
2688       else
2689         {
2690           gtk_adjustment_set_value (tree_view->priv->hadjustment, 0);
2691           tree_view->priv->init_hadjust_value = TRUE;
2692         }
2693     }
2694   else
2695     if (gtk_adjustment_get_value (tree_view->priv->hadjustment) + allocation->width > tree_view->priv->width)
2696       gtk_adjustment_set_value (tree_view->priv->hadjustment,
2697                                 MAX (tree_view->priv->width -
2698                                      allocation->width, 0));
2699
2700   g_object_freeze_notify (G_OBJECT (tree_view->priv->vadjustment));
2701   gtk_adjustment_set_page_size (tree_view->priv->vadjustment,
2702                                 allocation->height -
2703                                 gtk_tree_view_get_effective_header_height (tree_view));
2704   gtk_adjustment_set_step_increment (tree_view->priv->vadjustment,
2705                                      gtk_adjustment_get_page_size (tree_view->priv->vadjustment) * 0.1);
2706   gtk_adjustment_set_page_increment (tree_view->priv->vadjustment,
2707                                      gtk_adjustment_get_page_size (tree_view->priv->vadjustment) * 0.9);
2708   gtk_adjustment_set_lower (tree_view->priv->vadjustment, 0);
2709   gtk_adjustment_set_upper (tree_view->priv->vadjustment,
2710                             MAX (gtk_adjustment_get_page_size (tree_view->priv->vadjustment),
2711                                  tree_view->priv->height));
2712   g_object_thaw_notify (G_OBJECT (tree_view->priv->vadjustment));
2713
2714   /* now the adjustments and window sizes are in sync, we can sync toprow/dy again */
2715   if (tree_view->priv->height <= gtk_adjustment_get_page_size (tree_view->priv->vadjustment))
2716     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
2717   else if (gtk_adjustment_get_value (tree_view->priv->vadjustment) + gtk_adjustment_get_page_size (tree_view->priv->vadjustment) > tree_view->priv->height)
2718     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment),
2719                               tree_view->priv->height - gtk_adjustment_get_page_size (tree_view->priv->vadjustment));
2720   else if (gtk_tree_row_reference_valid (tree_view->priv->top_row))
2721     gtk_tree_view_top_row_to_dy (tree_view);
2722   else
2723     gtk_tree_view_dy_to_top_row (tree_view);
2724   
2725   if (gtk_widget_get_realized (widget))
2726     {
2727       gdk_window_move_resize (gtk_widget_get_window (widget),
2728                               allocation->x, allocation->y,
2729                               allocation->width, allocation->height);
2730       gdk_window_move_resize (tree_view->priv->header_window,
2731                               - (gint) gtk_adjustment_get_value (tree_view->priv->hadjustment),
2732                               0,
2733                               MAX (tree_view->priv->width, allocation->width),
2734                               tree_view->priv->header_height);
2735       gdk_window_move_resize (tree_view->priv->bin_window,
2736                               - (gint) gtk_adjustment_get_value (tree_view->priv->hadjustment),
2737                               gtk_tree_view_get_effective_header_height (tree_view),
2738                               MAX (tree_view->priv->width, allocation->width),
2739                               allocation->height - gtk_tree_view_get_effective_header_height (tree_view));
2740
2741       if (tree_view->priv->tree == NULL)
2742         invalidate_empty_focus (tree_view);
2743
2744       if (width_changed && tree_view->priv->expander_column)
2745         {
2746           /* Might seem awkward, but is the best heuristic I could come up
2747            * with.  Only if the width of the columns before the expander
2748            * changes, we will update the prelight status.  It is this
2749            * width that makes the expander move vertically.  Always updating
2750            * prelight status causes trouble with hover selections.
2751            */
2752           gint width_before_expander;
2753
2754           width_before_expander = gtk_tree_view_calculate_width_before_expander (tree_view);
2755
2756           if (tree_view->priv->prev_width_before_expander
2757               != width_before_expander)
2758               update_prelight (tree_view,
2759                                tree_view->priv->event_last_x,
2760                                tree_view->priv->event_last_y);
2761
2762           tree_view->priv->prev_width_before_expander = width_before_expander;
2763         }
2764     }
2765 }
2766
2767 /* Grabs the focus and unsets the GTK_TREE_VIEW_DRAW_KEYFOCUS flag */
2768 static void
2769 grab_focus_and_unset_draw_keyfocus (GtkTreeView *tree_view)
2770 {
2771   GtkWidget *widget = GTK_WIDGET (tree_view);
2772
2773   if (gtk_widget_get_can_focus (widget) && !gtk_widget_has_focus (widget))
2774     gtk_widget_grab_focus (widget);
2775   tree_view->priv->draw_keyfocus = 0;
2776 }
2777
2778 static inline gboolean
2779 row_is_separator (GtkTreeView *tree_view,
2780                   GtkTreeIter *iter,
2781                   GtkTreePath *path)
2782 {
2783   gboolean is_separator = FALSE;
2784
2785   if (tree_view->priv->row_separator_func)
2786     {
2787       GtkTreeIter tmpiter;
2788
2789       if (iter)
2790         tmpiter = *iter;
2791       else
2792         {
2793           if (!gtk_tree_model_get_iter (tree_view->priv->model, &tmpiter, path))
2794             return FALSE;
2795         }
2796
2797       is_separator = tree_view->priv->row_separator_func (tree_view->priv->model,
2798                                                           &tmpiter,
2799                                                           tree_view->priv->row_separator_data);
2800     }
2801
2802   return is_separator;
2803 }
2804
2805 static int
2806 gtk_tree_view_get_expander_size (GtkTreeView *tree_view)
2807 {
2808   gint expander_size;
2809
2810   gtk_widget_style_get (GTK_WIDGET (tree_view),
2811                         "expander-size", &expander_size,
2812                         NULL);
2813   expander_size += EXPANDER_EXTRA_PADDING;
2814
2815   return expander_size;
2816 }
2817
2818 static gboolean
2819 gtk_tree_view_button_press (GtkWidget      *widget,
2820                             GdkEventButton *event)
2821 {
2822   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2823   GList *list;
2824   GtkTreeViewColumn *column = NULL;
2825   gint i;
2826   GdkRectangle background_area;
2827   GdkRectangle cell_area;
2828   gint vertical_separator;
2829   gint horizontal_separator;
2830   gboolean path_is_selectable;
2831   gboolean rtl;
2832
2833   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
2834   gtk_tree_view_stop_editing (tree_view, FALSE);
2835   gtk_widget_style_get (widget,
2836                         "vertical-separator", &vertical_separator,
2837                         "horizontal-separator", &horizontal_separator,
2838                         NULL);
2839
2840   /* Don't handle extra mouse buttons events, let them bubble up */
2841   if (event->button > 5)
2842     return FALSE;
2843  
2844   /* Because grab_focus can cause reentrancy, we delay grab_focus until after
2845    * we're done handling the button press.
2846    */
2847
2848   if (event->window == tree_view->priv->bin_window)
2849     {
2850       GtkRBNode *node;
2851       GtkRBTree *tree;
2852       GtkTreePath *path;
2853       gint depth;
2854       gint new_y;
2855       gint y_offset;
2856       gint dval;
2857       gint pre_val, aft_val;
2858       GtkTreeViewColumn *column = NULL;
2859       gint column_handled_click = FALSE;
2860       gboolean row_double_click = FALSE;
2861       gboolean rtl;
2862       gboolean node_selected;
2863       GdkModifierType extend_mod_mask;
2864       GdkModifierType modify_mod_mask;
2865
2866       /* Empty tree? */
2867       if (tree_view->priv->tree == NULL)
2868         {
2869           grab_focus_and_unset_draw_keyfocus (tree_view);
2870           return TRUE;
2871         }
2872
2873       /* are we in an arrow? */
2874       if (tree_view->priv->prelight_node &&
2875           tree_view->priv->arrow_prelit &&
2876           gtk_tree_view_draw_expanders (tree_view))
2877         {
2878           if (event->button == GDK_BUTTON_PRIMARY)
2879             {
2880               gtk_grab_add (widget);
2881               tree_view->priv->button_pressed_node = tree_view->priv->prelight_node;
2882               tree_view->priv->button_pressed_tree = tree_view->priv->prelight_tree;
2883               gtk_tree_view_queue_draw_arrow (GTK_TREE_VIEW (widget),
2884                                               tree_view->priv->prelight_tree,
2885                                               tree_view->priv->prelight_node);
2886             }
2887
2888           grab_focus_and_unset_draw_keyfocus (tree_view);
2889           return TRUE;
2890         }
2891
2892       /* find the node that was clicked */
2893       new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
2894       if (new_y < 0)
2895         new_y = 0;
2896       y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
2897
2898       if (node == NULL)
2899         {
2900           /* We clicked in dead space */
2901           grab_focus_and_unset_draw_keyfocus (tree_view);
2902           return TRUE;
2903         }
2904
2905       /* Get the path and the node */
2906       path = _gtk_tree_path_new_from_rbtree (tree, node);
2907       path_is_selectable = !row_is_separator (tree_view, NULL, path);
2908
2909       if (!path_is_selectable)
2910         {
2911           gtk_tree_path_free (path);
2912           grab_focus_and_unset_draw_keyfocus (tree_view);
2913           return TRUE;
2914         }
2915
2916       depth = gtk_tree_path_get_depth (path);
2917       background_area.y = y_offset + event->y;
2918       background_area.height = gtk_tree_view_get_row_height (tree_view, node);
2919       background_area.x = 0;
2920
2921
2922       /* Let the column have a chance at selecting it. */
2923       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2924       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
2925            list; list = (rtl ? list->prev : list->next))
2926         {
2927           GtkTreeViewColumn *candidate = list->data;
2928
2929           if (!gtk_tree_view_column_get_visible (candidate))
2930             continue;
2931
2932           background_area.width = gtk_tree_view_column_get_width (candidate);
2933           if ((background_area.x > (gint) event->x) ||
2934               (background_area.x + background_area.width <= (gint) event->x))
2935             {
2936               background_area.x += background_area.width;
2937               continue;
2938             }
2939
2940           /* we found the focus column */
2941           column = candidate;
2942           cell_area = background_area;
2943           cell_area.width -= horizontal_separator;
2944           cell_area.height -= vertical_separator;
2945           cell_area.x += horizontal_separator/2;
2946           cell_area.y += vertical_separator/2;
2947           if (gtk_tree_view_is_expander_column (tree_view, column))
2948             {
2949               if (!rtl)
2950                 cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
2951               cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
2952
2953               if (gtk_tree_view_draw_expanders (tree_view))
2954                 {
2955                   gint expander_size = gtk_tree_view_get_expander_size (tree_view);
2956                   if (!rtl)
2957                     cell_area.x += depth * expander_size;
2958                   cell_area.width -= depth * expander_size;
2959                 }
2960             }
2961           break;
2962         }
2963
2964       if (column == NULL)
2965         {
2966           gtk_tree_path_free (path);
2967           grab_focus_and_unset_draw_keyfocus (tree_view);
2968           return FALSE;
2969         }
2970
2971       _gtk_tree_view_set_focus_column (tree_view, column);
2972
2973       /* decide if we edit */
2974       if (event->type == GDK_BUTTON_PRESS && event->button == GDK_BUTTON_PRIMARY &&
2975           !(event->state & gtk_accelerator_get_default_mod_mask ()))
2976         {
2977           GtkTreePath *anchor;
2978           GtkTreeIter iter;
2979
2980           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
2981           gtk_tree_view_column_cell_set_cell_data (column,
2982                                                    tree_view->priv->model,
2983                                                    &iter,
2984                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
2985                                                    node->children?TRUE:FALSE);
2986
2987           if (tree_view->priv->anchor)
2988             anchor = gtk_tree_row_reference_get_path (tree_view->priv->anchor);
2989           else
2990             anchor = NULL;
2991
2992           if ((anchor && !gtk_tree_path_compare (anchor, path))
2993               || !_gtk_tree_view_column_has_editable_cell (column))
2994             {
2995               GtkCellEditable *cell_editable = NULL;
2996
2997               /* FIXME: get the right flags */
2998               guint flags = 0;
2999
3000               if (_gtk_tree_view_column_cell_event (column,
3001                                                     (GdkEvent *)event,
3002                                                     &cell_area, flags))
3003                 {
3004                   GtkCellArea *area = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (column));
3005                   cell_editable = gtk_cell_area_get_edit_widget (area);
3006
3007                   if (cell_editable != NULL)
3008                     {
3009                       gtk_tree_path_free (path);
3010                       gtk_tree_path_free (anchor);
3011                       return TRUE;
3012                     }
3013                   column_handled_click = TRUE;
3014                 }
3015             }
3016           if (anchor)
3017             gtk_tree_path_free (anchor);
3018         }
3019
3020       extend_mod_mask =
3021         gtk_widget_get_modifier_mask (widget, GDK_MODIFIER_INTENT_EXTEND_SELECTION);
3022
3023       modify_mod_mask =
3024         gtk_widget_get_modifier_mask (widget, GDK_MODIFIER_INTENT_MODIFY_SELECTION);
3025
3026       /* select */
3027       node_selected = GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED);
3028       pre_val = gtk_adjustment_get_value (tree_view->priv->vadjustment);
3029
3030       /* we only handle selection modifications on the first button press
3031        */
3032       if (event->type == GDK_BUTTON_PRESS)
3033         {
3034           GtkCellRenderer *focus_cell;
3035
3036           if ((event->state & modify_mod_mask) == modify_mod_mask)
3037             tree_view->priv->modify_selection_pressed = TRUE;
3038           if ((event->state & extend_mod_mask) == extend_mod_mask)
3039             tree_view->priv->extend_selection_pressed = TRUE;
3040
3041           /* We update the focus cell here, this is also needed if the
3042            * column does not contain an editable cell.  In this case,
3043            * GtkCellArea did not receive the event for processing (and
3044            * could not update the focus cell).
3045            */
3046           focus_cell = _gtk_tree_view_column_get_cell_at_pos (column,
3047                                                               &cell_area,
3048                                                               &background_area,
3049                                                               event->x,
3050                                                               event->y);
3051
3052           if (focus_cell)
3053             gtk_tree_view_column_focus_cell (column, focus_cell);
3054
3055           if (event->state & modify_mod_mask)
3056             {
3057               gtk_tree_view_real_set_cursor (tree_view, path, CLAMP_NODE);
3058               gtk_tree_view_real_toggle_cursor_row (tree_view);
3059             }
3060           else if (event->state & extend_mod_mask)
3061             {
3062               gtk_tree_view_real_set_cursor (tree_view, path, CLAMP_NODE);
3063               gtk_tree_view_real_select_cursor_row (tree_view, FALSE);
3064             }
3065           else
3066             {
3067               gtk_tree_view_real_set_cursor (tree_view, path, CLEAR_AND_SELECT | CLAMP_NODE);
3068             }
3069
3070           tree_view->priv->modify_selection_pressed = FALSE;
3071           tree_view->priv->extend_selection_pressed = FALSE;
3072         }
3073
3074       /* the treeview may have been scrolled because of _set_cursor,
3075        * correct here
3076        */
3077
3078       aft_val = gtk_adjustment_get_value (tree_view->priv->vadjustment);
3079       dval = pre_val - aft_val;
3080
3081       cell_area.y += dval;
3082       background_area.y += dval;
3083
3084       /* Save press to possibly begin a drag
3085        */
3086       if (!column_handled_click &&
3087           !tree_view->priv->in_grab &&
3088           tree_view->priv->pressed_button < 0)
3089         {
3090           tree_view->priv->pressed_button = event->button;
3091           tree_view->priv->press_start_x = event->x;
3092           tree_view->priv->press_start_y = event->y;
3093
3094           if (tree_view->priv->rubber_banding_enable
3095               && !node_selected
3096               && gtk_tree_selection_get_mode (tree_view->priv->selection) == GTK_SELECTION_MULTIPLE)
3097             {
3098               tree_view->priv->press_start_y += tree_view->priv->dy;
3099               tree_view->priv->rubber_band_x = event->x;
3100               tree_view->priv->rubber_band_y = event->y + tree_view->priv->dy;
3101               tree_view->priv->rubber_band_status = RUBBER_BAND_MAYBE_START;
3102
3103               if ((event->state & modify_mod_mask) == modify_mod_mask)
3104                 tree_view->priv->rubber_band_modify = TRUE;
3105               if ((event->state & extend_mod_mask) == extend_mod_mask)
3106                 tree_view->priv->rubber_band_extend = TRUE;
3107             }
3108         }
3109
3110       /* Test if a double click happened on the same row. */
3111       if (event->button == GDK_BUTTON_PRIMARY && event->type == GDK_BUTTON_PRESS)
3112         {
3113           int double_click_time, double_click_distance;
3114
3115           g_object_get (gtk_settings_get_default (),
3116                         "gtk-double-click-time", &double_click_time,
3117                         "gtk-double-click-distance", &double_click_distance,
3118                         NULL);
3119
3120           /* Same conditions as _gdk_event_button_generate */
3121           if (tree_view->priv->last_button_x != -1 &&
3122               (event->time < tree_view->priv->last_button_time + double_click_time) &&
3123               (ABS (event->x - tree_view->priv->last_button_x) <= double_click_distance) &&
3124               (ABS (event->y - tree_view->priv->last_button_y) <= double_click_distance))
3125             {
3126               /* We do no longer compare paths of this row and the
3127                * row clicked previously.  We use the double click
3128                * distance to decide whether this is a valid click,
3129                * allowing the mouse to slightly move over another row.
3130                */
3131               row_double_click = TRUE;
3132
3133               tree_view->priv->last_button_time = 0;
3134               tree_view->priv->last_button_x = -1;
3135               tree_view->priv->last_button_y = -1;
3136             }
3137           else
3138             {
3139               tree_view->priv->last_button_time = event->time;
3140               tree_view->priv->last_button_x = event->x;
3141               tree_view->priv->last_button_y = event->y;
3142             }
3143         }
3144
3145       if (row_double_click)
3146         {
3147           gtk_grab_remove (widget);
3148           gtk_tree_view_row_activated (tree_view, path, column);
3149
3150           if (tree_view->priv->pressed_button == event->button)
3151             tree_view->priv->pressed_button = -1;
3152         }
3153
3154       gtk_tree_path_free (path);
3155
3156       /* If we activated the row through a double click we don't want to grab
3157        * focus back, as moving focus to another widget is pretty common.
3158        */
3159       if (!row_double_click)
3160         grab_focus_and_unset_draw_keyfocus (tree_view);
3161
3162       return TRUE;
3163     }
3164
3165   /* We didn't click in the window.  Let's check to see if we clicked on a column resize window.
3166    */
3167   for (i = 0, list = tree_view->priv->columns; list; list = list->next, i++)
3168     {
3169       column = list->data;
3170       if (event->window == _gtk_tree_view_column_get_window (column) &&
3171           gtk_tree_view_column_get_resizable (column) &&
3172           _gtk_tree_view_column_get_window (column))
3173         {
3174           gpointer drag_data;
3175
3176           if (event->type == GDK_2BUTTON_PRESS &&
3177               gtk_tree_view_column_get_sizing (column) != GTK_TREE_VIEW_COLUMN_AUTOSIZE)
3178             {
3179               _gtk_tree_view_column_set_use_resized_width (column, FALSE);
3180               _gtk_tree_view_column_autosize (tree_view, column);
3181               return TRUE;
3182             }
3183
3184           if (gdk_device_grab (gdk_event_get_device ((GdkEvent*)event),
3185                                _gtk_tree_view_column_get_window (column),
3186                                GDK_OWNERSHIP_NONE,
3187                                FALSE,
3188                                GDK_POINTER_MOTION_HINT_MASK
3189                                 | GDK_BUTTON1_MOTION_MASK
3190                                 | GDK_BUTTON_RELEASE_MASK,
3191                                NULL,
3192                                event->time) != GDK_GRAB_SUCCESS)
3193             return FALSE;
3194
3195           gtk_grab_add (widget);
3196           tree_view->priv->in_column_resize = TRUE;
3197
3198           _gtk_tree_view_column_set_resized_width (column, gtk_tree_view_column_get_width (column) -
3199                                                    tree_view->priv->last_extra_space_per_column);
3200
3201           /* block attached dnd signal handler */
3202           drag_data = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
3203           if (drag_data)
3204             g_signal_handlers_block_matched (widget,
3205                                              G_SIGNAL_MATCH_DATA,
3206                                              0, 0, NULL, NULL,
3207                                              drag_data);
3208
3209           tree_view->priv->drag_pos = i;
3210           tree_view->priv->x_drag = gtk_tree_view_column_get_x_offset (column) + (rtl ? 0 : gtk_tree_view_column_get_width (column));
3211
3212           if (!gtk_widget_has_focus (widget))
3213             gtk_widget_grab_focus (widget);
3214
3215           return TRUE;
3216         }
3217     }
3218   return FALSE;
3219 }
3220
3221 /* GtkWidget::button_release_event helper */
3222 static gboolean
3223 gtk_tree_view_button_release_drag_column (GtkWidget      *widget,
3224                                           GdkEventButton *event)
3225 {
3226   GtkTreeView *tree_view;
3227   GtkWidget *button;
3228   GList *l;
3229   gboolean rtl;
3230   GdkDevice *device, *other;
3231   GtkStyleContext *context;
3232
3233   tree_view = GTK_TREE_VIEW (widget);
3234
3235   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
3236   device = gdk_event_get_device ((GdkEvent*)event);
3237   other = gdk_device_get_associated_device (device);
3238   gdk_device_ungrab (device, event->time);
3239   gdk_device_ungrab (other, event->time);
3240
3241   /* Move the button back */
3242   button = gtk_tree_view_column_get_button (tree_view->priv->drag_column);
3243
3244   context = gtk_widget_get_style_context (button);
3245   gtk_style_context_remove_class (context, GTK_STYLE_CLASS_DND);
3246
3247   g_object_ref (button);
3248   gtk_container_remove (GTK_CONTAINER (tree_view), button);
3249   gtk_widget_set_parent_window (button, tree_view->priv->header_window);
3250   gtk_widget_set_parent (button, GTK_WIDGET (tree_view));
3251   g_object_unref (button);
3252   gtk_widget_queue_resize (widget);
3253   if (gtk_tree_view_column_get_resizable (tree_view->priv->drag_column))
3254     {
3255       gdk_window_raise (_gtk_tree_view_column_get_window (tree_view->priv->drag_column));
3256       gdk_window_show (_gtk_tree_view_column_get_window (tree_view->priv->drag_column));
3257     }
3258   else
3259     gdk_window_hide (_gtk_tree_view_column_get_window (tree_view->priv->drag_column));
3260
3261   gtk_widget_grab_focus (button);
3262
3263   if (rtl)
3264     {
3265       if (tree_view->priv->cur_reorder &&
3266           tree_view->priv->cur_reorder->right_column != tree_view->priv->drag_column)
3267         gtk_tree_view_move_column_after (tree_view, tree_view->priv->drag_column,
3268                                          tree_view->priv->cur_reorder->right_column);
3269     }
3270   else
3271     {
3272       if (tree_view->priv->cur_reorder &&
3273           tree_view->priv->cur_reorder->left_column != tree_view->priv->drag_column)
3274         gtk_tree_view_move_column_after (tree_view, tree_view->priv->drag_column,
3275                                          tree_view->priv->cur_reorder->left_column);
3276     }
3277   tree_view->priv->drag_column = NULL;
3278   gdk_window_destroy (tree_view->priv->drag_window);
3279   tree_view->priv->drag_window = NULL;
3280
3281   for (l = tree_view->priv->column_drag_info; l != NULL; l = l->next)
3282     g_slice_free (GtkTreeViewColumnReorder, l->data);
3283   g_list_free (tree_view->priv->column_drag_info);
3284   tree_view->priv->column_drag_info = NULL;
3285   tree_view->priv->cur_reorder = NULL;
3286
3287   if (tree_view->priv->drag_highlight_window)
3288     gdk_window_hide (tree_view->priv->drag_highlight_window);
3289
3290   /* Reset our flags */
3291   tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_UNSET;
3292   tree_view->priv->in_column_drag = FALSE;
3293
3294   return TRUE;
3295 }
3296
3297 /* GtkWidget::button_release_event helper */
3298 static gboolean
3299 gtk_tree_view_button_release_column_resize (GtkWidget      *widget,
3300                                             GdkEventButton *event)
3301 {
3302   GtkTreeView *tree_view;
3303   gpointer drag_data;
3304
3305   tree_view = GTK_TREE_VIEW (widget);
3306
3307   tree_view->priv->drag_pos = -1;
3308
3309   /* unblock attached dnd signal handler */
3310   drag_data = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
3311   if (drag_data)
3312     g_signal_handlers_unblock_matched (widget,
3313                                        G_SIGNAL_MATCH_DATA,
3314                                        0, 0, NULL, NULL,
3315                                        drag_data);
3316
3317   tree_view->priv->in_column_resize = FALSE;
3318   gtk_grab_remove (widget);
3319   gdk_device_ungrab (gdk_event_get_device ((GdkEvent*)event), event->time);
3320   return TRUE;
3321 }
3322
3323 static gboolean
3324 gtk_tree_view_button_release (GtkWidget      *widget,
3325                               GdkEventButton *event)
3326 {
3327   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
3328
3329   if (tree_view->priv->in_column_drag)
3330     return gtk_tree_view_button_release_drag_column (widget, event);
3331
3332   if (tree_view->priv->rubber_band_status)
3333     gtk_tree_view_stop_rubber_band (tree_view);
3334
3335   if (tree_view->priv->pressed_button == event->button)
3336     tree_view->priv->pressed_button = -1;
3337
3338   if (tree_view->priv->in_column_resize)
3339     return gtk_tree_view_button_release_column_resize (widget, event);
3340
3341   if (tree_view->priv->button_pressed_node == NULL)
3342     return FALSE;
3343
3344   if (event->button == GDK_BUTTON_PRIMARY)
3345     {
3346       if (tree_view->priv->button_pressed_node == tree_view->priv->prelight_node &&
3347           tree_view->priv->arrow_prelit)
3348         {
3349           GtkTreePath *path = NULL;
3350
3351           path = _gtk_tree_path_new_from_rbtree (tree_view->priv->button_pressed_tree,
3352                                                  tree_view->priv->button_pressed_node);
3353           /* Actually activate the node */
3354           if (tree_view->priv->button_pressed_node->children == NULL)
3355             gtk_tree_view_real_expand_row (tree_view, path,
3356                                            tree_view->priv->button_pressed_tree,
3357                                            tree_view->priv->button_pressed_node,
3358                                            FALSE, TRUE);
3359           else
3360             gtk_tree_view_real_collapse_row (GTK_TREE_VIEW (widget), path,
3361                                              tree_view->priv->button_pressed_tree,
3362                                              tree_view->priv->button_pressed_node, TRUE);
3363           gtk_tree_path_free (path);
3364         }
3365
3366       gtk_grab_remove (widget);
3367       tree_view->priv->button_pressed_tree = NULL;
3368       tree_view->priv->button_pressed_node = NULL;
3369     }
3370
3371   return TRUE;
3372 }
3373
3374 static gboolean
3375 gtk_tree_view_grab_broken (GtkWidget          *widget,
3376                            GdkEventGrabBroken *event)
3377 {
3378   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
3379
3380   if (tree_view->priv->in_column_drag)
3381     gtk_tree_view_button_release_drag_column (widget, (GdkEventButton *)event);
3382
3383   if (tree_view->priv->in_column_resize)
3384     gtk_tree_view_button_release_column_resize (widget, (GdkEventButton *)event);
3385
3386   return TRUE;
3387 }
3388
3389 #if 0
3390 static gboolean
3391 gtk_tree_view_configure (GtkWidget *widget,
3392                          GdkEventConfigure *event)
3393 {
3394   GtkTreeView *tree_view;
3395
3396   tree_view = GTK_TREE_VIEW (widget);
3397   tree_view->priv->search_position_func (tree_view, tree_view->priv->search_window);
3398
3399   return FALSE;
3400 }
3401 #endif
3402
3403 /* GtkWidget::motion_event function set.
3404  */
3405
3406 static gboolean
3407 coords_are_over_arrow (GtkTreeView *tree_view,
3408                        GtkRBTree   *tree,
3409                        GtkRBNode   *node,
3410                        /* these are in bin window coords */
3411                        gint         x,
3412                        gint         y)
3413 {
3414   GdkRectangle arrow;
3415   gint x2;
3416
3417   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
3418     return FALSE;
3419
3420   if ((node->flags & GTK_RBNODE_IS_PARENT) == 0)
3421     return FALSE;
3422
3423   arrow.y = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
3424   arrow.height = gtk_tree_view_get_row_height (tree_view, node);
3425
3426   gtk_tree_view_get_arrow_xrange (tree_view, tree, &arrow.x, &x2);
3427
3428   arrow.width = x2 - arrow.x;
3429
3430   return (x >= arrow.x &&
3431           x < (arrow.x + arrow.width) &&
3432           y >= arrow.y &&
3433           y < (arrow.y + arrow.height));
3434 }
3435
3436 static gboolean
3437 auto_expand_timeout (gpointer data)
3438 {
3439   GtkTreeView *tree_view = GTK_TREE_VIEW (data);
3440   GtkTreePath *path;
3441
3442   if (tree_view->priv->prelight_node)
3443     {
3444       path = _gtk_tree_path_new_from_rbtree (tree_view->priv->prelight_tree,
3445                                              tree_view->priv->prelight_node);
3446
3447       if (tree_view->priv->prelight_node->children)
3448         gtk_tree_view_collapse_row (tree_view, path);
3449       else
3450         gtk_tree_view_expand_row (tree_view, path, FALSE);
3451
3452       gtk_tree_path_free (path);
3453     }
3454
3455   tree_view->priv->auto_expand_timeout = 0;
3456
3457   return FALSE;
3458 }
3459
3460 static void
3461 remove_auto_expand_timeout (GtkTreeView *tree_view)
3462 {
3463   if (tree_view->priv->auto_expand_timeout != 0)
3464     {
3465       g_source_remove (tree_view->priv->auto_expand_timeout);
3466       tree_view->priv->auto_expand_timeout = 0;
3467     }
3468 }
3469
3470 static void
3471 do_prelight (GtkTreeView *tree_view,
3472              GtkRBTree   *tree,
3473              GtkRBNode   *node,
3474              /* these are in bin_window coords */
3475              gint         x,
3476              gint         y)
3477 {
3478   if (tree_view->priv->prelight_tree == tree &&
3479       tree_view->priv->prelight_node == node)
3480     {
3481       /*  We are still on the same node,
3482           but we might need to take care of the arrow  */
3483
3484       if (tree && node && gtk_tree_view_draw_expanders (tree_view))
3485         {
3486           gboolean over_arrow;
3487
3488           over_arrow = coords_are_over_arrow (tree_view, tree, node, x, y);
3489
3490           if (over_arrow != tree_view->priv->arrow_prelit)
3491             {
3492               if (over_arrow)
3493                 tree_view->priv->arrow_prelit = TRUE;
3494               else
3495                 tree_view->priv->arrow_prelit = FALSE;
3496
3497               gtk_tree_view_queue_draw_arrow (tree_view, tree, node);
3498             }
3499         }
3500
3501       return;
3502     }
3503
3504   if (tree_view->priv->prelight_tree && tree_view->priv->prelight_node)
3505     {
3506       /*  Unprelight the old node and arrow  */
3507
3508       GTK_RBNODE_UNSET_FLAG (tree_view->priv->prelight_node,
3509                              GTK_RBNODE_IS_PRELIT);
3510
3511       if (tree_view->priv->arrow_prelit
3512           && gtk_tree_view_draw_expanders (tree_view))
3513         {
3514           tree_view->priv->arrow_prelit = FALSE;
3515           
3516           gtk_tree_view_queue_draw_arrow (tree_view,
3517                                           tree_view->priv->prelight_tree,
3518                                           tree_view->priv->prelight_node);
3519         }
3520
3521       _gtk_tree_view_queue_draw_node (tree_view,
3522                                       tree_view->priv->prelight_tree,
3523                                       tree_view->priv->prelight_node,
3524                                       NULL);
3525     }
3526
3527
3528   if (tree_view->priv->hover_expand)
3529     remove_auto_expand_timeout (tree_view);
3530
3531   /*  Set the new prelight values  */
3532   tree_view->priv->prelight_node = node;
3533   tree_view->priv->prelight_tree = tree;
3534
3535   if (!node || !tree)
3536     return;
3537
3538   /*  Prelight the new node and arrow  */
3539
3540   if (gtk_tree_view_draw_expanders (tree_view)
3541       && coords_are_over_arrow (tree_view, tree, node, x, y))
3542     {
3543       tree_view->priv->arrow_prelit = TRUE;
3544
3545       gtk_tree_view_queue_draw_arrow (tree_view, tree, node);
3546     }
3547
3548   GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_PRELIT);
3549
3550   _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
3551
3552   if (tree_view->priv->hover_expand)
3553     {
3554       tree_view->priv->auto_expand_timeout = 
3555         gdk_threads_add_timeout (AUTO_EXPAND_TIMEOUT, auto_expand_timeout, tree_view);
3556     }
3557 }
3558
3559 static void
3560 prelight_or_select (GtkTreeView *tree_view,
3561                     GtkRBTree   *tree,
3562                     GtkRBNode   *node,
3563                     /* these are in bin_window coords */
3564                     gint         x,
3565                     gint         y)
3566 {
3567   GtkSelectionMode mode = gtk_tree_selection_get_mode (tree_view->priv->selection);
3568   
3569   if (tree_view->priv->hover_selection &&
3570       (mode == GTK_SELECTION_SINGLE || mode == GTK_SELECTION_BROWSE) &&
3571       !(tree_view->priv->edited_column &&
3572         gtk_cell_area_get_edit_widget 
3573         (gtk_cell_layout_get_area (GTK_CELL_LAYOUT (tree_view->priv->edited_column)))))
3574     {
3575       if (node)
3576         {
3577           if (!GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
3578             {
3579               GtkTreePath *path;
3580               
3581               path = _gtk_tree_path_new_from_rbtree (tree, node);
3582               gtk_tree_selection_select_path (tree_view->priv->selection, path);
3583               if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
3584                 {
3585                   tree_view->priv->draw_keyfocus = FALSE;
3586                   gtk_tree_view_real_set_cursor (tree_view, path, 0);
3587                 }
3588               gtk_tree_path_free (path);
3589             }
3590         }
3591
3592       else if (mode == GTK_SELECTION_SINGLE)
3593         gtk_tree_selection_unselect_all (tree_view->priv->selection);
3594     }
3595
3596     do_prelight (tree_view, tree, node, x, y);
3597 }
3598
3599 static void
3600 ensure_unprelighted (GtkTreeView *tree_view)
3601 {
3602   do_prelight (tree_view,
3603                NULL, NULL,
3604                -1000, -1000); /* coords not possibly over an arrow */
3605
3606   g_assert (tree_view->priv->prelight_node == NULL);
3607 }
3608
3609 static void
3610 update_prelight (GtkTreeView *tree_view,
3611                  gint         x,
3612                  gint         y)
3613 {
3614   int new_y;
3615   GtkRBTree *tree;
3616   GtkRBNode *node;
3617
3618   if (tree_view->priv->tree == NULL)
3619     return;
3620
3621   if (x == -10000)
3622     {
3623       ensure_unprelighted (tree_view);
3624       return;
3625     }
3626
3627   new_y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, y);
3628   if (new_y < 0)
3629     new_y = 0;
3630
3631   _gtk_rbtree_find_offset (tree_view->priv->tree,
3632                            new_y, &tree, &node);
3633
3634   if (node)
3635     prelight_or_select (tree_view, tree, node, x, y);
3636 }
3637
3638
3639
3640
3641 /* Our motion arrow is either a box (in the case of the original spot)
3642  * or an arrow.  It is expander_size wide.
3643  */
3644 /*
3645  * 11111111111111
3646  * 01111111111110
3647  * 00111111111100
3648  * 00011111111000
3649  * 00001111110000
3650  * 00000111100000
3651  * 00000111100000
3652  * 00000111100000
3653  * ~ ~ ~ ~ ~ ~ ~
3654  * 00000111100000
3655  * 00000111100000
3656  * 00000111100000
3657  * 00001111110000
3658  * 00011111111000
3659  * 00111111111100
3660  * 01111111111110
3661  * 11111111111111
3662  */
3663
3664 static void
3665 gtk_tree_view_motion_draw_column_motion_arrow (GtkTreeView *tree_view)
3666 {
3667   GtkTreeViewColumnReorder *reorder = tree_view->priv->cur_reorder;
3668   GtkWidget *widget = GTK_WIDGET (tree_view);
3669   cairo_surface_t *mask_image;
3670   cairo_region_t *mask_region;
3671   gint x;
3672   gint y;
3673   gint width;
3674   gint height;
3675   gint arrow_type = DRAG_COLUMN_WINDOW_STATE_UNSET;
3676   GdkWindowAttr attributes;
3677   guint attributes_mask;
3678   cairo_t *cr;
3679
3680   if (!reorder ||
3681       reorder->left_column == tree_view->priv->drag_column ||
3682       reorder->right_column == tree_view->priv->drag_column)
3683     arrow_type = DRAG_COLUMN_WINDOW_STATE_ORIGINAL;
3684   else if (reorder->left_column || reorder->right_column)
3685     {
3686       GtkAllocation left_allocation, right_allocation;
3687       GdkRectangle visible_rect;
3688       GtkWidget *button;
3689
3690       gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
3691       if (reorder->left_column)
3692         {
3693           button = gtk_tree_view_column_get_button (reorder->left_column);
3694           gtk_widget_get_allocation (button, &left_allocation);
3695           x = left_allocation.x + left_allocation.width;
3696         }
3697       else
3698         {
3699           button = gtk_tree_view_column_get_button (reorder->right_column);
3700           gtk_widget_get_allocation (button, &right_allocation);
3701           x = right_allocation.x;
3702         }
3703
3704       if (x < visible_rect.x)
3705         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT;
3706       else if (x > visible_rect.x + visible_rect.width)
3707         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT;
3708       else
3709         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW;
3710     }
3711
3712   /* We want to draw the rectangle over the initial location. */
3713   if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ORIGINAL)
3714     {
3715       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ORIGINAL)
3716         {
3717           GtkAllocation drag_allocation;
3718           GtkWidget    *button;
3719
3720           if (tree_view->priv->drag_highlight_window)
3721             {
3722               gdk_window_set_user_data (tree_view->priv->drag_highlight_window,
3723                                         NULL);
3724               gdk_window_destroy (tree_view->priv->drag_highlight_window);
3725             }
3726
3727           button = gtk_tree_view_column_get_button (tree_view->priv->drag_column);
3728           attributes.window_type = GDK_WINDOW_CHILD;
3729           attributes.wclass = GDK_INPUT_OUTPUT;
3730           attributes.x = tree_view->priv->drag_column_x;
3731           attributes.y = 0;
3732           gtk_widget_get_allocation (button, &drag_allocation);
3733           width = attributes.width = drag_allocation.width;
3734           height = attributes.height = drag_allocation.height;
3735           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
3736           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3737           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
3738           tree_view->priv->drag_highlight_window = gdk_window_new (tree_view->priv->header_window, &attributes, attributes_mask);
3739           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
3740
3741           mask_image = cairo_image_surface_create (CAIRO_FORMAT_A1, width, height);
3742           cr = cairo_create (mask_image);
3743
3744           cairo_rectangle (cr, 1, 1, width - 2, height - 2);
3745           cairo_stroke (cr);
3746           cairo_destroy (cr);
3747
3748           mask_region = gdk_cairo_region_create_from_surface (mask_image);
3749           gdk_window_shape_combine_region (tree_view->priv->drag_highlight_window,
3750                                            mask_region, 0, 0);
3751
3752           cairo_region_destroy (mask_region);
3753           cairo_surface_destroy (mask_image);
3754
3755           tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_ORIGINAL;
3756         }
3757     }
3758   else if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW)
3759     {
3760       GtkAllocation button_allocation;
3761       GtkWidget    *button;
3762
3763       width = gtk_tree_view_get_expander_size (tree_view);
3764
3765       /* Get x, y, width, height of arrow */
3766       gdk_window_get_origin (tree_view->priv->header_window, &x, &y);
3767       if (reorder->left_column)
3768         {
3769           button = gtk_tree_view_column_get_button (reorder->left_column);
3770           gtk_widget_get_allocation (button, &button_allocation);
3771           x += button_allocation.x + button_allocation.width - width/2;
3772           height = button_allocation.height;
3773         }
3774       else
3775         {
3776           button = gtk_tree_view_column_get_button (reorder->right_column);
3777           gtk_widget_get_allocation (button, &button_allocation);
3778           x += button_allocation.x - width/2;
3779           height = button_allocation.height;
3780         }
3781       y -= width/2; /* The arrow takes up only half the space */
3782       height += width;
3783
3784       /* Create the new window */
3785       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW)
3786         {
3787           if (tree_view->priv->drag_highlight_window)
3788             {
3789               gdk_window_set_user_data (tree_view->priv->drag_highlight_window,
3790                                         NULL);
3791               gdk_window_destroy (tree_view->priv->drag_highlight_window);
3792             }
3793
3794           attributes.window_type = GDK_WINDOW_TEMP;
3795           attributes.wclass = GDK_INPUT_OUTPUT;
3796           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
3797           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3798           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
3799           attributes.x = x;
3800           attributes.y = y;
3801           attributes.width = width;
3802           attributes.height = height;
3803           tree_view->priv->drag_highlight_window = gdk_window_new (gtk_widget_get_root_window (widget),
3804                                                                    &attributes, attributes_mask);
3805           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
3806
3807           mask_image = cairo_image_surface_create (CAIRO_FORMAT_A1, width, height);
3808
3809           cr = cairo_create (mask_image);
3810           cairo_move_to (cr, 0, 0);
3811           cairo_line_to (cr, width, 0);
3812           cairo_line_to (cr, width / 2., width / 2);
3813           cairo_move_to (cr, 0, height);
3814           cairo_line_to (cr, width, height);
3815           cairo_line_to (cr, width / 2., height - width / 2.);
3816           cairo_fill (cr);
3817           cairo_destroy (cr);
3818
3819           mask_region = gdk_cairo_region_create_from_surface (mask_image);
3820           gdk_window_shape_combine_region (tree_view->priv->drag_highlight_window,
3821                                            mask_region, 0, 0);
3822
3823           cairo_region_destroy (mask_region);
3824           cairo_surface_destroy (mask_image);
3825         }
3826
3827       tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_ARROW;
3828       gdk_window_move (tree_view->priv->drag_highlight_window, x, y);
3829     }
3830   else if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT ||
3831            arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
3832     {
3833       GtkAllocation allocation;
3834       GtkWidget    *button;
3835       gint          expander_size;
3836
3837       expander_size = gtk_tree_view_get_expander_size (tree_view);
3838
3839       /* Get x, y, width, height of arrow */
3840       width = expander_size/2; /* remember, the arrow only takes half the available width */
3841       gdk_window_get_origin (gtk_widget_get_window (widget),
3842                              &x, &y);
3843       if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
3844         {
3845           gtk_widget_get_allocation (widget, &allocation);
3846           x += allocation.width - width;
3847         }
3848
3849       if (reorder->left_column)
3850         {
3851           button = gtk_tree_view_column_get_button (reorder->left_column);
3852           gtk_widget_get_allocation (button, &allocation);
3853           height = allocation.height;
3854         }
3855       else
3856         {
3857           button = gtk_tree_view_column_get_button (reorder->right_column);
3858           gtk_widget_get_allocation (button, &allocation);
3859           height = allocation.height;
3860         }
3861
3862       y -= expander_size;
3863       height += 2 * expander_size;
3864
3865       /* Create the new window */
3866       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT &&
3867           tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
3868         {
3869           if (tree_view->priv->drag_highlight_window)
3870             {
3871               gdk_window_set_user_data (tree_view->priv->drag_highlight_window,
3872                                         NULL);
3873               gdk_window_destroy (tree_view->priv->drag_highlight_window);
3874             }
3875
3876           attributes.window_type = GDK_WINDOW_TEMP;
3877           attributes.wclass = GDK_INPUT_OUTPUT;
3878           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
3879           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3880           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
3881           attributes.x = x;
3882           attributes.y = y;
3883           attributes.width = width;
3884           attributes.height = height;
3885           tree_view->priv->drag_highlight_window = gdk_window_new (gtk_widget_get_root_window (widget), &attributes, attributes_mask);
3886           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
3887
3888           mask_image = cairo_image_surface_create (CAIRO_FORMAT_A1, width, height);
3889
3890           cr = cairo_create (mask_image);
3891           /* mirror if we're on the left */
3892           if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT)
3893             {
3894               cairo_translate (cr, width, 0);
3895               cairo_scale (cr, -1, 1);
3896             }
3897           cairo_move_to (cr, 0, 0);
3898           cairo_line_to (cr, width, width);
3899           cairo_line_to (cr, 0, expander_size);
3900           cairo_move_to (cr, 0, height);
3901           cairo_line_to (cr, width, height - width);
3902           cairo_line_to (cr, 0, height - expander_size);
3903           cairo_fill (cr);
3904           cairo_destroy (cr);
3905
3906           mask_region = gdk_cairo_region_create_from_surface (mask_image);
3907           gdk_window_shape_combine_region (tree_view->priv->drag_highlight_window,
3908                                            mask_region, 0, 0);
3909
3910           cairo_region_destroy (mask_region);
3911           cairo_surface_destroy (mask_image);
3912         }
3913
3914       tree_view->priv->drag_column_window_state = arrow_type;
3915       gdk_window_move (tree_view->priv->drag_highlight_window, x, y);
3916    }
3917   else
3918     {
3919       g_warning (G_STRLOC"Invalid GtkTreeViewColumnReorder struct");
3920       gdk_window_hide (tree_view->priv->drag_highlight_window);
3921       return;
3922     }
3923
3924   gdk_window_show (tree_view->priv->drag_highlight_window);
3925   gdk_window_raise (tree_view->priv->drag_highlight_window);
3926 }
3927
3928 static gboolean
3929 gtk_tree_view_motion_resize_column (GtkWidget      *widget,
3930                                     GdkEventMotion *event)
3931 {
3932   gint x;
3933   gint new_width;
3934   GtkTreeViewColumn *column;
3935   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
3936
3937   column = gtk_tree_view_get_column (tree_view, tree_view->priv->drag_pos);
3938
3939   if (event->is_hint || event->window != gtk_widget_get_window (widget))
3940     gdk_window_get_device_position (gtk_widget_get_window (widget),
3941                                     gdk_event_get_device ((GdkEvent *) event),
3942                                     &x, NULL, NULL);
3943   else
3944     x = event->x;
3945
3946   if (tree_view->priv->hadjustment)
3947     x += gtk_adjustment_get_value (tree_view->priv->hadjustment);
3948
3949   new_width = gtk_tree_view_new_column_width (tree_view,
3950                                               tree_view->priv->drag_pos, &x);
3951   if (x != tree_view->priv->x_drag &&
3952       (new_width != gtk_tree_view_column_get_fixed_width (column)))
3953     {
3954       _gtk_tree_view_column_set_use_resized_width (column, TRUE);
3955
3956       if (gtk_tree_view_column_get_expand (column))
3957         new_width -= tree_view->priv->last_extra_space_per_column;
3958
3959       _gtk_tree_view_column_set_resized_width (column, new_width);
3960
3961
3962       gtk_widget_queue_resize (widget);
3963     }
3964
3965   return FALSE;
3966 }
3967
3968
3969 static void
3970 gtk_tree_view_update_current_reorder (GtkTreeView *tree_view,
3971                                       GdkEvent    *event)
3972 {
3973   GtkTreeViewColumnReorder *reorder = NULL;
3974   GList *list;
3975   gint mouse_x;
3976
3977   gdk_window_get_device_position (tree_view->priv->header_window,
3978                                   gdk_event_get_device (event),
3979                                   &mouse_x, NULL, NULL);
3980   for (list = tree_view->priv->column_drag_info; list; list = list->next)
3981     {
3982       reorder = (GtkTreeViewColumnReorder *) list->data;
3983       if (mouse_x >= reorder->left_align && mouse_x < reorder->right_align)
3984         break;
3985       reorder = NULL;
3986     }
3987
3988   /*  if (reorder && reorder == tree_view->priv->cur_reorder)
3989       return;*/
3990
3991   tree_view->priv->cur_reorder = reorder;
3992   gtk_tree_view_motion_draw_column_motion_arrow (tree_view);
3993 }
3994
3995 static void
3996 gtk_tree_view_vertical_autoscroll (GtkTreeView *tree_view)
3997 {
3998   GdkRectangle visible_rect;
3999   gint y;
4000   gint offset;
4001
4002   gdk_window_get_device_position (tree_view->priv->bin_window,
4003                                   gdk_device_manager_get_client_pointer (
4004                                     gdk_display_get_device_manager (
4005                                       gtk_widget_get_display (GTK_WIDGET (tree_view)))),
4006                                   NULL, &y, NULL);
4007   y += tree_view->priv->dy;
4008
4009   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
4010
4011   /* see if we are near the edge. */
4012   offset = y - (visible_rect.y + 2 * SCROLL_EDGE_SIZE);
4013   if (offset > 0)
4014     {
4015       offset = y - (visible_rect.y + visible_rect.height - 2 * SCROLL_EDGE_SIZE);
4016       if (offset < 0)
4017         return;
4018     }
4019
4020   gtk_adjustment_set_value (tree_view->priv->vadjustment,
4021                             MAX (gtk_adjustment_get_value (tree_view->priv->vadjustment) + offset, 0.0));
4022 }
4023
4024 static gboolean
4025 gtk_tree_view_horizontal_autoscroll (GtkTreeView *tree_view,
4026                                      GdkEvent    *event)
4027 {
4028   GdkRectangle visible_rect;
4029   gint x;
4030   gint offset;
4031
4032   gdk_window_get_device_position (tree_view->priv->bin_window,
4033                                   gdk_event_get_device (event),
4034                                   &x, NULL, NULL);
4035
4036   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
4037
4038   /* See if we are near the edge. */
4039   offset = x - (visible_rect.x + SCROLL_EDGE_SIZE);
4040   if (offset > 0)
4041     {
4042       offset = x - (visible_rect.x + visible_rect.width - SCROLL_EDGE_SIZE);
4043       if (offset < 0)
4044         return TRUE;
4045     }
4046   offset = offset/3;
4047
4048   gtk_adjustment_set_value (tree_view->priv->hadjustment,
4049                             MAX (gtk_adjustment_get_value (tree_view->priv->hadjustment) + offset, 0.0));
4050
4051   return TRUE;
4052
4053 }
4054
4055 static gboolean
4056 gtk_tree_view_motion_drag_column (GtkWidget      *widget,
4057                                   GdkEventMotion *event)
4058 {
4059   GtkAllocation allocation, button_allocation;
4060   GtkTreeView *tree_view = (GtkTreeView *) widget;
4061   GtkTreeViewColumn *column = tree_view->priv->drag_column;
4062   GtkWidget *button;
4063   gint x, y;
4064
4065   /* Sanity Check */
4066   if ((column == NULL) ||
4067       (event->window != tree_view->priv->drag_window))
4068     return FALSE;
4069
4070   button = gtk_tree_view_column_get_button (column);
4071
4072   /* Handle moving the header */
4073   gdk_window_get_position (tree_view->priv->drag_window, &x, &y);
4074   gtk_widget_get_allocation (widget, &allocation);
4075   gtk_widget_get_allocation (button, &button_allocation);
4076   x = CLAMP (x + (gint)event->x - _gtk_tree_view_column_get_drag_x (column), 0,
4077              MAX (tree_view->priv->width, allocation.width) - button_allocation.width);
4078   gdk_window_move (tree_view->priv->drag_window, x, y);
4079   
4080   /* autoscroll, if needed */
4081   gtk_tree_view_horizontal_autoscroll (tree_view, (GdkEvent *) event);
4082   /* Update the current reorder position and arrow; */
4083   gtk_tree_view_update_current_reorder (tree_view, (GdkEvent *) event);
4084
4085   return TRUE;
4086 }
4087
4088 static void
4089 gtk_tree_view_stop_rubber_band (GtkTreeView *tree_view)
4090 {
4091   remove_scroll_timeout (tree_view);
4092   gtk_grab_remove (GTK_WIDGET (tree_view));
4093
4094   if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
4095     {
4096       GtkTreePath *tmp_path;
4097
4098       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
4099
4100       /* The anchor path should be set to the start path */
4101       tmp_path = _gtk_tree_path_new_from_rbtree (tree_view->priv->rubber_band_start_tree,
4102                                                  tree_view->priv->rubber_band_start_node);
4103
4104       if (tree_view->priv->anchor)
4105         gtk_tree_row_reference_free (tree_view->priv->anchor);
4106
4107       tree_view->priv->anchor =
4108         gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
4109                                           tree_view->priv->model,
4110                                           tmp_path);
4111
4112       gtk_tree_path_free (tmp_path);
4113
4114       /* ... and the cursor to the end path */
4115       tmp_path = _gtk_tree_path_new_from_rbtree (tree_view->priv->rubber_band_end_tree,
4116                                                  tree_view->priv->rubber_band_end_node);
4117       gtk_tree_view_real_set_cursor (GTK_TREE_VIEW (tree_view), tmp_path, 0);
4118       gtk_tree_path_free (tmp_path);
4119
4120       _gtk_tree_selection_emit_changed (tree_view->priv->selection);
4121     }
4122
4123   /* Clear status variables */
4124   tree_view->priv->rubber_band_status = RUBBER_BAND_OFF;
4125   tree_view->priv->rubber_band_extend = FALSE;
4126   tree_view->priv->rubber_band_modify = FALSE;
4127
4128   tree_view->priv->rubber_band_start_node = NULL;
4129   tree_view->priv->rubber_band_start_tree = NULL;
4130   tree_view->priv->rubber_band_end_node = NULL;
4131   tree_view->priv->rubber_band_end_tree = NULL;
4132 }
4133
4134 static void
4135 gtk_tree_view_update_rubber_band_selection_range (GtkTreeView *tree_view,
4136                                                  GtkRBTree   *start_tree,
4137                                                  GtkRBNode   *start_node,
4138                                                  GtkRBTree   *end_tree,
4139                                                  GtkRBNode   *end_node,
4140                                                  gboolean     select,
4141                                                  gboolean     skip_start,
4142                                                  gboolean     skip_end)
4143 {
4144   if (start_node == end_node)
4145     return;
4146
4147   /* We skip the first node and jump inside the loop */
4148   if (skip_start)
4149     goto skip_first;
4150
4151   do
4152     {
4153       /* Small optimization by assuming insensitive nodes are never
4154        * selected.
4155        */
4156       if (!GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
4157         {
4158           GtkTreePath *path;
4159           gboolean selectable;
4160
4161           path = _gtk_tree_path_new_from_rbtree (start_tree, start_node);
4162           selectable = _gtk_tree_selection_row_is_selectable (tree_view->priv->selection, start_node, path);
4163           gtk_tree_path_free (path);
4164
4165           if (!selectable)
4166             goto node_not_selectable;
4167         }
4168
4169       if (select)
4170         {
4171           if (tree_view->priv->rubber_band_extend)
4172             GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4173           else if (tree_view->priv->rubber_band_modify)
4174             {
4175               /* Toggle the selection state */
4176               if (GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
4177                 GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4178               else
4179                 GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4180             }
4181           else
4182             GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4183         }
4184       else
4185         {
4186           /* Mirror the above */
4187           if (tree_view->priv->rubber_band_extend)
4188             GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4189           else if (tree_view->priv->rubber_band_modify)
4190             {
4191               /* Toggle the selection state */
4192               if (GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
4193                 GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4194               else
4195                 GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4196             }
4197           else
4198             GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4199         }
4200
4201       _gtk_tree_view_queue_draw_node (tree_view, start_tree, start_node, NULL);
4202
4203 node_not_selectable:
4204       if (start_node == end_node)
4205         break;
4206
4207 skip_first:
4208
4209       if (start_node->children)
4210         {
4211           start_tree = start_node->children;
4212           start_node = _gtk_rbtree_first (start_tree);
4213         }
4214       else
4215         {
4216           _gtk_rbtree_next_full (start_tree, start_node, &start_tree, &start_node);
4217
4218           if (!start_tree)
4219             /* Ran out of tree */
4220             break;
4221         }
4222
4223       if (skip_end && start_node == end_node)
4224         break;
4225     }
4226   while (TRUE);
4227 }
4228
4229 static void
4230 gtk_tree_view_update_rubber_band_selection (GtkTreeView *tree_view)
4231 {
4232   GtkRBTree *start_tree, *end_tree;
4233   GtkRBNode *start_node, *end_node;
4234
4235   _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);
4236   _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);
4237
4238   /* Handle the start area first */
4239   if (!tree_view->priv->rubber_band_start_node)
4240     {
4241       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4242                                                        start_tree,
4243                                                        start_node,
4244                                                        end_tree,
4245                                                        end_node,
4246                                                        TRUE,
4247                                                        FALSE,
4248                                                        FALSE);
4249     }
4250   else if (_gtk_rbtree_node_find_offset (start_tree, start_node) <
4251            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_start_tree, tree_view->priv->rubber_band_start_node))
4252     {
4253       /* New node is above the old one; selection became bigger */
4254       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4255                                                        start_tree,
4256                                                        start_node,
4257                                                        tree_view->priv->rubber_band_start_tree,
4258                                                        tree_view->priv->rubber_band_start_node,
4259                                                        TRUE,
4260                                                        FALSE,
4261                                                        TRUE);
4262     }
4263   else if (_gtk_rbtree_node_find_offset (start_tree, start_node) >
4264            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_start_tree, tree_view->priv->rubber_band_start_node))
4265     {
4266       /* New node is below the old one; selection became smaller */
4267       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4268                                                        tree_view->priv->rubber_band_start_tree,
4269                                                        tree_view->priv->rubber_band_start_node,
4270                                                        start_tree,
4271                                                        start_node,
4272                                                        FALSE,
4273                                                        FALSE,
4274                                                        TRUE);
4275     }
4276
4277   tree_view->priv->rubber_band_start_tree = start_tree;
4278   tree_view->priv->rubber_band_start_node = start_node;
4279
4280   /* Next, handle the end area */
4281   if (!tree_view->priv->rubber_band_end_node)
4282     {
4283       /* In the event this happens, start_node was also NULL; this case is
4284        * handled above.
4285        */
4286     }
4287   else if (!end_node)
4288     {
4289       /* Find the last node in the tree */
4290       _gtk_rbtree_find_offset (tree_view->priv->tree, tree_view->priv->height - 1,
4291                                &end_tree, &end_node);
4292
4293       /* Selection reached end of the tree */
4294       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4295                                                        tree_view->priv->rubber_band_end_tree,
4296                                                        tree_view->priv->rubber_band_end_node,
4297                                                        end_tree,
4298                                                        end_node,
4299                                                        TRUE,
4300                                                        TRUE,
4301                                                        FALSE);
4302     }
4303   else if (_gtk_rbtree_node_find_offset (end_tree, end_node) >
4304            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_end_tree, tree_view->priv->rubber_band_end_node))
4305     {
4306       /* New node is below the old one; selection became bigger */
4307       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4308                                                        tree_view->priv->rubber_band_end_tree,
4309                                                        tree_view->priv->rubber_band_end_node,
4310                                                        end_tree,
4311                                                        end_node,
4312                                                        TRUE,
4313                                                        TRUE,
4314                                                        FALSE);
4315     }
4316   else if (_gtk_rbtree_node_find_offset (end_tree, end_node) <
4317            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_end_tree, tree_view->priv->rubber_band_end_node))
4318     {
4319       /* New node is above the old one; selection became smaller */
4320       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4321                                                        end_tree,
4322                                                        end_node,
4323                                                        tree_view->priv->rubber_band_end_tree,
4324                                                        tree_view->priv->rubber_band_end_node,
4325                                                        FALSE,
4326                                                        TRUE,
4327                                                        FALSE);
4328     }
4329
4330   tree_view->priv->rubber_band_end_tree = end_tree;
4331   tree_view->priv->rubber_band_end_node = end_node;
4332 }
4333
4334 static void
4335 gtk_tree_view_update_rubber_band (GtkTreeView *tree_view)
4336 {
4337   gint x, y;
4338   GdkRectangle old_area;
4339   GdkRectangle new_area;
4340   GdkRectangle common;
4341   cairo_region_t *invalid_region;
4342
4343   old_area.x = MIN (tree_view->priv->press_start_x, tree_view->priv->rubber_band_x);
4344   old_area.y = MIN (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y) - tree_view->priv->dy;
4345   old_area.width = ABS (tree_view->priv->rubber_band_x - tree_view->priv->press_start_x) + 1;
4346   old_area.height = ABS (tree_view->priv->rubber_band_y - tree_view->priv->press_start_y) + 1;
4347
4348   gdk_window_get_device_position (tree_view->priv->bin_window,
4349                                   gdk_device_manager_get_client_pointer (
4350                                     gdk_display_get_device_manager (
4351                                       gtk_widget_get_display (GTK_WIDGET (tree_view)))),
4352                                   &x, &y, NULL);
4353
4354   x = MAX (x, 0);
4355   y = MAX (y, 0) + tree_view->priv->dy;
4356
4357   new_area.x = MIN (tree_view->priv->press_start_x, x);
4358   new_area.y = MIN (tree_view->priv->press_start_y, y) - tree_view->priv->dy;
4359   new_area.width = ABS (x - tree_view->priv->press_start_x) + 1;
4360   new_area.height = ABS (y - tree_view->priv->press_start_y) + 1;
4361
4362   invalid_region = cairo_region_create_rectangle (&old_area);
4363   cairo_region_union_rectangle (invalid_region, &new_area);
4364
4365   gdk_rectangle_intersect (&old_area, &new_area, &common);
4366   if (common.width > 2 && common.height > 2)
4367     {
4368       cairo_region_t *common_region;
4369
4370       /* make sure the border is invalidated */
4371       common.x += 1;
4372       common.y += 1;
4373       common.width -= 2;
4374       common.height -= 2;
4375
4376       common_region = cairo_region_create_rectangle (&common);
4377
4378       cairo_region_subtract (invalid_region, common_region);
4379       cairo_region_destroy (common_region);
4380     }
4381
4382   gdk_window_invalidate_region (tree_view->priv->bin_window, invalid_region, TRUE);
4383
4384   cairo_region_destroy (invalid_region);
4385
4386   tree_view->priv->rubber_band_x = x;
4387   tree_view->priv->rubber_band_y = y;
4388
4389   gtk_tree_view_update_rubber_band_selection (tree_view);
4390 }
4391
4392 static void
4393 gtk_tree_view_paint_rubber_band (GtkTreeView  *tree_view,
4394                                  cairo_t      *cr)
4395 {
4396   GdkRectangle rect;
4397   GtkStyleContext *context;
4398
4399   cairo_save (cr);
4400
4401   context = gtk_widget_get_style_context (GTK_WIDGET (tree_view));
4402
4403   gtk_style_context_save (context);
4404   gtk_style_context_add_class (context, GTK_STYLE_CLASS_RUBBERBAND);
4405
4406   rect.x = MIN (tree_view->priv->press_start_x, tree_view->priv->rubber_band_x);
4407   rect.y = MIN (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y) - tree_view->priv->dy;
4408   rect.width = ABS (tree_view->priv->press_start_x - tree_view->priv->rubber_band_x) + 1;
4409   rect.height = ABS (tree_view->priv->press_start_y - tree_view->priv->rubber_band_y) + 1;
4410
4411   gdk_cairo_rectangle (cr, &rect);
4412   cairo_clip (cr);
4413
4414   gtk_render_background (context, cr,
4415                          rect.x, rect.y,
4416                          rect.width, rect.height);
4417   gtk_render_frame (context, cr,
4418                     rect.x, rect.y,
4419                     rect.width, rect.height);
4420
4421   gtk_style_context_restore (context);
4422   cairo_restore (cr);
4423 }
4424
4425 static gboolean
4426 gtk_tree_view_motion_bin_window (GtkWidget      *widget,
4427                                  GdkEventMotion *event)
4428 {
4429   GtkTreeView *tree_view;
4430   GtkRBTree *tree;
4431   GtkRBNode *node;
4432   gint new_y;
4433
4434   tree_view = (GtkTreeView *) widget;
4435
4436   if (tree_view->priv->tree == NULL)
4437     return FALSE;
4438
4439   if (tree_view->priv->rubber_band_status == RUBBER_BAND_MAYBE_START)
4440     {
4441       gtk_grab_add (GTK_WIDGET (tree_view));
4442       gtk_tree_view_update_rubber_band (tree_view);
4443
4444       tree_view->priv->rubber_band_status = RUBBER_BAND_ACTIVE;
4445     }
4446   else if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
4447     {
4448       gtk_tree_view_update_rubber_band (tree_view);
4449
4450       add_scroll_timeout (tree_view);
4451     }
4452
4453   /* only check for an initiated drag when a button is pressed */
4454   if (tree_view->priv->pressed_button >= 0
4455       && !tree_view->priv->rubber_band_status)
4456     gtk_tree_view_maybe_begin_dragging_row (tree_view, event);
4457
4458   new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
4459   if (new_y < 0)
4460     new_y = 0;
4461
4462   _gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
4463
4464   /* If we are currently pressing down a button, we don't want to prelight anything else. */
4465   if ((tree_view->priv->button_pressed_node != NULL) &&
4466       (tree_view->priv->button_pressed_node != node))
4467     node = NULL;
4468
4469   tree_view->priv->event_last_x = event->x;
4470   tree_view->priv->event_last_y = event->y;
4471
4472   prelight_or_select (tree_view, tree, node, event->x, event->y);
4473
4474   return TRUE;
4475 }
4476
4477 static gboolean
4478 gtk_tree_view_motion (GtkWidget      *widget,
4479                       GdkEventMotion *event)
4480 {
4481   GtkTreeView *tree_view;
4482
4483   tree_view = (GtkTreeView *) widget;
4484
4485   /* Resizing a column */
4486   if (tree_view->priv->in_column_resize)
4487     return gtk_tree_view_motion_resize_column (widget, event);
4488
4489   /* Drag column */
4490   if (tree_view->priv->in_column_drag)
4491     return gtk_tree_view_motion_drag_column (widget, event);
4492
4493   /* Sanity check it */
4494   if (event->window == tree_view->priv->bin_window)
4495     return gtk_tree_view_motion_bin_window (widget, event);
4496
4497   return FALSE;
4498 }
4499
4500 /* Invalidate the focus rectangle near the edge of the bin_window; used when
4501  * the tree is empty.
4502  */
4503 static void
4504 invalidate_empty_focus (GtkTreeView *tree_view)
4505 {
4506   GdkRectangle area;
4507
4508   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
4509     return;
4510
4511   area.x = 0;
4512   area.y = 0;
4513   area.width = gdk_window_get_width (tree_view->priv->bin_window);
4514   area.height = gdk_window_get_height (tree_view->priv->bin_window);
4515   gdk_window_invalidate_rect (tree_view->priv->bin_window, &area, FALSE);
4516 }
4517
4518 /* Draws a focus rectangle near the edge of the bin_window; used when the tree
4519  * is empty.
4520  */
4521 static void
4522 draw_empty_focus (GtkTreeView *tree_view, cairo_t *cr)
4523 {
4524   GtkWidget *widget = GTK_WIDGET (tree_view);
4525   gint w, h;
4526
4527   if (!gtk_widget_has_visible_focus (widget))
4528     return;
4529
4530   w = gdk_window_get_width (tree_view->priv->bin_window) - 2;
4531   h = gdk_window_get_height (tree_view->priv->bin_window) - 2;
4532
4533   if (w > 0 && h > 0)
4534     {
4535       GtkStyleContext *context;
4536
4537       context = gtk_widget_get_style_context (widget);
4538
4539       gtk_render_focus (context, cr, 1, 1, w, h);
4540     }
4541 }
4542
4543 typedef enum {
4544   GTK_TREE_VIEW_GRID_LINE,
4545   GTK_TREE_VIEW_TREE_LINE,
4546   GTK_TREE_VIEW_FOREGROUND_LINE
4547 } GtkTreeViewLineType;
4548
4549 static void
4550 gtk_tree_view_draw_line (GtkTreeView         *tree_view,
4551                          cairo_t             *cr,
4552                          GtkTreeViewLineType  type,
4553                          int                  x1,
4554                          int                  y1,
4555                          int                  x2,
4556                          int                  y2)
4557 {
4558   cairo_save (cr);
4559
4560   switch (type)
4561     {
4562     case GTK_TREE_VIEW_TREE_LINE:
4563       cairo_set_source_rgb (cr, 0, 0, 0);
4564       cairo_set_line_width (cr, tree_view->priv->tree_line_width);
4565       if (tree_view->priv->tree_line_dashes[0])
4566         cairo_set_dash (cr, 
4567                         tree_view->priv->tree_line_dashes,
4568                         2, 0.5);
4569       break;
4570     case GTK_TREE_VIEW_GRID_LINE:
4571       cairo_set_source_rgb (cr, 0, 0, 0);
4572       cairo_set_line_width (cr, tree_view->priv->grid_line_width);
4573       if (tree_view->priv->grid_line_dashes[0])
4574         cairo_set_dash (cr, 
4575                         tree_view->priv->grid_line_dashes,
4576                         2, 0.5);
4577       break;
4578     default:
4579       g_assert_not_reached ();
4580       /* fall through */
4581     case GTK_TREE_VIEW_FOREGROUND_LINE:
4582       {
4583         GtkStyleContext *context;
4584         GtkStateFlags state;
4585         GdkRGBA color;
4586
4587         context = gtk_widget_get_style_context (GTK_WIDGET (tree_view));
4588         state = gtk_widget_get_state_flags (GTK_WIDGET (tree_view));
4589
4590         cairo_set_line_width (cr, 1.0);
4591         gtk_style_context_get_color (context, state, &color);
4592         gdk_cairo_set_source_rgba (cr, &color);
4593       }
4594
4595       break;
4596     }
4597
4598   cairo_move_to (cr, x1 + 0.5, y1 + 0.5);
4599   cairo_line_to (cr, x2 + 0.5, y2 + 0.5);
4600   cairo_stroke (cr);
4601
4602   cairo_restore (cr);
4603 }
4604                          
4605 static void
4606 gtk_tree_view_draw_grid_lines (GtkTreeView    *tree_view,
4607                                cairo_t        *cr,
4608                                gint            n_visible_columns)
4609 {
4610   GList *list = tree_view->priv->columns;
4611   gint i = 0;
4612   gint current_x = 0;
4613
4614   if (tree_view->priv->grid_lines != GTK_TREE_VIEW_GRID_LINES_VERTICAL
4615       && tree_view->priv->grid_lines != GTK_TREE_VIEW_GRID_LINES_BOTH)
4616     return;
4617
4618   /* Only draw the lines for visible rows and columns */
4619   for (list = tree_view->priv->columns; list; list = list->next, i++)
4620     {
4621       GtkTreeViewColumn *column = list->data;
4622
4623       /* We don't want a line for the last column */
4624       if (i == n_visible_columns - 1)
4625         break;
4626
4627       if (!gtk_tree_view_column_get_visible (column))
4628         continue;
4629
4630       current_x += gtk_tree_view_column_get_width (column);
4631
4632       gtk_tree_view_draw_line (tree_view, cr,
4633                                GTK_TREE_VIEW_GRID_LINE,
4634                                current_x - 1, 0,
4635                                current_x - 1, tree_view->priv->height);
4636     }
4637 }
4638
4639 /* Warning: Very scary function.
4640  * Modify at your own risk
4641  *
4642  * KEEP IN SYNC WITH gtk_tree_view_create_row_drag_icon()!
4643  * FIXME: It's not...
4644  */
4645 static gboolean
4646 gtk_tree_view_bin_draw (GtkWidget      *widget,
4647                         cairo_t        *cr)
4648 {
4649   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
4650   GtkTreePath *path;
4651   GtkRBTree *tree;
4652   GList *list;
4653   GtkRBNode *node;
4654   GtkRBNode *drag_highlight = NULL;
4655   GtkRBTree *drag_highlight_tree = NULL;
4656   GtkTreeIter iter;
4657   gint new_y;
4658   gint y_offset, cell_offset;
4659   gint max_height;
4660   gint depth;
4661   GdkRectangle background_area;
4662   GdkRectangle cell_area;
4663   GdkRectangle clip;
4664   guint flags;
4665   gint highlight_x;
4666   gint expander_cell_width;
4667   gint bin_window_width;
4668   gint bin_window_height;
4669   GtkTreePath *drag_dest_path;
4670   GList *first_column, *last_column;
4671   gint vertical_separator;
4672   gint horizontal_separator;
4673   gboolean allow_rules;
4674   gboolean has_can_focus_cell;
4675   gboolean rtl;
4676   gint n_visible_columns;
4677   gint grid_line_width;
4678   gint expander_size;
4679   gboolean draw_vgrid_lines, draw_hgrid_lines;
4680   GtkStyleContext *context;
4681   gboolean parity;
4682
4683   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
4684   context = gtk_widget_get_style_context (widget);
4685
4686   gtk_widget_style_get (widget,
4687                         "horizontal-separator", &horizontal_separator,
4688                         "vertical-separator", &vertical_separator,
4689                         "allow-rules", &allow_rules,
4690                         NULL);
4691
4692   if (tree_view->priv->tree == NULL)
4693     {
4694       draw_empty_focus (tree_view, cr);
4695       return TRUE;
4696     }
4697
4698   bin_window_width = gdk_window_get_width (tree_view->priv->bin_window);
4699   bin_window_height = gdk_window_get_height (tree_view->priv->bin_window);
4700   cairo_rectangle (cr, 0, 0, bin_window_width, bin_window_height);
4701   cairo_clip (cr);
4702   if (!gdk_cairo_get_clip_rectangle (cr, &clip))
4703     return TRUE;
4704
4705   new_y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, clip.y);
4706
4707   if (new_y < 0)
4708     new_y = 0;
4709   y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
4710
4711   if (tree_view->priv->height < bin_window_height)
4712     {
4713       gtk_style_context_save (context);
4714       gtk_style_context_add_class (context, GTK_STYLE_CLASS_CELL);
4715
4716       gtk_render_background (context, cr,
4717                              0, tree_view->priv->height,
4718                              bin_window_width,
4719                              bin_window_height - tree_view->priv->height);
4720
4721       gtk_style_context_restore (context);
4722     }
4723
4724   if (node == NULL)
4725     return TRUE;
4726
4727   /* find the path for the node */
4728   path = _gtk_tree_path_new_from_rbtree (tree, node);
4729   gtk_tree_model_get_iter (tree_view->priv->model,
4730                            &iter,
4731                            path);
4732   depth = gtk_tree_path_get_depth (path);
4733   gtk_tree_path_free (path);
4734   
4735   drag_dest_path = NULL;
4736
4737   if (tree_view->priv->drag_dest_row)
4738     drag_dest_path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
4739
4740   if (drag_dest_path)
4741     _gtk_tree_view_find_node (tree_view, drag_dest_path,
4742                               &drag_highlight_tree, &drag_highlight);
4743
4744   draw_vgrid_lines =
4745     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_VERTICAL
4746     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
4747   draw_hgrid_lines =
4748     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_HORIZONTAL
4749     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
4750   expander_size = gtk_tree_view_get_expander_size (tree_view);
4751
4752   if (draw_vgrid_lines || draw_hgrid_lines)
4753     gtk_widget_style_get (widget, "grid-line-width", &grid_line_width, NULL);
4754   
4755   n_visible_columns = 0;
4756   for (list = tree_view->priv->columns; list; list = list->next)
4757     {
4758       if (!gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (list->data)))
4759         continue;
4760       n_visible_columns ++;
4761     }
4762
4763   /* Find the last column */
4764   for (last_column = g_list_last (tree_view->priv->columns);
4765        last_column &&
4766        !(gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (last_column->data)));
4767        last_column = last_column->prev)
4768     ;
4769
4770   /* and the first */
4771   for (first_column = g_list_first (tree_view->priv->columns);
4772        first_column &&
4773        !(gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (first_column->data)));
4774        first_column = first_column->next)
4775     ;
4776
4777   /* Actually process the expose event.  To do this, we want to
4778    * start at the first node of the event, and walk the tree in
4779    * order, drawing each successive node.
4780    */
4781   
4782   parity = !(_gtk_rbtree_node_get_index (tree, node) % 2);
4783
4784   do
4785     {
4786       gboolean is_separator = FALSE;
4787       gboolean is_first = FALSE;
4788       gboolean is_last = FALSE;
4789       gint n_col = 0;
4790
4791       parity = !parity;
4792       is_separator = row_is_separator (tree_view, &iter, NULL);
4793
4794       max_height = gtk_tree_view_get_row_height (tree_view, node);
4795
4796       cell_offset = 0;
4797       highlight_x = 0; /* should match x coord of first cell */
4798       expander_cell_width = 0;
4799
4800       background_area.y = y_offset + clip.y;
4801       background_area.height = max_height;
4802
4803       flags = 0;
4804
4805       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PRELIT))
4806         flags |= GTK_CELL_RENDERER_PRELIT;
4807
4808       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
4809         flags |= GTK_CELL_RENDERER_SELECTED;
4810
4811       /* we *need* to set cell data on all cells before the call
4812        * to _has_can_focus_cell, else _has_can_focus_cell() does not
4813        * return a correct value.
4814        */
4815       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
4816            list;
4817            list = (rtl ? list->prev : list->next))
4818         {
4819           GtkTreeViewColumn *column = list->data;
4820           gtk_tree_view_column_cell_set_cell_data (column,
4821                                                    tree_view->priv->model,
4822                                                    &iter,
4823                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
4824                                                    node->children?TRUE:FALSE);
4825         }
4826
4827       has_can_focus_cell = gtk_tree_view_has_can_focus_cell (tree_view);
4828
4829       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
4830            list;
4831            list = (rtl ? list->prev : list->next))
4832         {
4833           GtkTreeViewColumn *column = list->data;
4834           GtkRegionFlags row_flags = 0, column_flags = 0;
4835           GtkStateFlags state = 0;
4836           gint width;
4837           gboolean draw_focus;
4838
4839           if (!gtk_tree_view_column_get_visible (column))
4840             continue;
4841
4842           n_col++;
4843           width = gtk_tree_view_column_get_width (column);
4844
4845           if (cell_offset > clip.x + clip.width ||
4846               cell_offset + width < clip.x)
4847             {
4848               cell_offset += width;
4849               continue;
4850             }
4851
4852           if (gtk_tree_view_column_get_sort_indicator (column))
4853             flags |= GTK_CELL_RENDERER_SORTED;
4854           else
4855             flags &= ~GTK_CELL_RENDERER_SORTED;
4856
4857           if (tree_view->priv->cursor_node == node)
4858             flags |= GTK_CELL_RENDERER_FOCUSED;
4859           else
4860             flags &= ~GTK_CELL_RENDERER_FOCUSED;
4861
4862           if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
4863             flags |= GTK_CELL_RENDERER_EXPANDABLE;
4864           else
4865             flags &= ~GTK_CELL_RENDERER_EXPANDABLE;
4866
4867           if (node->children)
4868             flags |= GTK_CELL_RENDERER_EXPANDED;
4869           else
4870             flags &= ~GTK_CELL_RENDERER_EXPANDED;
4871
4872           background_area.x = cell_offset;
4873           background_area.width = width;
4874
4875           cell_area = background_area;
4876           cell_area.y += vertical_separator / 2;
4877           cell_area.x += horizontal_separator / 2;
4878           cell_area.height -= vertical_separator;
4879           cell_area.width -= horizontal_separator;
4880
4881           if (draw_vgrid_lines)
4882             {
4883               if (list == first_column)
4884                 {
4885                   cell_area.width -= grid_line_width / 2;
4886                 }
4887               else if (list == last_column)
4888                 {
4889                   cell_area.x += grid_line_width / 2;
4890                   cell_area.width -= grid_line_width / 2;
4891                 }
4892               else
4893                 {
4894                   cell_area.x += grid_line_width / 2;
4895                   cell_area.width -= grid_line_width;
4896                 }
4897             }
4898
4899           if (draw_hgrid_lines)
4900             {
4901               cell_area.y += grid_line_width / 2;
4902               cell_area.height -= grid_line_width;
4903             }
4904
4905           if (!gdk_rectangle_intersect (&clip, &background_area, NULL))
4906             {
4907               cell_offset += gtk_tree_view_column_get_width (column);
4908               continue;
4909             }
4910
4911           gtk_tree_view_column_cell_set_cell_data (column,
4912                                                    tree_view->priv->model,
4913                                                    &iter,
4914                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
4915                                                    node->children?TRUE:FALSE);
4916
4917           /* Select the detail for drawing the cell.  relevant
4918            * factors are parity, sortedness, and whether to
4919            * display rules.
4920            */
4921           if (allow_rules && tree_view->priv->has_rules)
4922             {
4923               if (parity)
4924                 row_flags |= GTK_REGION_ODD;
4925               else
4926                 row_flags |= GTK_REGION_EVEN;
4927             }
4928
4929           if ((flags & GTK_CELL_RENDERER_SORTED) &&
4930               n_visible_columns >= 3)
4931             column_flags |= GTK_REGION_SORTED;
4932
4933           is_first = (rtl ? !list->next : !list->prev);
4934           is_last = (rtl ? !list->prev : !list->next);
4935
4936           if (is_first)
4937             column_flags |= GTK_REGION_FIRST;
4938
4939           if (is_last)
4940             column_flags |= GTK_REGION_LAST;
4941
4942           if ((n_col % 2) == 0)
4943             column_flags |= GTK_REGION_EVEN;
4944           else
4945             column_flags |= GTK_REGION_ODD;
4946
4947           gtk_style_context_save (context);
4948
4949           state = gtk_cell_renderer_get_state (NULL, widget, flags);
4950           gtk_style_context_set_state (context, state);
4951
4952           gtk_style_context_add_class (context, GTK_STYLE_CLASS_CELL);
4953           gtk_style_context_add_region (context, GTK_STYLE_REGION_ROW, row_flags);
4954           gtk_style_context_add_region (context, GTK_STYLE_REGION_COLUMN, column_flags);
4955
4956           if (node == tree_view->priv->cursor_node && has_can_focus_cell
4957               && ((column == tree_view->priv->focus_column
4958                    && tree_view->priv->draw_keyfocus &&
4959                    gtk_widget_has_visible_focus (widget))
4960                   || (column == tree_view->priv->edited_column)))
4961             draw_focus = TRUE;
4962           else
4963             draw_focus = FALSE;
4964
4965           /* Draw background */
4966           gtk_render_background (context, cr,
4967                                  background_area.x,
4968                                  background_area.y,
4969                                  background_area.width,
4970                                  background_area.height);
4971
4972           /* Draw frame */
4973           gtk_render_frame (context, cr,
4974                             background_area.x,
4975                             background_area.y,
4976                             background_area.width,
4977                             background_area.height);
4978
4979           if (gtk_tree_view_is_expander_column (tree_view, column))
4980             {
4981               if (!rtl)
4982                 cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
4983               cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
4984
4985               if (gtk_tree_view_draw_expanders (tree_view))
4986                 {
4987                   int expander_size = gtk_tree_view_get_expander_size (tree_view);
4988                   if (!rtl)
4989                     cell_area.x += depth * expander_size;
4990                   cell_area.width -= depth * expander_size;
4991                 }
4992
4993               /* If we have an expander column, the highlight underline
4994                * starts with that column, so that it indicates which
4995                * level of the tree we're dropping at.
4996                */
4997               highlight_x = cell_area.x;
4998               expander_cell_width = cell_area.width;
4999
5000               if (is_separator)
5001                 {
5002                   gtk_style_context_save (context);
5003                   gtk_style_context_add_class (context, GTK_STYLE_CLASS_SEPARATOR);
5004
5005                   gtk_render_line (context, cr,
5006                                    cell_area.x,
5007                                    cell_area.y + cell_area.height / 2,
5008                                    cell_area.x + cell_area.width,
5009                                    cell_area.y + cell_area.height / 2);
5010
5011                   gtk_style_context_restore (context);
5012                 }
5013               else
5014                 {
5015                   _gtk_tree_view_column_cell_render (column,
5016                                                      cr,
5017                                                      &background_area,
5018                                                      &cell_area,
5019                                                      flags,
5020                                                      draw_focus);
5021                 }
5022
5023               if (gtk_tree_view_draw_expanders (tree_view)
5024                   && (node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT)
5025                 {
5026                   gtk_tree_view_draw_arrow (GTK_TREE_VIEW (widget),
5027                                             cr,
5028                                             tree,
5029                                             node);
5030                 }
5031             }
5032           else
5033             {
5034               if (is_separator)
5035                 {
5036                   gtk_style_context_save (context);
5037                   gtk_style_context_add_class (context, GTK_STYLE_CLASS_SEPARATOR);
5038
5039                   gtk_render_line (context, cr,
5040                                    cell_area.x,
5041                                    cell_area.y + cell_area.height / 2,
5042                                    cell_area.x + cell_area.width,
5043                                    cell_area.y + cell_area.height / 2);
5044
5045                   gtk_style_context_restore (context);
5046                 }
5047               else
5048                 _gtk_tree_view_column_cell_render (column,
5049                                                    cr,
5050                                                    &background_area,
5051                                                    &cell_area,
5052                                                    flags,
5053                                                    draw_focus);
5054             }
5055
5056           if (draw_hgrid_lines)
5057             {
5058               if (background_area.y > 0)
5059                 gtk_tree_view_draw_line (tree_view, cr,
5060                                          GTK_TREE_VIEW_GRID_LINE,
5061                                          background_area.x, background_area.y,
5062                                          background_area.x + background_area.width,
5063                                          background_area.y);
5064
5065               if (y_offset + max_height >= clip.height)
5066                 gtk_tree_view_draw_line (tree_view, cr,
5067                                          GTK_TREE_VIEW_GRID_LINE,
5068                                          background_area.x, background_area.y + max_height,
5069                                          background_area.x + background_area.width,
5070                                          background_area.y + max_height);
5071             }
5072
5073           if (gtk_tree_view_is_expander_column (tree_view, column) &&
5074               tree_view->priv->tree_lines_enabled)
5075             {
5076               gint x = background_area.x;
5077               gint mult = rtl ? -1 : 1;
5078               gint y0 = background_area.y;
5079               gint y1 = background_area.y + background_area.height/2;
5080               gint y2 = background_area.y + background_area.height;
5081
5082               if (rtl)
5083                 x += background_area.width - 1;
5084
5085               if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT
5086                   && depth > 1)
5087                 {
5088                   gtk_tree_view_draw_line (tree_view, cr,
5089                                            GTK_TREE_VIEW_TREE_LINE,
5090                                            x + expander_size * (depth - 1.5) * mult,
5091                                            y1,
5092                                            x + expander_size * (depth - 1.1) * mult,
5093                                            y1);
5094                 }
5095               else if (depth > 1)
5096                 {
5097                   gtk_tree_view_draw_line (tree_view, cr,
5098                                            GTK_TREE_VIEW_TREE_LINE,
5099                                            x + expander_size * (depth - 1.5) * mult,
5100                                            y1,
5101                                            x + expander_size * (depth - 0.5) * mult,
5102                                            y1);
5103                 }
5104
5105               if (depth > 1)
5106                 {
5107                   gint i;
5108                   GtkRBNode *tmp_node;
5109                   GtkRBTree *tmp_tree;
5110
5111                   if (!_gtk_rbtree_next (tree, node))
5112                     gtk_tree_view_draw_line (tree_view, cr,
5113                                              GTK_TREE_VIEW_TREE_LINE,
5114                                              x + expander_size * (depth - 1.5) * mult,
5115                                              y0,
5116                                              x + expander_size * (depth - 1.5) * mult,
5117                                              y1);
5118                   else
5119                     gtk_tree_view_draw_line (tree_view, cr,
5120                                              GTK_TREE_VIEW_TREE_LINE,
5121                                              x + expander_size * (depth - 1.5) * mult,
5122                                              y0,
5123                                              x + expander_size * (depth - 1.5) * mult,
5124                                              y2);
5125
5126                   tmp_node = tree->parent_node;
5127                   tmp_tree = tree->parent_tree;
5128
5129                   for (i = depth - 2; i > 0; i--)
5130                     {
5131                       if (_gtk_rbtree_next (tmp_tree, tmp_node))
5132                         gtk_tree_view_draw_line (tree_view, cr,
5133                                                  GTK_TREE_VIEW_TREE_LINE,
5134                                                  x + expander_size * (i - 0.5) * mult,
5135                                                  y0,
5136                                                  x + expander_size * (i - 0.5) * mult,
5137                                                  y2);
5138
5139                       tmp_node = tmp_tree->parent_node;
5140                       tmp_tree = tmp_tree->parent_tree;
5141                     }
5142                 }
5143             }
5144
5145           gtk_style_context_restore (context);
5146           cell_offset += gtk_tree_view_column_get_width (column);
5147         }
5148
5149       if (node == drag_highlight)
5150         {
5151           /* Draw indicator for the drop
5152            */
5153           gint highlight_y = -1;
5154           GtkRBTree *tree = NULL;
5155           GtkRBNode *node = NULL;
5156
5157           gtk_style_context_save (context);
5158           gtk_style_context_add_class (context, GTK_STYLE_CLASS_DND);
5159
5160           switch (tree_view->priv->drag_dest_pos)
5161             {
5162             case GTK_TREE_VIEW_DROP_BEFORE:
5163               highlight_y = background_area.y - 1;
5164               if (highlight_y < 0)
5165                       highlight_y = 0;
5166               break;
5167
5168             case GTK_TREE_VIEW_DROP_AFTER:
5169               highlight_y = background_area.y + background_area.height - 1;
5170               break;
5171
5172             case GTK_TREE_VIEW_DROP_INTO_OR_BEFORE:
5173             case GTK_TREE_VIEW_DROP_INTO_OR_AFTER:
5174               _gtk_tree_view_find_node (tree_view, drag_dest_path, &tree, &node);
5175
5176               if (tree == NULL)
5177                 break;
5178
5179               gtk_render_frame (context, cr,
5180                                 0, gtk_tree_view_get_row_y_offset (tree_view, tree, node),
5181                                 gdk_window_get_width (tree_view->priv->bin_window),
5182                                 gtk_tree_view_get_row_height (tree_view, node));
5183               break;
5184             }
5185
5186           if (highlight_y >= 0)
5187             {
5188               gtk_tree_view_draw_line (tree_view, cr,
5189                                        GTK_TREE_VIEW_FOREGROUND_LINE,
5190                                        rtl ? highlight_x + expander_cell_width : highlight_x,
5191                                        highlight_y,
5192                                        rtl ? 0 : bin_window_width,
5193                                        highlight_y);
5194             }
5195
5196           gtk_style_context_restore (context);
5197         }
5198
5199       /* draw the big row-spanning focus rectangle, if needed */
5200       if (!has_can_focus_cell && node == tree_view->priv->cursor_node &&
5201           tree_view->priv->draw_keyfocus &&
5202           gtk_widget_has_visible_focus (widget))
5203         {
5204           gint tmp_y, tmp_height;
5205           GtkStateFlags focus_rect_state = 0;
5206
5207           gtk_style_context_save (context);
5208
5209           focus_rect_state = gtk_cell_renderer_get_state (NULL, widget, flags);
5210           gtk_style_context_set_state (context, focus_rect_state);
5211
5212           if (draw_hgrid_lines)
5213             {
5214               tmp_y = gtk_tree_view_get_row_y_offset (tree_view, tree, node) + grid_line_width / 2;
5215               tmp_height = gtk_tree_view_get_row_height (tree_view, node) - grid_line_width;
5216             }
5217           else
5218             {
5219               tmp_y = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
5220               tmp_height = gtk_tree_view_get_row_height (tree_view, node);
5221             }
5222
5223           gtk_render_focus (context, cr,
5224                             0, tmp_y,
5225                             gdk_window_get_width (tree_view->priv->bin_window),
5226                             tmp_height);
5227
5228           gtk_style_context_restore (context);
5229         }
5230
5231       y_offset += max_height;
5232       if (node->children)
5233         {
5234           GtkTreeIter parent = iter;
5235           gboolean has_child;
5236
5237           tree = node->children;
5238           node = _gtk_rbtree_first (tree);
5239
5240           has_child = gtk_tree_model_iter_children (tree_view->priv->model,
5241                                                     &iter,
5242                                                     &parent);
5243           depth++;
5244
5245           /* Sanity Check! */
5246           TREE_VIEW_INTERNAL_ASSERT (has_child, FALSE);
5247         }
5248       else
5249         {
5250           gboolean done = FALSE;
5251
5252           do
5253             {
5254               node = _gtk_rbtree_next (tree, node);
5255               if (node != NULL)
5256                 {
5257                   gboolean has_next = gtk_tree_model_iter_next (tree_view->priv->model, &iter);
5258                   done = TRUE;
5259
5260                   /* Sanity Check! */
5261                   TREE_VIEW_INTERNAL_ASSERT (has_next, FALSE);
5262                 }
5263               else
5264                 {
5265                   GtkTreeIter parent_iter = iter;
5266                   gboolean has_parent;
5267
5268                   node = tree->parent_node;
5269                   tree = tree->parent_tree;
5270                   if (tree == NULL)
5271                     /* we should go to done to free some memory */
5272                     goto done;
5273                   has_parent = gtk_tree_model_iter_parent (tree_view->priv->model,
5274                                                            &iter,
5275                                                            &parent_iter);
5276                   depth--;
5277
5278                   /* Sanity check */
5279                   TREE_VIEW_INTERNAL_ASSERT (has_parent, FALSE);
5280                 }
5281             }
5282           while (!done);
5283         }
5284     }
5285   while (y_offset < clip.height);
5286
5287 done:
5288   gtk_tree_view_draw_grid_lines (tree_view, cr, n_visible_columns);
5289
5290   if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
5291     gtk_tree_view_paint_rubber_band (tree_view, cr);
5292
5293   if (drag_dest_path)
5294     gtk_tree_path_free (drag_dest_path);
5295
5296   return FALSE;
5297 }
5298
5299 static gboolean
5300 gtk_tree_view_draw (GtkWidget *widget,
5301                     cairo_t   *cr)
5302 {
5303   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
5304   GtkWidget   *button;
5305   GtkStyleContext *context;
5306
5307   context = gtk_widget_get_style_context (widget);
5308   gtk_render_background (context, cr,
5309                          0, 0,
5310                          gtk_widget_get_allocated_width (widget),
5311                          gtk_widget_get_allocated_height (widget));
5312
5313   if (gtk_cairo_should_draw_window (cr, tree_view->priv->bin_window))
5314     {
5315       GList *tmp_list;
5316
5317       cairo_save (cr);
5318
5319       gtk_cairo_transform_to_window (cr, widget, tree_view->priv->bin_window);
5320       gtk_tree_view_bin_draw (widget, cr);
5321
5322       cairo_restore (cr);
5323
5324       /* We can't just chain up to Container::draw as it will try to send the
5325        * event to the headers, so we handle propagating it to our children
5326        * (eg. widgets being edited) ourselves.
5327        */
5328       tmp_list = tree_view->priv->children;
5329       while (tmp_list)
5330         {
5331           GtkTreeViewChild *child = tmp_list->data;
5332           tmp_list = tmp_list->next;
5333
5334           gtk_container_propagate_draw (GTK_CONTAINER (tree_view), child->widget, cr);
5335         }
5336     }
5337
5338   gtk_style_context_save (context);
5339   gtk_style_context_remove_class (context, GTK_STYLE_CLASS_VIEW);
5340
5341   if (gtk_cairo_should_draw_window (cr, tree_view->priv->header_window))
5342     {
5343       GList *list;
5344       
5345       for (list = tree_view->priv->columns; list != NULL; list = list->next)
5346         {
5347           GtkTreeViewColumn *column = list->data;
5348
5349           if (column == tree_view->priv->drag_column)
5350             continue;
5351
5352           if (gtk_tree_view_column_get_visible (column))
5353             {
5354               button = gtk_tree_view_column_get_button (column);
5355               gtk_container_propagate_draw (GTK_CONTAINER (tree_view),
5356                                             button, cr);
5357             }
5358         }
5359     }
5360   
5361   if (tree_view->priv->drag_window &&
5362       gtk_cairo_should_draw_window (cr, tree_view->priv->drag_window))
5363     {
5364       button = gtk_tree_view_column_get_button (tree_view->priv->drag_column);
5365       gtk_container_propagate_draw (GTK_CONTAINER (tree_view),
5366                                     button, cr);
5367     }
5368
5369   gtk_style_context_restore (context);
5370
5371   return FALSE;
5372 }
5373
5374 enum
5375 {
5376   DROP_HOME,
5377   DROP_RIGHT,
5378   DROP_LEFT,
5379   DROP_END
5380 };
5381
5382 /* returns 0x1 when no column has been found -- yes it's hackish */
5383 static GtkTreeViewColumn *
5384 gtk_tree_view_get_drop_column (GtkTreeView       *tree_view,
5385                                GtkTreeViewColumn *column,
5386                                gint               drop_position)
5387 {
5388   GtkTreeViewColumn *left_column = NULL;
5389   GtkTreeViewColumn *cur_column = NULL;
5390   GList *tmp_list;
5391
5392   if (!gtk_tree_view_column_get_reorderable (column))
5393     return (GtkTreeViewColumn *)0x1;
5394
5395   switch (drop_position)
5396     {
5397       case DROP_HOME:
5398         /* find first column where we can drop */
5399         tmp_list = tree_view->priv->columns;
5400         if (column == GTK_TREE_VIEW_COLUMN (tmp_list->data))
5401           return (GtkTreeViewColumn *)0x1;
5402
5403         while (tmp_list)
5404           {
5405             g_assert (tmp_list);
5406
5407             cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5408             tmp_list = tmp_list->next;
5409
5410             if (left_column &&
5411                 gtk_tree_view_column_get_visible (left_column) == FALSE)
5412               continue;
5413
5414             if (!tree_view->priv->column_drop_func)
5415               return left_column;
5416
5417             if (!tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5418               {
5419                 left_column = cur_column;
5420                 continue;
5421               }
5422
5423             return left_column;
5424           }
5425
5426         if (!tree_view->priv->column_drop_func)
5427           return left_column;
5428
5429         if (tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data))
5430           return left_column;
5431         else
5432           return (GtkTreeViewColumn *)0x1;
5433         break;
5434
5435       case DROP_RIGHT:
5436         /* find first column after column where we can drop */
5437         tmp_list = tree_view->priv->columns;
5438
5439         for (; tmp_list; tmp_list = tmp_list->next)
5440           if (GTK_TREE_VIEW_COLUMN (tmp_list->data) == column)
5441             break;
5442
5443         if (!tmp_list || !tmp_list->next)
5444           return (GtkTreeViewColumn *)0x1;
5445
5446         tmp_list = tmp_list->next;
5447         left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5448         tmp_list = tmp_list->next;
5449
5450         while (tmp_list)
5451           {
5452             g_assert (tmp_list);
5453
5454             cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5455             tmp_list = tmp_list->next;
5456
5457             if (left_column &&
5458                 gtk_tree_view_column_get_visible (left_column) == FALSE)
5459               {
5460                 left_column = cur_column;
5461                 if (tmp_list)
5462                   tmp_list = tmp_list->next;
5463                 continue;
5464               }
5465
5466             if (!tree_view->priv->column_drop_func)
5467               return left_column;
5468
5469             if (!tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5470               {
5471                 left_column = cur_column;
5472                 continue;
5473               }
5474
5475             return left_column;
5476           }
5477
5478         if (!tree_view->priv->column_drop_func)
5479           return left_column;
5480
5481         if (tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data))
5482           return left_column;
5483         else
5484           return (GtkTreeViewColumn *)0x1;
5485         break;
5486
5487       case DROP_LEFT:
5488         /* find first column before column where we can drop */
5489         tmp_list = tree_view->priv->columns;
5490
5491         for (; tmp_list; tmp_list = tmp_list->next)
5492           if (GTK_TREE_VIEW_COLUMN (tmp_list->data) == column)
5493             break;
5494
5495         if (!tmp_list || !tmp_list->prev)
5496           return (GtkTreeViewColumn *)0x1;
5497
5498         tmp_list = tmp_list->prev;
5499         cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5500         tmp_list = tmp_list->prev;
5501
5502         while (tmp_list)
5503           {
5504             g_assert (tmp_list);
5505
5506             left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5507
5508             if (left_column &&
5509                 gtk_tree_view_column_get_visible (left_column) == FALSE)
5510               {
5511                 /*if (!tmp_list->prev)
5512                   return (GtkTreeViewColumn *)0x1;
5513                   */
5514 /*
5515                 cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->prev->data);
5516                 tmp_list = tmp_list->prev->prev;
5517                 continue;*/
5518
5519                 cur_column = left_column;
5520                 if (tmp_list)
5521                   tmp_list = tmp_list->prev;
5522                 continue;
5523               }
5524
5525             if (!tree_view->priv->column_drop_func)
5526               return left_column;
5527
5528             if (tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5529               return left_column;
5530
5531             cur_column = left_column;
5532             tmp_list = tmp_list->prev;
5533           }
5534
5535         if (!tree_view->priv->column_drop_func)
5536           return NULL;
5537
5538         if (tree_view->priv->column_drop_func (tree_view, column, NULL, cur_column, tree_view->priv->column_drop_func_data))
5539           return NULL;
5540         else
5541           return (GtkTreeViewColumn *)0x1;
5542         break;
5543
5544       case DROP_END:
5545         /* same as DROP_HOME case, but doing it backwards */
5546         tmp_list = g_list_last (tree_view->priv->columns);
5547         cur_column = NULL;
5548
5549         if (column == GTK_TREE_VIEW_COLUMN (tmp_list->data))
5550           return (GtkTreeViewColumn *)0x1;
5551
5552         while (tmp_list)
5553           {
5554             g_assert (tmp_list);
5555
5556             left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5557
5558             if (left_column &&
5559                 gtk_tree_view_column_get_visible (left_column) == FALSE)
5560               {
5561                 cur_column = left_column;
5562                 tmp_list = tmp_list->prev;
5563               }
5564
5565             if (!tree_view->priv->column_drop_func)
5566               return left_column;
5567
5568             if (tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5569               return left_column;
5570
5571             cur_column = left_column;
5572             tmp_list = tmp_list->prev;
5573           }
5574
5575         if (!tree_view->priv->column_drop_func)
5576           return NULL;
5577
5578         if (tree_view->priv->column_drop_func (tree_view, column, NULL, cur_column, tree_view->priv->column_drop_func_data))
5579           return NULL;
5580         else
5581           return (GtkTreeViewColumn *)0x1;
5582         break;
5583     }
5584
5585   return (GtkTreeViewColumn *)0x1;
5586 }
5587
5588 static gboolean
5589 gtk_tree_view_key_press (GtkWidget   *widget,
5590                          GdkEventKey *event)
5591 {
5592   GtkTreeView *tree_view = (GtkTreeView *) widget;
5593   GtkWidget   *button;
5594
5595   if (tree_view->priv->rubber_band_status)
5596     {
5597       if (event->keyval == GDK_KEY_Escape)
5598         gtk_tree_view_stop_rubber_band (tree_view);
5599
5600       return TRUE;
5601     }
5602
5603   if (tree_view->priv->in_column_drag)
5604     {
5605       if (event->keyval == GDK_KEY_Escape)
5606         {
5607           tree_view->priv->cur_reorder = NULL;
5608           gtk_tree_view_button_release_drag_column (widget, NULL);
5609         }
5610       return TRUE;
5611     }
5612
5613   if (tree_view->priv->headers_visible)
5614     {
5615       GList *focus_column;
5616       gboolean rtl;
5617
5618       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
5619
5620       for (focus_column = tree_view->priv->columns;
5621            focus_column;
5622            focus_column = focus_column->next)
5623         {
5624           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
5625           
5626           button = gtk_tree_view_column_get_button (column);
5627           if (gtk_widget_has_focus (button))
5628             break;
5629         }
5630
5631       if (focus_column &&
5632           (event->state & GDK_SHIFT_MASK) && (event->state & GDK_MOD1_MASK) &&
5633           (event->keyval == GDK_KEY_Left || event->keyval == GDK_KEY_KP_Left
5634            || event->keyval == GDK_KEY_Right || event->keyval == GDK_KEY_KP_Right))
5635         {
5636           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
5637           gint max_width, min_width;
5638
5639           if (!gtk_tree_view_column_get_resizable (column))
5640             {
5641               gtk_widget_error_bell (widget);
5642               return TRUE;
5643             }
5644
5645           if (event->keyval == (rtl ? GDK_KEY_Right : GDK_KEY_Left)
5646               || event->keyval == (rtl ? GDK_KEY_KP_Right : GDK_KEY_KP_Left))
5647             {
5648               GtkRequisition button_req;
5649               gint old_width = _gtk_tree_view_column_get_resized_width (column);
5650               gint new_width;
5651
5652               button = gtk_tree_view_column_get_button (column);
5653
5654               gtk_widget_get_preferred_size (button, &button_req, NULL);
5655
5656               new_width = MAX (old_width, gtk_tree_view_column_get_width (column));
5657               new_width -= 2;
5658               if (new_width < 0)
5659                 new_width = 0;
5660
5661               _gtk_tree_view_column_set_resized_width (column, new_width);
5662
5663               min_width = gtk_tree_view_column_get_min_width (column);
5664               if (min_width == -1)
5665                 new_width = MAX (button_req.width, new_width);
5666               else
5667                 {
5668                   new_width = MAX (min_width, new_width);
5669                 }
5670
5671               max_width = gtk_tree_view_column_get_max_width (column);
5672               if (max_width != -1)
5673                 new_width = MIN (new_width, max_width);
5674
5675               _gtk_tree_view_column_set_use_resized_width (column, TRUE);
5676
5677               if (new_width != old_width)
5678                 {
5679                   _gtk_tree_view_column_set_resized_width (column, new_width);
5680                   gtk_widget_queue_resize (widget);
5681                 }
5682               else
5683                 gtk_widget_error_bell (widget);
5684             }
5685           else if (event->keyval == (rtl ? GDK_KEY_Left : GDK_KEY_Right)
5686                    || event->keyval == (rtl ? GDK_KEY_KP_Left : GDK_KEY_KP_Right))
5687             {
5688               gint old_width = _gtk_tree_view_column_get_resized_width (column);
5689               gint new_width;
5690
5691               new_width = MAX (old_width, gtk_tree_view_column_get_width (column));
5692               new_width += 2;
5693
5694               max_width = gtk_tree_view_column_get_max_width (column);
5695               if (max_width != -1)
5696                 new_width = MIN (new_width, max_width);
5697
5698               _gtk_tree_view_column_set_use_resized_width (column, TRUE);
5699
5700               if (new_width != old_width)
5701                 {
5702                   _gtk_tree_view_column_set_resized_width (column, new_width);
5703                   gtk_widget_queue_resize (widget);
5704                 }
5705               else
5706                 gtk_widget_error_bell (widget);
5707             }
5708
5709           return TRUE;
5710         }
5711
5712       if (focus_column &&
5713           (event->state & GDK_MOD1_MASK) &&
5714           (event->keyval == GDK_KEY_Left || event->keyval == GDK_KEY_KP_Left
5715            || event->keyval == GDK_KEY_Right || event->keyval == GDK_KEY_KP_Right
5716            || event->keyval == GDK_KEY_Home || event->keyval == GDK_KEY_KP_Home
5717            || event->keyval == GDK_KEY_End || event->keyval == GDK_KEY_KP_End))
5718         {
5719           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
5720
5721           if (event->keyval == (rtl ? GDK_KEY_Right : GDK_KEY_Left)
5722               || event->keyval == (rtl ? GDK_KEY_KP_Right : GDK_KEY_KP_Left))
5723             {
5724               GtkTreeViewColumn *col;
5725               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_LEFT);
5726               if (col != (GtkTreeViewColumn *)0x1)
5727                 gtk_tree_view_move_column_after (tree_view, column, col);
5728               else
5729                 gtk_widget_error_bell (widget);
5730             }
5731           else if (event->keyval == (rtl ? GDK_KEY_Left : GDK_KEY_Right)
5732                    || event->keyval == (rtl ? GDK_KEY_KP_Left : GDK_KEY_KP_Right))
5733             {
5734               GtkTreeViewColumn *col;
5735               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_RIGHT);
5736               if (col != (GtkTreeViewColumn *)0x1)
5737                 gtk_tree_view_move_column_after (tree_view, column, col);
5738               else
5739                 gtk_widget_error_bell (widget);
5740             }
5741           else if (event->keyval == GDK_KEY_Home || event->keyval == GDK_KEY_KP_Home)
5742             {
5743               GtkTreeViewColumn *col;
5744               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_HOME);
5745               if (col != (GtkTreeViewColumn *)0x1)
5746                 gtk_tree_view_move_column_after (tree_view, column, col);
5747               else
5748                 gtk_widget_error_bell (widget);
5749             }
5750           else if (event->keyval == GDK_KEY_End || event->keyval == GDK_KEY_KP_End)
5751             {
5752               GtkTreeViewColumn *col;
5753               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_END);
5754               if (col != (GtkTreeViewColumn *)0x1)
5755                 gtk_tree_view_move_column_after (tree_view, column, col);
5756               else
5757                 gtk_widget_error_bell (widget);
5758             }
5759
5760           return TRUE;
5761         }
5762     }
5763
5764   /* Chain up to the parent class.  It handles the keybindings. */
5765   if (GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->key_press_event (widget, event))
5766     return TRUE;
5767
5768   if (tree_view->priv->search_entry_avoid_unhandled_binding)
5769     {
5770       tree_view->priv->search_entry_avoid_unhandled_binding = FALSE;
5771       return FALSE;
5772     }
5773
5774   /* We pass the event to the search_entry.  If its text changes, then we start
5775    * the typeahead find capabilities. */
5776   if (gtk_widget_has_focus (GTK_WIDGET (tree_view))
5777       && tree_view->priv->enable_search
5778       && !tree_view->priv->search_custom_entry_set)
5779     {
5780       GdkEvent *new_event;
5781       char *old_text;
5782       const char *new_text;
5783       gboolean retval;
5784       GdkScreen *screen;
5785       gboolean text_modified;
5786       gulong popup_menu_id;
5787
5788       gtk_tree_view_ensure_interactive_directory (tree_view);
5789
5790       /* Make a copy of the current text */
5791       old_text = g_strdup (gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry)));
5792       new_event = gdk_event_copy ((GdkEvent *) event);
5793       g_object_unref (((GdkEventKey *) new_event)->window);
5794       ((GdkEventKey *) new_event)->window = g_object_ref (gtk_widget_get_window (tree_view->priv->search_window));
5795       gtk_widget_realize (tree_view->priv->search_window);
5796
5797       popup_menu_id = g_signal_connect (tree_view->priv->search_entry, 
5798                                         "popup-menu", G_CALLBACK (gtk_true),
5799                                         NULL);
5800
5801       /* Move the entry off screen */
5802       screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
5803       gtk_window_move (GTK_WINDOW (tree_view->priv->search_window),
5804                        gdk_screen_get_width (screen) + 1,
5805                        gdk_screen_get_height (screen) + 1);
5806       gtk_widget_show (tree_view->priv->search_window);
5807
5808       /* Send the event to the window.  If the preedit_changed signal is emitted
5809        * during this event, we will set priv->imcontext_changed  */
5810       tree_view->priv->imcontext_changed = FALSE;
5811       retval = gtk_widget_event (tree_view->priv->search_window, new_event);
5812       gdk_event_free (new_event);
5813       gtk_widget_hide (tree_view->priv->search_window);
5814
5815       g_signal_handler_disconnect (tree_view->priv->search_entry, 
5816                                    popup_menu_id);
5817
5818       /* We check to make sure that the entry tried to handle the text, and that
5819        * the text has changed.
5820        */
5821       new_text = gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry));
5822       text_modified = strcmp (old_text, new_text) != 0;
5823       g_free (old_text);
5824       if (tree_view->priv->imcontext_changed ||    /* we're in a preedit */
5825           (retval && text_modified))               /* ...or the text was modified */
5826         {
5827           if (gtk_tree_view_real_start_interactive_search (tree_view,
5828                                                            gdk_event_get_device ((GdkEvent *) event),
5829                                                            FALSE))
5830             {
5831               gtk_widget_grab_focus (GTK_WIDGET (tree_view));
5832               return TRUE;
5833             }
5834           else
5835             {
5836               gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
5837               return FALSE;
5838             }
5839         }
5840     }
5841
5842   return FALSE;
5843 }
5844
5845 static gboolean
5846 gtk_tree_view_key_release (GtkWidget   *widget,
5847                            GdkEventKey *event)
5848 {
5849   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
5850
5851   if (tree_view->priv->rubber_band_status)
5852     return TRUE;
5853
5854   return GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->key_release_event (widget, event);
5855 }
5856
5857 /* FIXME Is this function necessary? Can I get an enter_notify event
5858  * w/o either an expose event or a mouse motion event?
5859  */
5860 static gboolean
5861 gtk_tree_view_enter_notify (GtkWidget        *widget,
5862                             GdkEventCrossing *event)
5863 {
5864   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
5865   GtkRBTree *tree;
5866   GtkRBNode *node;
5867   gint new_y;
5868
5869   /* Sanity check it */
5870   if (event->window != tree_view->priv->bin_window)
5871     return FALSE;
5872
5873   if (tree_view->priv->tree == NULL)
5874     return FALSE;
5875
5876   if (event->mode == GDK_CROSSING_GRAB ||
5877       event->mode == GDK_CROSSING_GTK_GRAB ||
5878       event->mode == GDK_CROSSING_GTK_UNGRAB ||
5879       event->mode == GDK_CROSSING_STATE_CHANGED)
5880     return TRUE;
5881
5882   /* find the node internally */
5883   new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
5884   if (new_y < 0)
5885     new_y = 0;
5886   _gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
5887
5888   tree_view->priv->event_last_x = event->x;
5889   tree_view->priv->event_last_y = event->y;
5890
5891   if ((tree_view->priv->button_pressed_node == NULL) ||
5892       (tree_view->priv->button_pressed_node == node))
5893     prelight_or_select (tree_view, tree, node, event->x, event->y);
5894
5895   return TRUE;
5896 }
5897
5898 static gboolean
5899 gtk_tree_view_leave_notify (GtkWidget        *widget,
5900                             GdkEventCrossing *event)
5901 {
5902   GtkTreeView *tree_view;
5903
5904   if (event->mode == GDK_CROSSING_GRAB ||
5905       event->mode == GDK_CROSSING_GTK_GRAB ||
5906       event->mode == GDK_CROSSING_GTK_UNGRAB)
5907     return TRUE;
5908
5909   tree_view = GTK_TREE_VIEW (widget);
5910
5911   if (tree_view->priv->prelight_node)
5912     _gtk_tree_view_queue_draw_node (tree_view,
5913                                    tree_view->priv->prelight_tree,
5914                                    tree_view->priv->prelight_node,
5915                                    NULL);
5916
5917   tree_view->priv->event_last_x = -10000;
5918   tree_view->priv->event_last_y = -10000;
5919
5920   prelight_or_select (tree_view,
5921                       NULL, NULL,
5922                       -1000, -1000); /* coords not possibly over an arrow */
5923
5924   return TRUE;
5925 }
5926
5927
5928 static gint
5929 gtk_tree_view_focus_out (GtkWidget     *widget,
5930                          GdkEventFocus *event)
5931 {
5932   GtkTreeView *tree_view;
5933
5934   tree_view = GTK_TREE_VIEW (widget);
5935
5936   gtk_widget_queue_draw (widget);
5937
5938   /* destroy interactive search dialog */
5939   if (tree_view->priv->search_window)
5940     gtk_tree_view_search_dialog_hide (tree_view->priv->search_window, tree_view,
5941                                       gdk_event_get_device ((GdkEvent *) event));
5942
5943   return FALSE;
5944 }
5945
5946
5947 /* Incremental Reflow
5948  */
5949
5950 static void
5951 gtk_tree_view_node_queue_redraw (GtkTreeView *tree_view,
5952                                  GtkRBTree   *tree,
5953                                  GtkRBNode   *node)
5954 {
5955   GtkAllocation allocation;
5956   gint y;
5957
5958   y = _gtk_rbtree_node_find_offset (tree, node)
5959     - gtk_adjustment_get_value (tree_view->priv->vadjustment)
5960     + gtk_tree_view_get_effective_header_height (tree_view);
5961
5962   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
5963   gtk_widget_queue_draw_area (GTK_WIDGET (tree_view),
5964                               0, y,
5965                               allocation.width,
5966                               GTK_RBNODE_GET_HEIGHT (node));
5967 }
5968
5969 static gboolean
5970 node_is_visible (GtkTreeView *tree_view,
5971                  GtkRBTree   *tree,
5972                  GtkRBNode   *node)
5973 {
5974   int y;
5975   int height;
5976
5977   y = _gtk_rbtree_node_find_offset (tree, node);
5978   height = gtk_tree_view_get_row_height (tree_view, node);
5979
5980   if (y >= gtk_adjustment_get_value (tree_view->priv->vadjustment) &&
5981       y + height <= (gtk_adjustment_get_value (tree_view->priv->vadjustment)
5982                      + gtk_adjustment_get_page_size (tree_view->priv->vadjustment)))
5983     return TRUE;
5984
5985   return FALSE;
5986 }
5987
5988 /* Returns TRUE if it updated the size
5989  */
5990 static gboolean
5991 validate_row (GtkTreeView *tree_view,
5992               GtkRBTree   *tree,
5993               GtkRBNode   *node,
5994               GtkTreeIter *iter,
5995               GtkTreePath *path)
5996 {
5997   GtkTreeViewColumn *column;
5998   GList *list, *first_column, *last_column;
5999   gint height = 0;
6000   gint horizontal_separator;
6001   gint vertical_separator;
6002   gint depth = gtk_tree_path_get_depth (path);
6003   gboolean retval = FALSE;
6004   gboolean is_separator = FALSE;
6005   gboolean draw_vgrid_lines, draw_hgrid_lines;
6006   gint focus_pad;
6007   gint grid_line_width;
6008   gboolean wide_separators;
6009   gint separator_height;
6010   gint expander_size;
6011
6012   /* double check the row needs validating */
6013   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) &&
6014       ! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6015     return FALSE;
6016
6017   is_separator = row_is_separator (tree_view, iter, NULL);
6018
6019   gtk_widget_style_get (GTK_WIDGET (tree_view),
6020                         "focus-padding", &focus_pad,
6021                         "horizontal-separator", &horizontal_separator,
6022                         "vertical-separator", &vertical_separator,
6023                         "grid-line-width", &grid_line_width,
6024                         "wide-separators",  &wide_separators,
6025                         "separator-height", &separator_height,
6026                         NULL);
6027   
6028   draw_vgrid_lines =
6029     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_VERTICAL
6030     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
6031   draw_hgrid_lines =
6032     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_HORIZONTAL
6033     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
6034   expander_size = gtk_tree_view_get_expander_size (tree_view);
6035
6036   for (last_column = g_list_last (tree_view->priv->columns);
6037        last_column &&
6038        !(gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (last_column->data)));
6039        last_column = last_column->prev)
6040     ;
6041
6042   for (first_column = g_list_first (tree_view->priv->columns);
6043        first_column &&
6044        !(gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (first_column->data)));
6045        first_column = first_column->next)
6046     ;
6047
6048   for (list = tree_view->priv->columns; list; list = list->next)
6049     {
6050       gint padding = 0;
6051       gint original_width;
6052       gint new_width;
6053       gint row_height;
6054
6055       column = list->data;
6056
6057       if (!gtk_tree_view_column_get_visible (column))
6058         continue;
6059
6060       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID) && 
6061           !_gtk_tree_view_column_cell_get_dirty (column))
6062         continue;
6063
6064       original_width = _gtk_tree_view_column_get_requested_width (column);
6065
6066       gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, iter,
6067                                                GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
6068                                                node->children?TRUE:FALSE);
6069       gtk_tree_view_column_cell_get_size (column,
6070                                           NULL, NULL, NULL,
6071                                           NULL, &row_height);
6072
6073       if (!is_separator)
6074         {
6075           row_height += vertical_separator;
6076           height = MAX (height, row_height);
6077           height = MAX (height, expander_size);
6078         }
6079       else
6080         {
6081           if (wide_separators)
6082             height = separator_height + 2 * focus_pad;
6083           else
6084             height = 2 + 2 * focus_pad;
6085         }
6086
6087       if (gtk_tree_view_is_expander_column (tree_view, column))
6088         {
6089           padding += horizontal_separator + (depth - 1) * tree_view->priv->level_indentation;
6090
6091           if (gtk_tree_view_draw_expanders (tree_view))
6092             padding += depth * expander_size;
6093         }
6094       else
6095         padding += horizontal_separator;
6096
6097       if (draw_vgrid_lines)
6098         {
6099           if (list->data == first_column || list->data == last_column)
6100             padding += grid_line_width / 2.0;
6101           else
6102             padding += grid_line_width;
6103         }
6104
6105       /* Update the padding for the column */
6106       _gtk_tree_view_column_push_padding (column, padding);
6107       new_width = _gtk_tree_view_column_get_requested_width (column);
6108
6109       if (new_width > original_width)
6110         retval = TRUE;
6111     }
6112
6113   if (draw_hgrid_lines)
6114     height += grid_line_width;
6115
6116   if (height != GTK_RBNODE_GET_HEIGHT (node))
6117     {
6118       retval = TRUE;
6119       _gtk_rbtree_node_set_height (tree, node, height);
6120     }
6121   _gtk_rbtree_node_mark_valid (tree, node);
6122   tree_view->priv->post_validation_flag = TRUE;
6123
6124   return retval;
6125 }
6126
6127
6128 static void
6129 validate_visible_area (GtkTreeView *tree_view)
6130 {
6131   GtkAllocation allocation;
6132   GtkTreePath *path = NULL;
6133   GtkTreePath *above_path = NULL;
6134   GtkTreeIter iter;
6135   GtkRBTree *tree = NULL;
6136   GtkRBNode *node = NULL;
6137   gboolean need_redraw = FALSE;
6138   gboolean size_changed = FALSE;
6139   gint total_height;
6140   gint area_above = 0;
6141   gint area_below = 0;
6142
6143   if (tree_view->priv->tree == NULL)
6144     return;
6145
6146   if (! GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID) &&
6147       tree_view->priv->scroll_to_path == NULL)
6148     return;
6149
6150   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
6151   total_height = allocation.height - gtk_tree_view_get_effective_header_height (tree_view);
6152
6153   if (total_height == 0)
6154     return;
6155
6156   /* First, we check to see if we need to scroll anywhere
6157    */
6158   if (tree_view->priv->scroll_to_path)
6159     {
6160       path = gtk_tree_row_reference_get_path (tree_view->priv->scroll_to_path);
6161       if (path && !_gtk_tree_view_find_node (tree_view, path, &tree, &node))
6162         {
6163           /* we are going to scroll, and will update dy */
6164           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6165           if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6166               GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6167             {
6168               _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
6169               if (validate_row (tree_view, tree, node, &iter, path))
6170                 size_changed = TRUE;
6171             }
6172
6173           if (tree_view->priv->scroll_to_use_align)
6174             {
6175               gint height = gtk_tree_view_get_row_height (tree_view, node);
6176               area_above = (total_height - height) *
6177                 tree_view->priv->scroll_to_row_align;
6178               area_below = total_height - area_above - height;
6179               area_above = MAX (area_above, 0);
6180               area_below = MAX (area_below, 0);
6181             }
6182           else
6183             {
6184               /* two cases:
6185                * 1) row not visible
6186                * 2) row visible
6187                */
6188               gint dy;
6189               gint height = gtk_tree_view_get_row_height (tree_view, node);
6190
6191               dy = _gtk_rbtree_node_find_offset (tree, node);
6192
6193               if (dy >= gtk_adjustment_get_value (tree_view->priv->vadjustment) &&
6194                   dy + height <= (gtk_adjustment_get_value (tree_view->priv->vadjustment)
6195                                   + gtk_adjustment_get_page_size (tree_view->priv->vadjustment)))
6196                 {
6197                   /* row visible: keep the row at the same position */
6198                   area_above = dy - gtk_adjustment_get_value (tree_view->priv->vadjustment);
6199                   area_below = (gtk_adjustment_get_value (tree_view->priv->vadjustment) +
6200                                 gtk_adjustment_get_page_size (tree_view->priv->vadjustment))
6201                                - dy - height;
6202                 }
6203               else
6204                 {
6205                   /* row not visible */
6206                   if (dy >= 0
6207                       && dy + height <= gtk_adjustment_get_page_size (tree_view->priv->vadjustment))
6208                     {
6209                       /* row at the beginning -- fixed */
6210                       area_above = dy;
6211                       area_below = gtk_adjustment_get_page_size (tree_view->priv->vadjustment)
6212                                    - area_above - height;
6213                     }
6214                   else if (dy >= (gtk_adjustment_get_upper (tree_view->priv->vadjustment) -
6215                                   gtk_adjustment_get_page_size (tree_view->priv->vadjustment)))
6216                     {
6217                       /* row at the end -- fixed */
6218                       area_above = dy - (gtk_adjustment_get_upper (tree_view->priv->vadjustment) -
6219                                    gtk_adjustment_get_page_size (tree_view->priv->vadjustment));
6220                       area_below = gtk_adjustment_get_page_size (tree_view->priv->vadjustment) -
6221                                    area_above - height;
6222
6223                       if (area_below < 0)
6224                         {
6225                           area_above = gtk_adjustment_get_page_size (tree_view->priv->vadjustment) - height;
6226                           area_below = 0;
6227                         }
6228                     }
6229                   else
6230                     {
6231                       /* row somewhere in the middle, bring it to the top
6232                        * of the view
6233                        */
6234                       area_above = 0;
6235                       area_below = total_height - height;
6236                     }
6237                 }
6238             }
6239         }
6240       else
6241         /* the scroll to isn't valid; ignore it.
6242          */
6243         {
6244           if (tree_view->priv->scroll_to_path && !path)
6245             {
6246               gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
6247               tree_view->priv->scroll_to_path = NULL;
6248             }
6249           if (path)
6250             gtk_tree_path_free (path);
6251           path = NULL;
6252         }      
6253     }
6254
6255   /* We didn't have a scroll_to set, so we just handle things normally
6256    */
6257   if (path == NULL)
6258     {
6259       gint offset;
6260
6261       offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
6262                                         TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, 0),
6263                                         &tree, &node);
6264       if (node == NULL)
6265         {
6266           /* In this case, nothing has been validated */
6267           path = gtk_tree_path_new_first ();
6268           _gtk_tree_view_find_node (tree_view, path, &tree, &node);
6269         }
6270       else
6271         {
6272           path = _gtk_tree_path_new_from_rbtree (tree, node);
6273           total_height += offset;
6274         }
6275
6276       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6277
6278       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6279           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6280         {
6281           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
6282           if (validate_row (tree_view, tree, node, &iter, path))
6283             size_changed = TRUE;
6284         }
6285       area_above = 0;
6286       area_below = total_height - gtk_tree_view_get_row_height (tree_view, node);
6287     }
6288
6289   above_path = gtk_tree_path_copy (path);
6290
6291   /* if we do not validate any row above the new top_row, we will make sure
6292    * that the row immediately above top_row has been validated. (if we do not
6293    * do this, _gtk_rbtree_find_offset will find the row above top_row, because
6294    * when invalidated that row's height will be zero. and this will mess up
6295    * scrolling).
6296    */
6297   if (area_above == 0)
6298     {
6299       GtkRBTree *tmptree;
6300       GtkRBNode *tmpnode;
6301
6302       _gtk_tree_view_find_node (tree_view, above_path, &tmptree, &tmpnode);
6303       _gtk_rbtree_prev_full (tmptree, tmpnode, &tmptree, &tmpnode);
6304
6305       if (tmpnode)
6306         {
6307           GtkTreePath *tmppath;
6308           GtkTreeIter tmpiter;
6309
6310           tmppath = _gtk_tree_path_new_from_rbtree (tmptree, tmpnode);
6311           gtk_tree_model_get_iter (tree_view->priv->model, &tmpiter, tmppath);
6312
6313           if (GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_INVALID) ||
6314               GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_COLUMN_INVALID))
6315             {
6316               _gtk_tree_view_queue_draw_node (tree_view, tmptree, tmpnode, NULL);
6317               if (validate_row (tree_view, tmptree, tmpnode, &tmpiter, tmppath))
6318                 size_changed = TRUE;
6319             }
6320
6321           gtk_tree_path_free (tmppath);
6322         }
6323     }
6324
6325   /* Now, we walk forwards and backwards, measuring rows. Unfortunately,
6326    * backwards is much slower then forward, as there is no iter_prev function.
6327    * We go forwards first in case we run out of tree.  Then we go backwards to
6328    * fill out the top.
6329    */
6330   while (node && area_below > 0)
6331     {
6332       if (node->children)
6333         {
6334           GtkTreeIter parent = iter;
6335           gboolean has_child;
6336
6337           tree = node->children;
6338           node = _gtk_rbtree_first (tree);
6339
6340           has_child = gtk_tree_model_iter_children (tree_view->priv->model,
6341                                                     &iter,
6342                                                     &parent);
6343           TREE_VIEW_INTERNAL_ASSERT_VOID (has_child);
6344           gtk_tree_path_down (path);
6345         }
6346       else
6347         {
6348           gboolean done = FALSE;
6349           do
6350             {
6351               node = _gtk_rbtree_next (tree, node);
6352               if (node != NULL)
6353                 {
6354                   gboolean has_next = gtk_tree_model_iter_next (tree_view->priv->model, &iter);
6355                   done = TRUE;
6356                   gtk_tree_path_next (path);
6357
6358                   /* Sanity Check! */
6359                   TREE_VIEW_INTERNAL_ASSERT_VOID (has_next);
6360                 }
6361               else
6362                 {
6363                   GtkTreeIter parent_iter = iter;
6364                   gboolean has_parent;
6365
6366                   node = tree->parent_node;
6367                   tree = tree->parent_tree;
6368                   if (tree == NULL)
6369                     break;
6370                   has_parent = gtk_tree_model_iter_parent (tree_view->priv->model,
6371                                                            &iter,
6372                                                            &parent_iter);
6373                   gtk_tree_path_up (path);
6374
6375                   /* Sanity check */
6376                   TREE_VIEW_INTERNAL_ASSERT_VOID (has_parent);
6377                 }
6378             }
6379           while (!done);
6380         }
6381
6382       if (!node)
6383         break;
6384
6385       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6386           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6387         {
6388           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
6389           if (validate_row (tree_view, tree, node, &iter, path))
6390               size_changed = TRUE;
6391         }
6392
6393       area_below -= gtk_tree_view_get_row_height (tree_view, node);
6394     }
6395   gtk_tree_path_free (path);
6396
6397   /* If we ran out of tree, and have extra area_below left, we need to add it
6398    * to area_above */
6399   if (area_below > 0)
6400     area_above += area_below;
6401
6402   _gtk_tree_view_find_node (tree_view, above_path, &tree, &node);
6403
6404   /* We walk backwards */
6405   while (area_above > 0)
6406     {
6407       _gtk_rbtree_prev_full (tree, node, &tree, &node);
6408
6409       /* Always find the new path in the tree.  We cannot just assume
6410        * a gtk_tree_path_prev() is enough here, as there might be children
6411        * in between this node and the previous sibling node.  If this
6412        * appears to be a performance hotspot in profiles, we can look into
6413        * intrigate logic for keeping path, node and iter in sync like
6414        * we do for forward walks.  (Which will be hard because of the lacking
6415        * iter_prev).
6416        */
6417
6418       if (node == NULL)
6419         break;
6420
6421       gtk_tree_path_free (above_path);
6422       above_path = _gtk_tree_path_new_from_rbtree (tree, node);
6423
6424       gtk_tree_model_get_iter (tree_view->priv->model, &iter, above_path);
6425
6426       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6427           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6428         {
6429           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
6430           if (validate_row (tree_view, tree, node, &iter, above_path))
6431             size_changed = TRUE;
6432         }
6433       area_above -= gtk_tree_view_get_row_height (tree_view, node);
6434     }
6435
6436   /* if we scrolled to a path, we need to set the dy here,
6437    * and sync the top row accordingly
6438    */
6439   if (tree_view->priv->scroll_to_path)
6440     {
6441       gtk_tree_view_set_top_row (tree_view, above_path, -area_above);
6442       gtk_tree_view_top_row_to_dy (tree_view);
6443
6444       need_redraw = TRUE;
6445     }
6446   else if (tree_view->priv->height <= gtk_adjustment_get_page_size (tree_view->priv->vadjustment))
6447     {
6448       /* when we are not scrolling, we should never set dy to something
6449        * else than zero. we update top_row to be in sync with dy = 0.
6450        */
6451       gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
6452       gtk_tree_view_dy_to_top_row (tree_view);
6453     }
6454   else if (gtk_adjustment_get_value (tree_view->priv->vadjustment) + gtk_adjustment_get_page_size (tree_view->priv->vadjustment) > tree_view->priv->height)
6455     {
6456       gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), tree_view->priv->height - gtk_adjustment_get_page_size (tree_view->priv->vadjustment));
6457       gtk_tree_view_dy_to_top_row (tree_view);
6458     }
6459   else
6460     gtk_tree_view_top_row_to_dy (tree_view);
6461
6462   /* update width/height and queue a resize */
6463   if (size_changed)
6464     {
6465       GtkRequisition requisition;
6466
6467       /* We temporarily guess a size, under the assumption that it will be the
6468        * same when we get our next size_allocate.  If we don't do this, we'll be
6469        * in an inconsistent state if we call top_row_to_dy. */
6470
6471       gtk_widget_get_preferred_size (GTK_WIDGET (tree_view),
6472                                      &requisition, NULL);
6473       gtk_adjustment_set_upper (tree_view->priv->hadjustment,
6474                                 MAX (gtk_adjustment_get_upper (tree_view->priv->hadjustment), requisition.width));
6475       gtk_adjustment_set_upper (tree_view->priv->vadjustment,
6476                                 MAX (gtk_adjustment_get_upper (tree_view->priv->vadjustment), requisition.height));
6477       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6478     }
6479
6480   if (tree_view->priv->scroll_to_path)
6481     {
6482       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
6483       tree_view->priv->scroll_to_path = NULL;
6484     }
6485
6486   if (above_path)
6487     gtk_tree_path_free (above_path);
6488
6489   if (tree_view->priv->scroll_to_column)
6490     {
6491       tree_view->priv->scroll_to_column = NULL;
6492     }
6493   if (need_redraw)
6494     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
6495 }
6496
6497 static void
6498 initialize_fixed_height_mode (GtkTreeView *tree_view)
6499 {
6500   if (!tree_view->priv->tree)
6501     return;
6502
6503   if (tree_view->priv->fixed_height < 0)
6504     {
6505       GtkTreeIter iter;
6506       GtkTreePath *path;
6507
6508       GtkRBTree *tree = NULL;
6509       GtkRBNode *node = NULL;
6510
6511       tree = tree_view->priv->tree;
6512       node = tree->root;
6513
6514       path = _gtk_tree_path_new_from_rbtree (tree, node);
6515       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6516
6517       validate_row (tree_view, tree, node, &iter, path);
6518
6519       gtk_tree_path_free (path);
6520
6521       tree_view->priv->fixed_height = gtk_tree_view_get_row_height (tree_view, node);
6522     }
6523
6524    _gtk_rbtree_set_fixed_height (tree_view->priv->tree,
6525                                  tree_view->priv->fixed_height, TRUE);
6526 }
6527
6528 /* Our strategy for finding nodes to validate is a little convoluted.  We find
6529  * the left-most uninvalidated node.  We then try walking right, validating
6530  * nodes.  Once we find a valid node, we repeat the previous process of finding
6531  * the first invalid node.
6532  */
6533
6534 static gboolean
6535 do_validate_rows (GtkTreeView *tree_view, gboolean queue_resize)
6536 {
6537   GtkRBTree *tree = NULL;
6538   GtkRBNode *node = NULL;
6539   gboolean validated_area = FALSE;
6540   gint retval = TRUE;
6541   GtkTreePath *path = NULL;
6542   GtkTreeIter iter;
6543   GTimer *timer;
6544   gint i = 0;
6545
6546   gint y = -1;
6547   gint prev_height = -1;
6548   gboolean fixed_height = TRUE;
6549
6550   g_assert (tree_view);
6551
6552   if (tree_view->priv->tree == NULL)
6553       return FALSE;
6554
6555   if (tree_view->priv->fixed_height_mode)
6556     {
6557       if (tree_view->priv->fixed_height < 0)
6558         initialize_fixed_height_mode (tree_view);
6559
6560       return FALSE;
6561     }
6562
6563   timer = g_timer_new ();
6564   g_timer_start (timer);
6565
6566   do
6567     {
6568       gboolean changed = FALSE;
6569
6570       if (! GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID))
6571         {
6572           retval = FALSE;
6573           goto done;
6574         }
6575
6576       if (path != NULL)
6577         {
6578           node = _gtk_rbtree_next (tree, node);
6579           if (node != NULL)
6580             {
6581               TREE_VIEW_INTERNAL_ASSERT (gtk_tree_model_iter_next (tree_view->priv->model, &iter), FALSE);
6582               gtk_tree_path_next (path);
6583             }
6584           else
6585             {
6586               gtk_tree_path_free (path);
6587               path = NULL;
6588             }
6589         }
6590
6591       if (path == NULL)
6592         {
6593           tree = tree_view->priv->tree;
6594           node = tree_view->priv->tree->root;
6595
6596           g_assert (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_DESCENDANTS_INVALID));
6597
6598           do
6599             {
6600               if (!_gtk_rbtree_is_nil (node->left) &&
6601                   GTK_RBNODE_FLAG_SET (node->left, GTK_RBNODE_DESCENDANTS_INVALID))
6602                 {
6603                   node = node->left;
6604                 }
6605               else if (!_gtk_rbtree_is_nil (node->right) &&
6606                        GTK_RBNODE_FLAG_SET (node->right, GTK_RBNODE_DESCENDANTS_INVALID))
6607                 {
6608                   node = node->right;
6609                 }
6610               else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6611                        GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6612                 {
6613                   break;
6614                 }
6615               else if (node->children != NULL)
6616                 {
6617                   tree = node->children;
6618                   node = tree->root;
6619                 }
6620               else
6621                 /* RBTree corruption!  All bad */
6622                 g_assert_not_reached ();
6623             }
6624           while (TRUE);
6625           path = _gtk_tree_path_new_from_rbtree (tree, node);
6626           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6627         }
6628
6629       changed = validate_row (tree_view, tree, node, &iter, path);
6630       validated_area = changed || validated_area;
6631
6632       if (changed)
6633         {
6634           gint offset = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
6635
6636           if (y == -1 || y > offset)
6637             y = offset;
6638         }
6639
6640       if (!tree_view->priv->fixed_height_check)
6641         {
6642           gint height;
6643
6644           height = gtk_tree_view_get_row_height (tree_view, node);
6645           if (prev_height < 0)
6646             prev_height = height;
6647           else if (prev_height != height)
6648             fixed_height = FALSE;
6649         }
6650
6651       i++;
6652     }
6653   while (g_timer_elapsed (timer, NULL) < GTK_TREE_VIEW_TIME_MS_PER_IDLE / 1000.);
6654
6655   if (!tree_view->priv->fixed_height_check)
6656    {
6657      if (fixed_height)
6658        _gtk_rbtree_set_fixed_height (tree_view->priv->tree, prev_height, FALSE);
6659
6660      tree_view->priv->fixed_height_check = 1;
6661    }
6662   
6663  done:
6664   if (validated_area)
6665     {
6666       /* If rows above the current position have changed height, this has
6667        * affected the current view and thus needs a redraw.
6668        */
6669       if (y != -1 && y < gtk_adjustment_get_value (tree_view->priv->vadjustment))
6670         gtk_widget_queue_draw (GTK_WIDGET (tree_view));
6671
6672       if (queue_resize)
6673         gtk_widget_queue_resize_no_redraw (GTK_WIDGET (tree_view));
6674     }
6675
6676   if (path) gtk_tree_path_free (path);
6677   g_timer_destroy (timer);
6678
6679   return retval;
6680 }
6681
6682 static gboolean
6683 validate_rows (GtkTreeView *tree_view)
6684 {
6685   gboolean retval;
6686   
6687   retval = do_validate_rows (tree_view, TRUE);
6688   
6689   if (! retval && tree_view->priv->validate_rows_timer)
6690     {
6691       g_source_remove (tree_view->priv->validate_rows_timer);
6692       tree_view->priv->validate_rows_timer = 0;
6693     }
6694
6695   return retval;
6696 }
6697
6698 static gboolean
6699 validate_rows_handler (GtkTreeView *tree_view)
6700 {
6701   gboolean retval;
6702
6703   retval = do_validate_rows (tree_view, TRUE);
6704   if (! retval && tree_view->priv->validate_rows_timer)
6705     {
6706       g_source_remove (tree_view->priv->validate_rows_timer);
6707       tree_view->priv->validate_rows_timer = 0;
6708     }
6709
6710   return retval;
6711 }
6712
6713 static gboolean
6714 do_presize_handler (GtkTreeView *tree_view)
6715 {
6716   if (tree_view->priv->mark_rows_col_dirty)
6717     {
6718       if (tree_view->priv->tree)
6719         _gtk_rbtree_column_invalid (tree_view->priv->tree);
6720       tree_view->priv->mark_rows_col_dirty = FALSE;
6721     }
6722   validate_visible_area (tree_view);
6723   tree_view->priv->presize_handler_timer = 0;
6724
6725   if (tree_view->priv->fixed_height_mode)
6726     {
6727       GtkRequisition requisition;
6728
6729       gtk_widget_get_preferred_size (GTK_WIDGET (tree_view),
6730                                      &requisition, NULL);
6731
6732       gtk_adjustment_set_upper (tree_view->priv->hadjustment,
6733                                 MAX (gtk_adjustment_get_upper (tree_view->priv->hadjustment), requisition.width));
6734       gtk_adjustment_set_upper (tree_view->priv->vadjustment,
6735                                 MAX (gtk_adjustment_get_upper (tree_view->priv->vadjustment), requisition.height));
6736       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6737     }
6738                    
6739   return FALSE;
6740 }
6741
6742 static gboolean
6743 presize_handler_callback (gpointer data)
6744 {
6745   do_presize_handler (GTK_TREE_VIEW (data));
6746                    
6747   return FALSE;
6748 }
6749
6750 static void
6751 install_presize_handler (GtkTreeView *tree_view)
6752 {
6753   if (! gtk_widget_get_realized (GTK_WIDGET (tree_view)))
6754     return;
6755
6756   if (! tree_view->priv->presize_handler_timer)
6757     {
6758       tree_view->priv->presize_handler_timer =
6759         gdk_threads_add_idle_full (GTK_PRIORITY_RESIZE - 2, presize_handler_callback, tree_view, NULL);
6760     }
6761   if (! tree_view->priv->validate_rows_timer)
6762     {
6763       tree_view->priv->validate_rows_timer =
6764         gdk_threads_add_idle_full (GTK_TREE_VIEW_PRIORITY_VALIDATE, (GSourceFunc) validate_rows_handler, tree_view, NULL);
6765     }
6766 }
6767
6768 static gboolean
6769 scroll_sync_handler (GtkTreeView *tree_view)
6770 {
6771   if (tree_view->priv->height <= gtk_adjustment_get_page_size (tree_view->priv->vadjustment))
6772     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
6773   else if (gtk_tree_row_reference_valid (tree_view->priv->top_row))
6774     gtk_tree_view_top_row_to_dy (tree_view);
6775   else
6776     gtk_tree_view_dy_to_top_row (tree_view);
6777
6778   tree_view->priv->scroll_sync_timer = 0;
6779
6780   return FALSE;
6781 }
6782
6783 static void
6784 install_scroll_sync_handler (GtkTreeView *tree_view)
6785 {
6786   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
6787     return;
6788
6789   if (!tree_view->priv->scroll_sync_timer)
6790     {
6791       tree_view->priv->scroll_sync_timer =
6792         gdk_threads_add_idle_full (GTK_TREE_VIEW_PRIORITY_SCROLL_SYNC, (GSourceFunc) scroll_sync_handler, tree_view, NULL);
6793     }
6794 }
6795
6796 static void
6797 gtk_tree_view_set_top_row (GtkTreeView *tree_view,
6798                            GtkTreePath *path,
6799                            gint         offset)
6800 {
6801   gtk_tree_row_reference_free (tree_view->priv->top_row);
6802
6803   if (!path)
6804     {
6805       tree_view->priv->top_row = NULL;
6806       tree_view->priv->top_row_dy = 0;
6807     }
6808   else
6809     {
6810       tree_view->priv->top_row = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
6811       tree_view->priv->top_row_dy = offset;
6812     }
6813 }
6814
6815 /* Always call this iff dy is in the visible range.  If the tree is empty, then
6816  * it's set to be NULL, and top_row_dy is 0;
6817  */
6818 static void
6819 gtk_tree_view_dy_to_top_row (GtkTreeView *tree_view)
6820 {
6821   gint offset;
6822   GtkTreePath *path;
6823   GtkRBTree *tree;
6824   GtkRBNode *node;
6825
6826   if (tree_view->priv->tree == NULL)
6827     {
6828       gtk_tree_view_set_top_row (tree_view, NULL, 0);
6829     }
6830   else
6831     {
6832       offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
6833                                         tree_view->priv->dy,
6834                                         &tree, &node);
6835
6836       if (tree == NULL)
6837         {
6838           gtk_tree_view_set_top_row (tree_view, NULL, 0);
6839         }
6840       else
6841         {
6842           path = _gtk_tree_path_new_from_rbtree (tree, node);
6843           gtk_tree_view_set_top_row (tree_view, path, offset);
6844           gtk_tree_path_free (path);
6845         }
6846     }
6847 }
6848
6849 static void
6850 gtk_tree_view_top_row_to_dy (GtkTreeView *tree_view)
6851 {
6852   GtkTreePath *path;
6853   GtkRBTree *tree;
6854   GtkRBNode *node;
6855   int new_dy;
6856
6857   /* Avoid recursive calls */
6858   if (tree_view->priv->in_top_row_to_dy)
6859     return;
6860
6861   if (tree_view->priv->top_row)
6862     path = gtk_tree_row_reference_get_path (tree_view->priv->top_row);
6863   else
6864     path = NULL;
6865
6866   if (!path)
6867     tree = NULL;
6868   else
6869     _gtk_tree_view_find_node (tree_view, path, &tree, &node);
6870
6871   if (path)
6872     gtk_tree_path_free (path);
6873
6874   if (tree == NULL)
6875     {
6876       /* keep dy and set new toprow */
6877       gtk_tree_row_reference_free (tree_view->priv->top_row);
6878       tree_view->priv->top_row = NULL;
6879       tree_view->priv->top_row_dy = 0;
6880       /* DO NOT install the idle handler */
6881       gtk_tree_view_dy_to_top_row (tree_view);
6882       return;
6883     }
6884
6885   if (gtk_tree_view_get_row_height (tree_view, node)
6886       < tree_view->priv->top_row_dy)
6887     {
6888       /* new top row -- do NOT install the idle handler */
6889       gtk_tree_view_dy_to_top_row (tree_view);
6890       return;
6891     }
6892
6893   new_dy = _gtk_rbtree_node_find_offset (tree, node);
6894   new_dy += tree_view->priv->top_row_dy;
6895
6896   if (new_dy + gtk_adjustment_get_page_size (tree_view->priv->vadjustment) > tree_view->priv->height)
6897     new_dy = tree_view->priv->height - gtk_adjustment_get_page_size (tree_view->priv->vadjustment);
6898
6899   new_dy = MAX (0, new_dy);
6900
6901   tree_view->priv->in_top_row_to_dy = TRUE;
6902   gtk_adjustment_set_value (tree_view->priv->vadjustment, (gdouble)new_dy);
6903   tree_view->priv->in_top_row_to_dy = FALSE;
6904 }
6905
6906
6907 void
6908 _gtk_tree_view_install_mark_rows_col_dirty (GtkTreeView *tree_view,
6909                                             gboolean     install_handler)
6910 {
6911   tree_view->priv->mark_rows_col_dirty = TRUE;
6912
6913   if (install_handler)
6914     install_presize_handler (tree_view);
6915 }
6916
6917 /*
6918  * This function works synchronously (due to the while (validate_rows...)
6919  * loop).
6920  *
6921  * There was a check for column_type != GTK_TREE_VIEW_COLUMN_AUTOSIZE
6922  * here. You now need to check that yourself.
6923  */
6924 void
6925 _gtk_tree_view_column_autosize (GtkTreeView *tree_view,
6926                                 GtkTreeViewColumn *column)
6927 {
6928   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
6929   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (column));
6930
6931   _gtk_tree_view_column_cell_set_dirty (column, FALSE);
6932
6933   do_presize_handler (tree_view);
6934   while (validate_rows (tree_view));
6935
6936   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6937 }
6938
6939 /* Drag-and-drop */
6940
6941 static void
6942 set_source_row (GdkDragContext *context,
6943                 GtkTreeModel   *model,
6944                 GtkTreePath    *source_row)
6945 {
6946   g_object_set_data_full (G_OBJECT (context),
6947                           I_("gtk-tree-view-source-row"),
6948                           source_row ? gtk_tree_row_reference_new (model, source_row) : NULL,
6949                           (GDestroyNotify) (source_row ? gtk_tree_row_reference_free : NULL));
6950 }
6951
6952 static GtkTreePath*
6953 get_source_row (GdkDragContext *context)
6954 {
6955   GtkTreeRowReference *ref =
6956     g_object_get_data (G_OBJECT (context), "gtk-tree-view-source-row");
6957
6958   if (ref)
6959     return gtk_tree_row_reference_get_path (ref);
6960   else
6961     return NULL;
6962 }
6963
6964 typedef struct
6965 {
6966   GtkTreeRowReference *dest_row;
6967   guint                path_down_mode   : 1;
6968   guint                empty_view_drop  : 1;
6969   guint                drop_append_mode : 1;
6970 }
6971 DestRow;
6972
6973 static void
6974 dest_row_free (gpointer data)
6975 {
6976   DestRow *dr = (DestRow *)data;
6977
6978   gtk_tree_row_reference_free (dr->dest_row);
6979   g_slice_free (DestRow, dr);
6980 }
6981
6982 static void
6983 set_dest_row (GdkDragContext *context,
6984               GtkTreeModel   *model,
6985               GtkTreePath    *dest_row,
6986               gboolean        path_down_mode,
6987               gboolean        empty_view_drop,
6988               gboolean        drop_append_mode)
6989 {
6990   DestRow *dr;
6991
6992   if (!dest_row)
6993     {
6994       g_object_set_data_full (G_OBJECT (context), I_("gtk-tree-view-dest-row"),
6995                               NULL, NULL);
6996       return;
6997     }
6998
6999   dr = g_slice_new (DestRow);
7000
7001   dr->dest_row = gtk_tree_row_reference_new (model, dest_row);
7002   dr->path_down_mode = path_down_mode != FALSE;
7003   dr->empty_view_drop = empty_view_drop != FALSE;
7004   dr->drop_append_mode = drop_append_mode != FALSE;
7005
7006   g_object_set_data_full (G_OBJECT (context), I_("gtk-tree-view-dest-row"),
7007                           dr, (GDestroyNotify) dest_row_free);
7008 }
7009
7010 static GtkTreePath*
7011 get_dest_row (GdkDragContext *context,
7012               gboolean       *path_down_mode)
7013 {
7014   DestRow *dr =
7015     g_object_get_data (G_OBJECT (context), "gtk-tree-view-dest-row");
7016
7017   if (dr)
7018     {
7019       GtkTreePath *path = NULL;
7020
7021       if (path_down_mode)
7022         *path_down_mode = dr->path_down_mode;
7023
7024       if (dr->dest_row)
7025         path = gtk_tree_row_reference_get_path (dr->dest_row);
7026       else if (dr->empty_view_drop)
7027         path = gtk_tree_path_new_from_indices (0, -1);
7028       else
7029         path = NULL;
7030
7031       if (path && dr->drop_append_mode)
7032         gtk_tree_path_next (path);
7033
7034       return path;
7035     }
7036   else
7037     return NULL;
7038 }
7039
7040 /* Get/set whether drag_motion requested the drag data and
7041  * drag_data_received should thus not actually insert the data,
7042  * since the data doesn't result from a drop.
7043  */
7044 static void
7045 set_status_pending (GdkDragContext *context,
7046                     GdkDragAction   suggested_action)
7047 {
7048   g_object_set_data (G_OBJECT (context),
7049                      I_("gtk-tree-view-status-pending"),
7050                      GINT_TO_POINTER (suggested_action));
7051 }
7052
7053 static GdkDragAction
7054 get_status_pending (GdkDragContext *context)
7055 {
7056   return GPOINTER_TO_INT (g_object_get_data (G_OBJECT (context),
7057                                              "gtk-tree-view-status-pending"));
7058 }
7059
7060 static TreeViewDragInfo*
7061 get_info (GtkTreeView *tree_view)
7062 {
7063   return g_object_get_data (G_OBJECT (tree_view), "gtk-tree-view-drag-info");
7064 }
7065
7066 static void
7067 destroy_info (TreeViewDragInfo *di)
7068 {
7069   g_slice_free (TreeViewDragInfo, di);
7070 }
7071
7072 static TreeViewDragInfo*
7073 ensure_info (GtkTreeView *tree_view)
7074 {
7075   TreeViewDragInfo *di;
7076
7077   di = get_info (tree_view);
7078
7079   if (di == NULL)
7080     {
7081       di = g_slice_new0 (TreeViewDragInfo);
7082
7083       g_object_set_data_full (G_OBJECT (tree_view),
7084                               I_("gtk-tree-view-drag-info"),
7085                               di,
7086                               (GDestroyNotify) destroy_info);
7087     }
7088
7089   return di;
7090 }
7091
7092 static void
7093 remove_info (GtkTreeView *tree_view)
7094 {
7095   g_object_set_data (G_OBJECT (tree_view), I_("gtk-tree-view-drag-info"), NULL);
7096 }
7097
7098 #if 0
7099 static gint
7100 drag_scan_timeout (gpointer data)
7101 {
7102   GtkTreeView *tree_view;
7103   gint x, y;
7104   GdkModifierType state;
7105   GtkTreePath *path = NULL;
7106   GtkTreeViewColumn *column = NULL;
7107   GdkRectangle visible_rect;
7108
7109   gdk_threads_enter ();
7110
7111   tree_view = GTK_TREE_VIEW (data);
7112
7113   gdk_window_get_device_position (tree_view->priv->bin_window,
7114                                   gdk_device_manager_get_client_pointer (
7115                                     gdk_display_get_device_manager (
7116                                       gtk_widget_get_display (GTK_WIDGET (tree_view)))),
7117                                   &x, &y, &state);
7118
7119   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
7120
7121   /* See if we are near the edge. */
7122   if ((x - visible_rect.x) < SCROLL_EDGE_SIZE ||
7123       (visible_rect.x + visible_rect.width - x) < SCROLL_EDGE_SIZE ||
7124       (y - visible_rect.y) < SCROLL_EDGE_SIZE ||
7125       (visible_rect.y + visible_rect.height - y) < SCROLL_EDGE_SIZE)
7126     {
7127       gtk_tree_view_get_path_at_pos (tree_view,
7128                                      tree_view->priv->bin_window,
7129                                      x, y,
7130                                      &path,
7131                                      &column,
7132                                      NULL,
7133                                      NULL);
7134
7135       if (path != NULL)
7136         {
7137           gtk_tree_view_scroll_to_cell (tree_view,
7138                                         path,
7139                                         column,
7140                                         TRUE,
7141                                         0.5, 0.5);
7142
7143           gtk_tree_path_free (path);
7144         }
7145     }
7146
7147   gdk_threads_leave ();
7148
7149   return TRUE;
7150 }
7151 #endif /* 0 */
7152
7153 static void
7154 add_scroll_timeout (GtkTreeView *tree_view)
7155 {
7156   if (tree_view->priv->scroll_timeout == 0)
7157     {
7158       tree_view->priv->scroll_timeout =
7159         gdk_threads_add_timeout (150, scroll_row_timeout, tree_view);
7160     }
7161 }
7162
7163 static void
7164 remove_scroll_timeout (GtkTreeView *tree_view)
7165 {
7166   if (tree_view->priv->scroll_timeout != 0)
7167     {
7168       g_source_remove (tree_view->priv->scroll_timeout);
7169       tree_view->priv->scroll_timeout = 0;
7170     }
7171 }
7172
7173 static gboolean
7174 check_model_dnd (GtkTreeModel *model,
7175                  GType         required_iface,
7176                  const gchar  *signal)
7177 {
7178   if (model == NULL || !G_TYPE_CHECK_INSTANCE_TYPE ((model), required_iface))
7179     {
7180       g_warning ("You must override the default '%s' handler "
7181                  "on GtkTreeView when using models that don't support "
7182                  "the %s interface and enabling drag-and-drop. The simplest way to do this "
7183                  "is to connect to '%s' and call "
7184                  "g_signal_stop_emission_by_name() in your signal handler to prevent "
7185                  "the default handler from running. Look at the source code "
7186                  "for the default handler in gtktreeview.c to get an idea what "
7187                  "your handler should do. (gtktreeview.c is in the GTK source "
7188                  "code.) If you're using GTK from a language other than C, "
7189                  "there may be a more natural way to override default handlers, e.g. via derivation.",
7190                  signal, g_type_name (required_iface), signal);
7191       return FALSE;
7192     }
7193   else
7194     return TRUE;
7195 }
7196
7197 static void
7198 remove_open_timeout (GtkTreeView *tree_view)
7199 {
7200   if (tree_view->priv->open_dest_timeout != 0)
7201     {
7202       g_source_remove (tree_view->priv->open_dest_timeout);
7203       tree_view->priv->open_dest_timeout = 0;
7204     }
7205 }
7206
7207
7208 static gint
7209 open_row_timeout (gpointer data)
7210 {
7211   GtkTreeView *tree_view = data;
7212   GtkTreePath *dest_path = NULL;
7213   GtkTreeViewDropPosition pos;
7214   gboolean result = FALSE;
7215
7216   gtk_tree_view_get_drag_dest_row (tree_view,
7217                                    &dest_path,
7218                                    &pos);
7219
7220   if (dest_path &&
7221       (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
7222        pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
7223     {
7224       gtk_tree_view_expand_row (tree_view, dest_path, FALSE);
7225       tree_view->priv->open_dest_timeout = 0;
7226
7227       gtk_tree_path_free (dest_path);
7228     }
7229   else
7230     {
7231       if (dest_path)
7232         gtk_tree_path_free (dest_path);
7233
7234       result = TRUE;
7235     }
7236
7237   return result;
7238 }
7239
7240 static gboolean
7241 scroll_row_timeout (gpointer data)
7242 {
7243   GtkTreeView *tree_view = data;
7244
7245   gtk_tree_view_vertical_autoscroll (tree_view);
7246
7247   if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
7248     gtk_tree_view_update_rubber_band (tree_view);
7249
7250   return TRUE;
7251 }
7252
7253 /* Returns TRUE if event should not be propagated to parent widgets */
7254 static gboolean
7255 set_destination_row (GtkTreeView    *tree_view,
7256                      GdkDragContext *context,
7257                      /* coordinates relative to the widget */
7258                      gint            x,
7259                      gint            y,
7260                      GdkDragAction  *suggested_action,
7261                      GdkAtom        *target)
7262 {
7263   GtkTreePath *path = NULL;
7264   GtkTreeViewDropPosition pos;
7265   GtkTreeViewDropPosition old_pos;
7266   TreeViewDragInfo *di;
7267   GtkWidget *widget;
7268   GtkTreePath *old_dest_path = NULL;
7269   gboolean can_drop = FALSE;
7270
7271   *suggested_action = 0;
7272   *target = GDK_NONE;
7273
7274   widget = GTK_WIDGET (tree_view);
7275
7276   di = get_info (tree_view);
7277
7278   if (di == NULL || y - gtk_tree_view_get_effective_header_height (tree_view) < 0)
7279     {
7280       /* someone unset us as a drag dest, note that if
7281        * we return FALSE drag_leave isn't called
7282        */
7283
7284       gtk_tree_view_set_drag_dest_row (tree_view,
7285                                        NULL,
7286                                        GTK_TREE_VIEW_DROP_BEFORE);
7287
7288       remove_scroll_timeout (GTK_TREE_VIEW (widget));
7289       remove_open_timeout (GTK_TREE_VIEW (widget));
7290
7291       return FALSE; /* no longer a drop site */
7292     }
7293
7294   *target = gtk_drag_dest_find_target (widget, context,
7295                                        gtk_drag_dest_get_target_list (widget));
7296   if (*target == GDK_NONE)
7297     {
7298       return FALSE;
7299     }
7300
7301   if (!gtk_tree_view_get_dest_row_at_pos (tree_view,
7302                                           x, y,
7303                                           &path,
7304                                           &pos))
7305     {
7306       gint n_children;
7307       GtkTreeModel *model;
7308
7309       remove_open_timeout (tree_view);
7310
7311       /* the row got dropped on empty space, let's setup a special case
7312        */
7313
7314       if (path)
7315         gtk_tree_path_free (path);
7316
7317       model = gtk_tree_view_get_model (tree_view);
7318
7319       n_children = gtk_tree_model_iter_n_children (model, NULL);
7320       if (n_children)
7321         {
7322           pos = GTK_TREE_VIEW_DROP_AFTER;
7323           path = gtk_tree_path_new_from_indices (n_children - 1, -1);
7324         }
7325       else
7326         {
7327           pos = GTK_TREE_VIEW_DROP_BEFORE;
7328           path = gtk_tree_path_new_from_indices (0, -1);
7329         }
7330
7331       can_drop = TRUE;
7332
7333       goto out;
7334     }
7335
7336   g_assert (path);
7337
7338   /* If we left the current row's "open" zone, unset the timeout for
7339    * opening the row
7340    */
7341   gtk_tree_view_get_drag_dest_row (tree_view,
7342                                    &old_dest_path,
7343                                    &old_pos);
7344
7345   if (old_dest_path &&
7346       (gtk_tree_path_compare (path, old_dest_path) != 0 ||
7347        !(pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
7348          pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE)))
7349     remove_open_timeout (tree_view);
7350
7351   if (old_dest_path)
7352     gtk_tree_path_free (old_dest_path);
7353
7354   if (TRUE /* FIXME if the location droppable predicate */)
7355     {
7356       can_drop = TRUE;
7357     }
7358
7359 out:
7360   if (can_drop)
7361     {
7362       GtkWidget *source_widget;
7363
7364       *suggested_action = gdk_drag_context_get_suggested_action (context);
7365       source_widget = gtk_drag_get_source_widget (context);
7366
7367       if (source_widget == widget)
7368         {
7369           /* Default to MOVE, unless the user has
7370            * pressed ctrl or shift to affect available actions
7371            */
7372           if ((gdk_drag_context_get_actions (context) & GDK_ACTION_MOVE) != 0)
7373             *suggested_action = GDK_ACTION_MOVE;
7374         }
7375
7376       gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7377                                        path, pos);
7378     }
7379   else
7380     {
7381       /* can't drop here */
7382       remove_open_timeout (tree_view);
7383
7384       gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7385                                        NULL,
7386                                        GTK_TREE_VIEW_DROP_BEFORE);
7387     }
7388
7389   if (path)
7390     gtk_tree_path_free (path);
7391
7392   return TRUE;
7393 }
7394
7395 static GtkTreePath*
7396 get_logical_dest_row (GtkTreeView *tree_view,
7397                       gboolean    *path_down_mode,
7398                       gboolean    *drop_append_mode)
7399 {
7400   /* adjust path to point to the row the drop goes in front of */
7401   GtkTreePath *path = NULL;
7402   GtkTreeViewDropPosition pos;
7403
7404   g_return_val_if_fail (path_down_mode != NULL, NULL);
7405   g_return_val_if_fail (drop_append_mode != NULL, NULL);
7406
7407   *path_down_mode = FALSE;
7408   *drop_append_mode = 0;
7409
7410   gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
7411
7412   if (path == NULL)
7413     return NULL;
7414
7415   if (pos == GTK_TREE_VIEW_DROP_BEFORE)
7416     ; /* do nothing */
7417   else if (pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE ||
7418            pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER)
7419     *path_down_mode = TRUE;
7420   else
7421     {
7422       GtkTreeIter iter;
7423       GtkTreeModel *model = gtk_tree_view_get_model (tree_view);
7424
7425       g_assert (pos == GTK_TREE_VIEW_DROP_AFTER);
7426
7427       if (!gtk_tree_model_get_iter (model, &iter, path) ||
7428           !gtk_tree_model_iter_next (model, &iter))
7429         *drop_append_mode = 1;
7430       else
7431         {
7432           *drop_append_mode = 0;
7433           gtk_tree_path_next (path);
7434         }
7435     }
7436
7437   return path;
7438 }
7439
7440 static gboolean
7441 gtk_tree_view_maybe_begin_dragging_row (GtkTreeView      *tree_view,
7442                                         GdkEventMotion   *event)
7443 {
7444   GtkWidget *widget = GTK_WIDGET (tree_view);
7445   GdkDragContext *context;
7446   TreeViewDragInfo *di;
7447   GtkTreePath *path = NULL;
7448   gint button;
7449   gint cell_x, cell_y;
7450   GtkTreeModel *model;
7451   gboolean retval = FALSE;
7452
7453   di = get_info (tree_view);
7454
7455   if (di == NULL || !di->source_set)
7456     goto out;
7457
7458   if (tree_view->priv->pressed_button < 0)
7459     goto out;
7460
7461   if (!gtk_drag_check_threshold (widget,
7462                                  tree_view->priv->press_start_x,
7463                                  tree_view->priv->press_start_y,
7464                                  event->x, event->y))
7465     goto out;
7466
7467   model = gtk_tree_view_get_model (tree_view);
7468
7469   if (model == NULL)
7470     goto out;
7471
7472   button = tree_view->priv->pressed_button;
7473   tree_view->priv->pressed_button = -1;
7474
7475   gtk_tree_view_get_path_at_pos (tree_view,
7476                                  tree_view->priv->press_start_x,
7477                                  tree_view->priv->press_start_y,
7478                                  &path,
7479                                  NULL,
7480                                  &cell_x,
7481                                  &cell_y);
7482
7483   if (path == NULL)
7484     goto out;
7485
7486   if (!GTK_IS_TREE_DRAG_SOURCE (model) ||
7487       !gtk_tree_drag_source_row_draggable (GTK_TREE_DRAG_SOURCE (model),
7488                                            path))
7489     goto out;
7490
7491   if (!(GDK_BUTTON1_MASK << (button - 1) & di->start_button_mask))
7492     goto out;
7493
7494   /* Now we can begin the drag */
7495
7496   retval = TRUE;
7497
7498   context = gtk_drag_begin (widget,
7499                             gtk_drag_source_get_target_list (widget),
7500                             di->source_actions,
7501                             button,
7502                             (GdkEvent*)event);
7503
7504   set_source_row (context, model, path);
7505
7506  out:
7507   if (path)
7508     gtk_tree_path_free (path);
7509
7510   return retval;
7511 }
7512
7513
7514 static void
7515 gtk_tree_view_drag_begin (GtkWidget      *widget,
7516                           GdkDragContext *context)
7517 {
7518   GtkTreeView *tree_view;
7519   GtkTreePath *path = NULL;
7520   gint cell_x, cell_y;
7521   cairo_surface_t *row_pix;
7522   TreeViewDragInfo *di;
7523
7524   tree_view = GTK_TREE_VIEW (widget);
7525
7526   /* if the user uses a custom DND source impl, we don't set the icon here */
7527   di = get_info (tree_view);
7528
7529   if (di == NULL || !di->source_set)
7530     return;
7531
7532   gtk_tree_view_get_path_at_pos (tree_view,
7533                                  tree_view->priv->press_start_x,
7534                                  tree_view->priv->press_start_y,
7535                                  &path,
7536                                  NULL,
7537                                  &cell_x,
7538                                  &cell_y);
7539
7540   /* If path is NULL, there's nothing we can drag.  For now, we silently
7541    * bail out.  Actually, dragging should not be possible from an empty
7542    * tree view, but there's no way we can cancel that from here.
7543    * Automatically unsetting the tree view as drag source for empty models
7544    * is something that would likely break other people's code ...
7545    */
7546   if (!path)
7547     return;
7548
7549   row_pix = gtk_tree_view_create_row_drag_icon (tree_view,
7550                                                 path);
7551   cairo_surface_set_device_offset (row_pix,
7552                                    /* the + 1 is for the black border in the icon */
7553                                    - (tree_view->priv->press_start_x + 1),
7554                                    - (cell_y + 1));
7555
7556   gtk_drag_set_icon_surface (context, row_pix);
7557
7558   cairo_surface_destroy (row_pix);
7559   gtk_tree_path_free (path);
7560 }
7561
7562 static void
7563 gtk_tree_view_drag_end (GtkWidget      *widget,
7564                         GdkDragContext *context)
7565 {
7566   /* do nothing */
7567 }
7568
7569 /* Default signal implementations for the drag signals */
7570 static void
7571 gtk_tree_view_drag_data_get (GtkWidget        *widget,
7572                              GdkDragContext   *context,
7573                              GtkSelectionData *selection_data,
7574                              guint             info,
7575                              guint             time)
7576 {
7577   GtkTreeView *tree_view;
7578   GtkTreeModel *model;
7579   TreeViewDragInfo *di;
7580   GtkTreePath *source_row;
7581
7582   tree_view = GTK_TREE_VIEW (widget);
7583
7584   model = gtk_tree_view_get_model (tree_view);
7585
7586   if (model == NULL)
7587     return;
7588
7589   di = get_info (GTK_TREE_VIEW (widget));
7590
7591   if (di == NULL)
7592     return;
7593
7594   source_row = get_source_row (context);
7595
7596   if (source_row == NULL)
7597     return;
7598
7599   /* We can implement the GTK_TREE_MODEL_ROW target generically for
7600    * any model; for DragSource models there are some other targets
7601    * we also support.
7602    */
7603
7604   if (GTK_IS_TREE_DRAG_SOURCE (model) &&
7605       gtk_tree_drag_source_drag_data_get (GTK_TREE_DRAG_SOURCE (model),
7606                                           source_row,
7607                                           selection_data))
7608     goto done;
7609
7610   /* If drag_data_get does nothing, try providing row data. */
7611   if (gtk_selection_data_get_target (selection_data) == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
7612     {
7613       gtk_tree_set_row_drag_data (selection_data,
7614                                   model,
7615                                   source_row);
7616     }
7617
7618  done:
7619   gtk_tree_path_free (source_row);
7620 }
7621
7622
7623 static void
7624 gtk_tree_view_drag_data_delete (GtkWidget      *widget,
7625                                 GdkDragContext *context)
7626 {
7627   TreeViewDragInfo *di;
7628   GtkTreeModel *model;
7629   GtkTreeView *tree_view;
7630   GtkTreePath *source_row;
7631
7632   tree_view = GTK_TREE_VIEW (widget);
7633   model = gtk_tree_view_get_model (tree_view);
7634
7635   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_SOURCE, "drag_data_delete"))
7636     return;
7637
7638   di = get_info (tree_view);
7639
7640   if (di == NULL)
7641     return;
7642
7643   source_row = get_source_row (context);
7644
7645   if (source_row == NULL)
7646     return;
7647
7648   gtk_tree_drag_source_drag_data_delete (GTK_TREE_DRAG_SOURCE (model),
7649                                          source_row);
7650
7651   gtk_tree_path_free (source_row);
7652
7653   set_source_row (context, NULL, NULL);
7654 }
7655
7656 static void
7657 gtk_tree_view_drag_leave (GtkWidget      *widget,
7658                           GdkDragContext *context,
7659                           guint             time)
7660 {
7661   /* unset any highlight row */
7662   gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7663                                    NULL,
7664                                    GTK_TREE_VIEW_DROP_BEFORE);
7665
7666   remove_scroll_timeout (GTK_TREE_VIEW (widget));
7667   remove_open_timeout (GTK_TREE_VIEW (widget));
7668 }
7669
7670
7671 static gboolean
7672 gtk_tree_view_drag_motion (GtkWidget        *widget,
7673                            GdkDragContext   *context,
7674                            /* coordinates relative to the widget */
7675                            gint              x,
7676                            gint              y,
7677                            guint             time)
7678 {
7679   gboolean empty;
7680   GtkTreePath *path = NULL;
7681   GtkTreeViewDropPosition pos;
7682   GtkTreeView *tree_view;
7683   GdkDragAction suggested_action = 0;
7684   GdkAtom target;
7685
7686   tree_view = GTK_TREE_VIEW (widget);
7687
7688   if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
7689     return FALSE;
7690
7691   gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
7692
7693   /* we only know this *after* set_desination_row */
7694   empty = tree_view->priv->empty_view_drop;
7695
7696   if (path == NULL && !empty)
7697     {
7698       /* Can't drop here. */
7699       gdk_drag_status (context, 0, time);
7700     }
7701   else
7702     {
7703       if (tree_view->priv->open_dest_timeout == 0 &&
7704           (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
7705            pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
7706         {
7707           tree_view->priv->open_dest_timeout =
7708             gdk_threads_add_timeout (AUTO_EXPAND_TIMEOUT, open_row_timeout, tree_view);
7709         }
7710       else
7711         {
7712           add_scroll_timeout (tree_view);
7713         }
7714
7715       if (target == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
7716         {
7717           /* Request data so we can use the source row when
7718            * determining whether to accept the drop
7719            */
7720           set_status_pending (context, suggested_action);
7721           gtk_drag_get_data (widget, context, target, time);
7722         }
7723       else
7724         {
7725           set_status_pending (context, 0);
7726           gdk_drag_status (context, suggested_action, time);
7727         }
7728     }
7729
7730   if (path)
7731     gtk_tree_path_free (path);
7732
7733   return TRUE;
7734 }
7735
7736
7737 static gboolean
7738 gtk_tree_view_drag_drop (GtkWidget        *widget,
7739                          GdkDragContext   *context,
7740                          /* coordinates relative to the widget */
7741                          gint              x,
7742                          gint              y,
7743                          guint             time)
7744 {
7745   GtkTreeView *tree_view;
7746   GtkTreePath *path;
7747   GdkDragAction suggested_action = 0;
7748   GdkAtom target = GDK_NONE;
7749   TreeViewDragInfo *di;
7750   GtkTreeModel *model;
7751   gboolean path_down_mode;
7752   gboolean drop_append_mode;
7753
7754   tree_view = GTK_TREE_VIEW (widget);
7755
7756   model = gtk_tree_view_get_model (tree_view);
7757
7758   remove_scroll_timeout (GTK_TREE_VIEW (widget));
7759   remove_open_timeout (GTK_TREE_VIEW (widget));
7760
7761   di = get_info (tree_view);
7762
7763   if (di == NULL)
7764     return FALSE;
7765
7766   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_drop"))
7767     return FALSE;
7768
7769   if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
7770     return FALSE;
7771
7772   path = get_logical_dest_row (tree_view, &path_down_mode, &drop_append_mode);
7773
7774   if (target != GDK_NONE && path != NULL)
7775     {
7776       /* in case a motion had requested drag data, change things so we
7777        * treat drag data receives as a drop.
7778        */
7779       set_status_pending (context, 0);
7780       set_dest_row (context, model, path,
7781                     path_down_mode, tree_view->priv->empty_view_drop,
7782                     drop_append_mode);
7783     }
7784
7785   if (path)
7786     gtk_tree_path_free (path);
7787
7788   /* Unset this thing */
7789   gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7790                                    NULL,
7791                                    GTK_TREE_VIEW_DROP_BEFORE);
7792
7793   if (target != GDK_NONE)
7794     {
7795       gtk_drag_get_data (widget, context, target, time);
7796       return TRUE;
7797     }
7798   else
7799     return FALSE;
7800 }
7801
7802 static void
7803 gtk_tree_view_drag_data_received (GtkWidget        *widget,
7804                                   GdkDragContext   *context,
7805                                   /* coordinates relative to the widget */
7806                                   gint              x,
7807                                   gint              y,
7808                                   GtkSelectionData *selection_data,
7809                                   guint             info,
7810                                   guint             time)
7811 {
7812   GtkTreePath *path;
7813   TreeViewDragInfo *di;
7814   gboolean accepted = FALSE;
7815   GtkTreeModel *model;
7816   GtkTreeView *tree_view;
7817   GtkTreePath *dest_row;
7818   GdkDragAction suggested_action;
7819   gboolean path_down_mode;
7820   gboolean drop_append_mode;
7821
7822   tree_view = GTK_TREE_VIEW (widget);
7823
7824   model = gtk_tree_view_get_model (tree_view);
7825
7826   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_data_received"))
7827     return;
7828
7829   di = get_info (tree_view);
7830
7831   if (di == NULL)
7832     return;
7833
7834   suggested_action = get_status_pending (context);
7835
7836   if (suggested_action)
7837     {
7838       /* We are getting this data due to a request in drag_motion,
7839        * rather than due to a request in drag_drop, so we are just
7840        * supposed to call drag_status, not actually paste in the
7841        * data.
7842        */
7843       path = get_logical_dest_row (tree_view, &path_down_mode,
7844                                    &drop_append_mode);
7845
7846       if (path == NULL)
7847         suggested_action = 0;
7848       else if (path_down_mode)
7849         gtk_tree_path_down (path);
7850
7851       if (suggested_action)
7852         {
7853           if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
7854                                                      path,
7855                                                      selection_data))
7856             {
7857               if (path_down_mode)
7858                 {
7859                   path_down_mode = FALSE;
7860                   gtk_tree_path_up (path);
7861
7862                   if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
7863                                                              path,
7864                                                              selection_data))
7865                     suggested_action = 0;
7866                 }
7867               else
7868                 suggested_action = 0;
7869             }
7870         }
7871
7872       gdk_drag_status (context, suggested_action, time);
7873
7874       if (path)
7875         gtk_tree_path_free (path);
7876
7877       /* If you can't drop, remove user drop indicator until the next motion */
7878       if (suggested_action == 0)
7879         gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7880                                          NULL,
7881                                          GTK_TREE_VIEW_DROP_BEFORE);
7882
7883       return;
7884     }
7885
7886   dest_row = get_dest_row (context, &path_down_mode);
7887
7888   if (dest_row == NULL)
7889     return;
7890
7891   if (gtk_selection_data_get_length (selection_data) >= 0)
7892     {
7893       if (path_down_mode)
7894         {
7895           gtk_tree_path_down (dest_row);
7896           if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
7897                                                      dest_row, selection_data))
7898             gtk_tree_path_up (dest_row);
7899         }
7900     }
7901
7902   if (gtk_selection_data_get_length (selection_data) >= 0)
7903     {
7904       if (gtk_tree_drag_dest_drag_data_received (GTK_TREE_DRAG_DEST (model),
7905                                                  dest_row,
7906                                                  selection_data))
7907         accepted = TRUE;
7908     }
7909
7910   gtk_drag_finish (context,
7911                    accepted,
7912                    (gdk_drag_context_get_selected_action (context) == GDK_ACTION_MOVE),
7913                    time);
7914
7915   if (gtk_tree_path_get_depth (dest_row) == 1 &&
7916       gtk_tree_path_get_indices (dest_row)[0] == 0 &&
7917       gtk_tree_model_iter_n_children (tree_view->priv->model, NULL) != 0)
7918     {
7919       /* special special case drag to "0", scroll to first item */
7920       if (!tree_view->priv->scroll_to_path)
7921         gtk_tree_view_scroll_to_cell (tree_view, dest_row, NULL, FALSE, 0.0, 0.0);
7922     }
7923
7924   gtk_tree_path_free (dest_row);
7925
7926   /* drop dest_row */
7927   set_dest_row (context, NULL, NULL, FALSE, FALSE, FALSE);
7928 }
7929
7930
7931
7932 /* GtkContainer Methods
7933  */
7934
7935
7936 static void
7937 gtk_tree_view_remove (GtkContainer *container,
7938                       GtkWidget    *widget)
7939 {
7940   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
7941   GtkTreeViewChild *child = NULL;
7942   GList *tmp_list;
7943
7944   tmp_list = tree_view->priv->children;
7945   while (tmp_list)
7946     {
7947       child = tmp_list->data;
7948       if (child->widget == widget)
7949         {
7950           gtk_widget_unparent (widget);
7951
7952           tree_view->priv->children = g_list_remove_link (tree_view->priv->children, tmp_list);
7953           g_list_free_1 (tmp_list);
7954           g_slice_free (GtkTreeViewChild, child);
7955           return;
7956         }
7957
7958       tmp_list = tmp_list->next;
7959     }
7960
7961   tmp_list = tree_view->priv->columns;
7962
7963   while (tmp_list)
7964     {
7965       GtkTreeViewColumn *column;
7966       GtkWidget         *button;
7967
7968       column = tmp_list->data;
7969       button = gtk_tree_view_column_get_button (column);
7970
7971       if (button == widget)
7972         {
7973           gtk_widget_unparent (widget);
7974           return;
7975         }
7976       tmp_list = tmp_list->next;
7977     }
7978 }
7979
7980 static void
7981 gtk_tree_view_forall (GtkContainer *container,
7982                       gboolean      include_internals,
7983                       GtkCallback   callback,
7984                       gpointer      callback_data)
7985 {
7986   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
7987   GtkTreeViewChild *child = NULL;
7988   GtkTreeViewColumn *column;
7989   GtkWidget *button;
7990   GList *tmp_list;
7991
7992   tmp_list = tree_view->priv->children;
7993   while (tmp_list)
7994     {
7995       child = tmp_list->data;
7996       tmp_list = tmp_list->next;
7997
7998       (* callback) (child->widget, callback_data);
7999     }
8000   if (include_internals == FALSE)
8001     return;
8002
8003   for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
8004     {
8005       column = tmp_list->data;
8006       button = gtk_tree_view_column_get_button (column);
8007
8008       if (button)
8009         (* callback) (button, callback_data);
8010     }
8011 }
8012
8013 /* Returns TRUE is any of the columns contains a cell that can-focus.
8014  * If this is not the case, a column-spanning focus rectangle will be
8015  * drawn.
8016  */
8017 static gboolean
8018 gtk_tree_view_has_can_focus_cell (GtkTreeView *tree_view)
8019 {
8020   GList *list;
8021
8022   for (list = tree_view->priv->columns; list; list = list->next)
8023     {
8024       GtkTreeViewColumn *column = list->data;
8025
8026       if (!gtk_tree_view_column_get_visible (column))
8027         continue;
8028       if (gtk_cell_area_is_activatable (gtk_cell_layout_get_area (GTK_CELL_LAYOUT (column))))
8029         return TRUE;
8030     }
8031
8032   return FALSE;
8033 }
8034
8035 static void
8036 column_sizing_notify (GObject    *object,
8037                       GParamSpec *pspec,
8038                       gpointer    data)
8039 {
8040   GtkTreeViewColumn *c = GTK_TREE_VIEW_COLUMN (object);
8041
8042   if (gtk_tree_view_column_get_sizing (c) != GTK_TREE_VIEW_COLUMN_FIXED)
8043     /* disable fixed height mode */
8044     g_object_set (data, "fixed-height-mode", FALSE, NULL);
8045 }
8046
8047 /**
8048  * gtk_tree_view_set_fixed_height_mode:
8049  * @tree_view: a #GtkTreeView 
8050  * @enable: %TRUE to enable fixed height mode
8051  * 
8052  * Enables or disables the fixed height mode of @tree_view. 
8053  * Fixed height mode speeds up #GtkTreeView by assuming that all 
8054  * rows have the same height. 
8055  * Only enable this option if all rows are the same height and all
8056  * columns are of type %GTK_TREE_VIEW_COLUMN_FIXED.
8057  *
8058  * Since: 2.6 
8059  **/
8060 void
8061 gtk_tree_view_set_fixed_height_mode (GtkTreeView *tree_view,
8062                                      gboolean     enable)
8063 {
8064   GList *l;
8065   
8066   enable = enable != FALSE;
8067
8068   if (enable == tree_view->priv->fixed_height_mode)
8069     return;
8070
8071   if (!enable)
8072     {
8073       tree_view->priv->fixed_height_mode = 0;
8074       tree_view->priv->fixed_height = -1;
8075     }
8076   else 
8077     {
8078       /* make sure all columns are of type FIXED */
8079       for (l = tree_view->priv->columns; l; l = l->next)
8080         {
8081           GtkTreeViewColumn *c = l->data;
8082           
8083           g_return_if_fail (gtk_tree_view_column_get_sizing (c) == GTK_TREE_VIEW_COLUMN_FIXED);
8084         }
8085       
8086       /* yes, we really have to do this is in a separate loop */
8087       for (l = tree_view->priv->columns; l; l = l->next)
8088         g_signal_connect (l->data, "notify::sizing",
8089                           G_CALLBACK (column_sizing_notify), tree_view);
8090       
8091       tree_view->priv->fixed_height_mode = 1;
8092       tree_view->priv->fixed_height = -1;
8093     }
8094
8095   /* force a revalidation */
8096   install_presize_handler (tree_view);
8097
8098   g_object_notify (G_OBJECT (tree_view), "fixed-height-mode");
8099 }
8100
8101 /**
8102  * gtk_tree_view_get_fixed_height_mode:
8103  * @tree_view: a #GtkTreeView
8104  * 
8105  * Returns whether fixed height mode is turned on for @tree_view.
8106  * 
8107  * Return value: %TRUE if @tree_view is in fixed height mode
8108  * 
8109  * Since: 2.6
8110  **/
8111 gboolean
8112 gtk_tree_view_get_fixed_height_mode (GtkTreeView *tree_view)
8113 {
8114   return tree_view->priv->fixed_height_mode;
8115 }
8116
8117 /* Returns TRUE if the focus is within the headers, after the focus operation is
8118  * done
8119  */
8120 static gboolean
8121 gtk_tree_view_header_focus (GtkTreeView      *tree_view,
8122                             GtkDirectionType  dir,
8123                             gboolean          clamp_column_visible)
8124 {
8125   GtkTreeViewColumn *column;
8126   GtkWidget *focus_child;
8127   GtkWidget *button;
8128   GList *last_column, *first_column;
8129   GList *tmp_list;
8130   gboolean rtl;
8131
8132   if (! tree_view->priv->headers_visible)
8133     return FALSE;
8134
8135   focus_child = gtk_container_get_focus_child (GTK_CONTAINER (tree_view));
8136
8137   first_column = tree_view->priv->columns;
8138   while (first_column)
8139     {
8140       column = GTK_TREE_VIEW_COLUMN (first_column->data);
8141       button = gtk_tree_view_column_get_button (column);
8142
8143       if (gtk_widget_get_can_focus (button) &&
8144           gtk_tree_view_column_get_visible (column) &&
8145           (gtk_tree_view_column_get_clickable (column) ||
8146            gtk_tree_view_column_get_reorderable (column)))
8147         break;
8148       first_column = first_column->next;
8149     }
8150
8151   /* No headers are visible, or are focusable.  We can't focus in or out.
8152    */
8153   if (first_column == NULL)
8154     return FALSE;
8155
8156   last_column = g_list_last (tree_view->priv->columns);
8157   while (last_column)
8158     {
8159       column = GTK_TREE_VIEW_COLUMN (last_column->data);
8160       button = gtk_tree_view_column_get_button (column);
8161
8162       if (gtk_widget_get_can_focus (button) &&
8163           gtk_tree_view_column_get_visible (column) &&
8164           (gtk_tree_view_column_get_clickable (column) ||
8165            gtk_tree_view_column_get_reorderable (column)))
8166         break;
8167       last_column = last_column->prev;
8168     }
8169
8170
8171   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
8172
8173   switch (dir)
8174     {
8175     case GTK_DIR_TAB_BACKWARD:
8176     case GTK_DIR_TAB_FORWARD:
8177     case GTK_DIR_UP:
8178     case GTK_DIR_DOWN:
8179       if (focus_child == NULL)
8180         {
8181           if (tree_view->priv->focus_column != NULL)
8182             button = gtk_tree_view_column_get_button (tree_view->priv->focus_column);
8183           else 
8184             button = NULL;
8185
8186           if (button && gtk_widget_get_can_focus (button))
8187             focus_child = button;
8188           else
8189             focus_child = gtk_tree_view_column_get_button (GTK_TREE_VIEW_COLUMN (first_column->data));
8190
8191           gtk_widget_grab_focus (focus_child);
8192           break;
8193         }
8194       return FALSE;
8195
8196     case GTK_DIR_LEFT:
8197     case GTK_DIR_RIGHT:
8198       if (focus_child == NULL)
8199         {
8200           if (tree_view->priv->focus_column != NULL)
8201             focus_child = gtk_tree_view_column_get_button (tree_view->priv->focus_column);
8202           else if (dir == GTK_DIR_LEFT)
8203             focus_child = gtk_tree_view_column_get_button (GTK_TREE_VIEW_COLUMN (last_column->data));
8204           else
8205             focus_child = gtk_tree_view_column_get_button (GTK_TREE_VIEW_COLUMN (first_column->data));
8206
8207           gtk_widget_grab_focus (focus_child);
8208           break;
8209         }
8210
8211       if (gtk_widget_child_focus (focus_child, dir))
8212         {
8213           /* The focus moves inside the button. */
8214           /* This is probably a great example of bad UI */
8215           break;
8216         }
8217
8218       /* We need to move the focus among the row of buttons. */
8219       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
8220         if (gtk_tree_view_column_get_button (GTK_TREE_VIEW_COLUMN (tmp_list->data)) == focus_child)
8221           break;
8222
8223       if ((tmp_list == first_column && dir == (rtl ? GTK_DIR_RIGHT : GTK_DIR_LEFT))
8224           || (tmp_list == last_column && dir == (rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT)))
8225         {
8226           gtk_widget_error_bell (GTK_WIDGET (tree_view));
8227           break;
8228         }
8229
8230       while (tmp_list)
8231         {
8232           GtkTreeViewColumn *column;
8233           GtkWidget         *button;
8234
8235           if (dir == (rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT))
8236             tmp_list = tmp_list->next;
8237           else
8238             tmp_list = tmp_list->prev;
8239
8240           if (tmp_list == NULL)
8241             {
8242               g_warning ("Internal button not found");
8243               break;
8244             }
8245           column = tmp_list->data;
8246           button = gtk_tree_view_column_get_button (column);
8247           if (button &&
8248               gtk_tree_view_column_get_visible (column) &&
8249               gtk_widget_get_can_focus (button))
8250             {
8251               focus_child = button;
8252               gtk_widget_grab_focus (button);
8253               break;
8254             }
8255         }
8256       break;
8257     default:
8258       g_assert_not_reached ();
8259       break;
8260     }
8261
8262   /* if focus child is non-null, we assume it's been set to the current focus child
8263    */
8264   if (focus_child)
8265     {
8266       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
8267         if (gtk_tree_view_column_get_button (GTK_TREE_VIEW_COLUMN (tmp_list->data)) == focus_child)
8268           {
8269             _gtk_tree_view_set_focus_column (tree_view, GTK_TREE_VIEW_COLUMN (tmp_list->data));
8270             break;
8271           }
8272
8273       if (clamp_column_visible)
8274         {
8275           gtk_tree_view_clamp_column_visible (tree_view,
8276                                               tree_view->priv->focus_column,
8277                                               FALSE);
8278         }
8279     }
8280
8281   return (focus_child != NULL);
8282 }
8283
8284 /* This function returns in 'path' the first focusable path, if the given path
8285  * is already focusable, it's the returned one.
8286  */
8287 static gboolean
8288 search_first_focusable_path (GtkTreeView  *tree_view,
8289                              GtkTreePath **path,
8290                              gboolean      search_forward,
8291                              GtkRBTree   **new_tree,
8292                              GtkRBNode   **new_node)
8293 {
8294   GtkRBTree *tree = NULL;
8295   GtkRBNode *node = NULL;
8296
8297   if (!path || !*path)
8298     return FALSE;
8299
8300   _gtk_tree_view_find_node (tree_view, *path, &tree, &node);
8301
8302   if (!tree || !node)
8303     return FALSE;
8304
8305   while (node && row_is_separator (tree_view, NULL, *path))
8306     {
8307       if (search_forward)
8308         _gtk_rbtree_next_full (tree, node, &tree, &node);
8309       else
8310         _gtk_rbtree_prev_full (tree, node, &tree, &node);
8311
8312       if (*path)
8313         gtk_tree_path_free (*path);
8314
8315       if (node)
8316         *path = _gtk_tree_path_new_from_rbtree (tree, node);
8317       else
8318         *path = NULL;
8319     }
8320
8321   if (new_tree)
8322     *new_tree = tree;
8323
8324   if (new_node)
8325     *new_node = node;
8326
8327   return (*path != NULL);
8328 }
8329
8330 static gint
8331 gtk_tree_view_focus (GtkWidget        *widget,
8332                      GtkDirectionType  direction)
8333 {
8334   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
8335   GtkContainer *container = GTK_CONTAINER (widget);
8336   GtkWidget *focus_child;
8337
8338   if (!gtk_widget_is_sensitive (widget) || !gtk_widget_get_can_focus (widget))
8339     return FALSE;
8340
8341   focus_child = gtk_container_get_focus_child (container);
8342
8343   gtk_tree_view_stop_editing (GTK_TREE_VIEW (widget), FALSE);
8344   /* Case 1.  Headers currently have focus. */
8345   if (focus_child)
8346     {
8347       switch (direction)
8348         {
8349         case GTK_DIR_LEFT:
8350         case GTK_DIR_RIGHT:
8351           gtk_tree_view_header_focus (tree_view, direction, TRUE);
8352           return TRUE;
8353         case GTK_DIR_TAB_BACKWARD:
8354         case GTK_DIR_UP:
8355           return FALSE;
8356         case GTK_DIR_TAB_FORWARD:
8357         case GTK_DIR_DOWN:
8358           gtk_widget_grab_focus (widget);
8359           return TRUE;
8360         default:
8361           g_assert_not_reached ();
8362           return FALSE;
8363         }
8364     }
8365
8366   /* Case 2. We don't have focus at all. */
8367   if (!gtk_widget_has_focus (widget))
8368     {
8369       gtk_widget_grab_focus (widget);
8370       return TRUE;
8371     }
8372
8373   /* Case 3. We have focus already. */
8374   if (direction == GTK_DIR_TAB_BACKWARD)
8375     return (gtk_tree_view_header_focus (tree_view, direction, FALSE));
8376   else if (direction == GTK_DIR_TAB_FORWARD)
8377     return FALSE;
8378
8379   /* Other directions caught by the keybindings */
8380   gtk_widget_grab_focus (widget);
8381   return TRUE;
8382 }
8383
8384 static void
8385 gtk_tree_view_grab_focus (GtkWidget *widget)
8386 {
8387   GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->grab_focus (widget);
8388
8389   gtk_tree_view_focus_to_cursor (GTK_TREE_VIEW (widget));
8390 }
8391
8392 static void
8393 gtk_tree_view_style_updated (GtkWidget *widget)
8394 {
8395   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
8396   GList *list;
8397   GtkTreeViewColumn *column;
8398   GtkStyleContext *style_context;
8399   const GtkBitmask *changes;
8400
8401   GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->style_updated (widget);
8402
8403   if (gtk_widget_get_realized (widget))
8404     {
8405       gtk_tree_view_ensure_background (tree_view);
8406
8407       gtk_tree_view_set_grid_lines (tree_view, tree_view->priv->grid_lines);
8408       gtk_tree_view_set_enable_tree_lines (tree_view, tree_view->priv->tree_lines_enabled);
8409     }
8410
8411   style_context = gtk_widget_get_style_context (widget);
8412   changes = _gtk_style_context_get_changes (style_context);
8413   if (changes == NULL || _gtk_css_style_property_changes_affect_size (changes))
8414     {
8415       for (list = tree_view->priv->columns; list; list = list->next)
8416         {
8417           column = list->data;
8418           _gtk_tree_view_column_cell_set_dirty (column, TRUE);
8419         }
8420
8421       tree_view->priv->fixed_height = -1;
8422       _gtk_rbtree_mark_invalid (tree_view->priv->tree);
8423     }
8424 }
8425
8426
8427 static void
8428 gtk_tree_view_set_focus_child (GtkContainer *container,
8429                                GtkWidget    *child)
8430 {
8431   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
8432   GList *list;
8433
8434   for (list = tree_view->priv->columns; list; list = list->next)
8435     {
8436       if (gtk_tree_view_column_get_button (GTK_TREE_VIEW_COLUMN (list->data)) == child)
8437         {
8438           _gtk_tree_view_set_focus_column (tree_view, GTK_TREE_VIEW_COLUMN (list->data));
8439           break;
8440         }
8441     }
8442
8443   GTK_CONTAINER_CLASS (gtk_tree_view_parent_class)->set_focus_child (container, child);
8444 }
8445
8446 static GtkWidgetPath *
8447 gtk_tree_view_get_path_for_child (GtkContainer *container,
8448                                   GtkWidget    *child)
8449 {
8450   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
8451   GtkWidgetPath *path;
8452   gboolean rtl;
8453   GList *list, *visible_columns = NULL;
8454   gint n_col = 0;
8455
8456   path = GTK_CONTAINER_CLASS (gtk_tree_view_parent_class)->get_path_for_child (container, child);
8457   rtl = (gtk_widget_get_direction (GTK_WIDGET (container)) == GTK_TEXT_DIR_RTL);
8458
8459   for (list = tree_view->priv->columns; list; list = list->next)
8460     {
8461       GtkTreeViewColumn *column = list->data;
8462
8463       if (gtk_tree_view_column_get_visible (column))
8464         visible_columns = g_list_prepend (visible_columns, column);
8465     }
8466
8467   if (!rtl)
8468     visible_columns = g_list_reverse (visible_columns);
8469
8470   for (list = visible_columns; list != NULL; list = list->next)
8471     {
8472       GtkTreeViewColumn *column = list->data;
8473       GtkRegionFlags flags = 0;
8474
8475       n_col++;
8476
8477       if (gtk_tree_view_column_get_widget (column) != child &&
8478           gtk_tree_view_column_get_button (column) != child)
8479         continue;
8480
8481       if ((n_col % 2) == 0)
8482         flags |= GTK_REGION_EVEN;
8483       else
8484         flags |= GTK_REGION_ODD;
8485
8486       if (n_col == 1)
8487         flags |= GTK_REGION_FIRST;
8488
8489       if (!list->next)
8490         flags |= GTK_REGION_LAST;
8491
8492       gtk_widget_path_iter_add_region (path, gtk_widget_path_length (path) - 2, GTK_STYLE_REGION_COLUMN_HEADER, flags);
8493       break;
8494     }
8495   g_list_free (visible_columns);
8496
8497   return path;
8498 }
8499
8500 static gboolean
8501 gtk_tree_view_real_move_cursor (GtkTreeView       *tree_view,
8502                                 GtkMovementStep    step,
8503                                 gint               count)
8504 {
8505   GdkModifierType state;
8506
8507   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
8508   g_return_val_if_fail (step == GTK_MOVEMENT_LOGICAL_POSITIONS ||
8509                         step == GTK_MOVEMENT_VISUAL_POSITIONS ||
8510                         step == GTK_MOVEMENT_DISPLAY_LINES ||
8511                         step == GTK_MOVEMENT_PAGES ||
8512                         step == GTK_MOVEMENT_BUFFER_ENDS, FALSE);
8513
8514   if (tree_view->priv->tree == NULL)
8515     return FALSE;
8516   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
8517     return FALSE;
8518
8519   gtk_tree_view_stop_editing (tree_view, FALSE);
8520   tree_view->priv->draw_keyfocus = TRUE;
8521   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
8522
8523   if (gtk_get_current_event_state (&state))
8524     {
8525       GdkModifierType extend_mod_mask;
8526       GdkModifierType modify_mod_mask;
8527
8528       extend_mod_mask =
8529         gtk_widget_get_modifier_mask (GTK_WIDGET (tree_view),
8530                                       GDK_MODIFIER_INTENT_EXTEND_SELECTION);
8531
8532       modify_mod_mask =
8533         gtk_widget_get_modifier_mask (GTK_WIDGET (tree_view),
8534                                       GDK_MODIFIER_INTENT_MODIFY_SELECTION);
8535
8536       if ((state & modify_mod_mask) == modify_mod_mask)
8537         tree_view->priv->modify_selection_pressed = TRUE;
8538       if ((state & extend_mod_mask) == extend_mod_mask)
8539         tree_view->priv->extend_selection_pressed = TRUE;
8540     }
8541   /* else we assume not pressed */
8542
8543   switch (step)
8544     {
8545       /* currently we make no distinction.  When we go bi-di, we need to */
8546     case GTK_MOVEMENT_LOGICAL_POSITIONS:
8547     case GTK_MOVEMENT_VISUAL_POSITIONS:
8548       gtk_tree_view_move_cursor_left_right (tree_view, count);
8549       break;
8550     case GTK_MOVEMENT_DISPLAY_LINES:
8551       gtk_tree_view_move_cursor_up_down (tree_view, count);
8552       break;
8553     case GTK_MOVEMENT_PAGES:
8554       gtk_tree_view_move_cursor_page_up_down (tree_view, count);
8555       break;
8556     case GTK_MOVEMENT_BUFFER_ENDS:
8557       gtk_tree_view_move_cursor_start_end (tree_view, count);
8558       break;
8559     default:
8560       g_assert_not_reached ();
8561     }
8562
8563   tree_view->priv->modify_selection_pressed = FALSE;
8564   tree_view->priv->extend_selection_pressed = FALSE;
8565
8566   return TRUE;
8567 }
8568
8569 static void
8570 gtk_tree_view_put (GtkTreeView *tree_view,
8571                    GtkWidget   *child_widget,
8572                    /* in bin_window coordinates */
8573                    gint         x,
8574                    gint         y,
8575                    gint         width,
8576                    gint         height)
8577 {
8578   GtkTreeViewChild *child;
8579   
8580   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8581   g_return_if_fail (GTK_IS_WIDGET (child_widget));
8582
8583   child = g_slice_new (GtkTreeViewChild);
8584
8585   child->widget = child_widget;
8586   child->x = x;
8587   child->y = y;
8588   child->width = width;
8589   child->height = height;
8590
8591   tree_view->priv->children = g_list_append (tree_view->priv->children, child);
8592
8593   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
8594     gtk_widget_set_parent_window (child->widget, tree_view->priv->bin_window);
8595   
8596   gtk_widget_set_parent (child_widget, GTK_WIDGET (tree_view));
8597 }
8598
8599 void
8600 _gtk_tree_view_child_move_resize (GtkTreeView *tree_view,
8601                                   GtkWidget   *widget,
8602                                   /* in tree coordinates */
8603                                   gint         x,
8604                                   gint         y,
8605                                   gint         width,
8606                                   gint         height)
8607 {
8608   GtkTreeViewChild *child = NULL;
8609   GList *list;
8610   GdkRectangle allocation;
8611
8612   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8613   g_return_if_fail (GTK_IS_WIDGET (widget));
8614
8615   for (list = tree_view->priv->children; list; list = list->next)
8616     {
8617       if (((GtkTreeViewChild *)list->data)->widget == widget)
8618         {
8619           child = list->data;
8620           break;
8621         }
8622     }
8623   if (child == NULL)
8624     return;
8625
8626   allocation.x = child->x = x;
8627   allocation.y = child->y = y;
8628   allocation.width = child->width = width;
8629   allocation.height = child->height = height;
8630
8631   if (gtk_widget_get_realized (widget))
8632     gtk_widget_size_allocate (widget, &allocation);
8633 }
8634
8635
8636 /* TreeModel Callbacks
8637  */
8638
8639 static void
8640 gtk_tree_view_row_changed (GtkTreeModel *model,
8641                            GtkTreePath  *path,
8642                            GtkTreeIter  *iter,
8643                            gpointer      data)
8644 {
8645   GtkTreeView *tree_view = (GtkTreeView *)data;
8646   GtkRBTree *tree;
8647   GtkRBNode *node;
8648   gboolean free_path = FALSE;
8649   GList *list;
8650   GtkTreePath *cursor_path;
8651
8652   g_return_if_fail (path != NULL || iter != NULL);
8653
8654   if (tree_view->priv->cursor_node != NULL)
8655     cursor_path = _gtk_tree_path_new_from_rbtree (tree_view->priv->cursor_tree,
8656                                                   tree_view->priv->cursor_node);
8657   else
8658     cursor_path = NULL;
8659
8660   if (tree_view->priv->edited_column &&
8661       (cursor_path == NULL || gtk_tree_path_compare (cursor_path, path) == 0))
8662     gtk_tree_view_stop_editing (tree_view, TRUE);
8663
8664   if (cursor_path != NULL)
8665     gtk_tree_path_free (cursor_path);
8666
8667   if (path == NULL)
8668     {
8669       path = gtk_tree_model_get_path (model, iter);
8670       free_path = TRUE;
8671     }
8672   else if (iter == NULL)
8673     gtk_tree_model_get_iter (model, iter, path);
8674
8675   if (_gtk_tree_view_find_node (tree_view,
8676                                 path,
8677                                 &tree,
8678                                 &node))
8679     /* We aren't actually showing the node */
8680     goto done;
8681
8682   if (tree == NULL)
8683     goto done;
8684
8685   _gtk_tree_view_accessible_changed (tree_view, tree, node);
8686
8687   if (tree_view->priv->fixed_height_mode
8688       && tree_view->priv->fixed_height >= 0)
8689     {
8690       _gtk_rbtree_node_set_height (tree, node, tree_view->priv->fixed_height);
8691       if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
8692         gtk_tree_view_node_queue_redraw (tree_view, tree, node);
8693     }
8694   else
8695     {
8696       _gtk_rbtree_node_mark_invalid (tree, node);
8697       for (list = tree_view->priv->columns; list; list = list->next)
8698         {
8699           GtkTreeViewColumn *column;
8700
8701           column = list->data;
8702           if (!gtk_tree_view_column_get_visible (column))
8703             continue;
8704
8705           if (gtk_tree_view_column_get_sizing (column) == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
8706             {
8707               _gtk_tree_view_column_cell_set_dirty (column, TRUE);
8708             }
8709         }
8710     }
8711
8712  done:
8713   if (!tree_view->priv->fixed_height_mode &&
8714       gtk_widget_get_realized (GTK_WIDGET (tree_view)))
8715     install_presize_handler (tree_view);
8716   if (free_path)
8717     gtk_tree_path_free (path);
8718 }
8719
8720 static void
8721 gtk_tree_view_row_inserted (GtkTreeModel *model,
8722                             GtkTreePath  *path,
8723                             GtkTreeIter  *iter,
8724                             gpointer      data)
8725 {
8726   GtkTreeView *tree_view = (GtkTreeView *) data;
8727   gint *indices;
8728   GtkRBTree *tree;
8729   GtkRBNode *tmpnode = NULL;
8730   gint depth;
8731   gint i = 0;
8732   gint height;
8733   gboolean free_path = FALSE;
8734   gboolean node_visible = TRUE;
8735
8736   g_return_if_fail (path != NULL || iter != NULL);
8737
8738   if (tree_view->priv->fixed_height_mode
8739       && tree_view->priv->fixed_height >= 0)
8740     height = tree_view->priv->fixed_height;
8741   else
8742     height = 0;
8743
8744   if (path == NULL)
8745     {
8746       path = gtk_tree_model_get_path (model, iter);
8747       free_path = TRUE;
8748     }
8749   else if (iter == NULL)
8750     gtk_tree_model_get_iter (model, iter, path);
8751
8752   if (tree_view->priv->tree == NULL)
8753     tree_view->priv->tree = _gtk_rbtree_new ();
8754
8755   tree = tree_view->priv->tree;
8756
8757   /* Update all row-references */
8758   gtk_tree_row_reference_inserted (G_OBJECT (data), path);
8759   depth = gtk_tree_path_get_depth (path);
8760   indices = gtk_tree_path_get_indices (path);
8761
8762   /* First, find the parent tree */
8763   while (i < depth - 1)
8764     {
8765       if (tree == NULL)
8766         {
8767           /* We aren't showing the node */
8768           node_visible = FALSE;
8769           goto done;
8770         }
8771
8772       tmpnode = _gtk_rbtree_find_count (tree, indices[i] + 1);
8773       if (tmpnode == NULL)
8774         {
8775           g_warning ("A node was inserted with a parent that's not in the tree.\n" \
8776                      "This possibly means that a GtkTreeModel inserted a child node\n" \
8777                      "before the parent was inserted.");
8778           goto done;
8779         }
8780       else if (!GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_IS_PARENT))
8781         {
8782           /* FIXME enforce correct behavior on model, probably */
8783           /* In theory, the model should have emitted has_child_toggled here.  We
8784            * try to catch it anyway, just to be safe, in case the model hasn't.
8785            */
8786           GtkTreePath *tmppath = _gtk_tree_path_new_from_rbtree (tree, tmpnode);
8787           gtk_tree_view_row_has_child_toggled (model, tmppath, NULL, data);
8788           gtk_tree_path_free (tmppath);
8789           goto done;
8790         }
8791
8792       tree = tmpnode->children;
8793       i++;
8794     }
8795
8796   if (tree == NULL)
8797     {
8798       node_visible = FALSE;
8799       goto done;
8800     }
8801
8802   /* ref the node */
8803   gtk_tree_model_ref_node (tree_view->priv->model, iter);
8804   if (indices[depth - 1] == 0)
8805     {
8806       tmpnode = _gtk_rbtree_find_count (tree, 1);
8807       tmpnode = _gtk_rbtree_insert_before (tree, tmpnode, height, FALSE);
8808     }
8809   else
8810     {
8811       tmpnode = _gtk_rbtree_find_count (tree, indices[depth - 1]);
8812       tmpnode = _gtk_rbtree_insert_after (tree, tmpnode, height, FALSE);
8813     }
8814
8815   _gtk_tree_view_accessible_add (tree_view, tree, tmpnode);
8816
8817  done:
8818   if (height > 0)
8819     {
8820       if (tree)
8821         _gtk_rbtree_node_mark_valid (tree, tmpnode);
8822
8823       if (node_visible && node_is_visible (tree_view, tree, tmpnode))
8824         gtk_widget_queue_resize (GTK_WIDGET (tree_view));
8825       else
8826         gtk_widget_queue_resize_no_redraw (GTK_WIDGET (tree_view));
8827     }
8828   else
8829     install_presize_handler (tree_view);
8830   if (free_path)
8831     gtk_tree_path_free (path);
8832 }
8833
8834 static void
8835 gtk_tree_view_row_has_child_toggled (GtkTreeModel *model,
8836                                      GtkTreePath  *path,
8837                                      GtkTreeIter  *iter,
8838                                      gpointer      data)
8839 {
8840   GtkTreeView *tree_view = (GtkTreeView *)data;
8841   GtkTreeIter real_iter;
8842   gboolean has_child;
8843   GtkRBTree *tree;
8844   GtkRBNode *node;
8845   gboolean free_path = FALSE;
8846
8847   g_return_if_fail (path != NULL || iter != NULL);
8848
8849   if (iter)
8850     real_iter = *iter;
8851
8852   if (path == NULL)
8853     {
8854       path = gtk_tree_model_get_path (model, iter);
8855       free_path = TRUE;
8856     }
8857   else if (iter == NULL)
8858     gtk_tree_model_get_iter (model, &real_iter, path);
8859
8860   if (_gtk_tree_view_find_node (tree_view,
8861                                 path,
8862                                 &tree,
8863                                 &node))
8864     /* We aren't actually showing the node */
8865     goto done;
8866
8867   if (tree == NULL)
8868     goto done;
8869
8870   has_child = gtk_tree_model_iter_has_child (model, &real_iter);
8871   /* Sanity check.
8872    */
8873   if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT) == has_child)
8874     goto done;
8875
8876   if (has_child)
8877     {
8878       GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_PARENT);
8879       _gtk_tree_view_accessible_add_state (tree_view, tree, node, GTK_CELL_RENDERER_EXPANDABLE);
8880     }
8881   else
8882     {
8883       GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_PARENT);
8884       _gtk_tree_view_accessible_remove_state (tree_view, tree, node, GTK_CELL_RENDERER_EXPANDABLE);
8885     }
8886
8887   if (has_child && tree_view->priv->is_list)
8888     {
8889       tree_view->priv->is_list = FALSE;
8890       if (tree_view->priv->show_expanders)
8891         {
8892           GList *list;
8893
8894           for (list = tree_view->priv->columns; list; list = list->next)
8895             if (gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (list->data)))
8896               {
8897                 _gtk_tree_view_column_cell_set_dirty (GTK_TREE_VIEW_COLUMN (list->data), TRUE);
8898                 break;
8899               }
8900         }
8901       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
8902     }
8903   else
8904     {
8905       _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
8906     }
8907
8908  done:
8909   if (free_path)
8910     gtk_tree_path_free (path);
8911 }
8912
8913 static void
8914 count_children_helper (GtkRBTree *tree,
8915                        GtkRBNode *node,
8916                        gpointer   data)
8917 {
8918   if (node->children)
8919     _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, data);
8920   (*((gint *)data))++;
8921 }
8922
8923 static void
8924 check_selection_helper (GtkRBTree *tree,
8925                         GtkRBNode *node,
8926                         gpointer   data)
8927 {
8928   gint *value = (gint *)data;
8929
8930   *value |= GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED);
8931
8932   if (node->children && !*value)
8933     _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, check_selection_helper, data);
8934 }
8935
8936 static void
8937 gtk_tree_view_row_deleted (GtkTreeModel *model,
8938                            GtkTreePath  *path,
8939                            gpointer      data)
8940 {
8941   GtkTreeView *tree_view = (GtkTreeView *)data;
8942   GtkRBTree *tree;
8943   GtkRBNode *node;
8944   GList *list;
8945   gboolean selection_changed = FALSE, cursor_changed = FALSE;
8946   GtkRBTree *cursor_tree = NULL;
8947   GtkRBNode *cursor_node = NULL;
8948
8949   g_return_if_fail (path != NULL);
8950
8951   gtk_tree_row_reference_deleted (G_OBJECT (data), path);
8952
8953   if (_gtk_tree_view_find_node (tree_view, path, &tree, &node))
8954     return;
8955
8956   if (tree == NULL)
8957     return;
8958
8959   /* check if the selection has been changed */
8960   _gtk_rbtree_traverse (tree, node, G_POST_ORDER,
8961                         check_selection_helper, &selection_changed);
8962
8963   for (list = tree_view->priv->columns; list; list = list->next)
8964     if (gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (list->data)) &&
8965         gtk_tree_view_column_get_sizing (GTK_TREE_VIEW_COLUMN (list->data)) == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
8966       _gtk_tree_view_column_cell_set_dirty ((GtkTreeViewColumn *)list->data, TRUE);
8967
8968   /* Ensure we don't have a dangling pointer to a dead node */
8969   ensure_unprelighted (tree_view);
8970
8971   /* Cancel editting if we've started */
8972   gtk_tree_view_stop_editing (tree_view, TRUE);
8973
8974   /* If the cursor row got deleted, move the cursor to the next row */
8975   if (tree_view->priv->cursor_node &&
8976       (tree_view->priv->cursor_node == node ||
8977        (node->children && (tree_view->priv->cursor_tree == node->children ||
8978                            _gtk_rbtree_contains (node->children, tree_view->priv->cursor_tree)))))
8979     {
8980       GtkTreePath *cursor_path;
8981
8982       cursor_tree = tree;
8983       cursor_node = _gtk_rbtree_next (tree, node);
8984       /* find the first node that is not going to be deleted */
8985       while (cursor_node == NULL && cursor_tree->parent_tree)
8986         {
8987           cursor_node = _gtk_rbtree_next (cursor_tree->parent_tree,
8988                                           cursor_tree->parent_node);
8989           cursor_tree = cursor_tree->parent_tree;
8990         }
8991
8992       if (cursor_node != NULL)
8993         cursor_path = _gtk_tree_path_new_from_rbtree (cursor_tree, cursor_node);
8994       else
8995         cursor_path = NULL;
8996
8997       if (cursor_path == NULL ||
8998           ! search_first_focusable_path (tree_view, &cursor_path, TRUE, 
8999                                          &cursor_tree, &cursor_node))
9000         {
9001           /* It looks like we reached the end of the view without finding
9002            * a focusable row.  We will step backwards to find the last
9003            * focusable row.
9004            */
9005           _gtk_rbtree_prev_full (tree, node, &cursor_tree, &cursor_node);
9006           if (cursor_node)
9007             {
9008               cursor_path = _gtk_tree_path_new_from_rbtree (cursor_tree, cursor_node);
9009               if (! search_first_focusable_path (tree_view, &cursor_path, FALSE,
9010                                                  &cursor_tree, &cursor_node))
9011                 cursor_node = NULL;
9012               gtk_tree_path_free (cursor_path);
9013             }
9014         }
9015       else if (cursor_path)
9016         gtk_tree_path_free (cursor_path);
9017
9018       cursor_changed = TRUE;
9019     }
9020
9021   if (tree_view->priv->destroy_count_func)
9022     {
9023       gint child_count = 0;
9024       if (node->children)
9025         _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, &child_count);
9026       tree_view->priv->destroy_count_func (tree_view, path, child_count, tree_view->priv->destroy_count_data);
9027     }
9028
9029   if (tree->root->count == 1)
9030     {
9031       if (tree_view->priv->tree == tree)
9032         tree_view->priv->tree = NULL;
9033
9034       _gtk_tree_view_accessible_remove_state (tree_view,
9035                                               tree->parent_tree, tree->parent_node,
9036                                               GTK_CELL_RENDERER_EXPANDED);
9037       _gtk_tree_view_accessible_remove (tree_view, tree, NULL);
9038       _gtk_rbtree_remove (tree);
9039     }
9040   else
9041     {
9042       _gtk_tree_view_accessible_remove (tree_view, tree, node);
9043       _gtk_rbtree_remove_node (tree, node);
9044     }
9045
9046   if (! gtk_tree_row_reference_valid (tree_view->priv->top_row))
9047     {
9048       gtk_tree_row_reference_free (tree_view->priv->top_row);
9049       tree_view->priv->top_row = NULL;
9050     }
9051
9052   install_scroll_sync_handler (tree_view);
9053
9054   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
9055
9056   if (cursor_changed)
9057     {
9058       if (cursor_node)
9059         {
9060           GtkTreePath *cursor_path = _gtk_tree_path_new_from_rbtree (cursor_tree, cursor_node);
9061           gtk_tree_view_real_set_cursor (tree_view, cursor_path, CLEAR_AND_SELECT | CURSOR_INVALID);
9062           gtk_tree_path_free (cursor_path);
9063         }
9064       else
9065         gtk_tree_view_real_set_cursor (tree_view, NULL, CLEAR_AND_SELECT | CURSOR_INVALID);
9066     }
9067   if (selection_changed)
9068     g_signal_emit_by_name (tree_view->priv->selection, "changed");
9069 }
9070
9071 static void
9072 gtk_tree_view_rows_reordered (GtkTreeModel *model,
9073                               GtkTreePath  *parent,
9074                               GtkTreeIter  *iter,
9075                               gint         *new_order,
9076                               gpointer      data)
9077 {
9078   GtkTreeView *tree_view = GTK_TREE_VIEW (data);
9079   GtkRBTree *tree;
9080   GtkRBNode *node;
9081   gint len;
9082
9083   len = gtk_tree_model_iter_n_children (model, iter);
9084
9085   if (len < 2)
9086     return;
9087
9088   gtk_tree_row_reference_reordered (G_OBJECT (data),
9089                                     parent,
9090                                     iter,
9091                                     new_order);
9092
9093   if (_gtk_tree_view_find_node (tree_view,
9094                                 parent,
9095                                 &tree,
9096                                 &node))
9097     return;
9098
9099   /* We need to special case the parent path */
9100   if (tree == NULL)
9101     tree = tree_view->priv->tree;
9102   else
9103     tree = node->children;
9104
9105   if (tree == NULL)
9106     return;
9107
9108   if (tree_view->priv->edited_column)
9109     gtk_tree_view_stop_editing (tree_view, TRUE);
9110
9111   /* we need to be unprelighted */
9112   ensure_unprelighted (tree_view);
9113
9114   _gtk_rbtree_reorder (tree, new_order, len);
9115
9116   _gtk_tree_view_accessible_reorder (tree_view);
9117
9118   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
9119
9120   gtk_tree_view_dy_to_top_row (tree_view);
9121 }
9122
9123
9124 /* Internal tree functions
9125  */
9126
9127
9128 static void
9129 gtk_tree_view_get_background_xrange (GtkTreeView       *tree_view,
9130                                      GtkRBTree         *tree,
9131                                      GtkTreeViewColumn *column,
9132                                      gint              *x1,
9133                                      gint              *x2)
9134 {
9135   GtkTreeViewColumn *tmp_column = NULL;
9136   gint total_width;
9137   GList *list;
9138   gboolean rtl;
9139
9140   if (x1)
9141     *x1 = 0;
9142
9143   if (x2)
9144     *x2 = 0;
9145
9146   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
9147
9148   total_width = 0;
9149   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
9150        list;
9151        list = (rtl ? list->prev : list->next))
9152     {
9153       tmp_column = list->data;
9154
9155       if (tmp_column == column)
9156         break;
9157
9158       if (gtk_tree_view_column_get_visible (tmp_column))
9159         total_width += gtk_tree_view_column_get_width (tmp_column);
9160     }
9161
9162   if (tmp_column != column)
9163     {
9164       g_warning (G_STRLOC": passed-in column isn't in the tree");
9165       return;
9166     }
9167
9168   if (x1)
9169     *x1 = total_width;
9170
9171   if (x2)
9172     {
9173       if (gtk_tree_view_column_get_visible (column))
9174         *x2 = total_width + gtk_tree_view_column_get_width (column);
9175       else
9176         *x2 = total_width; /* width of 0 */
9177     }
9178 }
9179
9180 static void
9181 gtk_tree_view_get_arrow_xrange (GtkTreeView *tree_view,
9182                                 GtkRBTree   *tree,
9183                                 gint        *x1,
9184                                 gint        *x2)
9185 {
9186   gint x_offset = 0;
9187   GList *list;
9188   GtkTreeViewColumn *tmp_column = NULL;
9189   gint total_width;
9190   gint expander_size;
9191   gboolean indent_expanders;
9192   gboolean rtl;
9193
9194   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
9195   expander_size = gtk_tree_view_get_expander_size (tree_view);
9196
9197   total_width = 0;
9198   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
9199        list;
9200        list = (rtl ? list->prev : list->next))
9201     {
9202       tmp_column = list->data;
9203
9204       if (gtk_tree_view_is_expander_column (tree_view, tmp_column))
9205         {
9206           if (rtl)
9207             x_offset = total_width + gtk_tree_view_column_get_width (tmp_column) - expander_size;
9208           else
9209             x_offset = total_width;
9210           break;
9211         }
9212
9213       if (gtk_tree_view_column_get_visible (tmp_column))
9214         total_width += gtk_tree_view_column_get_width (tmp_column);
9215     }
9216
9217   gtk_widget_style_get (GTK_WIDGET (tree_view),
9218                         "indent-expanders", &indent_expanders,
9219                         NULL);
9220
9221   if (indent_expanders)
9222     {
9223       if (rtl)
9224         x_offset -= expander_size * _gtk_rbtree_get_depth (tree);
9225       else
9226         x_offset += expander_size * _gtk_rbtree_get_depth (tree);
9227     }
9228
9229   *x1 = x_offset;
9230
9231   if (tmp_column &&
9232       gtk_tree_view_column_get_visible (tmp_column))
9233     /* +1 because x2 isn't included in the range. */
9234     *x2 = *x1 + expander_size + 1;
9235   else
9236     *x2 = *x1;
9237 }
9238
9239 static void
9240 gtk_tree_view_build_tree (GtkTreeView *tree_view,
9241                           GtkRBTree   *tree,
9242                           GtkTreeIter *iter,
9243                           gint         depth,
9244                           gboolean     recurse)
9245 {
9246   GtkRBNode *temp = NULL;
9247   GtkTreePath *path = NULL;
9248
9249   do
9250     {
9251       gtk_tree_model_ref_node (tree_view->priv->model, iter);
9252       temp = _gtk_rbtree_insert_after (tree, temp, 0, FALSE);
9253
9254       if (tree_view->priv->fixed_height > 0)
9255         {
9256           if (GTK_RBNODE_FLAG_SET (temp, GTK_RBNODE_INVALID))
9257             {
9258               _gtk_rbtree_node_set_height (tree, temp, tree_view->priv->fixed_height);
9259               _gtk_rbtree_node_mark_valid (tree, temp);
9260             }
9261         }
9262
9263       if (tree_view->priv->is_list)
9264         continue;
9265
9266       if (recurse)
9267         {
9268           GtkTreeIter child;
9269
9270           if (!path)
9271             path = gtk_tree_model_get_path (tree_view->priv->model, iter);
9272           else
9273             gtk_tree_path_next (path);
9274
9275           if (gtk_tree_model_iter_children (tree_view->priv->model, &child, iter))
9276             {
9277               gboolean expand;
9278
9279               g_signal_emit (tree_view, tree_view_signals[TEST_EXPAND_ROW], 0, iter, path, &expand);
9280
9281               if (gtk_tree_model_iter_has_child (tree_view->priv->model, iter)
9282                   && !expand)
9283                 {
9284                   temp->children = _gtk_rbtree_new ();
9285                   temp->children->parent_tree = tree;
9286                   temp->children->parent_node = temp;
9287                   gtk_tree_view_build_tree (tree_view, temp->children, &child, depth + 1, recurse);
9288                 }
9289             }
9290         }
9291
9292       if (gtk_tree_model_iter_has_child (tree_view->priv->model, iter))
9293         {
9294           if ((temp->flags&GTK_RBNODE_IS_PARENT) != GTK_RBNODE_IS_PARENT)
9295             temp->flags ^= GTK_RBNODE_IS_PARENT;
9296         }
9297     }
9298   while (gtk_tree_model_iter_next (tree_view->priv->model, iter));
9299
9300   if (path)
9301     gtk_tree_path_free (path);
9302 }
9303
9304 /* Make sure the node is visible vertically */
9305 static void
9306 gtk_tree_view_clamp_node_visible (GtkTreeView *tree_view,
9307                                   GtkRBTree   *tree,
9308                                   GtkRBNode   *node)
9309 {
9310   gint node_dy, height;
9311   GtkTreePath *path = NULL;
9312
9313   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
9314     return;
9315
9316   /* just return if the node is visible, avoiding a costly expose */
9317   node_dy = _gtk_rbtree_node_find_offset (tree, node);
9318   height = gtk_tree_view_get_row_height (tree_view, node);
9319   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID)
9320       && node_dy >= gtk_adjustment_get_value (tree_view->priv->vadjustment)
9321       && node_dy + height <= (gtk_adjustment_get_value (tree_view->priv->vadjustment)
9322                               + gtk_adjustment_get_page_size (tree_view->priv->vadjustment)))
9323     return;
9324
9325   path = _gtk_tree_path_new_from_rbtree (tree, node);
9326   if (path)
9327     {
9328       gtk_tree_view_scroll_to_cell (tree_view, path, NULL, FALSE, 0.0, 0.0);
9329       gtk_tree_path_free (path);
9330     }
9331 }
9332
9333 static void
9334 gtk_tree_view_clamp_column_visible (GtkTreeView       *tree_view,
9335                                     GtkTreeViewColumn *column,
9336                                     gboolean           focus_to_cell)
9337 {
9338   GtkAllocation allocation;
9339   gint x, width;
9340
9341   if (column == NULL)
9342     return;
9343
9344   gtk_widget_get_allocation (gtk_tree_view_column_get_button (column), &allocation);
9345   x = allocation.x;
9346   width = allocation.width;
9347
9348   if (width > gtk_adjustment_get_page_size (tree_view->priv->hadjustment))
9349     {
9350       /* The column is larger than the horizontal page size.  If the
9351        * column has cells which can be focussed individually, then we make
9352        * sure the cell which gets focus is fully visible (if even the
9353        * focus cell is bigger than the page size, we make sure the
9354        * left-hand side of the cell is visible).
9355        *
9356        * If the column does not have an activatable cell, we
9357        * make sure the left-hand side of the column is visible.
9358        */
9359
9360       if (focus_to_cell && gtk_tree_view_has_can_focus_cell (tree_view))
9361         {
9362           GtkCellArea *cell_area;
9363           GtkCellRenderer *focus_cell;
9364
9365           cell_area = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (column));
9366           focus_cell = gtk_cell_area_get_focus_cell (cell_area);
9367
9368           if (gtk_tree_view_column_cell_get_position (column, focus_cell,
9369                                                       &x, &width))
9370             {
9371               if (width < gtk_adjustment_get_page_size (tree_view->priv->hadjustment))
9372                 {
9373                   if (gtk_adjustment_get_value (tree_view->priv->hadjustment) + gtk_adjustment_get_page_size (tree_view->priv->hadjustment) < x + width)
9374                     gtk_adjustment_set_value (tree_view->priv->hadjustment,
9375                                               x + width - gtk_adjustment_get_page_size (tree_view->priv->hadjustment));
9376                   else if (gtk_adjustment_get_value (tree_view->priv->hadjustment) > x)
9377                     gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
9378                 }
9379             }
9380         }
9381
9382       gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
9383     }
9384   else
9385     {
9386       if ((gtk_adjustment_get_value (tree_view->priv->hadjustment) + gtk_adjustment_get_page_size (tree_view->priv->hadjustment)) < (x + width))
9387           gtk_adjustment_set_value (tree_view->priv->hadjustment,
9388                                     x + width - gtk_adjustment_get_page_size (tree_view->priv->hadjustment));
9389       else if (gtk_adjustment_get_value (tree_view->priv->hadjustment) > x)
9390         gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
9391   }
9392 }
9393
9394 /* This function could be more efficient.  I'll optimize it if profiling seems
9395  * to imply that it is important */
9396 GtkTreePath *
9397 _gtk_tree_path_new_from_rbtree (GtkRBTree   *tree,
9398                                 GtkRBNode   *node)
9399 {
9400   GtkTreePath *path;
9401   GtkRBTree *tmp_tree;
9402   GtkRBNode *tmp_node, *last;
9403   gint count;
9404
9405   path = gtk_tree_path_new ();
9406
9407   g_return_val_if_fail (node != NULL, path);
9408
9409   count = 1 + node->left->count;
9410
9411   last = node;
9412   tmp_node = node->parent;
9413   tmp_tree = tree;
9414   while (tmp_tree)
9415     {
9416       while (!_gtk_rbtree_is_nil (tmp_node))
9417         {
9418           if (tmp_node->right == last)
9419             count += 1 + tmp_node->left->count;
9420           last = tmp_node;
9421           tmp_node = tmp_node->parent;
9422         }
9423       gtk_tree_path_prepend_index (path, count - 1);
9424       last = tmp_tree->parent_node;
9425       tmp_tree = tmp_tree->parent_tree;
9426       if (last)
9427         {
9428           count = 1 + last->left->count;
9429           tmp_node = last->parent;
9430         }
9431     }
9432   return path;
9433 }
9434
9435 /* Returns TRUE if we ran out of tree before finding the path.  If the path is
9436  * invalid (ie. points to a node that's not in the tree), *tree and *node are
9437  * both set to NULL.
9438  */
9439 gboolean
9440 _gtk_tree_view_find_node (GtkTreeView  *tree_view,
9441                           GtkTreePath  *path,
9442                           GtkRBTree   **tree,
9443                           GtkRBNode   **node)
9444 {
9445   GtkRBNode *tmpnode = NULL;
9446   GtkRBTree *tmptree = tree_view->priv->tree;
9447   gint *indices = gtk_tree_path_get_indices (path);
9448   gint depth = gtk_tree_path_get_depth (path);
9449   gint i = 0;
9450
9451   *node = NULL;
9452   *tree = NULL;
9453
9454   if (depth == 0 || tmptree == NULL)
9455     return FALSE;
9456   do
9457     {
9458       tmpnode = _gtk_rbtree_find_count (tmptree, indices[i] + 1);
9459       ++i;
9460       if (tmpnode == NULL)
9461         {
9462           *tree = NULL;
9463           *node = NULL;
9464           return FALSE;
9465         }
9466       if (i >= depth)
9467         {
9468           *tree = tmptree;
9469           *node = tmpnode;
9470           return FALSE;
9471         }
9472       *tree = tmptree;
9473       *node = tmpnode;
9474       tmptree = tmpnode->children;
9475       if (tmptree == NULL)
9476         return TRUE;
9477     }
9478   while (1);
9479 }
9480
9481 static gboolean
9482 gtk_tree_view_is_expander_column (GtkTreeView       *tree_view,
9483                                   GtkTreeViewColumn *column)
9484 {
9485   GList *list;
9486
9487   if (tree_view->priv->is_list)
9488     return FALSE;
9489
9490   if (tree_view->priv->expander_column != NULL)
9491     {
9492       if (tree_view->priv->expander_column == column)
9493         return TRUE;
9494       return FALSE;
9495     }
9496   else
9497     {
9498       for (list = tree_view->priv->columns;
9499            list;
9500            list = list->next)
9501         if (gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (list->data)))
9502           break;
9503       if (list && list->data == column)
9504         return TRUE;
9505     }
9506   return FALSE;
9507 }
9508
9509 static inline gboolean
9510 gtk_tree_view_draw_expanders (GtkTreeView *tree_view)
9511 {
9512   if (!tree_view->priv->is_list && tree_view->priv->show_expanders)
9513     return TRUE;
9514   /* else */
9515   return FALSE;
9516 }
9517
9518 static void
9519 gtk_tree_view_add_move_binding (GtkBindingSet  *binding_set,
9520                                 guint           keyval,
9521                                 guint           modmask,
9522                                 gboolean        add_shifted_binding,
9523                                 GtkMovementStep step,
9524                                 gint            count)
9525 {
9526   
9527   gtk_binding_entry_add_signal (binding_set, keyval, modmask,
9528                                 "move-cursor", 2,
9529                                 G_TYPE_ENUM, step,
9530                                 G_TYPE_INT, count);
9531
9532   if (add_shifted_binding)
9533     gtk_binding_entry_add_signal (binding_set, keyval, GDK_SHIFT_MASK,
9534                                   "move-cursor", 2,
9535                                   G_TYPE_ENUM, step,
9536                                   G_TYPE_INT, count);
9537
9538   if ((modmask & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
9539    return;
9540
9541   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK | GDK_SHIFT_MASK,
9542                                 "move-cursor", 2,
9543                                 G_TYPE_ENUM, step,
9544                                 G_TYPE_INT, count);
9545
9546   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK,
9547                                 "move-cursor", 2,
9548                                 G_TYPE_ENUM, step,
9549                                 G_TYPE_INT, count);
9550 }
9551
9552 static gint
9553 gtk_tree_view_unref_tree_helper (GtkTreeModel *model,
9554                                  GtkTreeIter  *iter,
9555                                  GtkRBTree    *tree,
9556                                  GtkRBNode    *node)
9557 {
9558   gint retval = FALSE;
9559   do
9560     {
9561       g_return_val_if_fail (node != NULL, FALSE);
9562
9563       if (node->children)
9564         {
9565           GtkTreeIter child;
9566           GtkRBTree *new_tree;
9567           GtkRBNode *new_node;
9568
9569           new_tree = node->children;
9570           new_node = _gtk_rbtree_first (new_tree);
9571
9572           if (!gtk_tree_model_iter_children (model, &child, iter))
9573             return FALSE;
9574
9575           retval = gtk_tree_view_unref_tree_helper (model, &child, new_tree, new_node) | retval;
9576         }
9577
9578       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
9579         retval = TRUE;
9580       gtk_tree_model_unref_node (model, iter);
9581       node = _gtk_rbtree_next (tree, node);
9582     }
9583   while (gtk_tree_model_iter_next (model, iter));
9584
9585   return retval;
9586 }
9587
9588 static gint
9589 gtk_tree_view_unref_and_check_selection_tree (GtkTreeView *tree_view,
9590                                               GtkRBTree   *tree)
9591 {
9592   GtkTreeIter iter;
9593   GtkTreePath *path;
9594   GtkRBNode *node;
9595   gint retval;
9596
9597   if (!tree)
9598     return FALSE;
9599
9600   node = _gtk_rbtree_first (tree);
9601
9602   g_return_val_if_fail (node != NULL, FALSE);
9603   path = _gtk_tree_path_new_from_rbtree (tree, node);
9604   gtk_tree_model_get_iter (GTK_TREE_MODEL (tree_view->priv->model),
9605                            &iter, path);
9606   retval = gtk_tree_view_unref_tree_helper (GTK_TREE_MODEL (tree_view->priv->model), &iter, tree, node);
9607   gtk_tree_path_free (path);
9608
9609   return retval;
9610 }
9611
9612 static void
9613 gtk_tree_view_set_column_drag_info (GtkTreeView       *tree_view,
9614                                     GtkTreeViewColumn *column)
9615 {
9616   GtkTreeViewColumn *left_column;
9617   GtkTreeViewColumn *cur_column = NULL;
9618   GtkTreeViewColumnReorder *reorder;
9619   gboolean rtl;
9620   GList *tmp_list;
9621   gint left;
9622
9623   /* We want to precalculate the motion list such that we know what column slots
9624    * are available.
9625    */
9626   left_column = NULL;
9627   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
9628
9629   /* First, identify all possible drop spots */
9630   if (rtl)
9631     tmp_list = g_list_last (tree_view->priv->columns);
9632   else
9633     tmp_list = g_list_first (tree_view->priv->columns);
9634
9635   while (tmp_list)
9636     {
9637       cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
9638       tmp_list = rtl?g_list_previous (tmp_list):g_list_next (tmp_list);
9639
9640       if (gtk_tree_view_column_get_visible (cur_column) == FALSE)
9641         continue;
9642
9643       /* If it's not the column moving and func tells us to skip over the column, we continue. */
9644       if (left_column != column && cur_column != column &&
9645           tree_view->priv->column_drop_func &&
9646           ! tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
9647         {
9648           left_column = cur_column;
9649           continue;
9650         }
9651       reorder = g_slice_new0 (GtkTreeViewColumnReorder);
9652       reorder->left_column = left_column;
9653       left_column = reorder->right_column = cur_column;
9654
9655       tree_view->priv->column_drag_info = g_list_append (tree_view->priv->column_drag_info, reorder);
9656     }
9657
9658   /* Add the last one */
9659   if (tree_view->priv->column_drop_func == NULL ||
9660       ((left_column != column) &&
9661        tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data)))
9662     {
9663       reorder = g_slice_new0 (GtkTreeViewColumnReorder);
9664       reorder->left_column = left_column;
9665       reorder->right_column = NULL;
9666       tree_view->priv->column_drag_info = g_list_append (tree_view->priv->column_drag_info, reorder);
9667     }
9668
9669   /* We quickly check to see if it even makes sense to reorder columns. */
9670   /* If there is nothing that can be moved, then we return */
9671
9672   if (tree_view->priv->column_drag_info == NULL)
9673     return;
9674
9675   /* We know there are always 2 slots possbile, as you can always return column. */
9676   /* If that's all there is, return */
9677   if (tree_view->priv->column_drag_info->next == NULL || 
9678       (tree_view->priv->column_drag_info->next->next == NULL &&
9679        ((GtkTreeViewColumnReorder *)tree_view->priv->column_drag_info->data)->right_column == column &&
9680        ((GtkTreeViewColumnReorder *)tree_view->priv->column_drag_info->next->data)->left_column == column))
9681     {
9682       for (tmp_list = tree_view->priv->column_drag_info; tmp_list; tmp_list = tmp_list->next)
9683         g_slice_free (GtkTreeViewColumnReorder, tmp_list->data);
9684       g_list_free (tree_view->priv->column_drag_info);
9685       tree_view->priv->column_drag_info = NULL;
9686       return;
9687     }
9688   /* We fill in the ranges for the columns, now that we've isolated them */
9689   left = - TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER (tree_view);
9690
9691   for (tmp_list = tree_view->priv->column_drag_info; tmp_list; tmp_list = tmp_list->next)
9692     {
9693       reorder = (GtkTreeViewColumnReorder *) tmp_list->data;
9694
9695       reorder->left_align = left;
9696       if (tmp_list->next != NULL)
9697         {
9698           GtkAllocation right_allocation, left_allocation;
9699           GtkWidget    *left_button, *right_button;
9700
9701           g_assert (tmp_list->next->data);
9702
9703           right_button = gtk_tree_view_column_get_button (reorder->right_column);
9704           left_button  = gtk_tree_view_column_get_button
9705             (((GtkTreeViewColumnReorder *)tmp_list->next->data)->left_column);
9706
9707           gtk_widget_get_allocation (right_button, &right_allocation);
9708           gtk_widget_get_allocation (left_button, &left_allocation);
9709           left = reorder->right_align = (right_allocation.x + right_allocation.width + left_allocation.x) / 2;
9710         }
9711       else
9712         {
9713           reorder->right_align = gdk_window_get_width (tree_view->priv->header_window)
9714                                  + TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER (tree_view);
9715         }
9716     }
9717 }
9718
9719 void
9720 _gtk_tree_view_column_start_drag (GtkTreeView       *tree_view,
9721                                   GtkTreeViewColumn *column,
9722                                   GdkDevice         *device)
9723 {
9724   GdkEvent *send_event;
9725   GtkAllocation allocation;
9726   GtkAllocation button_allocation;
9727   GdkScreen *screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
9728   GtkWidget *button;
9729   GdkDevice *pointer, *keyboard;
9730   GdkWindowAttr attributes;
9731   guint attributes_mask;
9732   GtkStyleContext *context;
9733
9734   g_return_if_fail (tree_view->priv->column_drag_info == NULL);
9735   g_return_if_fail (tree_view->priv->cur_reorder == NULL);
9736   g_return_if_fail (tree_view->priv->drag_window == NULL);
9737
9738   gtk_tree_view_set_column_drag_info (tree_view, column);
9739
9740   if (tree_view->priv->column_drag_info == NULL)
9741     return;
9742
9743   button = gtk_tree_view_column_get_button (column);
9744
9745   context = gtk_widget_get_style_context (button);
9746   gtk_style_context_add_class (context, GTK_STYLE_CLASS_DND);
9747
9748   gtk_widget_get_allocation (button, &button_allocation);
9749
9750   attributes.window_type = GDK_WINDOW_CHILD;
9751   attributes.wclass = GDK_INPUT_OUTPUT;
9752   attributes.x = button_allocation.x;
9753   attributes.y = 0;
9754   attributes.width = button_allocation.width;
9755   attributes.height = button_allocation.height;
9756   attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
9757   attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
9758   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
9759
9760   tree_view->priv->drag_window = gdk_window_new (tree_view->priv->header_window,
9761                                                  &attributes,
9762                                                  attributes_mask);
9763   gdk_window_set_user_data (tree_view->priv->drag_window, GTK_WIDGET (tree_view));
9764
9765   if (gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD)
9766     {
9767       keyboard = device;
9768       pointer = gdk_device_get_associated_device (device);
9769     }
9770   else
9771     {
9772       pointer = device;
9773       keyboard = gdk_device_get_associated_device (device);
9774     }
9775
9776   gdk_device_ungrab (pointer, GDK_CURRENT_TIME);
9777   gdk_device_ungrab (keyboard, GDK_CURRENT_TIME);
9778
9779   gtk_grab_remove (button);
9780
9781   send_event = gdk_event_new (GDK_LEAVE_NOTIFY);
9782   send_event->crossing.send_event = TRUE;
9783   send_event->crossing.window = g_object_ref (gtk_button_get_event_window (GTK_BUTTON (button)));
9784   send_event->crossing.subwindow = NULL;
9785   send_event->crossing.detail = GDK_NOTIFY_ANCESTOR;
9786   send_event->crossing.time = GDK_CURRENT_TIME;
9787   gdk_event_set_device (send_event, device);
9788
9789   gtk_propagate_event (button, send_event);
9790   gdk_event_free (send_event);
9791
9792   send_event = gdk_event_new (GDK_BUTTON_RELEASE);
9793   send_event->button.window = g_object_ref (gdk_screen_get_root_window (screen));
9794   send_event->button.send_event = TRUE;
9795   send_event->button.time = GDK_CURRENT_TIME;
9796   send_event->button.x = -1;
9797   send_event->button.y = -1;
9798   send_event->button.axes = NULL;
9799   send_event->button.state = 0;
9800   send_event->button.button = GDK_BUTTON_PRIMARY;
9801   send_event->button.x_root = 0;
9802   send_event->button.y_root = 0;
9803   gdk_event_set_device (send_event, device);
9804
9805   gtk_propagate_event (button, send_event);
9806   gdk_event_free (send_event);
9807
9808   /* Kids, don't try this at home */
9809   g_object_ref (button);
9810   gtk_container_remove (GTK_CONTAINER (tree_view), button);
9811   gtk_widget_set_parent_window (button, tree_view->priv->drag_window);
9812   gtk_widget_set_parent (button, GTK_WIDGET (tree_view));
9813   g_object_unref (button);
9814
9815   gtk_widget_get_allocation (button, &button_allocation);
9816   tree_view->priv->drag_column_x = button_allocation.x;
9817   allocation = button_allocation;
9818   allocation.x = 0;
9819   gtk_widget_size_allocate (button, &allocation);
9820   gtk_widget_set_parent_window (button, tree_view->priv->drag_window);
9821
9822   tree_view->priv->drag_column = column;
9823   gdk_window_show (tree_view->priv->drag_window);
9824
9825   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
9826   while (gtk_events_pending ())
9827     gtk_main_iteration ();
9828
9829   tree_view->priv->in_column_drag = TRUE;
9830
9831   gdk_device_grab (pointer,
9832                    tree_view->priv->drag_window,
9833                    GDK_OWNERSHIP_NONE,
9834                    FALSE,
9835                    GDK_POINTER_MOTION_MASK|GDK_BUTTON_RELEASE_MASK,
9836                    NULL,
9837                    GDK_CURRENT_TIME);
9838   gdk_device_grab (keyboard,
9839                    tree_view->priv->drag_window,
9840                    GDK_OWNERSHIP_NONE,
9841                    FALSE,
9842                    GDK_KEY_PRESS_MASK|GDK_KEY_RELEASE_MASK,
9843                    NULL,
9844                    GDK_CURRENT_TIME);
9845 }
9846
9847 static void
9848 gtk_tree_view_queue_draw_arrow (GtkTreeView        *tree_view,
9849                                 GtkRBTree          *tree,
9850                                 GtkRBNode          *node)
9851 {
9852   GtkAllocation allocation;
9853   GdkRectangle rect;
9854
9855   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
9856     return;
9857
9858   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
9859   rect.x = 0;
9860   rect.width = gtk_tree_view_get_expander_size (tree_view);
9861   rect.width = MAX (rect.width, MAX (tree_view->priv->width, allocation.width));
9862
9863   rect.y = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
9864   rect.height = gtk_tree_view_get_row_height (tree_view, node);
9865
9866   gdk_window_invalidate_rect (tree_view->priv->bin_window, &rect, TRUE);
9867 }
9868
9869 void
9870 _gtk_tree_view_queue_draw_node (GtkTreeView        *tree_view,
9871                                 GtkRBTree          *tree,
9872                                 GtkRBNode          *node,
9873                                 const GdkRectangle *clip_rect)
9874 {
9875   GtkAllocation allocation;
9876   GdkRectangle rect;
9877
9878   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
9879     return;
9880
9881   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
9882   rect.x = 0;
9883   rect.width = MAX (tree_view->priv->width, allocation.width);
9884
9885   rect.y = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
9886   rect.height = gtk_tree_view_get_row_height (tree_view, node);
9887
9888   if (clip_rect)
9889     {
9890       GdkRectangle new_rect;
9891
9892       gdk_rectangle_intersect (clip_rect, &rect, &new_rect);
9893
9894       gdk_window_invalidate_rect (tree_view->priv->bin_window, &new_rect, TRUE);
9895     }
9896   else
9897     {
9898       gdk_window_invalidate_rect (tree_view->priv->bin_window, &rect, TRUE);
9899     }
9900 }
9901
9902 static inline gint
9903 gtk_tree_view_get_effective_header_height (GtkTreeView *tree_view)
9904 {
9905   if (tree_view->priv->headers_visible)
9906     return tree_view->priv->header_height;
9907   /* else */
9908   return 0;
9909 }
9910
9911 gint
9912 _gtk_tree_view_get_header_height (GtkTreeView *tree_view)
9913 {
9914   return tree_view->priv->header_height;
9915 }
9916
9917 void
9918 _gtk_tree_view_get_row_separator_func (GtkTreeView                 *tree_view,
9919                                        GtkTreeViewRowSeparatorFunc *func,
9920                                        gpointer                    *data)
9921 {
9922   *func = tree_view->priv->row_separator_func;
9923   *data = tree_view->priv->row_separator_data;
9924 }
9925
9926 GtkTreePath *
9927 _gtk_tree_view_get_anchor_path (GtkTreeView *tree_view)
9928 {
9929   if (tree_view->priv->anchor)
9930     return gtk_tree_row_reference_get_path (tree_view->priv->anchor);
9931
9932   return NULL;
9933 }
9934
9935 void
9936 _gtk_tree_view_set_anchor_path (GtkTreeView *tree_view,
9937                                 GtkTreePath *anchor_path)
9938 {
9939   if (tree_view->priv->anchor)
9940     {
9941       gtk_tree_row_reference_free (tree_view->priv->anchor);
9942       tree_view->priv->anchor = NULL;
9943     }
9944
9945   if (anchor_path && tree_view->priv->model)
9946     tree_view->priv->anchor =
9947       gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), 
9948                                         tree_view->priv->model, anchor_path);
9949 }
9950
9951 GtkRBTree *
9952 _gtk_tree_view_get_rbtree (GtkTreeView *tree_view)
9953 {
9954   return tree_view->priv->tree;
9955 }
9956
9957 gboolean
9958 _gtk_tree_view_get_cursor_node (GtkTreeView  *tree_view,
9959                                 GtkRBTree   **tree,
9960                                 GtkRBNode   **node)
9961 {
9962   GtkTreeViewPrivate *priv;
9963
9964   priv = tree_view->priv;
9965
9966   if (priv->cursor_node == NULL)
9967     return FALSE;
9968
9969   *tree = priv->cursor_tree;
9970   *node = priv->cursor_node;
9971
9972   return TRUE;
9973 }
9974
9975 GdkWindow *
9976 _gtk_tree_view_get_header_window (GtkTreeView *tree_view)
9977 {
9978   return tree_view->priv->header_window;
9979 }
9980
9981 GtkTreeViewColumn *
9982 _gtk_tree_view_get_focus_column (GtkTreeView *tree_view)
9983 {
9984   return tree_view->priv->focus_column;
9985 }
9986
9987 void
9988 _gtk_tree_view_set_focus_column (GtkTreeView       *tree_view,
9989                                  GtkTreeViewColumn *column)
9990 {
9991   GtkTreeViewColumn *old_column = tree_view->priv->focus_column;
9992
9993   if (old_column == column)
9994     return;
9995
9996   tree_view->priv->focus_column = column;
9997
9998   _gtk_tree_view_accessible_update_focus_column (tree_view, 
9999                                                  old_column,
10000                                                  column);
10001 }
10002
10003
10004 static void
10005 gtk_tree_view_queue_draw_path (GtkTreeView        *tree_view,
10006                                GtkTreePath        *path,
10007                                const GdkRectangle *clip_rect)
10008 {
10009   GtkRBTree *tree = NULL;
10010   GtkRBNode *node = NULL;
10011
10012   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
10013
10014   if (tree)
10015     _gtk_tree_view_queue_draw_node (tree_view, tree, node, clip_rect);
10016 }
10017
10018 /* x and y are the mouse position
10019  */
10020 static void
10021 gtk_tree_view_draw_arrow (GtkTreeView *tree_view,
10022                           cairo_t     *cr,
10023                           GtkRBTree   *tree,
10024                           GtkRBNode   *node)
10025 {
10026   GdkRectangle area;
10027   GtkStateFlags state = 0;
10028   GtkStyleContext *context;
10029   GtkWidget *widget;
10030   gint x_offset = 0;
10031   gint x2;
10032   gint vertical_separator;
10033   gint expander_size;
10034   GtkCellRendererState flags = 0;
10035
10036   widget = GTK_WIDGET (tree_view);
10037   context = gtk_widget_get_style_context (widget);
10038
10039   gtk_widget_style_get (widget,
10040                         "vertical-separator", &vertical_separator,
10041                         NULL);
10042   expander_size = gtk_tree_view_get_expander_size (tree_view) - EXPANDER_EXTRA_PADDING;
10043
10044   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
10045     return;
10046
10047   gtk_tree_view_get_arrow_xrange (tree_view, tree, &x_offset, &x2);
10048
10049   area.x = x_offset;
10050   area.y = gtk_tree_view_get_cell_area_y_offset (tree_view, tree, node,
10051                                                  vertical_separator);
10052   area.width = expander_size;
10053   area.height = gtk_tree_view_get_cell_area_height (tree_view, node,
10054                                                     vertical_separator);
10055
10056   if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
10057     flags |= GTK_CELL_RENDERER_SELECTED;
10058
10059   if (node == tree_view->priv->prelight_node &&
10060       tree_view->priv->arrow_prelit)
10061     flags |= GTK_CELL_RENDERER_PRELIT;
10062
10063   state = gtk_cell_renderer_get_state (NULL, widget, flags);
10064
10065   if (node->children != NULL)
10066     state |= GTK_STATE_FLAG_ACTIVE;
10067   else
10068     state &= ~(GTK_STATE_FLAG_ACTIVE);
10069
10070   gtk_style_context_save (context);
10071
10072   gtk_style_context_set_state (context, state);
10073   gtk_style_context_add_class (context, GTK_STYLE_CLASS_EXPANDER);
10074
10075   gtk_render_expander (context, cr,
10076                        area.x, area.y,
10077                        area.width, area.height);
10078
10079   gtk_style_context_restore (context);
10080 }
10081
10082 static void
10083 gtk_tree_view_focus_to_cursor (GtkTreeView *tree_view)
10084
10085 {
10086   GtkTreePath *cursor_path;
10087
10088   if ((tree_view->priv->tree == NULL) ||
10089       (! gtk_widget_get_realized (GTK_WIDGET (tree_view))))
10090     return;
10091
10092   cursor_path = NULL;
10093   if (tree_view->priv->cursor_node)
10094     cursor_path = _gtk_tree_path_new_from_rbtree (tree_view->priv->cursor_tree,
10095                                                   tree_view->priv->cursor_node);
10096
10097   if (cursor_path == NULL)
10098     {
10099       /* Consult the selection before defaulting to the
10100        * first focusable element
10101        */
10102       GList *selected_rows;
10103       GtkTreeModel *model;
10104       GtkTreeSelection *selection;
10105
10106       selection = gtk_tree_view_get_selection (tree_view);
10107       selected_rows = gtk_tree_selection_get_selected_rows (selection, &model);
10108
10109       if (selected_rows)
10110         {
10111           cursor_path = gtk_tree_path_copy((const GtkTreePath *)(selected_rows->data));
10112           g_list_free_full (selected_rows, (GDestroyNotify) gtk_tree_path_free);
10113         }
10114       else
10115         {
10116           cursor_path = gtk_tree_path_new_first ();
10117           search_first_focusable_path (tree_view, &cursor_path,
10118                                        TRUE, NULL, NULL);
10119         }
10120
10121       if (cursor_path)
10122         {
10123           if (gtk_tree_selection_get_mode (tree_view->priv->selection) == GTK_SELECTION_MULTIPLE)
10124             gtk_tree_view_real_set_cursor (tree_view, cursor_path, 0);
10125           else
10126             gtk_tree_view_real_set_cursor (tree_view, cursor_path, CLEAR_AND_SELECT);
10127         }
10128     }
10129
10130   if (cursor_path)
10131     {
10132       tree_view->priv->draw_keyfocus = TRUE;
10133
10134       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10135       gtk_tree_path_free (cursor_path);
10136
10137       if (tree_view->priv->focus_column == NULL)
10138         {
10139           GList *list;
10140           for (list = tree_view->priv->columns; list; list = list->next)
10141             {
10142               if (gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (list->data)))
10143                 {
10144                   GtkCellArea *cell_area;
10145
10146                   _gtk_tree_view_set_focus_column (tree_view, GTK_TREE_VIEW_COLUMN (list->data));
10147
10148                   /* This happens when the treeview initially grabs focus and there
10149                    * is no column in focus, here we explicitly focus into the first cell */
10150                   cell_area = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (tree_view->priv->focus_column));
10151                   if (!gtk_cell_area_get_focus_cell (cell_area))
10152                     {
10153                       gboolean rtl;
10154
10155                       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
10156                       gtk_cell_area_focus (cell_area,
10157                                            rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT);
10158                     }
10159
10160                   break;
10161                 }
10162             }
10163         }
10164     }
10165 }
10166
10167 static void
10168 gtk_tree_view_move_cursor_up_down (GtkTreeView *tree_view,
10169                                    gint         count)
10170 {
10171   gint selection_count;
10172   GtkRBTree *new_cursor_tree = NULL;
10173   GtkRBNode *new_cursor_node = NULL;
10174   GtkTreePath *cursor_path = NULL;
10175   gboolean grab_focus = TRUE;
10176   gboolean selectable;
10177   GtkDirectionType direction;
10178   GtkCellArea *cell_area = NULL;
10179   GtkCellRenderer *last_focus_cell = NULL;
10180   GtkTreeIter iter;
10181
10182   if (! gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10183     return;
10184
10185   if (tree_view->priv->cursor_node == NULL)
10186     return;
10187
10188   cursor_path = _gtk_tree_path_new_from_rbtree (tree_view->priv->cursor_tree,
10189                                                 tree_view->priv->cursor_node);
10190
10191   direction = count < 0 ? GTK_DIR_UP : GTK_DIR_DOWN;
10192
10193   if (tree_view->priv->focus_column)
10194     cell_area = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (tree_view->priv->focus_column));
10195
10196   /* If focus stays in the area for this row, then just return for this round */
10197   if (cell_area && (count == -1 || count == 1) &&
10198       gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path))
10199     {
10200       gtk_tree_view_column_cell_set_cell_data (tree_view->priv->focus_column,
10201                                                tree_view->priv->model,
10202                                                &iter,
10203                                                GTK_RBNODE_FLAG_SET (tree_view->priv->cursor_node, GTK_RBNODE_IS_PARENT),
10204                                                tree_view->priv->cursor_node->children ? TRUE : FALSE);
10205
10206       /* Save the last cell that had focus, if we hit the end of the view we'll give
10207        * focus back to it. */
10208       last_focus_cell = gtk_cell_area_get_focus_cell (cell_area);
10209
10210       /* If focus stays in the area, no need to change the cursor row */
10211       if (gtk_cell_area_focus (cell_area, direction))
10212         return;
10213     }
10214
10215   selection_count = gtk_tree_selection_count_selected_rows (tree_view->priv->selection);
10216   selectable = _gtk_tree_selection_row_is_selectable (tree_view->priv->selection,
10217                                                       tree_view->priv->cursor_node,
10218                                                       cursor_path);
10219
10220   if (selection_count == 0
10221       && gtk_tree_selection_get_mode (tree_view->priv->selection) != GTK_SELECTION_NONE
10222       && !tree_view->priv->modify_selection_pressed
10223       && selectable)
10224     {
10225       /* Don't move the cursor, but just select the current node */
10226       new_cursor_tree = tree_view->priv->cursor_tree;
10227       new_cursor_node = tree_view->priv->cursor_node;
10228     }
10229   else
10230     {
10231       if (count == -1)
10232         _gtk_rbtree_prev_full (tree_view->priv->cursor_tree, tree_view->priv->cursor_node,
10233                                &new_cursor_tree, &new_cursor_node);
10234       else
10235         _gtk_rbtree_next_full (tree_view->priv->cursor_tree, tree_view->priv->cursor_node,
10236                                &new_cursor_tree, &new_cursor_node);
10237     }
10238
10239   gtk_tree_path_free (cursor_path);
10240
10241   if (new_cursor_node)
10242     {
10243       cursor_path = _gtk_tree_path_new_from_rbtree (new_cursor_tree, new_cursor_node);
10244
10245       search_first_focusable_path (tree_view, &cursor_path,
10246                                    (count != -1),
10247                                    &new_cursor_tree,
10248                                    &new_cursor_node);
10249
10250       if (cursor_path)
10251         gtk_tree_path_free (cursor_path);
10252     }
10253
10254   /*
10255    * If the list has only one item and multi-selection is set then select
10256    * the row (if not yet selected).
10257    */
10258   if (gtk_tree_selection_get_mode (tree_view->priv->selection) == GTK_SELECTION_MULTIPLE &&
10259       new_cursor_node == NULL)
10260     {
10261       if (count == -1)
10262         _gtk_rbtree_next_full (tree_view->priv->cursor_tree, tree_view->priv->cursor_node,
10263                                &new_cursor_tree, &new_cursor_node);
10264       else
10265         _gtk_rbtree_prev_full (tree_view->priv->cursor_tree, tree_view->priv->cursor_node,
10266                                &new_cursor_tree, &new_cursor_node);
10267
10268       if (new_cursor_node == NULL
10269           && !GTK_RBNODE_FLAG_SET (tree_view->priv->cursor_node, GTK_RBNODE_IS_SELECTED))
10270         {
10271           new_cursor_node = tree_view->priv->cursor_node;
10272           new_cursor_tree = tree_view->priv->cursor_tree;
10273         }
10274       else
10275         {
10276           new_cursor_tree = NULL;
10277           new_cursor_node = NULL;
10278         }
10279     }
10280
10281   if (new_cursor_node)
10282     {
10283       cursor_path = _gtk_tree_path_new_from_rbtree (new_cursor_tree, new_cursor_node);
10284       gtk_tree_view_real_set_cursor (tree_view, cursor_path, CLEAR_AND_SELECT | CLAMP_NODE);
10285       gtk_tree_path_free (cursor_path);
10286
10287       /* Give focus to the area in the new row */
10288       if (cell_area)
10289         gtk_cell_area_focus (cell_area, direction);
10290     }
10291   else
10292     {
10293       gtk_tree_view_clamp_node_visible (tree_view, 
10294                                         tree_view->priv->cursor_tree,
10295                                         tree_view->priv->cursor_node);
10296
10297       if (!tree_view->priv->extend_selection_pressed)
10298         {
10299           if (! gtk_widget_keynav_failed (GTK_WIDGET (tree_view),
10300                                           count < 0 ?
10301                                           GTK_DIR_UP : GTK_DIR_DOWN))
10302             {
10303               GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (tree_view));
10304
10305               if (toplevel)
10306                 gtk_widget_child_focus (toplevel,
10307                                         count < 0 ?
10308                                         GTK_DIR_TAB_BACKWARD :
10309                                         GTK_DIR_TAB_FORWARD);
10310
10311               grab_focus = FALSE;
10312             }
10313         }
10314       else
10315         {
10316           gtk_widget_error_bell (GTK_WIDGET (tree_view));
10317         }
10318
10319       if (cell_area)
10320         gtk_cell_area_set_focus_cell (cell_area, last_focus_cell);
10321     }
10322
10323   if (grab_focus)
10324     gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10325 }
10326
10327 static void
10328 gtk_tree_view_move_cursor_page_up_down (GtkTreeView *tree_view,
10329                                         gint         count)
10330 {
10331   GtkTreePath *old_cursor_path = NULL;
10332   GtkTreePath *cursor_path = NULL;
10333   GtkRBTree *start_cursor_tree = NULL;
10334   GtkRBNode *start_cursor_node = NULL;
10335   GtkRBTree *cursor_tree;
10336   GtkRBNode *cursor_node;
10337   gint y;
10338   gint window_y;
10339   gint vertical_separator;
10340
10341   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10342     return;
10343
10344   if (tree_view->priv->cursor_node == NULL)
10345     return;
10346
10347   old_cursor_path = _gtk_tree_path_new_from_rbtree (tree_view->priv->cursor_tree,
10348                                                     tree_view->priv->cursor_node);
10349
10350   gtk_widget_style_get (GTK_WIDGET (tree_view), "vertical-separator", &vertical_separator, NULL);
10351
10352   y = _gtk_rbtree_node_find_offset (tree_view->priv->cursor_tree, tree_view->priv->cursor_node);
10353   window_y = RBTREE_Y_TO_TREE_WINDOW_Y (tree_view, y);
10354   y += tree_view->priv->cursor_offset;
10355   y += count * (int)gtk_adjustment_get_page_increment (tree_view->priv->vadjustment);
10356   y = CLAMP (y, (gint)gtk_adjustment_get_lower (tree_view->priv->vadjustment),  (gint)gtk_adjustment_get_upper (tree_view->priv->vadjustment) - vertical_separator);
10357
10358   if (y >= tree_view->priv->height)
10359     y = tree_view->priv->height - 1;
10360
10361   tree_view->priv->cursor_offset =
10362     _gtk_rbtree_find_offset (tree_view->priv->tree, y,
10363                              &cursor_tree, &cursor_node);
10364
10365   if (cursor_tree == NULL)
10366     {
10367       /* FIXME: we lost the cursor.  Should we try to get one? */
10368       gtk_tree_path_free (old_cursor_path);
10369       return;
10370     }
10371
10372   if (tree_view->priv->cursor_offset
10373       > gtk_tree_view_get_row_height (tree_view, cursor_node))
10374     {
10375       _gtk_rbtree_next_full (cursor_tree, cursor_node,
10376                              &cursor_tree, &cursor_node);
10377       tree_view->priv->cursor_offset -= gtk_tree_view_get_row_height (tree_view, cursor_node);
10378     }
10379
10380   y -= tree_view->priv->cursor_offset;
10381   cursor_path = _gtk_tree_path_new_from_rbtree (cursor_tree, cursor_node);
10382
10383   start_cursor_tree = cursor_tree;
10384   start_cursor_node = cursor_node;
10385
10386   if (! search_first_focusable_path (tree_view, &cursor_path,
10387                                      (count != -1),
10388                                      &cursor_tree, &cursor_node))
10389     {
10390       /* It looks like we reached the end of the view without finding
10391        * a focusable row.  We will step backwards to find the last
10392        * focusable row.
10393        */
10394       cursor_tree = start_cursor_tree;
10395       cursor_node = start_cursor_node;
10396       cursor_path = _gtk_tree_path_new_from_rbtree (cursor_tree, cursor_node);
10397
10398       search_first_focusable_path (tree_view, &cursor_path,
10399                                    (count == -1),
10400                                    &cursor_tree, &cursor_node);
10401     }
10402
10403   if (!cursor_path)
10404     goto cleanup;
10405
10406   /* update y */
10407   y = _gtk_rbtree_node_find_offset (cursor_tree, cursor_node);
10408
10409   gtk_tree_view_real_set_cursor (tree_view, cursor_path, CLEAR_AND_SELECT);
10410
10411   y -= window_y;
10412   gtk_tree_view_scroll_to_point (tree_view, -1, y);
10413   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10414   _gtk_tree_view_queue_draw_node (tree_view, cursor_tree, cursor_node, NULL);
10415
10416   if (!gtk_tree_path_compare (old_cursor_path, cursor_path))
10417     gtk_widget_error_bell (GTK_WIDGET (tree_view));
10418
10419   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10420
10421 cleanup:
10422   gtk_tree_path_free (old_cursor_path);
10423   gtk_tree_path_free (cursor_path);
10424 }
10425
10426 static void
10427 gtk_tree_view_move_cursor_left_right (GtkTreeView *tree_view,
10428                                       gint         count)
10429 {
10430   GtkTreePath *cursor_path = NULL;
10431   GtkTreeViewColumn *column;
10432   GtkTreeIter iter;
10433   GList *list;
10434   gboolean found_column = FALSE;
10435   gboolean rtl;
10436   GtkDirectionType direction;
10437   GtkCellArea     *cell_area;
10438   GtkCellRenderer *last_focus_cell = NULL;
10439   GtkCellArea     *last_focus_area = NULL;
10440
10441   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
10442
10443   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10444     return;
10445
10446   if (tree_view->priv->cursor_node == NULL)
10447     return;
10448
10449   cursor_path = _gtk_tree_path_new_from_rbtree (tree_view->priv->cursor_tree,
10450                                                 tree_view->priv->cursor_node);
10451
10452   if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path) == FALSE)
10453     {
10454       gtk_tree_path_free (cursor_path);
10455       return;
10456     }
10457   gtk_tree_path_free (cursor_path);
10458
10459   list = rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns);
10460   if (tree_view->priv->focus_column)
10461     {
10462       /* Save the cell/area we are moving focus from, if moving the cursor
10463        * by one step hits the end we'll set focus back here */
10464       last_focus_area = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (tree_view->priv->focus_column));
10465       last_focus_cell = gtk_cell_area_get_focus_cell (last_focus_area);
10466
10467       for (; list; list = (rtl ? list->prev : list->next))
10468         {
10469           if (list->data == tree_view->priv->focus_column)
10470             break;
10471         }
10472     }
10473
10474   direction = count > 0 ? GTK_DIR_RIGHT : GTK_DIR_LEFT;
10475
10476   while (list)
10477     {
10478       column = list->data;
10479       if (gtk_tree_view_column_get_visible (column) == FALSE)
10480         goto loop_end;
10481
10482       gtk_tree_view_column_cell_set_cell_data (column,
10483                                                tree_view->priv->model,
10484                                                &iter,
10485                                                GTK_RBNODE_FLAG_SET (tree_view->priv->cursor_node, GTK_RBNODE_IS_PARENT),
10486                                                tree_view->priv->cursor_node->children ? TRUE : FALSE);
10487
10488       cell_area = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (column));
10489       if (gtk_cell_area_focus (cell_area, direction))
10490         {
10491           _gtk_tree_view_set_focus_column (tree_view, column);
10492           found_column = TRUE;
10493           break;
10494         }
10495
10496     loop_end:
10497       if (count == 1)
10498         list = rtl ? list->prev : list->next;
10499       else
10500         list = rtl ? list->next : list->prev;
10501     }
10502
10503   if (found_column)
10504     {
10505       if (!gtk_tree_view_has_can_focus_cell (tree_view))
10506         _gtk_tree_view_queue_draw_node (tree_view,
10507                                         tree_view->priv->cursor_tree,
10508                                         tree_view->priv->cursor_node,
10509                                         NULL);
10510       g_signal_emit (tree_view, tree_view_signals[CURSOR_CHANGED], 0);
10511       gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10512     }
10513   else
10514     {
10515       gtk_widget_error_bell (GTK_WIDGET (tree_view));
10516
10517       if (last_focus_area)
10518         gtk_cell_area_set_focus_cell (last_focus_area, last_focus_cell);
10519     }
10520
10521   gtk_tree_view_clamp_column_visible (tree_view,
10522                                       tree_view->priv->focus_column, TRUE);
10523 }
10524
10525 static void
10526 gtk_tree_view_move_cursor_start_end (GtkTreeView *tree_view,
10527                                      gint         count)
10528 {
10529   GtkRBTree *cursor_tree;
10530   GtkRBNode *cursor_node;
10531   GtkTreePath *path;
10532   GtkTreePath *old_path;
10533
10534   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10535     return;
10536
10537   g_return_if_fail (tree_view->priv->tree != NULL);
10538
10539   gtk_tree_view_get_cursor (tree_view, &old_path, NULL);
10540
10541   cursor_tree = tree_view->priv->tree;
10542
10543   if (count == -1)
10544     {
10545       cursor_node = _gtk_rbtree_first (cursor_tree);
10546
10547       /* Now go forward to find the first focusable row. */
10548       path = _gtk_tree_path_new_from_rbtree (cursor_tree, cursor_node);
10549       search_first_focusable_path (tree_view, &path,
10550                                    TRUE, &cursor_tree, &cursor_node);
10551     }
10552   else
10553     {
10554       cursor_node = cursor_tree->root;
10555
10556       do
10557         {
10558           while (cursor_node && !_gtk_rbtree_is_nil (cursor_node->right))
10559             cursor_node = cursor_node->right;
10560           if (cursor_node->children == NULL)
10561             break;
10562
10563           cursor_tree = cursor_node->children;
10564           cursor_node = cursor_tree->root;
10565         }
10566       while (1);
10567
10568       /* Now go backwards to find last focusable row. */
10569       path = _gtk_tree_path_new_from_rbtree (cursor_tree, cursor_node);
10570       search_first_focusable_path (tree_view, &path,
10571                                    FALSE, &cursor_tree, &cursor_node);
10572     }
10573
10574   if (!path)
10575     goto cleanup;
10576
10577   if (gtk_tree_path_compare (old_path, path))
10578     {
10579       gtk_tree_view_real_set_cursor (tree_view, path, CLEAR_AND_SELECT | CLAMP_NODE);
10580       gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10581     }
10582   else
10583     {
10584       gtk_widget_error_bell (GTK_WIDGET (tree_view));
10585     }
10586
10587 cleanup:
10588   gtk_tree_path_free (old_path);
10589   gtk_tree_path_free (path);
10590 }
10591
10592 static gboolean
10593 gtk_tree_view_real_select_all (GtkTreeView *tree_view)
10594 {
10595   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10596     return FALSE;
10597
10598   if (gtk_tree_selection_get_mode (tree_view->priv->selection) != GTK_SELECTION_MULTIPLE)
10599     return FALSE;
10600
10601   gtk_tree_selection_select_all (tree_view->priv->selection);
10602
10603   return TRUE;
10604 }
10605
10606 static gboolean
10607 gtk_tree_view_real_unselect_all (GtkTreeView *tree_view)
10608 {
10609   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10610     return FALSE;
10611
10612   if (gtk_tree_selection_get_mode (tree_view->priv->selection) != GTK_SELECTION_MULTIPLE)
10613     return FALSE;
10614
10615   gtk_tree_selection_unselect_all (tree_view->priv->selection);
10616
10617   return TRUE;
10618 }
10619
10620 static gboolean
10621 gtk_tree_view_real_select_cursor_row (GtkTreeView *tree_view,
10622                                       gboolean     start_editing)
10623 {
10624   GtkRBTree *new_tree = NULL;
10625   GtkRBNode *new_node = NULL;
10626   GtkRBTree *cursor_tree = NULL;
10627   GtkRBNode *cursor_node = NULL;
10628   GtkTreePath *cursor_path = NULL;
10629   GtkTreeSelectMode mode = 0;
10630
10631   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10632     return FALSE;
10633
10634   if (tree_view->priv->cursor_node == NULL)
10635     return FALSE;
10636
10637   cursor_path = _gtk_tree_path_new_from_rbtree (tree_view->priv->cursor_tree,
10638                                                 tree_view->priv->cursor_node);
10639
10640   _gtk_tree_view_find_node (tree_view, cursor_path,
10641                             &cursor_tree, &cursor_node);
10642
10643   if (cursor_tree == NULL)
10644     {
10645       gtk_tree_path_free (cursor_path);
10646       return FALSE;
10647     }
10648
10649   if (!tree_view->priv->extend_selection_pressed && start_editing &&
10650       tree_view->priv->focus_column)
10651     {
10652       if (gtk_tree_view_start_editing (tree_view, cursor_path, FALSE))
10653         {
10654           gtk_tree_path_free (cursor_path);
10655           return TRUE;
10656         }
10657     }
10658
10659   if (tree_view->priv->modify_selection_pressed)
10660     mode |= GTK_TREE_SELECT_MODE_TOGGLE;
10661   if (tree_view->priv->extend_selection_pressed)
10662     mode |= GTK_TREE_SELECT_MODE_EXTEND;
10663
10664   _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
10665                                             cursor_node,
10666                                             cursor_tree,
10667                                             cursor_path,
10668                                             mode,
10669                                             FALSE);
10670
10671   /* We bail out if the original (tree, node) don't exist anymore after
10672    * handling the selection-changed callback.  We do return TRUE because
10673    * the key press has been handled at this point.
10674    */
10675   _gtk_tree_view_find_node (tree_view, cursor_path, &new_tree, &new_node);
10676
10677   if (cursor_tree != new_tree || cursor_node != new_node)
10678     return FALSE;
10679
10680   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10681
10682   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10683   _gtk_tree_view_queue_draw_node (tree_view, cursor_tree, cursor_node, NULL);
10684
10685   if (!tree_view->priv->extend_selection_pressed)
10686     gtk_tree_view_row_activated (tree_view, cursor_path,
10687                                  tree_view->priv->focus_column);
10688     
10689   gtk_tree_path_free (cursor_path);
10690
10691   return TRUE;
10692 }
10693
10694 static gboolean
10695 gtk_tree_view_real_toggle_cursor_row (GtkTreeView *tree_view)
10696 {
10697   GtkRBTree *new_tree = NULL;
10698   GtkRBNode *new_node = NULL;
10699   GtkTreePath *cursor_path = NULL;
10700
10701   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10702     return FALSE;
10703
10704   if (tree_view->priv->cursor_node == NULL)
10705     return FALSE;
10706
10707   cursor_path = _gtk_tree_path_new_from_rbtree (tree_view->priv->cursor_tree,
10708                                                 tree_view->priv->cursor_node);
10709
10710   _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
10711                                             tree_view->priv->cursor_node,
10712                                             tree_view->priv->cursor_tree,
10713                                             cursor_path,
10714                                             GTK_TREE_SELECT_MODE_TOGGLE,
10715                                             FALSE);
10716
10717   /* We bail out if the original (tree, node) don't exist anymore after
10718    * handling the selection-changed callback.  We do return TRUE because
10719    * the key press has been handled at this point.
10720    */
10721   _gtk_tree_view_find_node (tree_view, cursor_path, &new_tree, &new_node);
10722
10723   if (tree_view->priv->cursor_node != new_node)
10724     return FALSE;
10725
10726   gtk_tree_view_clamp_node_visible (tree_view,
10727                                     tree_view->priv->cursor_tree,
10728                                     tree_view->priv->cursor_node);
10729
10730   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10731   gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10732   gtk_tree_path_free (cursor_path);
10733
10734   return TRUE;
10735 }
10736
10737 static gboolean
10738 gtk_tree_view_real_expand_collapse_cursor_row (GtkTreeView *tree_view,
10739                                                gboolean     logical,
10740                                                gboolean     expand,
10741                                                gboolean     open_all)
10742 {
10743   GtkTreePath *cursor_path = NULL;
10744
10745   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10746     return FALSE;
10747
10748   if (tree_view->priv->cursor_node == NULL)
10749     return FALSE;
10750
10751   cursor_path = _gtk_tree_path_new_from_rbtree (tree_view->priv->cursor_tree,
10752                                                 tree_view->priv->cursor_node);
10753
10754   /* Don't handle the event if we aren't an expander */
10755   if (!GTK_RBNODE_FLAG_SET (tree_view->priv->cursor_node, GTK_RBNODE_IS_PARENT))
10756     return FALSE;
10757
10758   if (!logical
10759       && gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL)
10760     expand = !expand;
10761
10762   if (expand)
10763     gtk_tree_view_real_expand_row (tree_view,
10764                                    cursor_path,
10765                                    tree_view->priv->cursor_tree,
10766                                    tree_view->priv->cursor_node,
10767                                    open_all,
10768                                    TRUE);
10769   else
10770     gtk_tree_view_real_collapse_row (tree_view,
10771                                      cursor_path,
10772                                      tree_view->priv->cursor_tree,
10773                                      tree_view->priv->cursor_node,
10774                                      TRUE);
10775
10776   gtk_tree_path_free (cursor_path);
10777
10778   return TRUE;
10779 }
10780
10781 static gboolean
10782 gtk_tree_view_real_select_cursor_parent (GtkTreeView *tree_view)
10783 {
10784   GtkTreePath *cursor_path = NULL;
10785   GdkModifierType state;
10786
10787   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10788     goto out;
10789
10790   if (tree_view->priv->cursor_node == NULL)
10791     goto out;
10792
10793   cursor_path = _gtk_tree_path_new_from_rbtree (tree_view->priv->cursor_tree,
10794                                                 tree_view->priv->cursor_node);
10795
10796   if (tree_view->priv->cursor_tree->parent_node)
10797     {
10798       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10799
10800       gtk_tree_path_up (cursor_path);
10801
10802       if (gtk_get_current_event_state (&state))
10803         {
10804           GdkModifierType modify_mod_mask;
10805
10806           modify_mod_mask =
10807             gtk_widget_get_modifier_mask (GTK_WIDGET (tree_view),
10808                                           GDK_MODIFIER_INTENT_MODIFY_SELECTION);
10809
10810           if ((state & modify_mod_mask) == modify_mod_mask)
10811             tree_view->priv->modify_selection_pressed = TRUE;
10812         }
10813
10814       gtk_tree_view_real_set_cursor (tree_view, cursor_path, CLEAR_AND_SELECT | CLAMP_NODE);
10815       gtk_tree_path_free (cursor_path);
10816
10817       gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10818
10819       tree_view->priv->modify_selection_pressed = FALSE;
10820
10821       return TRUE;
10822     }
10823
10824  out:
10825
10826   tree_view->priv->search_entry_avoid_unhandled_binding = TRUE;
10827   return FALSE;
10828 }
10829
10830 static gboolean
10831 gtk_tree_view_search_entry_flush_timeout (GtkTreeView *tree_view)
10832 {
10833   gtk_tree_view_search_dialog_hide (tree_view->priv->search_window, tree_view, NULL);
10834   tree_view->priv->typeselect_flush_timeout = 0;
10835
10836   return FALSE;
10837 }
10838
10839 /* Cut and paste from gtkwindow.c */
10840 static void
10841 send_focus_change (GtkWidget *widget,
10842                    GdkDevice *device,
10843                    gboolean   in)
10844 {
10845   GdkDeviceManager *device_manager;
10846   GList *devices, *d;
10847
10848   device_manager = gdk_display_get_device_manager (gtk_widget_get_display (widget));
10849   devices = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER);
10850   devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_SLAVE));
10851   devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_FLOATING));
10852
10853   for (d = devices; d; d = d->next)
10854     {
10855       GdkDevice *dev = d->data;
10856       GdkEvent *fevent;
10857       GdkWindow *window;
10858
10859       if (gdk_device_get_source (dev) != GDK_SOURCE_KEYBOARD)
10860         continue;
10861
10862       window = gtk_widget_get_window (widget);
10863
10864       /* Skip non-master keyboards that haven't
10865        * selected for events from this window
10866        */
10867       if (gdk_device_get_device_type (dev) != GDK_DEVICE_TYPE_MASTER &&
10868           !gdk_window_get_device_events (window, dev))
10869         continue;
10870
10871       fevent = gdk_event_new (GDK_FOCUS_CHANGE);
10872
10873       fevent->focus_change.type = GDK_FOCUS_CHANGE;
10874       fevent->focus_change.window = g_object_ref (window);
10875       fevent->focus_change.in = in;
10876       gdk_event_set_device (fevent, device);
10877
10878       gtk_widget_send_focus_change (widget, fevent);
10879
10880       gdk_event_free (fevent);
10881     }
10882
10883   g_list_free (devices);
10884 }
10885
10886 static void
10887 gtk_tree_view_ensure_interactive_directory (GtkTreeView *tree_view)
10888 {
10889   GtkWidget *frame, *vbox, *toplevel;
10890   GdkScreen *screen;
10891
10892   if (tree_view->priv->search_custom_entry_set)
10893     return;
10894
10895   toplevel = gtk_widget_get_toplevel (GTK_WIDGET (tree_view));
10896   screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
10897
10898    if (tree_view->priv->search_window != NULL)
10899      {
10900        if (gtk_window_has_group (GTK_WINDOW (toplevel)))
10901          gtk_window_group_add_window (gtk_window_get_group (GTK_WINDOW (toplevel)),
10902                                       GTK_WINDOW (tree_view->priv->search_window));
10903        else if (gtk_window_has_group (GTK_WINDOW (tree_view->priv->search_window)))
10904          gtk_window_group_remove_window (gtk_window_get_group (GTK_WINDOW (tree_view->priv->search_window)),
10905                                          GTK_WINDOW (tree_view->priv->search_window));
10906
10907        gtk_window_set_screen (GTK_WINDOW (tree_view->priv->search_window), screen);
10908
10909        return;
10910      }
10911    
10912   tree_view->priv->search_window = gtk_window_new (GTK_WINDOW_POPUP);
10913   gtk_window_set_screen (GTK_WINDOW (tree_view->priv->search_window), screen);
10914
10915   if (gtk_window_has_group (GTK_WINDOW (toplevel)))
10916     gtk_window_group_add_window (gtk_window_get_group (GTK_WINDOW (toplevel)),
10917                                  GTK_WINDOW (tree_view->priv->search_window));
10918
10919   gtk_window_set_type_hint (GTK_WINDOW (tree_view->priv->search_window),
10920                             GDK_WINDOW_TYPE_HINT_UTILITY);
10921   gtk_window_set_modal (GTK_WINDOW (tree_view->priv->search_window), TRUE);
10922   g_signal_connect (tree_view->priv->search_window, "delete-event",
10923                     G_CALLBACK (gtk_tree_view_search_delete_event),
10924                     tree_view);
10925   g_signal_connect (tree_view->priv->search_window, "key-press-event",
10926                     G_CALLBACK (gtk_tree_view_search_key_press_event),
10927                     tree_view);
10928   g_signal_connect (tree_view->priv->search_window, "button-press-event",
10929                     G_CALLBACK (gtk_tree_view_search_button_press_event),
10930                     tree_view);
10931   g_signal_connect (tree_view->priv->search_window, "scroll-event",
10932                     G_CALLBACK (gtk_tree_view_search_scroll_event),
10933                     tree_view);
10934
10935   frame = gtk_frame_new (NULL);
10936   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
10937   gtk_widget_show (frame);
10938   gtk_container_add (GTK_CONTAINER (tree_view->priv->search_window), frame);
10939
10940   vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
10941   gtk_widget_show (vbox);
10942   gtk_container_add (GTK_CONTAINER (frame), vbox);
10943   gtk_container_set_border_width (GTK_CONTAINER (vbox), 3);
10944
10945   /* add entry */
10946   tree_view->priv->search_entry = gtk_entry_new ();
10947   gtk_widget_show (tree_view->priv->search_entry);
10948   g_signal_connect (tree_view->priv->search_entry, "populate-popup",
10949                     G_CALLBACK (gtk_tree_view_search_disable_popdown),
10950                     tree_view);
10951   g_signal_connect (tree_view->priv->search_entry,
10952                     "activate", G_CALLBACK (gtk_tree_view_search_activate),
10953                     tree_view);
10954
10955   g_signal_connect (_gtk_entry_get_im_context (GTK_ENTRY (tree_view->priv->search_entry)),
10956                     "preedit-changed",
10957                     G_CALLBACK (gtk_tree_view_search_preedit_changed),
10958                     tree_view);
10959
10960   gtk_container_add (GTK_CONTAINER (vbox),
10961                      tree_view->priv->search_entry);
10962
10963   gtk_widget_realize (tree_view->priv->search_entry);
10964 }
10965
10966 /* Pops up the interactive search entry.  If keybinding is TRUE then the user
10967  * started this by typing the start_interactive_search keybinding.  Otherwise, it came from 
10968  */
10969 static gboolean
10970 gtk_tree_view_real_start_interactive_search (GtkTreeView *tree_view,
10971                                              GdkDevice   *device,
10972                                              gboolean     keybinding)
10973 {
10974   /* We only start interactive search if we have focus or the columns
10975    * have focus.  If one of our children have focus, we don't want to
10976    * start the search.
10977    */
10978   GList *list;
10979   gboolean found_focus = FALSE;
10980   GtkWidgetClass *entry_parent_class;
10981   
10982   if (!tree_view->priv->enable_search && !keybinding)
10983     return FALSE;
10984
10985   if (tree_view->priv->search_custom_entry_set)
10986     return FALSE;
10987
10988   if (tree_view->priv->search_window != NULL &&
10989       gtk_widget_get_visible (tree_view->priv->search_window))
10990     return TRUE;
10991
10992   for (list = tree_view->priv->columns; list; list = list->next)
10993     {
10994       GtkTreeViewColumn *column;
10995       GtkWidget         *button;
10996
10997       column = list->data;
10998       if (!gtk_tree_view_column_get_visible (column))
10999         continue;
11000
11001       button = gtk_tree_view_column_get_button (column);
11002       if (gtk_widget_has_focus (button))
11003         {
11004           found_focus = TRUE;
11005           break;
11006         }
11007     }
11008   
11009   if (gtk_widget_has_focus (GTK_WIDGET (tree_view)))
11010     found_focus = TRUE;
11011
11012   if (!found_focus)
11013     return FALSE;
11014
11015   if (tree_view->priv->search_column < 0)
11016     return FALSE;
11017
11018   gtk_tree_view_ensure_interactive_directory (tree_view);
11019
11020   if (keybinding)
11021     gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
11022
11023   /* done, show it */
11024   tree_view->priv->search_position_func (tree_view, tree_view->priv->search_window, tree_view->priv->search_position_user_data);
11025   gtk_widget_show (tree_view->priv->search_window);
11026   if (tree_view->priv->search_entry_changed_id == 0)
11027     {
11028       tree_view->priv->search_entry_changed_id =
11029         g_signal_connect (tree_view->priv->search_entry, "changed",
11030                           G_CALLBACK (gtk_tree_view_search_init),
11031                           tree_view);
11032     }
11033
11034   tree_view->priv->typeselect_flush_timeout =
11035     gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
11036                    (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
11037                    tree_view);
11038
11039   /* Grab focus will select all the text.  We don't want that to happen, so we
11040    * call the parent instance and bypass the selection change.  This is probably
11041    * really non-kosher. */
11042   entry_parent_class = g_type_class_peek_parent (GTK_ENTRY_GET_CLASS (tree_view->priv->search_entry));
11043   (entry_parent_class->grab_focus) (tree_view->priv->search_entry);
11044
11045   /* send focus-in event */
11046   send_focus_change (tree_view->priv->search_entry, device, TRUE);
11047
11048   /* search first matching iter */
11049   gtk_tree_view_search_init (tree_view->priv->search_entry, tree_view);
11050
11051   return TRUE;
11052 }
11053
11054 static gboolean
11055 gtk_tree_view_start_interactive_search (GtkTreeView *tree_view)
11056 {
11057   return gtk_tree_view_real_start_interactive_search (tree_view,
11058                                                       gtk_get_current_event_device (),
11059                                                       TRUE);
11060 }
11061
11062 /* this function returns the new width of the column being resized given
11063  * the column and x position of the cursor; the x cursor position is passed
11064  * in as a pointer and automagicly corrected if it's beyond min/max limits
11065  */
11066 static gint
11067 gtk_tree_view_new_column_width (GtkTreeView *tree_view,
11068                                 gint       i,
11069                                 gint      *x)
11070 {
11071   GtkAllocation allocation;
11072   GtkTreeViewColumn *column;
11073   GtkRequisition button_req;
11074   gint max_width, min_width;
11075   gint width;
11076   gboolean rtl;
11077
11078   /* first translate the x position from widget->window
11079    * to clist->clist_window
11080    */
11081   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
11082   column = g_list_nth (tree_view->priv->columns, i)->data;
11083   gtk_widget_get_allocation (gtk_tree_view_column_get_button (column), &allocation);
11084   width = rtl ? (allocation.x + allocation.width - *x) : (*x - allocation.x);
11085
11086   /* Clamp down the value */
11087   min_width = gtk_tree_view_column_get_min_width (column);
11088   if (min_width == -1)
11089     {
11090       gtk_widget_get_preferred_size (gtk_tree_view_column_get_button (column), &button_req, NULL);
11091       width = MAX (button_req.width, width);
11092     }
11093   else
11094     width = MAX (min_width, width);
11095
11096   max_width = gtk_tree_view_column_get_max_width (column);
11097   if (max_width != -1)
11098     width = MIN (width, max_width);
11099
11100   *x = rtl ? (allocation.x + allocation.width - width) : (allocation.x + width);
11101
11102   return width;
11103 }
11104
11105
11106 /* FIXME this adjust_allocation is a big cut-and-paste from
11107  * GtkCList, needs to be some "official" way to do this
11108  * factored out.
11109  */
11110 typedef struct
11111 {
11112   GdkWindow *window;
11113   int dx;
11114   int dy;
11115 } ScrollData;
11116
11117 /* The window to which widget->window is relative */
11118 #define ALLOCATION_WINDOW(widget)               \
11119    (!gtk_widget_get_has_window (widget) ?                   \
11120     gtk_widget_get_window (widget) :                        \
11121     gdk_window_get_parent (gtk_widget_get_window (widget)))
11122
11123 static void
11124 adjust_allocation_recurse (GtkWidget *widget,
11125                            gpointer   data)
11126 {
11127   GtkAllocation allocation;
11128   ScrollData *scroll_data = data;
11129
11130   /* Need to really size allocate instead of just poking
11131    * into widget->allocation if the widget is not realized.
11132    * FIXME someone figure out why this was.
11133    */
11134   gtk_widget_get_allocation (widget, &allocation);
11135   if (!gtk_widget_get_realized (widget))
11136     {
11137       if (gtk_widget_get_visible (widget))
11138         {
11139           GdkRectangle tmp_rectangle = allocation;
11140           tmp_rectangle.x += scroll_data->dx;
11141           tmp_rectangle.y += scroll_data->dy;
11142           
11143           gtk_widget_size_allocate (widget, &tmp_rectangle);
11144         }
11145     }
11146   else
11147     {
11148       if (ALLOCATION_WINDOW (widget) == scroll_data->window)
11149         {
11150           allocation.x += scroll_data->dx;
11151           allocation.y += scroll_data->dy;
11152           gtk_widget_set_allocation (widget, &allocation);
11153
11154           if (GTK_IS_CONTAINER (widget))
11155             gtk_container_forall (GTK_CONTAINER (widget),
11156                                   adjust_allocation_recurse,
11157                                   data);
11158         }
11159     }
11160 }
11161
11162 static void
11163 adjust_allocation (GtkWidget *widget,
11164                    int        dx,
11165                    int        dy)
11166 {
11167   ScrollData scroll_data;
11168
11169   if (gtk_widget_get_realized (widget))
11170     scroll_data.window = ALLOCATION_WINDOW (widget);
11171   else
11172     scroll_data.window = NULL;
11173     
11174   scroll_data.dx = dx;
11175   scroll_data.dy = dy;
11176   
11177   adjust_allocation_recurse (widget, &scroll_data);
11178 }
11179
11180 /* Callbacks */
11181 static void
11182 gtk_tree_view_adjustment_changed (GtkAdjustment *adjustment,
11183                                   GtkTreeView   *tree_view)
11184 {
11185   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11186     {
11187       gint dy;
11188         
11189       gdk_window_move (tree_view->priv->bin_window,
11190                        - gtk_adjustment_get_value (tree_view->priv->hadjustment),
11191                        gtk_tree_view_get_effective_header_height (tree_view));
11192       gdk_window_move (tree_view->priv->header_window,
11193                        - gtk_adjustment_get_value (tree_view->priv->hadjustment),
11194                        0);
11195       dy = tree_view->priv->dy - (int) gtk_adjustment_get_value (tree_view->priv->vadjustment);
11196       if (dy)
11197         {
11198           update_prelight (tree_view,
11199                            tree_view->priv->event_last_x,
11200                            tree_view->priv->event_last_y - dy);
11201
11202           if (tree_view->priv->edited_column)
11203             {
11204               GList *list;
11205               GtkTreeViewChild *child = NULL;
11206               GtkCellEditable *edit_widget;
11207               GtkCellArea *area;
11208
11209               area        = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (tree_view->priv->edited_column));
11210               edit_widget = gtk_cell_area_get_edit_widget (area);
11211               if (GTK_IS_WIDGET (edit_widget))
11212                 {
11213                   adjust_allocation (GTK_WIDGET (edit_widget), 0, dy);
11214
11215                   for (list = tree_view->priv->children; list; list = list->next)
11216                     {
11217                       child = (GtkTreeViewChild *)list->data;
11218                       if (child->widget == GTK_WIDGET (edit_widget))
11219                         {
11220                           child->y += dy;
11221                           break;
11222                         }
11223                     }
11224                 }
11225             }
11226         }
11227       gdk_window_scroll (tree_view->priv->bin_window, 0, dy);
11228
11229       if (tree_view->priv->dy != (int) gtk_adjustment_get_value (tree_view->priv->vadjustment))
11230         {
11231           /* update our dy and top_row */
11232           tree_view->priv->dy = (int) gtk_adjustment_get_value (tree_view->priv->vadjustment);
11233
11234           if (!tree_view->priv->in_top_row_to_dy)
11235             gtk_tree_view_dy_to_top_row (tree_view);
11236         }
11237     }
11238 }
11239
11240 \f
11241
11242 /* Public methods
11243  */
11244
11245 /**
11246  * gtk_tree_view_new:
11247  *
11248  * Creates a new #GtkTreeView widget.
11249  *
11250  * Return value: A newly created #GtkTreeView widget.
11251  **/
11252 GtkWidget *
11253 gtk_tree_view_new (void)
11254 {
11255   return g_object_new (GTK_TYPE_TREE_VIEW, NULL);
11256 }
11257
11258 /**
11259  * gtk_tree_view_new_with_model:
11260  * @model: the model.
11261  *
11262  * Creates a new #GtkTreeView widget with the model initialized to @model.
11263  *
11264  * Return value: A newly created #GtkTreeView widget.
11265  **/
11266 GtkWidget *
11267 gtk_tree_view_new_with_model (GtkTreeModel *model)
11268 {
11269   return g_object_new (GTK_TYPE_TREE_VIEW, "model", model, NULL);
11270 }
11271
11272 /* Public Accessors
11273  */
11274
11275 /**
11276  * gtk_tree_view_get_model:
11277  * @tree_view: a #GtkTreeView
11278  *
11279  * Returns the model the #GtkTreeView is based on.  Returns %NULL if the
11280  * model is unset.
11281  *
11282  * Return value: (transfer none): A #GtkTreeModel, or %NULL if none is currently being used.
11283  **/
11284 GtkTreeModel *
11285 gtk_tree_view_get_model (GtkTreeView *tree_view)
11286 {
11287   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11288
11289   return tree_view->priv->model;
11290 }
11291
11292 /**
11293  * gtk_tree_view_set_model:
11294  * @tree_view: A #GtkTreeView.
11295  * @model: (allow-none): The model.
11296  *
11297  * Sets the model for a #GtkTreeView.  If the @tree_view already has a model
11298  * set, it will remove it before setting the new model.  If @model is %NULL,
11299  * then it will unset the old model.
11300  **/
11301 void
11302 gtk_tree_view_set_model (GtkTreeView  *tree_view,
11303                          GtkTreeModel *model)
11304 {
11305   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11306   g_return_if_fail (model == NULL || GTK_IS_TREE_MODEL (model));
11307
11308   if (model == tree_view->priv->model)
11309     return;
11310
11311   if (tree_view->priv->scroll_to_path)
11312     {
11313       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
11314       tree_view->priv->scroll_to_path = NULL;
11315     }
11316
11317   if (tree_view->priv->rubber_band_status)
11318     gtk_tree_view_stop_rubber_band (tree_view);
11319
11320   if (tree_view->priv->model)
11321     {
11322       GList *tmplist = tree_view->priv->columns;
11323
11324       gtk_tree_view_unref_and_check_selection_tree (tree_view, tree_view->priv->tree);
11325       gtk_tree_view_stop_editing (tree_view, TRUE);
11326
11327       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
11328                                             gtk_tree_view_row_changed,
11329                                             tree_view);
11330       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
11331                                             gtk_tree_view_row_inserted,
11332                                             tree_view);
11333       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
11334                                             gtk_tree_view_row_has_child_toggled,
11335                                             tree_view);
11336       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
11337                                             gtk_tree_view_row_deleted,
11338                                             tree_view);
11339       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
11340                                             gtk_tree_view_rows_reordered,
11341                                             tree_view);
11342
11343       for (; tmplist; tmplist = tmplist->next)
11344         _gtk_tree_view_column_unset_model (tmplist->data,
11345                                            tree_view->priv->model);
11346
11347       if (tree_view->priv->tree)
11348         gtk_tree_view_free_rbtree (tree_view);
11349
11350       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
11351       tree_view->priv->drag_dest_row = NULL;
11352       gtk_tree_row_reference_free (tree_view->priv->anchor);
11353       tree_view->priv->anchor = NULL;
11354       gtk_tree_row_reference_free (tree_view->priv->top_row);
11355       tree_view->priv->top_row = NULL;
11356       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
11357       tree_view->priv->scroll_to_path = NULL;
11358
11359       tree_view->priv->scroll_to_column = NULL;
11360
11361       g_object_unref (tree_view->priv->model);
11362
11363       tree_view->priv->search_column = -1;
11364       tree_view->priv->fixed_height_check = 0;
11365       tree_view->priv->fixed_height = -1;
11366       tree_view->priv->dy = tree_view->priv->top_row_dy = 0;
11367       tree_view->priv->last_button_x = -1;
11368       tree_view->priv->last_button_y = -1;
11369     }
11370
11371   tree_view->priv->model = model;
11372
11373   if (tree_view->priv->model)
11374     {
11375       gint i;
11376       GtkTreePath *path;
11377       GtkTreeIter iter;
11378       GtkTreeModelFlags flags;
11379
11380       if (tree_view->priv->search_column == -1)
11381         {
11382           for (i = 0; i < gtk_tree_model_get_n_columns (model); i++)
11383             {
11384               GType type = gtk_tree_model_get_column_type (model, i);
11385
11386               if (g_value_type_transformable (type, G_TYPE_STRING))
11387                 {
11388                   tree_view->priv->search_column = i;
11389                   break;
11390                 }
11391             }
11392         }
11393
11394       g_object_ref (tree_view->priv->model);
11395       g_signal_connect (tree_view->priv->model,
11396                         "row-changed",
11397                         G_CALLBACK (gtk_tree_view_row_changed),
11398                         tree_view);
11399       g_signal_connect (tree_view->priv->model,
11400                         "row-inserted",
11401                         G_CALLBACK (gtk_tree_view_row_inserted),
11402                         tree_view);
11403       g_signal_connect (tree_view->priv->model,
11404                         "row-has-child-toggled",
11405                         G_CALLBACK (gtk_tree_view_row_has_child_toggled),
11406                         tree_view);
11407       g_signal_connect (tree_view->priv->model,
11408                         "row-deleted",
11409                         G_CALLBACK (gtk_tree_view_row_deleted),
11410                         tree_view);
11411       g_signal_connect (tree_view->priv->model,
11412                         "rows-reordered",
11413                         G_CALLBACK (gtk_tree_view_rows_reordered),
11414                         tree_view);
11415
11416       flags = gtk_tree_model_get_flags (tree_view->priv->model);
11417       if ((flags & GTK_TREE_MODEL_LIST_ONLY) == GTK_TREE_MODEL_LIST_ONLY)
11418         tree_view->priv->is_list = TRUE;
11419       else
11420         tree_view->priv->is_list = FALSE;
11421
11422       path = gtk_tree_path_new_first ();
11423       if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, path))
11424         {
11425           tree_view->priv->tree = _gtk_rbtree_new ();
11426           gtk_tree_view_build_tree (tree_view, tree_view->priv->tree, &iter, 1, FALSE);
11427           _gtk_tree_view_accessible_add (tree_view, tree_view->priv->tree, NULL);
11428         }
11429       gtk_tree_path_free (path);
11430
11431       /*  FIXME: do I need to do this? gtk_tree_view_create_buttons (tree_view); */
11432       install_presize_handler (tree_view);
11433     }
11434
11435   gtk_tree_view_real_set_cursor (tree_view, NULL, CURSOR_INVALID);
11436
11437   g_object_notify (G_OBJECT (tree_view), "model");
11438
11439   if (tree_view->priv->selection)
11440   _gtk_tree_selection_emit_changed (tree_view->priv->selection);
11441
11442   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11443     gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11444 }
11445
11446 /**
11447  * gtk_tree_view_get_selection:
11448  * @tree_view: A #GtkTreeView.
11449  *
11450  * Gets the #GtkTreeSelection associated with @tree_view.
11451  *
11452  * Return value: (transfer none): A #GtkTreeSelection object.
11453  **/
11454 GtkTreeSelection *
11455 gtk_tree_view_get_selection (GtkTreeView *tree_view)
11456 {
11457   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11458
11459   return tree_view->priv->selection;
11460 }
11461
11462 /**
11463  * gtk_tree_view_get_hadjustment:
11464  * @tree_view: A #GtkTreeView
11465  *
11466  * Gets the #GtkAdjustment currently being used for the horizontal aspect.
11467  *
11468  * Return value: (transfer none): A #GtkAdjustment object, or %NULL
11469  *     if none is currently being used.
11470  *
11471  * Deprecated: 3.0: Use gtk_scrollable_get_hadjustment()
11472  **/
11473 GtkAdjustment *
11474 gtk_tree_view_get_hadjustment (GtkTreeView *tree_view)
11475 {
11476   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11477
11478   return gtk_tree_view_do_get_hadjustment (tree_view);
11479 }
11480
11481 static GtkAdjustment *
11482 gtk_tree_view_do_get_hadjustment (GtkTreeView *tree_view)
11483 {
11484   return tree_view->priv->hadjustment;
11485 }
11486
11487 /**
11488  * gtk_tree_view_set_hadjustment:
11489  * @tree_view: A #GtkTreeView
11490  * @adjustment: (allow-none): The #GtkAdjustment to set, or %NULL
11491  *
11492  * Sets the #GtkAdjustment for the current horizontal aspect.
11493  *
11494  * Deprecated: 3.0: Use gtk_scrollable_set_hadjustment()
11495  **/
11496 void
11497 gtk_tree_view_set_hadjustment (GtkTreeView   *tree_view,
11498                                GtkAdjustment *adjustment)
11499 {
11500   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11501   g_return_if_fail (adjustment == NULL || GTK_IS_ADJUSTMENT (adjustment));
11502
11503   gtk_tree_view_do_set_hadjustment (tree_view, adjustment);
11504 }
11505
11506 static void
11507 gtk_tree_view_do_set_hadjustment (GtkTreeView   *tree_view,
11508                                   GtkAdjustment *adjustment)
11509 {
11510   GtkTreeViewPrivate *priv = tree_view->priv;
11511
11512   if (adjustment && priv->hadjustment == adjustment)
11513     return;
11514
11515   if (priv->hadjustment != NULL)
11516     {
11517       g_signal_handlers_disconnect_by_func (priv->hadjustment,
11518                                             gtk_tree_view_adjustment_changed,
11519                                             tree_view);
11520       g_object_unref (priv->hadjustment);
11521     }
11522
11523   if (adjustment == NULL)
11524     adjustment = gtk_adjustment_new (0.0, 0.0, 0.0,
11525                                      0.0, 0.0, 0.0);
11526
11527   g_signal_connect (adjustment, "value-changed",
11528                     G_CALLBACK (gtk_tree_view_adjustment_changed), tree_view);
11529   priv->hadjustment = g_object_ref_sink (adjustment);
11530   /* FIXME: Adjustment should probably be populated here with fresh values, but
11531    * internal details are too complicated for me to decipher right now.
11532    */
11533   gtk_tree_view_adjustment_changed (NULL, tree_view);
11534
11535   g_object_notify (G_OBJECT (tree_view), "hadjustment");
11536 }
11537
11538 /**
11539  * gtk_tree_view_get_vadjustment:
11540  * @tree_view: A #GtkTreeView
11541  *
11542  * Gets the #GtkAdjustment currently being used for the vertical aspect.
11543  *
11544  * Return value: (transfer none): A #GtkAdjustment object, or %NULL
11545  *     if none is currently being used.
11546  *
11547  * Deprecated: 3.0: Use gtk_scrollable_get_vadjustment()
11548  **/
11549 GtkAdjustment *
11550 gtk_tree_view_get_vadjustment (GtkTreeView *tree_view)
11551 {
11552   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11553
11554   return gtk_tree_view_do_get_vadjustment (tree_view);
11555 }
11556
11557 static GtkAdjustment *
11558 gtk_tree_view_do_get_vadjustment (GtkTreeView *tree_view)
11559 {
11560   return tree_view->priv->vadjustment;
11561 }
11562
11563 /**
11564  * gtk_tree_view_set_vadjustment:
11565  * @tree_view: A #GtkTreeView
11566  * @adjustment: (allow-none): The #GtkAdjustment to set, or %NULL
11567  *
11568  * Sets the #GtkAdjustment for the current vertical aspect.
11569  *
11570  * Deprecated: 3.0: Use gtk_scrollable_set_vadjustment()
11571  **/
11572 void
11573 gtk_tree_view_set_vadjustment (GtkTreeView   *tree_view,
11574                                GtkAdjustment *adjustment)
11575 {
11576   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11577   g_return_if_fail (adjustment == NULL || GTK_IS_ADJUSTMENT (adjustment));
11578
11579   gtk_tree_view_do_set_vadjustment (tree_view, adjustment);
11580 }
11581
11582 static void
11583 gtk_tree_view_do_set_vadjustment (GtkTreeView   *tree_view,
11584                                   GtkAdjustment *adjustment)
11585 {
11586   GtkTreeViewPrivate *priv = tree_view->priv;
11587
11588   if (adjustment && priv->vadjustment == adjustment)
11589     return;
11590
11591   if (priv->vadjustment != NULL)
11592     {
11593       g_signal_handlers_disconnect_by_func (priv->vadjustment,
11594                                             gtk_tree_view_adjustment_changed,
11595                                             tree_view);
11596       g_object_unref (priv->vadjustment);
11597     }
11598
11599   if (adjustment == NULL)
11600     adjustment = gtk_adjustment_new (0.0, 0.0, 0.0,
11601                                      0.0, 0.0, 0.0);
11602
11603   g_signal_connect (adjustment, "value-changed",
11604                     G_CALLBACK (gtk_tree_view_adjustment_changed), tree_view);
11605   priv->vadjustment = g_object_ref_sink (adjustment);
11606   /* FIXME: Adjustment should probably be populated here with fresh values, but
11607    * internal details are too complicated for me to decipher right now.
11608    */
11609   gtk_tree_view_adjustment_changed (NULL, tree_view);
11610   g_object_notify (G_OBJECT (tree_view), "vadjustment");
11611 }
11612
11613 /* Column and header operations */
11614
11615 /**
11616  * gtk_tree_view_get_headers_visible:
11617  * @tree_view: A #GtkTreeView.
11618  *
11619  * Returns %TRUE if the headers on the @tree_view are visible.
11620  *
11621  * Return value: Whether the headers are visible or not.
11622  **/
11623 gboolean
11624 gtk_tree_view_get_headers_visible (GtkTreeView *tree_view)
11625 {
11626   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
11627
11628   return tree_view->priv->headers_visible;
11629 }
11630
11631 /**
11632  * gtk_tree_view_set_headers_visible:
11633  * @tree_view: A #GtkTreeView.
11634  * @headers_visible: %TRUE if the headers are visible
11635  *
11636  * Sets the visibility state of the headers.
11637  **/
11638 void
11639 gtk_tree_view_set_headers_visible (GtkTreeView *tree_view,
11640                                    gboolean     headers_visible)
11641 {
11642   gint x, y;
11643   GList *list;
11644   GtkTreeViewColumn *column;
11645   GtkAllocation allocation;
11646   GtkWidget *button;
11647
11648   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11649
11650   headers_visible = !! headers_visible;
11651
11652   if (tree_view->priv->headers_visible == headers_visible)
11653     return;
11654
11655   tree_view->priv->headers_visible = headers_visible == TRUE;
11656
11657   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11658     {
11659       gdk_window_get_position (tree_view->priv->bin_window, &x, &y);
11660       if (headers_visible)
11661         {
11662           gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
11663           gdk_window_move_resize (tree_view->priv->bin_window,
11664                                   x, y  + gtk_tree_view_get_effective_header_height (tree_view),
11665                                   tree_view->priv->width, allocation.height -  + gtk_tree_view_get_effective_header_height (tree_view));
11666
11667           if (gtk_widget_get_mapped (GTK_WIDGET (tree_view)))
11668             gtk_tree_view_map_buttons (tree_view);
11669         }
11670       else
11671         {
11672           gdk_window_move_resize (tree_view->priv->bin_window, x, y, tree_view->priv->width, tree_view->priv->height);
11673
11674           for (list = tree_view->priv->columns; list; list = list->next)
11675             {
11676               column = list->data;
11677               button = gtk_tree_view_column_get_button (column);
11678
11679               gtk_widget_hide (button);
11680               gtk_widget_unmap (button);
11681             }
11682           gdk_window_hide (tree_view->priv->header_window);
11683         }
11684     }
11685
11686   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
11687   gtk_adjustment_configure (tree_view->priv->vadjustment,
11688                             gtk_adjustment_get_value (tree_view->priv->vadjustment),
11689                             0,
11690                             tree_view->priv->height,
11691                             gtk_adjustment_get_step_increment (tree_view->priv->vadjustment),
11692                             (allocation.height - gtk_tree_view_get_effective_header_height (tree_view)) / 2,
11693                             allocation.height - gtk_tree_view_get_effective_header_height (tree_view));
11694
11695   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11696
11697   g_object_notify (G_OBJECT (tree_view), "headers-visible");
11698 }
11699
11700 /**
11701  * gtk_tree_view_columns_autosize:
11702  * @tree_view: A #GtkTreeView.
11703  *
11704  * Resizes all columns to their optimal width. Only works after the
11705  * treeview has been realized.
11706  **/
11707 void
11708 gtk_tree_view_columns_autosize (GtkTreeView *tree_view)
11709 {
11710   gboolean dirty = FALSE;
11711   GList *list;
11712   GtkTreeViewColumn *column;
11713
11714   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11715
11716   for (list = tree_view->priv->columns; list; list = list->next)
11717     {
11718       column = list->data;
11719       if (gtk_tree_view_column_get_sizing (column) == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
11720         continue;
11721       _gtk_tree_view_column_cell_set_dirty (column, TRUE);
11722       dirty = TRUE;
11723     }
11724
11725   if (dirty)
11726     gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11727 }
11728
11729 /**
11730  * gtk_tree_view_set_headers_clickable:
11731  * @tree_view: A #GtkTreeView.
11732  * @setting: %TRUE if the columns are clickable.
11733  *
11734  * Allow the column title buttons to be clicked.
11735  **/
11736 void
11737 gtk_tree_view_set_headers_clickable (GtkTreeView *tree_view,
11738                                      gboolean   setting)
11739 {
11740   GList *list;
11741
11742   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11743
11744   for (list = tree_view->priv->columns; list; list = list->next)
11745     gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (list->data), setting);
11746
11747   g_object_notify (G_OBJECT (tree_view), "headers-clickable");
11748 }
11749
11750
11751 /**
11752  * gtk_tree_view_get_headers_clickable:
11753  * @tree_view: A #GtkTreeView.
11754  *
11755  * Returns whether all header columns are clickable.
11756  *
11757  * Return value: %TRUE if all header columns are clickable, otherwise %FALSE
11758  *
11759  * Since: 2.10
11760  **/
11761 gboolean 
11762 gtk_tree_view_get_headers_clickable (GtkTreeView *tree_view)
11763 {
11764   GList *list;
11765   
11766   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
11767
11768   for (list = tree_view->priv->columns; list; list = list->next)
11769     if (!gtk_tree_view_column_get_clickable (GTK_TREE_VIEW_COLUMN (list->data)))
11770       return FALSE;
11771
11772   return TRUE;
11773 }
11774
11775 /**
11776  * gtk_tree_view_set_rules_hint:
11777  * @tree_view: a #GtkTreeView
11778  * @setting: %TRUE if the tree requires reading across rows
11779  *
11780  * This function tells GTK+ that the user interface for your
11781  * application requires users to read across tree rows and associate
11782  * cells with one another. By default, GTK+ will then render the tree
11783  * with alternating row colors. Do <emphasis>not</emphasis> use it
11784  * just because you prefer the appearance of the ruled tree; that's a
11785  * question for the theme. Some themes will draw tree rows in
11786  * alternating colors even when rules are turned off, and users who
11787  * prefer that appearance all the time can choose those themes. You
11788  * should call this function only as a <emphasis>semantic</emphasis>
11789  * hint to the theme engine that your tree makes alternating colors
11790  * useful from a functional standpoint (since it has lots of columns,
11791  * generally).
11792  *
11793  **/
11794 void
11795 gtk_tree_view_set_rules_hint (GtkTreeView  *tree_view,
11796                               gboolean      setting)
11797 {
11798   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11799
11800   setting = setting != FALSE;
11801
11802   if (tree_view->priv->has_rules != setting)
11803     {
11804       tree_view->priv->has_rules = setting;
11805       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
11806     }
11807
11808   g_object_notify (G_OBJECT (tree_view), "rules-hint");
11809 }
11810
11811 /**
11812  * gtk_tree_view_get_rules_hint:
11813  * @tree_view: a #GtkTreeView
11814  *
11815  * Gets the setting set by gtk_tree_view_set_rules_hint().
11816  *
11817  * Return value: %TRUE if rules are useful for the user of this tree
11818  **/
11819 gboolean
11820 gtk_tree_view_get_rules_hint (GtkTreeView  *tree_view)
11821 {
11822   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
11823
11824   return tree_view->priv->has_rules;
11825 }
11826
11827 /* Public Column functions
11828  */
11829
11830 /**
11831  * gtk_tree_view_append_column:
11832  * @tree_view: A #GtkTreeView.
11833  * @column: The #GtkTreeViewColumn to add.
11834  *
11835  * Appends @column to the list of columns. If @tree_view has "fixed_height"
11836  * mode enabled, then @column must have its "sizing" property set to be
11837  * GTK_TREE_VIEW_COLUMN_FIXED.
11838  *
11839  * Return value: The number of columns in @tree_view after appending.
11840  **/
11841 gint
11842 gtk_tree_view_append_column (GtkTreeView       *tree_view,
11843                              GtkTreeViewColumn *column)
11844 {
11845   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11846   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
11847   g_return_val_if_fail (gtk_tree_view_column_get_tree_view (column) == NULL, -1);
11848
11849   return gtk_tree_view_insert_column (tree_view, column, -1);
11850 }
11851
11852 void
11853 _gtk_tree_view_reset_header_styles (GtkTreeView *tree_view)
11854 {
11855   GList *columns;
11856
11857   for (columns = tree_view->priv->columns; columns; columns = columns->next)
11858     {
11859       GtkTreeViewColumn *column = columns->data;
11860       GtkWidget *header_widget;
11861
11862       if (!gtk_tree_view_column_get_visible (column))
11863         continue;
11864
11865       header_widget = gtk_tree_view_column_get_widget (column);
11866
11867       if (!header_widget)
11868         header_widget = gtk_tree_view_column_get_button (column);
11869
11870       _gtk_widget_invalidate_style_context (header_widget, GTK_CSS_CHANGE_PARENT_REGION);
11871     }
11872 }
11873
11874
11875 /**
11876  * gtk_tree_view_remove_column:
11877  * @tree_view: A #GtkTreeView.
11878  * @column: The #GtkTreeViewColumn to remove.
11879  *
11880  * Removes @column from @tree_view.
11881  *
11882  * Return value: The number of columns in @tree_view after removing.
11883  **/
11884 gint
11885 gtk_tree_view_remove_column (GtkTreeView       *tree_view,
11886                              GtkTreeViewColumn *column)
11887 {
11888   guint position;
11889
11890   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11891   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
11892   g_return_val_if_fail (gtk_tree_view_column_get_tree_view (column) == GTK_WIDGET (tree_view), -1);
11893
11894   if (tree_view->priv->focus_column == column)
11895     _gtk_tree_view_set_focus_column (tree_view, NULL);
11896
11897   if (tree_view->priv->edited_column == column)
11898     {
11899       gtk_tree_view_stop_editing (tree_view, TRUE);
11900
11901       /* no need to, but just to be sure ... */
11902       tree_view->priv->edited_column = NULL;
11903     }
11904
11905   if (tree_view->priv->expander_column == column)
11906     tree_view->priv->expander_column = NULL;
11907
11908   g_signal_handlers_disconnect_by_func (column,
11909                                         G_CALLBACK (column_sizing_notify),
11910                                         tree_view);
11911
11912   _gtk_tree_view_column_unset_tree_view (column);
11913
11914   position = g_list_index (tree_view->priv->columns, column);
11915
11916   tree_view->priv->columns = g_list_remove (tree_view->priv->columns, column);
11917   tree_view->priv->n_columns--;
11918
11919   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11920     {
11921       GList *list;
11922
11923       _gtk_tree_view_column_unrealize_button (column);
11924       for (list = tree_view->priv->columns; list; list = list->next)
11925         {
11926           GtkTreeViewColumn *tmp_column;
11927
11928           tmp_column = GTK_TREE_VIEW_COLUMN (list->data);
11929           if (gtk_tree_view_column_get_visible (tmp_column))
11930             _gtk_tree_view_column_cell_set_dirty (tmp_column, TRUE);
11931         }
11932
11933       if (tree_view->priv->n_columns == 0 &&
11934           gtk_tree_view_get_headers_visible (tree_view))
11935         gdk_window_hide (tree_view->priv->header_window);
11936
11937       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11938     }
11939
11940   _gtk_tree_view_reset_header_styles (tree_view);
11941
11942   _gtk_tree_view_accessible_remove_column (tree_view, column, position);
11943
11944   g_object_unref (column);
11945   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
11946
11947   return tree_view->priv->n_columns;
11948 }
11949
11950 /**
11951  * gtk_tree_view_insert_column:
11952  * @tree_view: A #GtkTreeView.
11953  * @column: The #GtkTreeViewColumn to be inserted.
11954  * @position: The position to insert @column in.
11955  *
11956  * This inserts the @column into the @tree_view at @position.  If @position is
11957  * -1, then the column is inserted at the end. If @tree_view has
11958  * "fixed_height" mode enabled, then @column must have its "sizing" property
11959  * set to be GTK_TREE_VIEW_COLUMN_FIXED.
11960  *
11961  * Return value: The number of columns in @tree_view after insertion.
11962  **/
11963 gint
11964 gtk_tree_view_insert_column (GtkTreeView       *tree_view,
11965                              GtkTreeViewColumn *column,
11966                              gint               position)
11967 {
11968   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11969   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
11970   g_return_val_if_fail (gtk_tree_view_column_get_tree_view (column) == NULL, -1);
11971
11972   if (tree_view->priv->fixed_height_mode)
11973     g_return_val_if_fail (gtk_tree_view_column_get_sizing (column)
11974                           == GTK_TREE_VIEW_COLUMN_FIXED, -1);
11975
11976   if (position < 0 || position > tree_view->priv->n_columns)
11977     position = tree_view->priv->n_columns;
11978
11979   g_object_ref_sink (column);
11980
11981   if (tree_view->priv->n_columns == 0 &&
11982       gtk_widget_get_realized (GTK_WIDGET (tree_view)) &&
11983       gtk_tree_view_get_headers_visible (tree_view))
11984     {
11985       gdk_window_show (tree_view->priv->header_window);
11986     }
11987
11988   g_signal_connect (column, "notify::sizing",
11989                     G_CALLBACK (column_sizing_notify), tree_view);
11990
11991   tree_view->priv->columns = g_list_insert (tree_view->priv->columns,
11992                                             column, position);
11993   tree_view->priv->n_columns++;
11994
11995   _gtk_tree_view_column_set_tree_view (column, tree_view);
11996
11997   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11998     {
11999       GList *list;
12000
12001       _gtk_tree_view_column_realize_button (column);
12002
12003       for (list = tree_view->priv->columns; list; list = list->next)
12004         {
12005           column = GTK_TREE_VIEW_COLUMN (list->data);
12006           if (gtk_tree_view_column_get_visible (column))
12007             _gtk_tree_view_column_cell_set_dirty (column, TRUE);
12008         }
12009       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
12010     }
12011
12012   _gtk_tree_view_reset_header_styles (tree_view);
12013
12014   _gtk_tree_view_accessible_add_column (tree_view, column, position);
12015
12016   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
12017
12018   return tree_view->priv->n_columns;
12019 }
12020
12021 /**
12022  * gtk_tree_view_insert_column_with_attributes:
12023  * @tree_view: A #GtkTreeView
12024  * @position: The position to insert the new column in
12025  * @title: The title to set the header to
12026  * @cell: The #GtkCellRenderer
12027  * @...: A %NULL-terminated list of attributes
12028  *
12029  * Creates a new #GtkTreeViewColumn and inserts it into the @tree_view at
12030  * @position.  If @position is -1, then the newly created column is inserted at
12031  * the end.  The column is initialized with the attributes given. If @tree_view
12032  * has "fixed_height" mode enabled, then the new column will have its sizing
12033  * property set to be GTK_TREE_VIEW_COLUMN_FIXED.
12034  *
12035  * Return value: The number of columns in @tree_view after insertion.
12036  **/
12037 gint
12038 gtk_tree_view_insert_column_with_attributes (GtkTreeView     *tree_view,
12039                                              gint             position,
12040                                              const gchar     *title,
12041                                              GtkCellRenderer *cell,
12042                                              ...)
12043 {
12044   GtkTreeViewColumn *column;
12045   gchar *attribute;
12046   va_list args;
12047   gint column_id;
12048
12049   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
12050
12051   column = gtk_tree_view_column_new ();
12052   if (tree_view->priv->fixed_height_mode)
12053     gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
12054
12055   gtk_tree_view_column_set_title (column, title);
12056   gtk_tree_view_column_pack_start (column, cell, TRUE);
12057
12058   va_start (args, cell);
12059
12060   attribute = va_arg (args, gchar *);
12061
12062   while (attribute != NULL)
12063     {
12064       column_id = va_arg (args, gint);
12065       gtk_tree_view_column_add_attribute (column, cell, attribute, column_id);
12066       attribute = va_arg (args, gchar *);
12067     }
12068
12069   va_end (args);
12070
12071   return gtk_tree_view_insert_column (tree_view, column, position);
12072 }
12073
12074 /**
12075  * gtk_tree_view_insert_column_with_data_func:
12076  * @tree_view: a #GtkTreeView
12077  * @position: Position to insert, -1 for append
12078  * @title: column title
12079  * @cell: cell renderer for column
12080  * @func: function to set attributes of cell renderer
12081  * @data: data for @func
12082  * @dnotify: destroy notifier for @data
12083  *
12084  * Convenience function that inserts a new column into the #GtkTreeView
12085  * with the given cell renderer and a #GtkTreeCellDataFunc to set cell renderer
12086  * attributes (normally using data from the model). See also
12087  * gtk_tree_view_column_set_cell_data_func(), gtk_tree_view_column_pack_start().
12088  * If @tree_view has "fixed_height" mode enabled, then the new column will have its
12089  * "sizing" property set to be GTK_TREE_VIEW_COLUMN_FIXED.
12090  *
12091  * Return value: number of columns in the tree view post-insert
12092  **/
12093 gint
12094 gtk_tree_view_insert_column_with_data_func  (GtkTreeView               *tree_view,
12095                                              gint                       position,
12096                                              const gchar               *title,
12097                                              GtkCellRenderer           *cell,
12098                                              GtkTreeCellDataFunc        func,
12099                                              gpointer                   data,
12100                                              GDestroyNotify             dnotify)
12101 {
12102   GtkTreeViewColumn *column;
12103
12104   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
12105
12106   column = gtk_tree_view_column_new ();
12107   if (tree_view->priv->fixed_height_mode)
12108     gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
12109
12110   gtk_tree_view_column_set_title (column, title);
12111   gtk_tree_view_column_pack_start (column, cell, TRUE);
12112   gtk_tree_view_column_set_cell_data_func (column, cell, func, data, dnotify);
12113
12114   return gtk_tree_view_insert_column (tree_view, column, position);
12115 }
12116
12117 /**
12118  * gtk_tree_view_get_n_columns:
12119  * @tree_view: a #GtkTreeView
12120  *
12121  * Queries the number of columns in the given @tree_view.
12122  *
12123  * Returns: The number of columns in the @tree_view
12124  *
12125  * Since: 3.4
12126  **/
12127 guint
12128 gtk_tree_view_get_n_columns (GtkTreeView *tree_view)
12129 {
12130   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
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
12233   _gtk_tree_view_accessible_reorder_column (tree_view, column);
12234
12235   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
12236 }
12237
12238 /**
12239  * gtk_tree_view_set_expander_column:
12240  * @tree_view: A #GtkTreeView
12241  * @column: %NULL, or the column to draw the expander arrow at.
12242  *
12243  * Sets the column to draw the expander arrow at. It must be in @tree_view.  
12244  * If @column is %NULL, then the expander arrow is always at the first 
12245  * visible column.
12246  *
12247  * If you do not want expander arrow to appear in your tree, set the 
12248  * expander column to a hidden column.
12249  **/
12250 void
12251 gtk_tree_view_set_expander_column (GtkTreeView       *tree_view,
12252                                    GtkTreeViewColumn *column)
12253 {
12254   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12255   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
12256   g_return_if_fail (column == NULL || gtk_tree_view_column_get_tree_view (column) == GTK_WIDGET (tree_view));
12257
12258   if (tree_view->priv->expander_column != column)
12259     {
12260       tree_view->priv->expander_column = column;
12261       g_object_notify (G_OBJECT (tree_view), "expander-column");
12262     }
12263 }
12264
12265 /**
12266  * gtk_tree_view_get_expander_column:
12267  * @tree_view: A #GtkTreeView
12268  *
12269  * Returns the column that is the current expander column.
12270  * This column has the expander arrow drawn next to it.
12271  *
12272  * Return value: (transfer none): The expander column.
12273  **/
12274 GtkTreeViewColumn *
12275 gtk_tree_view_get_expander_column (GtkTreeView *tree_view)
12276 {
12277   GList *list;
12278
12279   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
12280
12281   for (list = tree_view->priv->columns; list; list = list->next)
12282     if (gtk_tree_view_is_expander_column (tree_view, GTK_TREE_VIEW_COLUMN (list->data)))
12283       return (GtkTreeViewColumn *) list->data;
12284   return NULL;
12285 }
12286
12287
12288 /**
12289  * gtk_tree_view_set_column_drag_function:
12290  * @tree_view: A #GtkTreeView.
12291  * @func: (allow-none): A function to determine which columns are reorderable, or %NULL.
12292  * @user_data: (allow-none): User data to be passed to @func, or %NULL
12293  * @destroy: (allow-none): Destroy notifier for @user_data, or %NULL
12294  *
12295  * Sets a user function for determining where a column may be dropped when
12296  * dragged.  This function is called on every column pair in turn at the
12297  * beginning of a column drag to determine where a drop can take place.  The
12298  * arguments passed to @func are: the @tree_view, the #GtkTreeViewColumn being
12299  * dragged, the two #GtkTreeViewColumn s determining the drop spot, and
12300  * @user_data.  If either of the #GtkTreeViewColumn arguments for the drop spot
12301  * are %NULL, then they indicate an edge.  If @func is set to be %NULL, then
12302  * @tree_view reverts to the default behavior of allowing all columns to be
12303  * dropped everywhere.
12304  **/
12305 void
12306 gtk_tree_view_set_column_drag_function (GtkTreeView               *tree_view,
12307                                         GtkTreeViewColumnDropFunc  func,
12308                                         gpointer                   user_data,
12309                                         GDestroyNotify             destroy)
12310 {
12311   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12312
12313   if (tree_view->priv->column_drop_func_data_destroy)
12314     tree_view->priv->column_drop_func_data_destroy (tree_view->priv->column_drop_func_data);
12315
12316   tree_view->priv->column_drop_func = func;
12317   tree_view->priv->column_drop_func_data = user_data;
12318   tree_view->priv->column_drop_func_data_destroy = destroy;
12319 }
12320
12321 /**
12322  * gtk_tree_view_scroll_to_point:
12323  * @tree_view: a #GtkTreeView
12324  * @tree_x: X coordinate of new top-left pixel of visible area, or -1
12325  * @tree_y: Y coordinate of new top-left pixel of visible area, or -1
12326  *
12327  * Scrolls the tree view such that the top-left corner of the visible
12328  * area is @tree_x, @tree_y, where @tree_x and @tree_y are specified
12329  * in tree coordinates.  The @tree_view must be realized before
12330  * this function is called.  If it isn't, you probably want to be
12331  * using gtk_tree_view_scroll_to_cell().
12332  *
12333  * If either @tree_x or @tree_y are -1, then that direction isn't scrolled.
12334  **/
12335 void
12336 gtk_tree_view_scroll_to_point (GtkTreeView *tree_view,
12337                                gint         tree_x,
12338                                gint         tree_y)
12339 {
12340   GtkAdjustment *hadj;
12341   GtkAdjustment *vadj;
12342
12343   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12344   g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (tree_view)));
12345
12346   hadj = tree_view->priv->hadjustment;
12347   vadj = tree_view->priv->vadjustment;
12348
12349   if (tree_x != -1)
12350     gtk_adjustment_set_value (hadj, tree_x);
12351   if (tree_y != -1)
12352     gtk_adjustment_set_value (vadj, tree_y);
12353 }
12354
12355 /**
12356  * gtk_tree_view_scroll_to_cell:
12357  * @tree_view: A #GtkTreeView.
12358  * @path: (allow-none): The path of the row to move to, or %NULL.
12359  * @column: (allow-none): The #GtkTreeViewColumn to move horizontally to, or %NULL.
12360  * @use_align: whether to use alignment arguments, or %FALSE.
12361  * @row_align: The vertical alignment of the row specified by @path.
12362  * @col_align: The horizontal alignment of the column specified by @column.
12363  *
12364  * Moves the alignments of @tree_view to the position specified by @column and
12365  * @path.  If @column is %NULL, then no horizontal scrolling occurs.  Likewise,
12366  * if @path is %NULL no vertical scrolling occurs.  At a minimum, one of @column
12367  * or @path need to be non-%NULL.  @row_align determines where the row is
12368  * placed, and @col_align determines where @column is placed.  Both are expected
12369  * to be between 0.0 and 1.0. 0.0 means left/top alignment, 1.0 means
12370  * right/bottom alignment, 0.5 means center.
12371  *
12372  * If @use_align is %FALSE, then the alignment arguments are ignored, and the
12373  * tree does the minimum amount of work to scroll the cell onto the screen.
12374  * This means that the cell will be scrolled to the edge closest to its current
12375  * position.  If the cell is currently visible on the screen, nothing is done.
12376  *
12377  * This function only works if the model is set, and @path is a valid row on the
12378  * model.  If the model changes before the @tree_view is realized, the centered
12379  * path will be modified to reflect this change.
12380  **/
12381 void
12382 gtk_tree_view_scroll_to_cell (GtkTreeView       *tree_view,
12383                               GtkTreePath       *path,
12384                               GtkTreeViewColumn *column,
12385                               gboolean           use_align,
12386                               gfloat             row_align,
12387                               gfloat             col_align)
12388 {
12389   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12390   g_return_if_fail (tree_view->priv->model != NULL);
12391   g_return_if_fail (tree_view->priv->tree != NULL);
12392   g_return_if_fail (row_align >= 0.0 && row_align <= 1.0);
12393   g_return_if_fail (col_align >= 0.0 && col_align <= 1.0);
12394   g_return_if_fail (path != NULL || column != NULL);
12395
12396 #if 0
12397   g_print ("gtk_tree_view_scroll_to_cell:\npath: %s\ncolumn: %s\nuse_align: %d\nrow_align: %f\ncol_align: %f\n",
12398            gtk_tree_path_to_string (path), column?"non-null":"null", use_align, row_align, col_align);
12399 #endif
12400   row_align = CLAMP (row_align, 0.0, 1.0);
12401   col_align = CLAMP (col_align, 0.0, 1.0);
12402
12403
12404   /* Note: Despite the benefits that come from having one code path for the
12405    * scrolling code, we short-circuit validate_visible_area's immplementation as
12406    * it is much slower than just going to the point.
12407    */
12408   if (!gtk_widget_get_visible (GTK_WIDGET (tree_view)) ||
12409       !gtk_widget_get_realized (GTK_WIDGET (tree_view)) ||
12410       _gtk_widget_get_alloc_needed (GTK_WIDGET (tree_view)) ||
12411       GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID))
12412     {
12413       if (tree_view->priv->scroll_to_path)
12414         gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
12415
12416       tree_view->priv->scroll_to_path = NULL;
12417       tree_view->priv->scroll_to_column = NULL;
12418
12419       if (path)
12420         tree_view->priv->scroll_to_path = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
12421       if (column)
12422         tree_view->priv->scroll_to_column = column;
12423       tree_view->priv->scroll_to_use_align = use_align;
12424       tree_view->priv->scroll_to_row_align = row_align;
12425       tree_view->priv->scroll_to_col_align = col_align;
12426
12427       install_presize_handler (tree_view);
12428     }
12429   else
12430     {
12431       GdkRectangle cell_rect;
12432       GdkRectangle vis_rect;
12433       gint dest_x, dest_y;
12434
12435       gtk_tree_view_get_background_area (tree_view, path, column, &cell_rect);
12436       gtk_tree_view_get_visible_rect (tree_view, &vis_rect);
12437
12438       cell_rect.y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, cell_rect.y);
12439
12440       dest_x = vis_rect.x;
12441       dest_y = vis_rect.y;
12442
12443       if (column)
12444         {
12445           if (use_align)
12446             {
12447               dest_x = cell_rect.x - ((vis_rect.width - cell_rect.width) * col_align);
12448             }
12449           else
12450             {
12451               if (cell_rect.x < vis_rect.x)
12452                 dest_x = cell_rect.x;
12453               if (cell_rect.x + cell_rect.width > vis_rect.x + vis_rect.width)
12454                 dest_x = cell_rect.x + cell_rect.width - vis_rect.width;
12455             }
12456         }
12457
12458       if (path)
12459         {
12460           if (use_align)
12461             {
12462               dest_y = cell_rect.y - ((vis_rect.height - cell_rect.height) * row_align);
12463               dest_y = MAX (dest_y, 0);
12464             }
12465           else
12466             {
12467               if (cell_rect.y < vis_rect.y)
12468                 dest_y = cell_rect.y;
12469               if (cell_rect.y + cell_rect.height > vis_rect.y + vis_rect.height)
12470                 dest_y = cell_rect.y + cell_rect.height - vis_rect.height;
12471             }
12472         }
12473
12474       gtk_tree_view_scroll_to_point (tree_view, dest_x, dest_y);
12475     }
12476 }
12477
12478 /**
12479  * gtk_tree_view_row_activated:
12480  * @tree_view: A #GtkTreeView
12481  * @path: The #GtkTreePath to be activated.
12482  * @column: The #GtkTreeViewColumn to be activated.
12483  *
12484  * Activates the cell determined by @path and @column.
12485  **/
12486 void
12487 gtk_tree_view_row_activated (GtkTreeView       *tree_view,
12488                              GtkTreePath       *path,
12489                              GtkTreeViewColumn *column)
12490 {
12491   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12492
12493   g_signal_emit (tree_view, tree_view_signals[ROW_ACTIVATED], 0, path, column);
12494 }
12495
12496
12497 static void
12498 gtk_tree_view_expand_all_emission_helper (GtkRBTree *tree,
12499                                           GtkRBNode *node,
12500                                           gpointer   data)
12501 {
12502   GtkTreeView *tree_view = data;
12503
12504   if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT &&
12505       node->children)
12506     {
12507       GtkTreePath *path;
12508       GtkTreeIter iter;
12509
12510       path = _gtk_tree_path_new_from_rbtree (tree, node);
12511       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
12512
12513       g_signal_emit (tree_view, tree_view_signals[ROW_EXPANDED], 0, &iter, path);
12514
12515       gtk_tree_path_free (path);
12516     }
12517
12518   if (node->children)
12519     _gtk_rbtree_traverse (node->children,
12520                           node->children->root,
12521                           G_PRE_ORDER,
12522                           gtk_tree_view_expand_all_emission_helper,
12523                           tree_view);
12524 }
12525
12526 /**
12527  * gtk_tree_view_expand_all:
12528  * @tree_view: A #GtkTreeView.
12529  *
12530  * Recursively expands all nodes in the @tree_view.
12531  **/
12532 void
12533 gtk_tree_view_expand_all (GtkTreeView *tree_view)
12534 {
12535   GtkTreePath *path;
12536   GtkRBTree *tree;
12537   GtkRBNode *node;
12538
12539   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12540
12541   if (tree_view->priv->tree == NULL)
12542     return;
12543
12544   path = gtk_tree_path_new_first ();
12545   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
12546
12547   while (node)
12548     {
12549       gtk_tree_view_real_expand_row (tree_view, path, tree, node, TRUE, FALSE);
12550       node = _gtk_rbtree_next (tree, node);
12551       gtk_tree_path_next (path);
12552   }
12553
12554   gtk_tree_path_free (path);
12555 }
12556
12557 /**
12558  * gtk_tree_view_collapse_all:
12559  * @tree_view: A #GtkTreeView.
12560  *
12561  * Recursively collapses all visible, expanded nodes in @tree_view.
12562  **/
12563 void
12564 gtk_tree_view_collapse_all (GtkTreeView *tree_view)
12565 {
12566   GtkRBTree *tree;
12567   GtkRBNode *node;
12568   GtkTreePath *path;
12569   gint *indices;
12570
12571   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12572
12573   if (tree_view->priv->tree == NULL)
12574     return;
12575
12576   path = gtk_tree_path_new ();
12577   gtk_tree_path_down (path);
12578   indices = gtk_tree_path_get_indices (path);
12579
12580   tree = tree_view->priv->tree;
12581   node = _gtk_rbtree_first (tree);
12582
12583   while (node)
12584     {
12585       if (node->children)
12586         gtk_tree_view_real_collapse_row (tree_view, path, tree, node, FALSE);
12587       indices[0]++;
12588       node = _gtk_rbtree_next (tree, node);
12589     }
12590
12591   gtk_tree_path_free (path);
12592 }
12593
12594 /**
12595  * gtk_tree_view_expand_to_path:
12596  * @tree_view: A #GtkTreeView.
12597  * @path: path to a row.
12598  *
12599  * Expands the row at @path. This will also expand all parent rows of
12600  * @path as necessary.
12601  *
12602  * Since: 2.2
12603  **/
12604 void
12605 gtk_tree_view_expand_to_path (GtkTreeView *tree_view,
12606                               GtkTreePath *path)
12607 {
12608   gint i, depth;
12609   gint *indices;
12610   GtkTreePath *tmp;
12611
12612   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12613   g_return_if_fail (path != NULL);
12614
12615   depth = gtk_tree_path_get_depth (path);
12616   indices = gtk_tree_path_get_indices (path);
12617
12618   tmp = gtk_tree_path_new ();
12619   g_return_if_fail (tmp != NULL);
12620
12621   for (i = 0; i < depth; i++)
12622     {
12623       gtk_tree_path_append_index (tmp, indices[i]);
12624       gtk_tree_view_expand_row (tree_view, tmp, FALSE);
12625     }
12626
12627   gtk_tree_path_free (tmp);
12628 }
12629
12630 /* FIXME the bool return values for expand_row and collapse_row are
12631  * not analagous; they should be TRUE if the row had children and
12632  * was not already in the requested state.
12633  */
12634
12635
12636 static gboolean
12637 gtk_tree_view_real_expand_row (GtkTreeView *tree_view,
12638                                GtkTreePath *path,
12639                                GtkRBTree   *tree,
12640                                GtkRBNode   *node,
12641                                gboolean     open_all,
12642                                gboolean     animate)
12643 {
12644   GtkTreeIter iter;
12645   GtkTreeIter temp;
12646   gboolean expand;
12647
12648   if (animate)
12649     g_object_get (gtk_widget_get_settings (GTK_WIDGET (tree_view)),
12650                   "gtk-enable-animations", &animate,
12651                   NULL);
12652
12653   remove_auto_expand_timeout (tree_view);
12654
12655   if (node->children && !open_all)
12656     return FALSE;
12657
12658   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
12659     return FALSE;
12660
12661   gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
12662   if (! gtk_tree_model_iter_has_child (tree_view->priv->model, &iter))
12663     return FALSE;
12664
12665
12666    if (node->children && open_all)
12667     {
12668       gboolean retval = FALSE;
12669       GtkTreePath *tmp_path = gtk_tree_path_copy (path);
12670
12671       gtk_tree_path_append_index (tmp_path, 0);
12672       tree = node->children;
12673       node = _gtk_rbtree_first (tree);
12674       /* try to expand the children */
12675       do
12676         {
12677          gboolean t;
12678          t = gtk_tree_view_real_expand_row (tree_view, tmp_path, tree, node,
12679                                             TRUE, animate);
12680          if (t)
12681            retval = TRUE;
12682
12683          gtk_tree_path_next (tmp_path);
12684          node = _gtk_rbtree_next (tree, node);
12685        }
12686       while (node != NULL);
12687
12688       gtk_tree_path_free (tmp_path);
12689
12690       return retval;
12691     }
12692
12693   g_signal_emit (tree_view, tree_view_signals[TEST_EXPAND_ROW], 0, &iter, path, &expand);
12694
12695   if (!gtk_tree_model_iter_has_child (tree_view->priv->model, &iter))
12696     return FALSE;
12697
12698   if (expand)
12699     return FALSE;
12700
12701   node->children = _gtk_rbtree_new ();
12702   node->children->parent_tree = tree;
12703   node->children->parent_node = node;
12704
12705   gtk_tree_model_iter_children (tree_view->priv->model, &temp, &iter);
12706
12707   gtk_tree_view_build_tree (tree_view,
12708                             node->children,
12709                             &temp,
12710                             gtk_tree_path_get_depth (path) + 1,
12711                             open_all);
12712
12713   _gtk_tree_view_accessible_add (tree_view, node->children, NULL);
12714   _gtk_tree_view_accessible_add_state (tree_view,
12715                                        tree, node,
12716                                        GTK_CELL_RENDERER_EXPANDED);
12717
12718   install_presize_handler (tree_view);
12719
12720   g_signal_emit (tree_view, tree_view_signals[ROW_EXPANDED], 0, &iter, path);
12721   if (open_all && node->children)
12722     {
12723       _gtk_rbtree_traverse (node->children,
12724                             node->children->root,
12725                             G_PRE_ORDER,
12726                             gtk_tree_view_expand_all_emission_helper,
12727                             tree_view);
12728     }
12729   return TRUE;
12730 }
12731
12732
12733 /**
12734  * gtk_tree_view_expand_row:
12735  * @tree_view: a #GtkTreeView
12736  * @path: path to a row
12737  * @open_all: whether to recursively expand, or just expand immediate children
12738  *
12739  * Opens the row so its children are visible.
12740  *
12741  * Return value: %TRUE if the row existed and had children
12742  **/
12743 gboolean
12744 gtk_tree_view_expand_row (GtkTreeView *tree_view,
12745                           GtkTreePath *path,
12746                           gboolean     open_all)
12747 {
12748   GtkRBTree *tree;
12749   GtkRBNode *node;
12750
12751   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12752   g_return_val_if_fail (tree_view->priv->model != NULL, FALSE);
12753   g_return_val_if_fail (path != NULL, FALSE);
12754
12755   if (_gtk_tree_view_find_node (tree_view,
12756                                 path,
12757                                 &tree,
12758                                 &node))
12759     return FALSE;
12760
12761   if (tree != NULL)
12762     return gtk_tree_view_real_expand_row (tree_view, path, tree, node, open_all, FALSE);
12763   else
12764     return FALSE;
12765 }
12766
12767 static gboolean
12768 gtk_tree_view_real_collapse_row (GtkTreeView *tree_view,
12769                                  GtkTreePath *path,
12770                                  GtkRBTree   *tree,
12771                                  GtkRBNode   *node,
12772                                  gboolean     animate)
12773 {
12774   GtkTreeIter iter;
12775   GtkTreeIter children;
12776   gboolean collapse;
12777   gint x, y;
12778   GList *list;
12779   GdkWindow *child;
12780   gboolean selection_changed, cursor_changed;
12781
12782   if (animate)
12783     g_object_get (gtk_widget_get_settings (GTK_WIDGET (tree_view)),
12784                   "gtk-enable-animations", &animate,
12785                   NULL);
12786
12787   remove_auto_expand_timeout (tree_view);
12788
12789   if (node->children == NULL)
12790     return FALSE;
12791   gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
12792
12793   g_signal_emit (tree_view, tree_view_signals[TEST_COLLAPSE_ROW], 0, &iter, path, &collapse);
12794
12795   if (collapse)
12796     return FALSE;
12797
12798   /* if the prelighted node is a child of us, we want to unprelight it.  We have
12799    * a chance to prelight the correct node below */
12800
12801   if (tree_view->priv->prelight_tree)
12802     {
12803       GtkRBTree *parent_tree;
12804       GtkRBNode *parent_node;
12805
12806       parent_tree = tree_view->priv->prelight_tree->parent_tree;
12807       parent_node = tree_view->priv->prelight_tree->parent_node;
12808       while (parent_tree)
12809         {
12810           if (parent_tree == tree && parent_node == node)
12811             {
12812               ensure_unprelighted (tree_view);
12813               break;
12814             }
12815           parent_node = parent_tree->parent_node;
12816           parent_tree = parent_tree->parent_tree;
12817         }
12818     }
12819
12820   TREE_VIEW_INTERNAL_ASSERT (gtk_tree_model_iter_children (tree_view->priv->model, &children, &iter), FALSE);
12821
12822   for (list = tree_view->priv->columns; list; list = list->next)
12823     {
12824       GtkTreeViewColumn *column = list->data;
12825
12826       if (gtk_tree_view_column_get_visible (column) == FALSE)
12827         continue;
12828       if (gtk_tree_view_column_get_sizing (column) == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
12829         _gtk_tree_view_column_cell_set_dirty (column, TRUE);
12830     }
12831
12832   if (tree_view->priv->destroy_count_func)
12833     {
12834       GtkTreePath *child_path;
12835       gint child_count = 0;
12836       child_path = gtk_tree_path_copy (path);
12837       gtk_tree_path_down (child_path);
12838       if (node->children)
12839         _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, &child_count);
12840       tree_view->priv->destroy_count_func (tree_view, child_path, child_count, tree_view->priv->destroy_count_data);
12841       gtk_tree_path_free (child_path);
12842     }
12843
12844   if (tree_view->priv->cursor_node)
12845     {
12846       cursor_changed = (node->children == tree_view->priv->cursor_tree)
12847                        || _gtk_rbtree_contains (node->children, tree_view->priv->cursor_tree);
12848     }
12849   else
12850     cursor_changed = FALSE;
12851
12852   if (gtk_tree_row_reference_valid (tree_view->priv->anchor))
12853     {
12854       GtkTreePath *anchor_path = gtk_tree_row_reference_get_path (tree_view->priv->anchor);
12855       if (gtk_tree_path_is_ancestor (path, anchor_path))
12856         {
12857           gtk_tree_row_reference_free (tree_view->priv->anchor);
12858           tree_view->priv->anchor = NULL;
12859         }
12860       gtk_tree_path_free (anchor_path);
12861     }
12862
12863   selection_changed = gtk_tree_view_unref_and_check_selection_tree (tree_view, node->children);
12864   
12865   /* Stop a pending double click */
12866   tree_view->priv->last_button_x = -1;
12867   tree_view->priv->last_button_y = -1;
12868
12869   _gtk_tree_view_accessible_remove (tree_view, node->children, NULL);
12870   _gtk_tree_view_accessible_remove_state (tree_view,
12871                                           tree, node,
12872                                           GTK_CELL_RENDERER_EXPANDED);
12873
12874   _gtk_rbtree_remove (node->children);
12875
12876   if (cursor_changed)
12877     gtk_tree_view_real_set_cursor (tree_view, path, CLEAR_AND_SELECT | CURSOR_INVALID);
12878   if (selection_changed)
12879     g_signal_emit_by_name (tree_view->priv->selection, "changed");
12880
12881   if (gtk_widget_get_mapped (GTK_WIDGET (tree_view)))
12882     {
12883       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
12884     }
12885
12886   g_signal_emit (tree_view, tree_view_signals[ROW_COLLAPSED], 0, &iter, path);
12887   
12888   if (gtk_widget_get_mapped (GTK_WIDGET (tree_view)))
12889     {
12890       /* now that we've collapsed all rows, we want to try to set the prelight
12891        * again. To do this, we fake a motion event and send it to ourselves. */
12892
12893       child = gdk_window_get_device_position (gdk_window_get_parent (tree_view->priv->bin_window),
12894                                               gdk_device_manager_get_client_pointer (
12895                                                 gdk_display_get_device_manager (
12896                                                   gtk_widget_get_display (GTK_WIDGET (tree_view)))),
12897                                               &x, &y, NULL);
12898       if (child == tree_view->priv->bin_window)
12899         {
12900           GdkEventMotion event;
12901           gint child_x, child_y;
12902
12903           gdk_window_get_position (child, &child_x, &child_y);
12904
12905           event.window = tree_view->priv->bin_window;
12906           event.x = x - child_x;
12907           event.y = y - child_y;
12908
12909           /* despite the fact this isn't a real event, I'm almost positive it will
12910            * never trigger a drag event.  maybe_drag is the only function that uses
12911            * more than just event.x and event.y. */
12912           gtk_tree_view_motion_bin_window (GTK_WIDGET (tree_view), &event);
12913         }
12914     }
12915
12916   return TRUE;
12917 }
12918
12919 /**
12920  * gtk_tree_view_collapse_row:
12921  * @tree_view: a #GtkTreeView
12922  * @path: path to a row in the @tree_view
12923  *
12924  * Collapses a row (hides its child rows, if they exist).
12925  *
12926  * Return value: %TRUE if the row was collapsed.
12927  **/
12928 gboolean
12929 gtk_tree_view_collapse_row (GtkTreeView *tree_view,
12930                             GtkTreePath *path)
12931 {
12932   GtkRBTree *tree;
12933   GtkRBNode *node;
12934
12935   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12936   g_return_val_if_fail (tree_view->priv->tree != NULL, FALSE);
12937   g_return_val_if_fail (path != NULL, FALSE);
12938
12939   if (_gtk_tree_view_find_node (tree_view,
12940                                 path,
12941                                 &tree,
12942                                 &node))
12943     return FALSE;
12944
12945   if (tree == NULL || node->children == NULL)
12946     return FALSE;
12947
12948   return gtk_tree_view_real_collapse_row (tree_view, path, tree, node, FALSE);
12949 }
12950
12951 static void
12952 gtk_tree_view_map_expanded_rows_helper (GtkTreeView            *tree_view,
12953                                         GtkRBTree              *tree,
12954                                         GtkTreePath            *path,
12955                                         GtkTreeViewMappingFunc  func,
12956                                         gpointer                user_data)
12957 {
12958   GtkRBNode *node;
12959
12960   if (tree == NULL || tree->root == NULL)
12961     return;
12962
12963   node = _gtk_rbtree_first (tree);
12964
12965   while (node)
12966     {
12967       if (node->children)
12968         {
12969           (* func) (tree_view, path, user_data);
12970           gtk_tree_path_down (path);
12971           gtk_tree_view_map_expanded_rows_helper (tree_view, node->children, path, func, user_data);
12972           gtk_tree_path_up (path);
12973         }
12974       gtk_tree_path_next (path);
12975       node = _gtk_rbtree_next (tree, node);
12976     }
12977 }
12978
12979 /**
12980  * gtk_tree_view_map_expanded_rows:
12981  * @tree_view: A #GtkTreeView
12982  * @func: (scope call): A function to be called
12983  * @data: User data to be passed to the function.
12984  *
12985  * Calls @func on all expanded rows.
12986  **/
12987 void
12988 gtk_tree_view_map_expanded_rows (GtkTreeView            *tree_view,
12989                                  GtkTreeViewMappingFunc  func,
12990                                  gpointer                user_data)
12991 {
12992   GtkTreePath *path;
12993
12994   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12995   g_return_if_fail (func != NULL);
12996
12997   path = gtk_tree_path_new_first ();
12998
12999   gtk_tree_view_map_expanded_rows_helper (tree_view,
13000                                           tree_view->priv->tree,
13001                                           path, func, user_data);
13002
13003   gtk_tree_path_free (path);
13004 }
13005
13006 /**
13007  * gtk_tree_view_row_expanded:
13008  * @tree_view: A #GtkTreeView.
13009  * @path: A #GtkTreePath to test expansion state.
13010  *
13011  * Returns %TRUE if the node pointed to by @path is expanded in @tree_view.
13012  *
13013  * Return value: %TRUE if #path is expanded.
13014  **/
13015 gboolean
13016 gtk_tree_view_row_expanded (GtkTreeView *tree_view,
13017                             GtkTreePath *path)
13018 {
13019   GtkRBTree *tree;
13020   GtkRBNode *node;
13021
13022   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
13023   g_return_val_if_fail (path != NULL, FALSE);
13024
13025   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
13026
13027   if (node == NULL)
13028     return FALSE;
13029
13030   return (node->children != NULL);
13031 }
13032
13033 /**
13034  * gtk_tree_view_get_reorderable:
13035  * @tree_view: a #GtkTreeView
13036  *
13037  * Retrieves whether the user can reorder the tree via drag-and-drop. See
13038  * gtk_tree_view_set_reorderable().
13039  *
13040  * Return value: %TRUE if the tree can be reordered.
13041  **/
13042 gboolean
13043 gtk_tree_view_get_reorderable (GtkTreeView *tree_view)
13044 {
13045   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
13046
13047   return tree_view->priv->reorderable;
13048 }
13049
13050 /**
13051  * gtk_tree_view_set_reorderable:
13052  * @tree_view: A #GtkTreeView.
13053  * @reorderable: %TRUE, if the tree can be reordered.
13054  *
13055  * This function is a convenience function to allow you to reorder
13056  * models that support the #GtkTreeDragSourceIface and the
13057  * #GtkTreeDragDestIface.  Both #GtkTreeStore and #GtkListStore support
13058  * these.  If @reorderable is %TRUE, then the user can reorder the
13059  * model by dragging and dropping rows. The developer can listen to
13060  * these changes by connecting to the model's row_inserted and
13061  * row_deleted signals. The reordering is implemented by setting up
13062  * the tree view as a drag source and destination. Therefore, drag and
13063  * drop can not be used in a reorderable view for any other purpose.
13064  *
13065  * This function does not give you any degree of control over the order -- any
13066  * reordering is allowed.  If more control is needed, you should probably
13067  * handle drag and drop manually.
13068  **/
13069 void
13070 gtk_tree_view_set_reorderable (GtkTreeView *tree_view,
13071                                gboolean     reorderable)
13072 {
13073   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13074
13075   reorderable = reorderable != FALSE;
13076
13077   if (tree_view->priv->reorderable == reorderable)
13078     return;
13079
13080   if (reorderable)
13081     {
13082       const GtkTargetEntry row_targets[] = {
13083         { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, 0 }
13084       };
13085
13086       gtk_tree_view_enable_model_drag_source (tree_view,
13087                                               GDK_BUTTON1_MASK,
13088                                               row_targets,
13089                                               G_N_ELEMENTS (row_targets),
13090                                               GDK_ACTION_MOVE);
13091       gtk_tree_view_enable_model_drag_dest (tree_view,
13092                                             row_targets,
13093                                             G_N_ELEMENTS (row_targets),
13094                                             GDK_ACTION_MOVE);
13095     }
13096   else
13097     {
13098       gtk_tree_view_unset_rows_drag_source (tree_view);
13099       gtk_tree_view_unset_rows_drag_dest (tree_view);
13100     }
13101
13102   tree_view->priv->reorderable = reorderable;
13103
13104   g_object_notify (G_OBJECT (tree_view), "reorderable");
13105 }
13106
13107 static void
13108 gtk_tree_view_real_set_cursor (GtkTreeView     *tree_view,
13109                                GtkTreePath     *path,
13110                                SetCursorFlags   flags)
13111 {
13112   if (!(flags & CURSOR_INVALID) && tree_view->priv->cursor_node)
13113     {
13114       _gtk_tree_view_accessible_remove_state (tree_view,
13115                                               tree_view->priv->cursor_tree,
13116                                               tree_view->priv->cursor_node,
13117                                               GTK_CELL_RENDERER_FOCUSED);
13118       _gtk_tree_view_queue_draw_node (tree_view,
13119                                       tree_view->priv->cursor_tree,
13120                                       tree_view->priv->cursor_node,
13121                                       NULL);
13122     }
13123
13124   /* One cannot set the cursor on a separator.   Also, if
13125    * _gtk_tree_view_find_node returns TRUE, it ran out of tree
13126    * before finding the tree and node belonging to path.  The
13127    * path maps to a non-existing path and we will silently bail out.
13128    * We unset tree and node to avoid further processing.
13129    */
13130   if (path == NULL || 
13131       row_is_separator (tree_view, NULL, path)
13132       || _gtk_tree_view_find_node (tree_view,
13133                                    path,
13134                                    &tree_view->priv->cursor_tree,
13135                                    &tree_view->priv->cursor_node))
13136     {
13137       tree_view->priv->cursor_tree = NULL;
13138       tree_view->priv->cursor_node = NULL;
13139     }
13140
13141   if (tree_view->priv->cursor_node != NULL)
13142     {
13143       GtkRBTree *new_tree = NULL;
13144       GtkRBNode *new_node = NULL;
13145
13146       if ((flags & CLEAR_AND_SELECT) && !tree_view->priv->modify_selection_pressed)
13147         {
13148           GtkTreeSelectMode mode = 0;
13149
13150           if (tree_view->priv->extend_selection_pressed)
13151             mode |= GTK_TREE_SELECT_MODE_EXTEND;
13152
13153           _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
13154                                                     tree_view->priv->cursor_node,
13155                                                     tree_view->priv->cursor_tree,
13156                                                     path,
13157                                                     mode,
13158                                                     FALSE);
13159         }
13160
13161       /* We have to re-find tree and node here again, somebody might have
13162        * cleared the node or the whole tree in the GtkTreeSelection::changed
13163        * callback. If the nodes differ we bail out here.
13164        */
13165       _gtk_tree_view_find_node (tree_view, path, &new_tree, &new_node);
13166
13167       if (tree_view->priv->cursor_node != new_node)
13168         return;
13169
13170       if (flags & CLAMP_NODE)
13171         {
13172           gtk_tree_view_clamp_node_visible (tree_view,
13173                                             tree_view->priv->cursor_tree,
13174                                             tree_view->priv->cursor_node);
13175           _gtk_tree_view_queue_draw_node (tree_view,
13176                                           tree_view->priv->cursor_tree,
13177                                           tree_view->priv->cursor_node,
13178                                           NULL);
13179         }
13180
13181       _gtk_tree_view_accessible_add_state (tree_view,
13182                                            tree_view->priv->cursor_tree,
13183                                            tree_view->priv->cursor_node,
13184                                            GTK_CELL_RENDERER_FOCUSED);
13185     }
13186
13187   g_signal_emit (tree_view, tree_view_signals[CURSOR_CHANGED], 0);
13188 }
13189
13190 /**
13191  * gtk_tree_view_get_cursor:
13192  * @tree_view: A #GtkTreeView
13193  * @path: (out) (transfer full) (allow-none): A pointer to be filled with the current cursor path, or %NULL
13194  * @focus_column: (out) (transfer none) (allow-none): A pointer to be filled with the current focus column, or %NULL
13195  *
13196  * Fills in @path and @focus_column with the current path and focus column.  If
13197  * the cursor isn't currently set, then *@path will be %NULL.  If no column
13198  * currently has focus, then *@focus_column will be %NULL.
13199  *
13200  * The returned #GtkTreePath must be freed with gtk_tree_path_free() when
13201  * you are done with it.
13202  **/
13203 void
13204 gtk_tree_view_get_cursor (GtkTreeView        *tree_view,
13205                           GtkTreePath       **path,
13206                           GtkTreeViewColumn **focus_column)
13207 {
13208   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13209
13210   if (path)
13211     {
13212       if (tree_view->priv->cursor_node)
13213         *path = _gtk_tree_path_new_from_rbtree (tree_view->priv->cursor_tree,
13214                                                 tree_view->priv->cursor_node);
13215       else
13216         *path = NULL;
13217     }
13218
13219   if (focus_column)
13220     {
13221       *focus_column = tree_view->priv->focus_column;
13222     }
13223 }
13224
13225 /**
13226  * gtk_tree_view_set_cursor:
13227  * @tree_view: A #GtkTreeView
13228  * @path: A #GtkTreePath
13229  * @focus_column: (allow-none): A #GtkTreeViewColumn, or %NULL
13230  * @start_editing: %TRUE if the specified cell should start being edited.
13231  *
13232  * Sets the current keyboard focus to be at @path, and selects it.  This is
13233  * useful when you want to focus the user's attention on a particular row.  If
13234  * @focus_column is not %NULL, then focus is given to the column specified by 
13235  * it. Additionally, if @focus_column is specified, and @start_editing is 
13236  * %TRUE, then editing should be started in the specified cell.  
13237  * This function is often followed by @gtk_widget_grab_focus (@tree_view) 
13238  * in order to give keyboard focus to the widget.  Please note that editing 
13239  * can only happen when the widget is realized.
13240  *
13241  * If @path is invalid for @model, the current cursor (if any) will be unset
13242  * and the function will return without failing.
13243  **/
13244 void
13245 gtk_tree_view_set_cursor (GtkTreeView       *tree_view,
13246                           GtkTreePath       *path,
13247                           GtkTreeViewColumn *focus_column,
13248                           gboolean           start_editing)
13249 {
13250   gtk_tree_view_set_cursor_on_cell (tree_view, path, focus_column,
13251                                     NULL, start_editing);
13252 }
13253
13254 /**
13255  * gtk_tree_view_set_cursor_on_cell:
13256  * @tree_view: A #GtkTreeView
13257  * @path: A #GtkTreePath
13258  * @focus_column: (allow-none): A #GtkTreeViewColumn, or %NULL
13259  * @focus_cell: (allow-none): A #GtkCellRenderer, or %NULL
13260  * @start_editing: %TRUE if the specified cell should start being edited.
13261  *
13262  * Sets the current keyboard focus to be at @path, and selects it.  This is
13263  * useful when you want to focus the user's attention on a particular row.  If
13264  * @focus_column is not %NULL, then focus is given to the column specified by
13265  * it. If @focus_column and @focus_cell are not %NULL, and @focus_column
13266  * contains 2 or more editable or activatable cells, then focus is given to
13267  * the cell specified by @focus_cell. Additionally, if @focus_column is
13268  * specified, and @start_editing is %TRUE, then editing should be started in
13269  * the specified cell.  This function is often followed by
13270  * @gtk_widget_grab_focus (@tree_view) in order to give keyboard focus to the
13271  * widget.  Please note that editing can only happen when the widget is
13272  * realized.
13273  *
13274  * If @path is invalid for @model, the current cursor (if any) will be unset
13275  * and the function will return without failing.
13276  *
13277  * Since: 2.2
13278  **/
13279 void
13280 gtk_tree_view_set_cursor_on_cell (GtkTreeView       *tree_view,
13281                                   GtkTreePath       *path,
13282                                   GtkTreeViewColumn *focus_column,
13283                                   GtkCellRenderer   *focus_cell,
13284                                   gboolean           start_editing)
13285 {
13286   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13287   g_return_if_fail (path != NULL);
13288   g_return_if_fail (focus_column == NULL || GTK_IS_TREE_VIEW_COLUMN (focus_column));
13289
13290   if (!tree_view->priv->model)
13291     return;
13292
13293   if (focus_cell)
13294     {
13295       g_return_if_fail (focus_column);
13296       g_return_if_fail (GTK_IS_CELL_RENDERER (focus_cell));
13297     }
13298
13299   /* cancel the current editing, if it exists */
13300   if (tree_view->priv->edited_column &&
13301       gtk_cell_area_get_edit_widget
13302       (gtk_cell_layout_get_area (GTK_CELL_LAYOUT (tree_view->priv->edited_column))))
13303     gtk_tree_view_stop_editing (tree_view, TRUE);
13304
13305   gtk_tree_view_real_set_cursor (tree_view, path, CLEAR_AND_SELECT | CLAMP_NODE);
13306
13307   if (focus_column &&
13308       gtk_tree_view_column_get_visible (focus_column))
13309     {
13310       GList *list;
13311       gboolean column_in_tree = FALSE;
13312
13313       for (list = tree_view->priv->columns; list; list = list->next)
13314         if (list->data == focus_column)
13315           {
13316             column_in_tree = TRUE;
13317             break;
13318           }
13319       g_return_if_fail (column_in_tree);
13320       _gtk_tree_view_set_focus_column (tree_view, focus_column);
13321       if (focus_cell)
13322         gtk_tree_view_column_focus_cell (focus_column, focus_cell);
13323       if (start_editing)
13324         gtk_tree_view_start_editing (tree_view, path, TRUE);
13325     }
13326 }
13327
13328 /**
13329  * gtk_tree_view_get_bin_window:
13330  * @tree_view: A #GtkTreeView
13331  *
13332  * Returns the window that @tree_view renders to.
13333  * This is used primarily to compare to <literal>event->window</literal>
13334  * to confirm that the event on @tree_view is on the right window.
13335  *
13336  * Return value: (transfer none): A #GdkWindow, or %NULL when @tree_view
13337  *     hasn't been realized yet
13338  **/
13339 GdkWindow *
13340 gtk_tree_view_get_bin_window (GtkTreeView *tree_view)
13341 {
13342   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
13343
13344   return tree_view->priv->bin_window;
13345 }
13346
13347 /**
13348  * gtk_tree_view_get_path_at_pos:
13349  * @tree_view: A #GtkTreeView.
13350  * @x: The x position to be identified (relative to bin_window).
13351  * @y: The y position to be identified (relative to bin_window).
13352  * @path: (out) (allow-none): A pointer to a #GtkTreePath pointer to be filled in, or %NULL
13353  * @column: (out) (transfer none) (allow-none): A pointer to a #GtkTreeViewColumn pointer to be filled in, or %NULL
13354  * @cell_x: (out) (allow-none): A pointer where the X coordinate relative to the cell can be placed, or %NULL
13355  * @cell_y: (out) (allow-none): A pointer where the Y coordinate relative to the cell can be placed, or %NULL
13356  *
13357  * Finds the path at the point (@x, @y), relative to bin_window coordinates
13358  * (please see gtk_tree_view_get_bin_window()).
13359  * That is, @x and @y are relative to an events coordinates. @x and @y must
13360  * come from an event on the @tree_view only where <literal>event->window ==
13361  * gtk_tree_view_get_bin_window (<!-- -->)</literal>. It is primarily for
13362  * things like popup menus. If @path is non-%NULL, then it will be filled
13363  * with the #GtkTreePath at that point.  This path should be freed with
13364  * gtk_tree_path_free().  If @column is non-%NULL, then it will be filled
13365  * with the column at that point.  @cell_x and @cell_y return the coordinates
13366  * relative to the cell background (i.e. the @background_area passed to
13367  * gtk_cell_renderer_render()).  This function is only meaningful if
13368  * @tree_view is realized.  Therefore this function will always return %FALSE
13369  * if @tree_view is not realized or does not have a model.
13370  *
13371  * For converting widget coordinates (eg. the ones you get from
13372  * GtkWidget::query-tooltip), please see
13373  * gtk_tree_view_convert_widget_to_bin_window_coords().
13374  *
13375  * Return value: %TRUE if a row exists at that coordinate.
13376  **/
13377 gboolean
13378 gtk_tree_view_get_path_at_pos (GtkTreeView        *tree_view,
13379                                gint                x,
13380                                gint                y,
13381                                GtkTreePath       **path,
13382                                GtkTreeViewColumn **column,
13383                                gint               *cell_x,
13384                                gint               *cell_y)
13385 {
13386   GtkRBTree *tree;
13387   GtkRBNode *node;
13388   gint y_offset;
13389
13390   g_return_val_if_fail (tree_view != NULL, FALSE);
13391
13392   if (path)
13393     *path = NULL;
13394   if (column)
13395     *column = NULL;
13396
13397   if (tree_view->priv->bin_window == NULL)
13398     return FALSE;
13399
13400   if (tree_view->priv->tree == NULL)
13401     return FALSE;
13402
13403   if (x > gtk_adjustment_get_upper (tree_view->priv->hadjustment))
13404     return FALSE;
13405
13406   if (x < 0 || y < 0)
13407     return FALSE;
13408
13409   if (column || cell_x)
13410     {
13411       GtkTreeViewColumn *tmp_column;
13412       GtkTreeViewColumn *last_column = NULL;
13413       GList *list;
13414       gint remaining_x = x;
13415       gboolean found = FALSE;
13416       gboolean rtl;
13417       gint width;
13418
13419       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
13420       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
13421            list;
13422            list = (rtl ? list->prev : list->next))
13423         {
13424           tmp_column = list->data;
13425
13426           if (gtk_tree_view_column_get_visible (tmp_column) == FALSE)
13427             continue;
13428
13429           last_column = tmp_column;
13430           width = gtk_tree_view_column_get_width (tmp_column);
13431           if (remaining_x <= width)
13432             {
13433               found = TRUE;
13434
13435               if (column)
13436                 *column = tmp_column;
13437
13438               if (cell_x)
13439                 *cell_x = remaining_x;
13440
13441               break;
13442             }
13443           remaining_x -= width;
13444         }
13445
13446       /* If found is FALSE and there is a last_column, then it the remainder
13447        * space is in that area
13448        */
13449       if (!found)
13450         {
13451           if (last_column)
13452             {
13453               if (column)
13454                 *column = last_column;
13455               
13456               if (cell_x)
13457                 *cell_x = gtk_tree_view_column_get_width (last_column) + remaining_x;
13458             }
13459           else
13460             {
13461               return FALSE;
13462             }
13463         }
13464     }
13465
13466   y_offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
13467                                       TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, y),
13468                                       &tree, &node);
13469
13470   if (tree == NULL)
13471     return FALSE;
13472
13473   if (cell_y)
13474     *cell_y = y_offset;
13475
13476   if (path)
13477     *path = _gtk_tree_path_new_from_rbtree (tree, node);
13478
13479   return TRUE;
13480 }
13481
13482
13483 static inline gint
13484 gtk_tree_view_get_cell_area_height (GtkTreeView *tree_view,
13485                                     GtkRBNode   *node,
13486                                     gint         vertical_separator)
13487 {
13488   int expander_size = gtk_tree_view_get_expander_size (tree_view);
13489   int height;
13490
13491   /* The "cell" areas are the cell_area passed in to gtk_cell_renderer_render(),
13492    * i.e. just the cells, no spacing.
13493    *
13494    * The cell area height is at least expander_size - vertical_separator.
13495    * For regular nodes, the height is then at least expander_size. We should
13496    * be able to enforce the expander_size minimum here, because this
13497    * function will not be called for irregular (e.g. separator) rows.
13498    */
13499   height = gtk_tree_view_get_row_height (tree_view, node);
13500   if (height < expander_size)
13501     height = expander_size;
13502
13503   return height - vertical_separator;
13504 }
13505
13506 static inline gint
13507 gtk_tree_view_get_cell_area_y_offset (GtkTreeView *tree_view,
13508                                       GtkRBTree   *tree,
13509                                       GtkRBNode   *node,
13510                                       gint         vertical_separator)
13511 {
13512   int offset;
13513
13514   offset = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
13515   offset += vertical_separator / 2;
13516
13517   return offset;
13518 }
13519
13520 /**
13521  * gtk_tree_view_get_cell_area:
13522  * @tree_view: a #GtkTreeView
13523  * @path: (allow-none): a #GtkTreePath for the row, or %NULL to get only horizontal coordinates
13524  * @column: (allow-none): a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordinates
13525  * @rect: (out): rectangle to fill with cell rect
13526  *
13527  * Fills the bounding rectangle in bin_window coordinates for the cell at the
13528  * row specified by @path and the column specified by @column.  If @path is
13529  * %NULL, or points to a path not currently displayed, the @y and @height fields
13530  * of the rectangle will be filled with 0. If @column is %NULL, the @x and @width
13531  * fields will be filled with 0.  The sum of all cell rects does not cover the
13532  * entire tree; there are extra pixels in between rows, for example. The
13533  * returned rectangle is equivalent to the @cell_area passed to
13534  * gtk_cell_renderer_render().  This function is only valid if @tree_view is
13535  * realized.
13536  **/
13537 void
13538 gtk_tree_view_get_cell_area (GtkTreeView        *tree_view,
13539                              GtkTreePath        *path,
13540                              GtkTreeViewColumn  *column,
13541                              GdkRectangle       *rect)
13542 {
13543   GtkRBTree *tree = NULL;
13544   GtkRBNode *node = NULL;
13545   gint vertical_separator;
13546   gint horizontal_separator;
13547
13548   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13549   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
13550   g_return_if_fail (rect != NULL);
13551   g_return_if_fail (!column || gtk_tree_view_column_get_tree_view (column) == (GtkWidget *) tree_view);
13552   g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (tree_view)));
13553
13554   gtk_widget_style_get (GTK_WIDGET (tree_view),
13555                         "vertical-separator", &vertical_separator,
13556                         "horizontal-separator", &horizontal_separator,
13557                         NULL);
13558
13559   rect->x = 0;
13560   rect->y = 0;
13561   rect->width = 0;
13562   rect->height = 0;
13563
13564   if (column)
13565     {
13566       rect->x = gtk_tree_view_column_get_x_offset (column) + horizontal_separator/2;
13567       rect->width = gtk_tree_view_column_get_width (column) - horizontal_separator;
13568     }
13569
13570   if (path)
13571     {
13572       gboolean ret = _gtk_tree_view_find_node (tree_view, path, &tree, &node);
13573
13574       /* Get vertical coords */
13575       if ((!ret && tree == NULL) || ret)
13576         return;
13577
13578       if (row_is_separator (tree_view, NULL, path))
13579         {
13580           /* There isn't really a "cell area" for separator, so we
13581            * return the y, height values for background area instead.
13582            */
13583           rect->y = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
13584           rect->height = gtk_tree_view_get_row_height (tree_view, node);
13585         }
13586       else
13587         {
13588           rect->y = gtk_tree_view_get_cell_area_y_offset (tree_view, tree, node,
13589                                                           vertical_separator);
13590           rect->height = gtk_tree_view_get_cell_area_height (tree_view, node,
13591                                                              vertical_separator);
13592         }
13593
13594       if (column &&
13595           gtk_tree_view_is_expander_column (tree_view, column))
13596         {
13597           gint depth = gtk_tree_path_get_depth (path);
13598           gboolean rtl;
13599
13600           rtl = gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL;
13601
13602           if (!rtl)
13603             rect->x += (depth - 1) * tree_view->priv->level_indentation;
13604           rect->width -= (depth - 1) * tree_view->priv->level_indentation;
13605
13606           if (gtk_tree_view_draw_expanders (tree_view))
13607             {
13608               int expander_size = gtk_tree_view_get_expander_size (tree_view);
13609               if (!rtl)
13610                 rect->x += depth * expander_size;
13611               rect->width -= depth * expander_size;
13612             }
13613
13614           rect->width = MAX (rect->width, 0);
13615         }
13616     }
13617 }
13618
13619 static inline gint
13620 gtk_tree_view_get_row_height (GtkTreeView *tree_view,
13621                               GtkRBNode   *node)
13622 {
13623   int expander_size = gtk_tree_view_get_expander_size (tree_view);
13624   int height;
13625
13626   /* The "background" areas of all rows/cells add up to cover the entire tree.
13627    * The background includes all inter-row and inter-cell spacing.
13628    *
13629    * If the row pointed at by node does not have a height set, we default
13630    * to expander_size, which is the minimum height for regular nodes.
13631    * Non-regular nodes (e.g. separators) can have a height set smaller
13632    * than expander_size and should not be overruled here.
13633    */
13634   height = GTK_RBNODE_GET_HEIGHT (node);
13635   if (height <= 0)
13636     height = expander_size;
13637
13638   return height;
13639 }
13640
13641 static inline gint
13642 gtk_tree_view_get_row_y_offset (GtkTreeView *tree_view,
13643                                 GtkRBTree   *tree,
13644                                 GtkRBNode   *node)
13645 {
13646   int offset;
13647
13648   offset = _gtk_rbtree_node_find_offset (tree, node);
13649
13650   return RBTREE_Y_TO_TREE_WINDOW_Y (tree_view, offset);
13651 }
13652
13653 /**
13654  * gtk_tree_view_get_background_area:
13655  * @tree_view: a #GtkTreeView
13656  * @path: (allow-none): a #GtkTreePath for the row, or %NULL to get only horizontal coordinates
13657  * @column: (allow-none): a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordiantes
13658  * @rect: (out): rectangle to fill with cell background rect
13659  *
13660  * Fills the bounding rectangle in bin_window coordinates for the cell at the
13661  * row specified by @path and the column specified by @column.  If @path is
13662  * %NULL, or points to a node not found in the tree, the @y and @height fields of
13663  * the rectangle will be filled with 0. If @column is %NULL, the @x and @width
13664  * fields will be filled with 0.  The returned rectangle is equivalent to the
13665  * @background_area passed to gtk_cell_renderer_render().  These background
13666  * areas tile to cover the entire bin window.  Contrast with the @cell_area,
13667  * returned by gtk_tree_view_get_cell_area(), which returns only the cell
13668  * itself, excluding surrounding borders and the tree expander area.
13669  *
13670  **/
13671 void
13672 gtk_tree_view_get_background_area (GtkTreeView        *tree_view,
13673                                    GtkTreePath        *path,
13674                                    GtkTreeViewColumn  *column,
13675                                    GdkRectangle       *rect)
13676 {
13677   GtkRBTree *tree = NULL;
13678   GtkRBNode *node = NULL;
13679
13680   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13681   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
13682   g_return_if_fail (rect != NULL);
13683
13684   rect->x = 0;
13685   rect->y = 0;
13686   rect->width = 0;
13687   rect->height = 0;
13688
13689   if (path)
13690     {
13691       /* Get vertical coords */
13692
13693       if (!_gtk_tree_view_find_node (tree_view, path, &tree, &node) &&
13694           tree == NULL)
13695         return;
13696
13697       rect->y = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
13698       rect->height = gtk_tree_view_get_row_height (tree_view, node);
13699     }
13700
13701   if (column)
13702     {
13703       gint x2 = 0;
13704
13705       gtk_tree_view_get_background_xrange (tree_view, tree, column, &rect->x, &x2);
13706       rect->width = x2 - rect->x;
13707     }
13708 }
13709
13710 /**
13711  * gtk_tree_view_get_visible_rect:
13712  * @tree_view: a #GtkTreeView
13713  * @visible_rect: (out): rectangle to fill
13714  *
13715  * Fills @visible_rect with the currently-visible region of the
13716  * buffer, in tree coordinates. Convert to bin_window coordinates with
13717  * gtk_tree_view_convert_tree_to_bin_window_coords().
13718  * Tree coordinates start at 0,0 for row 0 of the tree, and cover the entire
13719  * scrollable area of the tree.
13720  **/
13721 void
13722 gtk_tree_view_get_visible_rect (GtkTreeView  *tree_view,
13723                                 GdkRectangle *visible_rect)
13724 {
13725   GtkAllocation allocation;
13726   GtkWidget *widget;
13727
13728   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13729
13730   widget = GTK_WIDGET (tree_view);
13731
13732   if (visible_rect)
13733     {
13734       gtk_widget_get_allocation (widget, &allocation);
13735       visible_rect->x = gtk_adjustment_get_value (tree_view->priv->hadjustment);
13736       visible_rect->y = gtk_adjustment_get_value (tree_view->priv->vadjustment);
13737       visible_rect->width = allocation.width;
13738       visible_rect->height = allocation.height - gtk_tree_view_get_effective_header_height (tree_view);
13739     }
13740 }
13741
13742 /**
13743  * gtk_tree_view_convert_widget_to_tree_coords:
13744  * @tree_view: a #GtkTreeView
13745  * @wx: X coordinate relative to the widget
13746  * @wy: Y coordinate relative to the widget
13747  * @tx: (out): return location for tree X coordinate
13748  * @ty: (out): return location for tree Y coordinate
13749  *
13750  * Converts widget coordinates to coordinates for the
13751  * tree (the full scrollable area of the tree).
13752  *
13753  * Since: 2.12
13754  **/
13755 void
13756 gtk_tree_view_convert_widget_to_tree_coords (GtkTreeView *tree_view,
13757                                              gint         wx,
13758                                              gint         wy,
13759                                              gint        *tx,
13760                                              gint        *ty)
13761 {
13762   gint x, y;
13763
13764   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13765
13766   gtk_tree_view_convert_widget_to_bin_window_coords (tree_view,
13767                                                      wx, wy,
13768                                                      &x, &y);
13769   gtk_tree_view_convert_bin_window_to_tree_coords (tree_view,
13770                                                    x, y,
13771                                                    tx, ty);
13772 }
13773
13774 /**
13775  * gtk_tree_view_convert_tree_to_widget_coords:
13776  * @tree_view: a #GtkTreeView
13777  * @tx: X coordinate relative to the tree
13778  * @ty: Y coordinate relative to the tree
13779  * @wx: (out): return location for widget X coordinate
13780  * @wy: (out): return location for widget Y coordinate
13781  *
13782  * Converts tree coordinates (coordinates in full scrollable area of the tree)
13783  * to widget coordinates.
13784  *
13785  * Since: 2.12
13786  **/
13787 void
13788 gtk_tree_view_convert_tree_to_widget_coords (GtkTreeView *tree_view,
13789                                              gint         tx,
13790                                              gint         ty,
13791                                              gint        *wx,
13792                                              gint        *wy)
13793 {
13794   gint x, y;
13795
13796   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13797
13798   gtk_tree_view_convert_tree_to_bin_window_coords (tree_view,
13799                                                    tx, ty,
13800                                                    &x, &y);
13801   gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
13802                                                      x, y,
13803                                                      wx, wy);
13804 }
13805
13806 /**
13807  * gtk_tree_view_convert_widget_to_bin_window_coords:
13808  * @tree_view: a #GtkTreeView
13809  * @wx: X coordinate relative to the widget
13810  * @wy: Y coordinate relative to the widget
13811  * @bx: (out): return location for bin_window X coordinate
13812  * @by: (out): return location for bin_window Y coordinate
13813  *
13814  * Converts widget coordinates to coordinates for the bin_window
13815  * (see gtk_tree_view_get_bin_window()).
13816  *
13817  * Since: 2.12
13818  **/
13819 void
13820 gtk_tree_view_convert_widget_to_bin_window_coords (GtkTreeView *tree_view,
13821                                                    gint         wx,
13822                                                    gint         wy,
13823                                                    gint        *bx,
13824                                                    gint        *by)
13825 {
13826   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13827
13828   if (bx)
13829     *bx = wx + gtk_adjustment_get_value (tree_view->priv->hadjustment);
13830   if (by)
13831     *by = wy - gtk_tree_view_get_effective_header_height (tree_view);
13832 }
13833
13834 /**
13835  * gtk_tree_view_convert_bin_window_to_widget_coords:
13836  * @tree_view: a #GtkTreeView
13837  * @bx: bin_window X coordinate
13838  * @by: bin_window Y coordinate
13839  * @wx: (out): return location for widget X coordinate
13840  * @wy: (out): return location for widget Y coordinate
13841  *
13842  * Converts bin_window coordinates (see gtk_tree_view_get_bin_window())
13843  * to widget relative coordinates.
13844  *
13845  * Since: 2.12
13846  **/
13847 void
13848 gtk_tree_view_convert_bin_window_to_widget_coords (GtkTreeView *tree_view,
13849                                                    gint         bx,
13850                                                    gint         by,
13851                                                    gint        *wx,
13852                                                    gint        *wy)
13853 {
13854   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13855
13856   if (wx)
13857     *wx = bx - gtk_adjustment_get_value (tree_view->priv->hadjustment);
13858   if (wy)
13859     *wy = by + gtk_tree_view_get_effective_header_height (tree_view);
13860 }
13861
13862 /**
13863  * gtk_tree_view_convert_tree_to_bin_window_coords:
13864  * @tree_view: a #GtkTreeView
13865  * @tx: tree X coordinate
13866  * @ty: tree Y coordinate
13867  * @bx: (out): return location for X coordinate relative to bin_window
13868  * @by: (out): return location for Y coordinate relative to bin_window
13869  *
13870  * Converts tree coordinates (coordinates in full scrollable area of the tree)
13871  * to bin_window coordinates.
13872  *
13873  * Since: 2.12
13874  **/
13875 void
13876 gtk_tree_view_convert_tree_to_bin_window_coords (GtkTreeView *tree_view,
13877                                                  gint         tx,
13878                                                  gint         ty,
13879                                                  gint        *bx,
13880                                                  gint        *by)
13881 {
13882   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13883
13884   if (bx)
13885     *bx = tx;
13886   if (by)
13887     *by = ty - tree_view->priv->dy;
13888 }
13889
13890 /**
13891  * gtk_tree_view_convert_bin_window_to_tree_coords:
13892  * @tree_view: a #GtkTreeView
13893  * @bx: X coordinate relative to bin_window
13894  * @by: Y coordinate relative to bin_window
13895  * @tx: (out): return location for tree X coordinate
13896  * @ty: (out): return location for tree Y coordinate
13897  *
13898  * Converts bin_window coordinates to coordinates for the
13899  * tree (the full scrollable area of the tree).
13900  *
13901  * Since: 2.12
13902  **/
13903 void
13904 gtk_tree_view_convert_bin_window_to_tree_coords (GtkTreeView *tree_view,
13905                                                  gint         bx,
13906                                                  gint         by,
13907                                                  gint        *tx,
13908                                                  gint        *ty)
13909 {
13910   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13911
13912   if (tx)
13913     *tx = bx;
13914   if (ty)
13915     *ty = by + tree_view->priv->dy;
13916 }
13917
13918
13919
13920 /**
13921  * gtk_tree_view_get_visible_range:
13922  * @tree_view: A #GtkTreeView
13923  * @start_path: (out) (allow-none): Return location for start of region,
13924  *              or %NULL.
13925  * @end_path: (out) (allow-none): Return location for end of region, or %NULL.
13926  *
13927  * Sets @start_path and @end_path to be the first and last visible path.
13928  * Note that there may be invisible paths in between.
13929  *
13930  * The paths should be freed with gtk_tree_path_free() after use.
13931  *
13932  * Returns: %TRUE, if valid paths were placed in @start_path and @end_path.
13933  *
13934  * Since: 2.8
13935  **/
13936 gboolean
13937 gtk_tree_view_get_visible_range (GtkTreeView  *tree_view,
13938                                  GtkTreePath **start_path,
13939                                  GtkTreePath **end_path)
13940 {
13941   GtkRBTree *tree;
13942   GtkRBNode *node;
13943   gboolean retval;
13944   
13945   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
13946
13947   if (!tree_view->priv->tree)
13948     return FALSE;
13949
13950   retval = TRUE;
13951
13952   if (start_path)
13953     {
13954       _gtk_rbtree_find_offset (tree_view->priv->tree,
13955                                TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, 0),
13956                                &tree, &node);
13957       if (node)
13958         *start_path = _gtk_tree_path_new_from_rbtree (tree, node);
13959       else
13960         retval = FALSE;
13961     }
13962
13963   if (end_path)
13964     {
13965       gint y;
13966
13967       if (tree_view->priv->height < gtk_adjustment_get_page_size (tree_view->priv->vadjustment))
13968         y = tree_view->priv->height - 1;
13969       else
13970         y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, gtk_adjustment_get_page_size (tree_view->priv->vadjustment)) - 1;
13971
13972       _gtk_rbtree_find_offset (tree_view->priv->tree, y, &tree, &node);
13973       if (node)
13974         *end_path = _gtk_tree_path_new_from_rbtree (tree, node);
13975       else
13976         retval = FALSE;
13977     }
13978
13979   return retval;
13980 }
13981
13982 /**
13983  * gtk_tree_view_is_blank_at_pos:
13984  * @tree_view: A #GtkTreeView
13985  * @x: The x position to be identified (relative to bin_window)
13986  * @y: The y position to be identified (relative to bin_window)
13987  * @path: (out) (allow-none): A pointer to a #GtkTreePath pointer to be filled in, or %NULL
13988  * @column: (out) (allow-none): A pointer to a #GtkTreeViewColumn pointer to be filled in, or %NULL
13989  * @cell_x: (out) (allow-none): A pointer where the X coordinate relative to the cell can be placed, or %NULL
13990  * @cell_y: (out) (allow-none): A pointer where the Y coordinate relative to the cell can be placed, or %NULL
13991  *
13992  * Determine whether the point (@x, @y) in @tree_view is blank, that is no
13993  * cell content nor an expander arrow is drawn at the location. If so, the
13994  * location can be considered as the background. You might wish to take
13995  * special action on clicks on the background, such as clearing a current
13996  * selection, having a custom context menu or starting rubber banding.
13997  *
13998  * The @x and @y coordinate that are provided must be relative to bin_window
13999  * coordinates.  That is, @x and @y must come from an event on @tree_view
14000  * where <literal>event->window == gtk_tree_view_get_bin_window (<!-- -->)</literal>.
14001  *
14002  * For converting widget coordinates (eg. the ones you get from
14003  * GtkWidget::query-tooltip), please see
14004  * gtk_tree_view_convert_widget_to_bin_window_coords().
14005  *
14006  * The @path, @column, @cell_x and @cell_y arguments will be filled in
14007  * likewise as for gtk_tree_view_get_path_at_pos().  Please see
14008  * gtk_tree_view_get_path_at_pos() for more information.
14009  *
14010  * Return value: %TRUE if the area at the given coordinates is blank,
14011  * %FALSE otherwise.
14012  *
14013  * Since: 3.0
14014  */
14015 gboolean
14016 gtk_tree_view_is_blank_at_pos (GtkTreeView       *tree_view,
14017                                gint                x,
14018                                gint                y,
14019                                GtkTreePath       **path,
14020                                GtkTreeViewColumn **column,
14021                                gint               *cell_x,
14022                                gint               *cell_y)
14023 {
14024   GtkRBTree *tree;
14025   GtkRBNode *node;
14026   GtkTreeIter iter;
14027   GtkTreePath *real_path;
14028   GtkTreeViewColumn *real_column;
14029   GdkRectangle cell_area, background_area;
14030
14031   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
14032
14033   if (!gtk_tree_view_get_path_at_pos (tree_view, x, y,
14034                                       &real_path, &real_column,
14035                                       cell_x, cell_y))
14036     /* If there's no path here, it is blank */
14037     return TRUE;
14038
14039   if (path)
14040     *path = real_path;
14041
14042   if (column)
14043     *column = real_column;
14044
14045   gtk_tree_model_get_iter (tree_view->priv->model, &iter, real_path);
14046   _gtk_tree_view_find_node (tree_view, real_path, &tree, &node);
14047
14048   /* Check if there's an expander arrow at (x, y) */
14049   if (real_column == tree_view->priv->expander_column
14050       && gtk_tree_view_draw_expanders (tree_view))
14051     {
14052       gboolean over_arrow;
14053
14054       over_arrow = coords_are_over_arrow (tree_view, tree, node, x, y);
14055
14056       if (over_arrow)
14057         {
14058           if (!path)
14059             gtk_tree_path_free (real_path);
14060           return FALSE;
14061         }
14062     }
14063
14064   /* Otherwise, have the column see if there's a cell at (x, y) */
14065   gtk_tree_view_column_cell_set_cell_data (real_column,
14066                                            tree_view->priv->model,
14067                                            &iter,
14068                                            GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
14069                                            node->children ? TRUE : FALSE);
14070
14071   gtk_tree_view_get_background_area (tree_view, real_path, real_column,
14072                                      &background_area);
14073   gtk_tree_view_get_cell_area (tree_view, real_path, real_column,
14074                                &cell_area);
14075
14076   if (!path)
14077     gtk_tree_path_free (real_path);
14078
14079   return _gtk_tree_view_column_is_blank_at_pos (real_column,
14080                                                 &cell_area,
14081                                                 &background_area,
14082                                                 x, y);
14083 }
14084
14085 static void
14086 unset_reorderable (GtkTreeView *tree_view)
14087 {
14088   if (tree_view->priv->reorderable)
14089     {
14090       tree_view->priv->reorderable = FALSE;
14091       g_object_notify (G_OBJECT (tree_view), "reorderable");
14092     }
14093 }
14094
14095 /**
14096  * gtk_tree_view_enable_model_drag_source:
14097  * @tree_view: a #GtkTreeView
14098  * @start_button_mask: Mask of allowed buttons to start drag
14099  * @targets: (array length=n_targets): the table of targets that the drag will support
14100  * @n_targets: the number of items in @targets
14101  * @actions: the bitmask of possible actions for a drag from this
14102  *    widget
14103  *
14104  * Turns @tree_view into a drag source for automatic DND. Calling this
14105  * method sets #GtkTreeView:reorderable to %FALSE.
14106  **/
14107 void
14108 gtk_tree_view_enable_model_drag_source (GtkTreeView              *tree_view,
14109                                         GdkModifierType           start_button_mask,
14110                                         const GtkTargetEntry     *targets,
14111                                         gint                      n_targets,
14112                                         GdkDragAction             actions)
14113 {
14114   TreeViewDragInfo *di;
14115
14116   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14117
14118   gtk_drag_source_set (GTK_WIDGET (tree_view),
14119                        0,
14120                        targets,
14121                        n_targets,
14122                        actions);
14123
14124   di = ensure_info (tree_view);
14125
14126   di->start_button_mask = start_button_mask;
14127   di->source_actions = actions;
14128   di->source_set = TRUE;
14129
14130   unset_reorderable (tree_view);
14131 }
14132
14133 /**
14134  * gtk_tree_view_enable_model_drag_dest:
14135  * @tree_view: a #GtkTreeView
14136  * @targets: (array length=n_targets): the table of targets that
14137  *           the drag will support
14138  * @n_targets: the number of items in @targets
14139  * @actions: the bitmask of possible actions for a drag from this
14140  *    widget
14141  * 
14142  * Turns @tree_view into a drop destination for automatic DND. Calling
14143  * this method sets #GtkTreeView:reorderable to %FALSE.
14144  **/
14145 void
14146 gtk_tree_view_enable_model_drag_dest (GtkTreeView              *tree_view,
14147                                       const GtkTargetEntry     *targets,
14148                                       gint                      n_targets,
14149                                       GdkDragAction             actions)
14150 {
14151   TreeViewDragInfo *di;
14152
14153   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14154
14155   gtk_drag_dest_set (GTK_WIDGET (tree_view),
14156                      0,
14157                      targets,
14158                      n_targets,
14159                      actions);
14160
14161   di = ensure_info (tree_view);
14162   di->dest_set = TRUE;
14163
14164   unset_reorderable (tree_view);
14165 }
14166
14167 /**
14168  * gtk_tree_view_unset_rows_drag_source:
14169  * @tree_view: a #GtkTreeView
14170  *
14171  * Undoes the effect of
14172  * gtk_tree_view_enable_model_drag_source(). Calling this method sets
14173  * #GtkTreeView:reorderable to %FALSE.
14174  **/
14175 void
14176 gtk_tree_view_unset_rows_drag_source (GtkTreeView *tree_view)
14177 {
14178   TreeViewDragInfo *di;
14179
14180   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14181
14182   di = get_info (tree_view);
14183
14184   if (di)
14185     {
14186       if (di->source_set)
14187         {
14188           gtk_drag_source_unset (GTK_WIDGET (tree_view));
14189           di->source_set = FALSE;
14190         }
14191
14192       if (!di->dest_set && !di->source_set)
14193         remove_info (tree_view);
14194     }
14195   
14196   unset_reorderable (tree_view);
14197 }
14198
14199 /**
14200  * gtk_tree_view_unset_rows_drag_dest:
14201  * @tree_view: a #GtkTreeView
14202  *
14203  * Undoes the effect of
14204  * gtk_tree_view_enable_model_drag_dest(). Calling this method sets
14205  * #GtkTreeView:reorderable to %FALSE.
14206  **/
14207 void
14208 gtk_tree_view_unset_rows_drag_dest (GtkTreeView *tree_view)
14209 {
14210   TreeViewDragInfo *di;
14211
14212   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14213
14214   di = get_info (tree_view);
14215
14216   if (di)
14217     {
14218       if (di->dest_set)
14219         {
14220           gtk_drag_dest_unset (GTK_WIDGET (tree_view));
14221           di->dest_set = FALSE;
14222         }
14223
14224       if (!di->dest_set && !di->source_set)
14225         remove_info (tree_view);
14226     }
14227
14228   unset_reorderable (tree_view);
14229 }
14230
14231 /**
14232  * gtk_tree_view_set_drag_dest_row:
14233  * @tree_view: a #GtkTreeView
14234  * @path: (allow-none): The path of the row to highlight, or %NULL
14235  * @pos: Specifies whether to drop before, after or into the row
14236  *
14237  * Sets the row that is highlighted for feedback.
14238  * If @path is %NULL, an existing highlight is removed.
14239  */
14240 void
14241 gtk_tree_view_set_drag_dest_row (GtkTreeView            *tree_view,
14242                                  GtkTreePath            *path,
14243                                  GtkTreeViewDropPosition pos)
14244 {
14245   GtkTreePath *current_dest;
14246
14247   /* Note; this function is exported to allow a custom DND
14248    * implementation, so it can't touch TreeViewDragInfo
14249    */
14250
14251   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14252
14253   current_dest = NULL;
14254
14255   if (tree_view->priv->drag_dest_row)
14256     {
14257       current_dest = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
14258       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
14259     }
14260
14261   /* special case a drop on an empty model */
14262   tree_view->priv->empty_view_drop = 0;
14263
14264   if (pos == GTK_TREE_VIEW_DROP_BEFORE && path
14265       && gtk_tree_path_get_depth (path) == 1
14266       && gtk_tree_path_get_indices (path)[0] == 0)
14267     {
14268       gint n_children;
14269
14270       n_children = gtk_tree_model_iter_n_children (tree_view->priv->model,
14271                                                    NULL);
14272
14273       if (!n_children)
14274         tree_view->priv->empty_view_drop = 1;
14275     }
14276
14277   tree_view->priv->drag_dest_pos = pos;
14278
14279   if (path)
14280     {
14281       tree_view->priv->drag_dest_row =
14282         gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
14283       gtk_tree_view_queue_draw_path (tree_view, path, NULL);
14284     }
14285   else
14286     tree_view->priv->drag_dest_row = NULL;
14287
14288   if (current_dest)
14289     {
14290       GtkRBTree *tree, *new_tree;
14291       GtkRBNode *node, *new_node;
14292
14293       _gtk_tree_view_find_node (tree_view, current_dest, &tree, &node);
14294       _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
14295
14296       if (tree && node)
14297         {
14298           _gtk_rbtree_next_full (tree, node, &new_tree, &new_node);
14299           if (new_tree && new_node)
14300             _gtk_tree_view_queue_draw_node (tree_view, new_tree, new_node, NULL);
14301
14302           _gtk_rbtree_prev_full (tree, node, &new_tree, &new_node);
14303           if (new_tree && new_node)
14304             _gtk_tree_view_queue_draw_node (tree_view, new_tree, new_node, NULL);
14305         }
14306       gtk_tree_path_free (current_dest);
14307     }
14308 }
14309
14310 /**
14311  * gtk_tree_view_get_drag_dest_row:
14312  * @tree_view: a #GtkTreeView
14313  * @path: (out) (allow-none): Return location for the path of the highlighted row, or %NULL.
14314  * @pos: (out) (allow-none): Return location for the drop position, or %NULL
14315  * 
14316  * Gets information about the row that is highlighted for feedback.
14317  **/
14318 void
14319 gtk_tree_view_get_drag_dest_row (GtkTreeView              *tree_view,
14320                                  GtkTreePath             **path,
14321                                  GtkTreeViewDropPosition  *pos)
14322 {
14323   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14324
14325   if (path)
14326     {
14327       if (tree_view->priv->drag_dest_row)
14328         *path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
14329       else
14330         {
14331           if (tree_view->priv->empty_view_drop)
14332             *path = gtk_tree_path_new_from_indices (0, -1);
14333           else
14334             *path = NULL;
14335         }
14336     }
14337
14338   if (pos)
14339     *pos = tree_view->priv->drag_dest_pos;
14340 }
14341
14342 /**
14343  * gtk_tree_view_get_dest_row_at_pos:
14344  * @tree_view: a #GtkTreeView
14345  * @drag_x: the position to determine the destination row for
14346  * @drag_y: the position to determine the destination row for
14347  * @path: (out) (allow-none): Return location for the path of the highlighted row, or %NULL.
14348  * @pos: (out) (allow-none): Return location for the drop position, or %NULL
14349  * 
14350  * Determines the destination row for a given position.  @drag_x and
14351  * @drag_y are expected to be in widget coordinates.  This function is only
14352  * meaningful if @tree_view is realized.  Therefore this function will always
14353  * return %FALSE if @tree_view is not realized or does not have a model.
14354  * 
14355  * Return value: whether there is a row at the given position, %TRUE if this
14356  * is indeed the case.
14357  **/
14358 gboolean
14359 gtk_tree_view_get_dest_row_at_pos (GtkTreeView             *tree_view,
14360                                    gint                     drag_x,
14361                                    gint                     drag_y,
14362                                    GtkTreePath            **path,
14363                                    GtkTreeViewDropPosition *pos)
14364 {
14365   gint cell_y;
14366   gint bin_x, bin_y;
14367   gdouble offset_into_row;
14368   gdouble third;
14369   GdkRectangle cell;
14370   GtkTreeViewColumn *column = NULL;
14371   GtkTreePath *tmp_path = NULL;
14372
14373   /* Note; this function is exported to allow a custom DND
14374    * implementation, so it can't touch TreeViewDragInfo
14375    */
14376
14377   g_return_val_if_fail (tree_view != NULL, FALSE);
14378   g_return_val_if_fail (drag_x >= 0, FALSE);
14379   g_return_val_if_fail (drag_y >= 0, FALSE);
14380
14381   if (path)
14382     *path = NULL;
14383
14384   if (tree_view->priv->bin_window == NULL)
14385     return FALSE;
14386
14387   if (tree_view->priv->tree == NULL)
14388     return FALSE;
14389
14390   /* If in the top third of a row, we drop before that row; if
14391    * in the bottom third, drop after that row; if in the middle,
14392    * and the row has children, drop into the row.
14393    */
14394   gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, drag_x, drag_y,
14395                                                      &bin_x, &bin_y);
14396
14397   if (!gtk_tree_view_get_path_at_pos (tree_view,
14398                                       bin_x,
14399                                       bin_y,
14400                                       &tmp_path,
14401                                       &column,
14402                                       NULL,
14403                                       &cell_y))
14404     return FALSE;
14405
14406   gtk_tree_view_get_background_area (tree_view, tmp_path, column,
14407                                      &cell);
14408
14409   offset_into_row = cell_y;
14410
14411   if (path)
14412     *path = tmp_path;
14413   else
14414     gtk_tree_path_free (tmp_path);
14415
14416   tmp_path = NULL;
14417
14418   third = cell.height / 3.0;
14419
14420   if (pos)
14421     {
14422       if (offset_into_row < third)
14423         {
14424           *pos = GTK_TREE_VIEW_DROP_BEFORE;
14425         }
14426       else if (offset_into_row < (cell.height / 2.0))
14427         {
14428           *pos = GTK_TREE_VIEW_DROP_INTO_OR_BEFORE;
14429         }
14430       else if (offset_into_row < third * 2.0)
14431         {
14432           *pos = GTK_TREE_VIEW_DROP_INTO_OR_AFTER;
14433         }
14434       else
14435         {
14436           *pos = GTK_TREE_VIEW_DROP_AFTER;
14437         }
14438     }
14439
14440   return TRUE;
14441 }
14442
14443
14444
14445 /* KEEP IN SYNC WITH GTK_TREE_VIEW_BIN_EXPOSE */
14446 /**
14447  * gtk_tree_view_create_row_drag_icon:
14448  * @tree_view: a #GtkTreeView
14449  * @path: a #GtkTreePath in @tree_view
14450  *
14451  * Creates a #cairo_surface_t representation of the row at @path.  
14452  * This image is used for a drag icon.
14453  *
14454  * Return value: (transfer full): a newly-allocated surface of the drag icon.
14455  **/
14456 cairo_surface_t *
14457 gtk_tree_view_create_row_drag_icon (GtkTreeView  *tree_view,
14458                                     GtkTreePath  *path)
14459 {
14460   GtkTreeIter   iter;
14461   GtkRBTree    *tree;
14462   GtkRBNode    *node;
14463   GtkStyleContext *context;
14464   gint cell_offset;
14465   GList *list;
14466   GdkRectangle background_area;
14467   GtkWidget *widget;
14468   gint depth;
14469   /* start drawing inside the black outline */
14470   gint x = 1, y = 1;
14471   cairo_surface_t *surface;
14472   gint bin_window_width;
14473   gboolean is_separator = FALSE;
14474   gboolean rtl, allow_rules;
14475   cairo_t *cr;
14476
14477   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14478   g_return_val_if_fail (path != NULL, NULL);
14479
14480   widget = GTK_WIDGET (tree_view);
14481
14482   if (!gtk_widget_get_realized (widget))
14483     return NULL;
14484
14485   depth = gtk_tree_path_get_depth (path);
14486
14487   _gtk_tree_view_find_node (tree_view,
14488                             path,
14489                             &tree,
14490                             &node);
14491
14492   if (tree == NULL)
14493     return NULL;
14494
14495   if (!gtk_tree_model_get_iter (tree_view->priv->model,
14496                                 &iter,
14497                                 path))
14498     return NULL;
14499
14500   context = gtk_widget_get_style_context (widget);
14501
14502   gtk_style_context_save (context);
14503   gtk_style_context_add_region (context, GTK_STYLE_REGION_COLUMN, 0);
14504
14505   gtk_widget_style_get (widget,
14506                         "allow-rules", &allow_rules,
14507                         NULL);
14508
14509   if (allow_rules && tree_view->priv->has_rules)
14510     {
14511       GtkRegionFlags row_flags;
14512
14513       if ((_gtk_rbtree_node_get_index (tree, node) % 2))
14514         row_flags = GTK_REGION_ODD;
14515       else
14516         row_flags = GTK_REGION_EVEN;
14517
14518       gtk_style_context_add_region (context, GTK_STYLE_REGION_ROW, row_flags);
14519     }
14520
14521   is_separator = row_is_separator (tree_view, &iter, NULL);
14522
14523   cell_offset = x;
14524
14525   background_area.y = y;
14526   background_area.height = gtk_tree_view_get_row_height (tree_view, node);
14527
14528   bin_window_width = gdk_window_get_width (tree_view->priv->bin_window);
14529
14530   surface = gdk_window_create_similar_surface (tree_view->priv->bin_window,
14531                                                CAIRO_CONTENT_COLOR,
14532                                                bin_window_width + 2,
14533                                                background_area.height + 2);
14534
14535   cr = cairo_create (surface);
14536
14537   gtk_render_background (context, cr, 0, 0,
14538                          bin_window_width + 2,
14539                          background_area.height + 2);
14540
14541   rtl = gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL;
14542
14543   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
14544       list;
14545       list = (rtl ? list->prev : list->next))
14546     {
14547       GtkTreeViewColumn *column = list->data;
14548       GdkRectangle cell_area;
14549       gint vertical_separator;
14550
14551       if (!gtk_tree_view_column_get_visible (column))
14552         continue;
14553
14554       gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, &iter,
14555                                                GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
14556                                                node->children?TRUE:FALSE);
14557
14558       background_area.x = cell_offset;
14559       background_area.width = gtk_tree_view_column_get_width (column);
14560
14561       gtk_widget_style_get (widget,
14562                             "vertical-separator", &vertical_separator,
14563                             NULL);
14564
14565       cell_area = background_area;
14566
14567       cell_area.y += vertical_separator / 2;
14568       cell_area.height -= vertical_separator;
14569
14570       if (gtk_tree_view_is_expander_column (tree_view, column))
14571         {
14572           if (!rtl)
14573             cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
14574           cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
14575
14576           if (gtk_tree_view_draw_expanders (tree_view))
14577             {
14578               int expander_size = gtk_tree_view_get_expander_size (tree_view);
14579               if (!rtl)
14580                 cell_area.x += depth * expander_size;
14581               cell_area.width -= depth * expander_size;
14582             }
14583         }
14584
14585       if (gtk_tree_view_column_cell_is_visible (column))
14586         {
14587           if (is_separator)
14588             {
14589               gtk_style_context_save (context);
14590               gtk_style_context_add_class (context, GTK_STYLE_CLASS_SEPARATOR);
14591
14592               gtk_render_line (context, cr,
14593                                cell_area.x,
14594                                cell_area.y + cell_area.height / 2,
14595                                cell_area.x + cell_area.width,
14596                                cell_area.y + cell_area.height / 2);
14597
14598               gtk_style_context_restore (context);
14599             }
14600           else
14601             {
14602               _gtk_tree_view_column_cell_render (column,
14603                                                  cr,
14604                                                  &background_area,
14605                                                  &cell_area,
14606                                                  0, FALSE);
14607             }
14608         }
14609       cell_offset += gtk_tree_view_column_get_width (column);
14610     }
14611
14612   cairo_set_source_rgb (cr, 0, 0, 0);
14613   cairo_rectangle (cr, 
14614                    0.5, 0.5, 
14615                    bin_window_width + 1,
14616                    background_area.height + 1);
14617   cairo_set_line_width (cr, 1.0);
14618   cairo_stroke (cr);
14619
14620   cairo_destroy (cr);
14621
14622   cairo_surface_set_device_offset (surface, 2, 2);
14623
14624   gtk_style_context_restore (context);
14625
14626   return surface;
14627 }
14628
14629
14630 /**
14631  * gtk_tree_view_set_destroy_count_func:
14632  * @tree_view: A #GtkTreeView
14633  * @func: (allow-none): Function to be called when a view row is destroyed, or %NULL
14634  * @data: (allow-none): User data to be passed to @func, or %NULL
14635  * @destroy: (allow-none): Destroy notifier for @data, or %NULL
14636  *
14637  * This function should almost never be used.  It is meant for private use by
14638  * ATK for determining the number of visible children that are removed when the
14639  * user collapses a row, or a row is deleted.
14640  *
14641  * Deprecated: 3.4: Accessibility does not need the function anymore.
14642  **/
14643 void
14644 gtk_tree_view_set_destroy_count_func (GtkTreeView             *tree_view,
14645                                       GtkTreeDestroyCountFunc  func,
14646                                       gpointer                 data,
14647                                       GDestroyNotify           destroy)
14648 {
14649   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14650
14651   if (tree_view->priv->destroy_count_destroy)
14652     tree_view->priv->destroy_count_destroy (tree_view->priv->destroy_count_data);
14653
14654   tree_view->priv->destroy_count_func = func;
14655   tree_view->priv->destroy_count_data = data;
14656   tree_view->priv->destroy_count_destroy = destroy;
14657 }
14658
14659
14660 /*
14661  * Interactive search
14662  */
14663
14664 /**
14665  * gtk_tree_view_set_enable_search:
14666  * @tree_view: A #GtkTreeView
14667  * @enable_search: %TRUE, if the user can search interactively
14668  *
14669  * If @enable_search is set, then the user can type in text to search through
14670  * the tree interactively (this is sometimes called "typeahead find").
14671  * 
14672  * Note that even if this is %FALSE, the user can still initiate a search 
14673  * using the "start-interactive-search" key binding.
14674  */
14675 void
14676 gtk_tree_view_set_enable_search (GtkTreeView *tree_view,
14677                                  gboolean     enable_search)
14678 {
14679   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14680
14681   enable_search = !!enable_search;
14682   
14683   if (tree_view->priv->enable_search != enable_search)
14684     {
14685        tree_view->priv->enable_search = enable_search;
14686        g_object_notify (G_OBJECT (tree_view), "enable-search");
14687     }
14688 }
14689
14690 /**
14691  * gtk_tree_view_get_enable_search:
14692  * @tree_view: A #GtkTreeView
14693  *
14694  * Returns whether or not the tree allows to start interactive searching 
14695  * by typing in text.
14696  *
14697  * Return value: whether or not to let the user search interactively
14698  */
14699 gboolean
14700 gtk_tree_view_get_enable_search (GtkTreeView *tree_view)
14701 {
14702   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
14703
14704   return tree_view->priv->enable_search;
14705 }
14706
14707
14708 /**
14709  * gtk_tree_view_get_search_column:
14710  * @tree_view: A #GtkTreeView
14711  *
14712  * Gets the column searched on by the interactive search code.
14713  *
14714  * Return value: the column the interactive search code searches in.
14715  */
14716 gint
14717 gtk_tree_view_get_search_column (GtkTreeView *tree_view)
14718 {
14719   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
14720
14721   return (tree_view->priv->search_column);
14722 }
14723
14724 /**
14725  * gtk_tree_view_set_search_column:
14726  * @tree_view: A #GtkTreeView
14727  * @column: the column of the model to search in, or -1 to disable searching
14728  *
14729  * Sets @column as the column where the interactive search code should
14730  * search in for the current model. 
14731  * 
14732  * If the search column is set, users can use the "start-interactive-search"
14733  * key binding to bring up search popup. The enable-search property controls
14734  * whether simply typing text will also start an interactive search.
14735  *
14736  * Note that @column refers to a column of the current model. The search 
14737  * column is reset to -1 when the model is changed.
14738  */
14739 void
14740 gtk_tree_view_set_search_column (GtkTreeView *tree_view,
14741                                  gint         column)
14742 {
14743   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14744   g_return_if_fail (column >= -1);
14745
14746   if (tree_view->priv->search_column == column)
14747     return;
14748
14749   tree_view->priv->search_column = column;
14750   g_object_notify (G_OBJECT (tree_view), "search-column");
14751 }
14752
14753 /**
14754  * gtk_tree_view_get_search_equal_func: (skip)
14755  * @tree_view: A #GtkTreeView
14756  *
14757  * Returns the compare function currently in use.
14758  *
14759  * Return value: the currently used compare function for the search code.
14760  */
14761
14762 GtkTreeViewSearchEqualFunc
14763 gtk_tree_view_get_search_equal_func (GtkTreeView *tree_view)
14764 {
14765   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14766
14767   return tree_view->priv->search_equal_func;
14768 }
14769
14770 /**
14771  * gtk_tree_view_set_search_equal_func:
14772  * @tree_view: A #GtkTreeView
14773  * @search_equal_func: the compare function to use during the search
14774  * @search_user_data: (allow-none): user data to pass to @search_equal_func, or %NULL
14775  * @search_destroy: (allow-none): Destroy notifier for @search_user_data, or %NULL
14776  *
14777  * Sets the compare function for the interactive search capabilities; note
14778  * that somewhat like strcmp() returning 0 for equality
14779  * #GtkTreeViewSearchEqualFunc returns %FALSE on matches.
14780  **/
14781 void
14782 gtk_tree_view_set_search_equal_func (GtkTreeView                *tree_view,
14783                                      GtkTreeViewSearchEqualFunc  search_equal_func,
14784                                      gpointer                    search_user_data,
14785                                      GDestroyNotify              search_destroy)
14786 {
14787   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14788   g_return_if_fail (search_equal_func != NULL);
14789
14790   if (tree_view->priv->search_destroy)
14791     tree_view->priv->search_destroy (tree_view->priv->search_user_data);
14792
14793   tree_view->priv->search_equal_func = search_equal_func;
14794   tree_view->priv->search_user_data = search_user_data;
14795   tree_view->priv->search_destroy = search_destroy;
14796   if (tree_view->priv->search_equal_func == NULL)
14797     tree_view->priv->search_equal_func = gtk_tree_view_search_equal_func;
14798 }
14799
14800 /**
14801  * gtk_tree_view_get_search_entry:
14802  * @tree_view: A #GtkTreeView
14803  *
14804  * Returns the #GtkEntry which is currently in use as interactive search
14805  * entry for @tree_view.  In case the built-in entry is being used, %NULL
14806  * will be returned.
14807  *
14808  * Return value: (transfer none): the entry currently in use as search entry.
14809  *
14810  * Since: 2.10
14811  */
14812 GtkEntry *
14813 gtk_tree_view_get_search_entry (GtkTreeView *tree_view)
14814 {
14815   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14816
14817   if (tree_view->priv->search_custom_entry_set)
14818     return GTK_ENTRY (tree_view->priv->search_entry);
14819
14820   return NULL;
14821 }
14822
14823 /**
14824  * gtk_tree_view_set_search_entry:
14825  * @tree_view: A #GtkTreeView
14826  * @entry: (allow-none): the entry the interactive search code of @tree_view should use or %NULL
14827  *
14828  * Sets the entry which the interactive search code will use for this
14829  * @tree_view.  This is useful when you want to provide a search entry
14830  * in our interface at all time at a fixed position.  Passing %NULL for
14831  * @entry will make the interactive search code use the built-in popup
14832  * entry again.
14833  *
14834  * Since: 2.10
14835  */
14836 void
14837 gtk_tree_view_set_search_entry (GtkTreeView *tree_view,
14838                                 GtkEntry    *entry)
14839 {
14840   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14841   g_return_if_fail (entry == NULL || GTK_IS_ENTRY (entry));
14842
14843   if (tree_view->priv->search_custom_entry_set)
14844     {
14845       if (tree_view->priv->search_entry_changed_id)
14846         {
14847           g_signal_handler_disconnect (tree_view->priv->search_entry,
14848                                        tree_view->priv->search_entry_changed_id);
14849           tree_view->priv->search_entry_changed_id = 0;
14850         }
14851       g_signal_handlers_disconnect_by_func (tree_view->priv->search_entry,
14852                                             G_CALLBACK (gtk_tree_view_search_key_press_event),
14853                                             tree_view);
14854
14855       g_object_unref (tree_view->priv->search_entry);
14856     }
14857   else if (tree_view->priv->search_window)
14858     {
14859       gtk_widget_destroy (tree_view->priv->search_window);
14860
14861       tree_view->priv->search_window = NULL;
14862     }
14863
14864   if (entry)
14865     {
14866       tree_view->priv->search_entry = g_object_ref (entry);
14867       tree_view->priv->search_custom_entry_set = TRUE;
14868
14869       if (tree_view->priv->search_entry_changed_id == 0)
14870         {
14871           tree_view->priv->search_entry_changed_id =
14872             g_signal_connect (tree_view->priv->search_entry, "changed",
14873                               G_CALLBACK (gtk_tree_view_search_init),
14874                               tree_view);
14875         }
14876       
14877         g_signal_connect (tree_view->priv->search_entry, "key-press-event",
14878                           G_CALLBACK (gtk_tree_view_search_key_press_event),
14879                           tree_view);
14880
14881         gtk_tree_view_search_init (tree_view->priv->search_entry, tree_view);
14882     }
14883   else
14884     {
14885       tree_view->priv->search_entry = NULL;
14886       tree_view->priv->search_custom_entry_set = FALSE;
14887     }
14888 }
14889
14890 /**
14891  * gtk_tree_view_set_search_position_func:
14892  * @tree_view: A #GtkTreeView
14893  * @func: (allow-none): the function to use to position the search dialog, or %NULL
14894  *    to use the default search position function
14895  * @data: (allow-none): user data to pass to @func, or %NULL
14896  * @destroy: (allow-none): Destroy notifier for @data, or %NULL
14897  *
14898  * Sets the function to use when positioning the search dialog.
14899  *
14900  * Since: 2.10
14901  **/
14902 void
14903 gtk_tree_view_set_search_position_func (GtkTreeView                   *tree_view,
14904                                         GtkTreeViewSearchPositionFunc  func,
14905                                         gpointer                       user_data,
14906                                         GDestroyNotify                 destroy)
14907 {
14908   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14909
14910   if (tree_view->priv->search_position_destroy)
14911     tree_view->priv->search_position_destroy (tree_view->priv->search_position_user_data);
14912
14913   tree_view->priv->search_position_func = func;
14914   tree_view->priv->search_position_user_data = user_data;
14915   tree_view->priv->search_position_destroy = destroy;
14916   if (tree_view->priv->search_position_func == NULL)
14917     tree_view->priv->search_position_func = gtk_tree_view_search_position_func;
14918 }
14919
14920 /**
14921  * gtk_tree_view_get_search_position_func: (skip)
14922  * @tree_view: A #GtkTreeView
14923  *
14924  * Returns the positioning function currently in use.
14925  *
14926  * Return value: the currently used function for positioning the search dialog.
14927  *
14928  * Since: 2.10
14929  */
14930 GtkTreeViewSearchPositionFunc
14931 gtk_tree_view_get_search_position_func (GtkTreeView *tree_view)
14932 {
14933   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14934
14935   return tree_view->priv->search_position_func;
14936 }
14937
14938
14939 static void
14940 gtk_tree_view_search_dialog_hide (GtkWidget   *search_dialog,
14941                                   GtkTreeView *tree_view,
14942                                   GdkDevice   *device)
14943 {
14944   if (tree_view->priv->disable_popdown)
14945     return;
14946
14947   if (tree_view->priv->search_entry_changed_id)
14948     {
14949       g_signal_handler_disconnect (tree_view->priv->search_entry,
14950                                    tree_view->priv->search_entry_changed_id);
14951       tree_view->priv->search_entry_changed_id = 0;
14952     }
14953   if (tree_view->priv->typeselect_flush_timeout)
14954     {
14955       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14956       tree_view->priv->typeselect_flush_timeout = 0;
14957     }
14958         
14959   if (gtk_widget_get_visible (search_dialog))
14960     {
14961       /* send focus-in event */
14962       send_focus_change (GTK_WIDGET (tree_view->priv->search_entry), device, FALSE);
14963       gtk_widget_hide (search_dialog);
14964       gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
14965       send_focus_change (GTK_WIDGET (tree_view), device, TRUE);
14966     }
14967 }
14968
14969 static void
14970 gtk_tree_view_search_position_func (GtkTreeView *tree_view,
14971                                     GtkWidget   *search_dialog,
14972                                     gpointer     user_data)
14973 {
14974   gint x, y;
14975   gint tree_x, tree_y;
14976   gint tree_width, tree_height;
14977   GdkWindow *tree_window = gtk_widget_get_window (GTK_WIDGET (tree_view));
14978   GdkScreen *screen = gdk_window_get_screen (tree_window);
14979   GtkRequisition requisition;
14980   gint monitor_num;
14981   GdkRectangle monitor;
14982
14983   monitor_num = gdk_screen_get_monitor_at_window (screen, tree_window);
14984   gdk_screen_get_monitor_workarea (screen, monitor_num, &monitor);
14985
14986   gtk_widget_realize (search_dialog);
14987
14988   gdk_window_get_origin (tree_window, &tree_x, &tree_y);
14989   tree_width = gdk_window_get_width (tree_window);
14990   tree_height = gdk_window_get_height (tree_window);
14991   gtk_widget_get_preferred_size (search_dialog, &requisition, NULL);
14992
14993   if (tree_x + tree_width > gdk_screen_get_width (screen))
14994     x = gdk_screen_get_width (screen) - requisition.width;
14995   else if (tree_x + tree_width - requisition.width < 0)
14996     x = 0;
14997   else
14998     x = tree_x + tree_width - requisition.width;
14999
15000   if (tree_y + tree_height + requisition.height > gdk_screen_get_height (screen))
15001     y = gdk_screen_get_height (screen) - requisition.height;
15002   else if (tree_y + tree_height < 0) /* isn't really possible ... */
15003     y = 0;
15004   else
15005     y = tree_y + tree_height;
15006
15007   gtk_window_move (GTK_WINDOW (search_dialog), x, y);
15008 }
15009
15010 static void
15011 gtk_tree_view_search_disable_popdown (GtkEntry *entry,
15012                                       GtkMenu  *menu,
15013                                       gpointer  data)
15014 {
15015   GtkTreeView *tree_view = (GtkTreeView *)data;
15016
15017   tree_view->priv->disable_popdown = 1;
15018   g_signal_connect (menu, "hide",
15019                     G_CALLBACK (gtk_tree_view_search_enable_popdown), data);
15020 }
15021
15022 /* Because we're visible but offscreen, we just set a flag in the preedit
15023  * callback.
15024  */
15025 static void
15026 gtk_tree_view_search_preedit_changed (GtkIMContext *im_context,
15027                                       GtkTreeView  *tree_view)
15028 {
15029   tree_view->priv->imcontext_changed = 1;
15030   if (tree_view->priv->typeselect_flush_timeout)
15031     {
15032       g_source_remove (tree_view->priv->typeselect_flush_timeout);
15033       tree_view->priv->typeselect_flush_timeout =
15034         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
15035                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
15036                        tree_view);
15037     }
15038
15039 }
15040
15041 static void
15042 gtk_tree_view_search_activate (GtkEntry    *entry,
15043                                GtkTreeView *tree_view)
15044 {
15045   GtkTreePath *path;
15046
15047   gtk_tree_view_search_dialog_hide (tree_view->priv->search_window,
15048                                     tree_view,
15049                                     gtk_get_current_event_device ());
15050
15051   /* If we have a row selected and it's the cursor row, we activate
15052    * the row XXX */
15053   if (tree_view->priv->cursor_node &&
15054       GTK_RBNODE_FLAG_SET (tree_view->priv->cursor_node, GTK_RBNODE_IS_SELECTED))
15055     {
15056       path = _gtk_tree_path_new_from_rbtree (tree_view->priv->cursor_tree,
15057                                              tree_view->priv->cursor_node);
15058       
15059       gtk_tree_view_row_activated (tree_view, path, tree_view->priv->focus_column);
15060       
15061       gtk_tree_path_free (path);
15062     }
15063 }
15064
15065 static gboolean
15066 gtk_tree_view_real_search_enable_popdown (gpointer data)
15067 {
15068   GtkTreeView *tree_view = (GtkTreeView *)data;
15069
15070   tree_view->priv->disable_popdown = 0;
15071
15072   return FALSE;
15073 }
15074
15075 static void
15076 gtk_tree_view_search_enable_popdown (GtkWidget *widget,
15077                                      gpointer   data)
15078 {
15079   gdk_threads_add_timeout_full (G_PRIORITY_HIGH, 200, gtk_tree_view_real_search_enable_popdown, g_object_ref (data), g_object_unref);
15080 }
15081
15082 static gboolean
15083 gtk_tree_view_search_delete_event (GtkWidget *widget,
15084                                    GdkEventAny *event,
15085                                    GtkTreeView *tree_view)
15086 {
15087   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
15088
15089   gtk_tree_view_search_dialog_hide (widget, tree_view, NULL);
15090
15091   return TRUE;
15092 }
15093
15094 static gboolean
15095 gtk_tree_view_search_button_press_event (GtkWidget *widget,
15096                                          GdkEventButton *event,
15097                                          GtkTreeView *tree_view)
15098 {
15099   GdkDevice *keyb_device;
15100
15101   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
15102
15103   keyb_device = gdk_device_get_associated_device (event->device);
15104   gtk_tree_view_search_dialog_hide (widget, tree_view, keyb_device);
15105
15106   if (event->window == tree_view->priv->bin_window)
15107     gtk_tree_view_button_press (GTK_WIDGET (tree_view), event);
15108
15109   return TRUE;
15110 }
15111
15112 static gboolean
15113 gtk_tree_view_search_scroll_event (GtkWidget *widget,
15114                                    GdkEventScroll *event,
15115                                    GtkTreeView *tree_view)
15116 {
15117   gboolean retval = FALSE;
15118
15119   if (event->direction == GDK_SCROLL_UP)
15120     {
15121       gtk_tree_view_search_move (widget, tree_view, TRUE);
15122       retval = TRUE;
15123     }
15124   else if (event->direction == GDK_SCROLL_DOWN)
15125     {
15126       gtk_tree_view_search_move (widget, tree_view, FALSE);
15127       retval = TRUE;
15128     }
15129
15130   /* renew the flush timeout */
15131   if (retval && tree_view->priv->typeselect_flush_timeout
15132       && !tree_view->priv->search_custom_entry_set)
15133     {
15134       g_source_remove (tree_view->priv->typeselect_flush_timeout);
15135       tree_view->priv->typeselect_flush_timeout =
15136         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
15137                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
15138                        tree_view);
15139     }
15140
15141   return retval;
15142 }
15143
15144 static gboolean
15145 gtk_tree_view_search_key_press_event (GtkWidget *widget,
15146                                       GdkEventKey *event,
15147                                       GtkTreeView *tree_view)
15148 {
15149   GdkModifierType default_accel;
15150   gboolean        retval = FALSE;
15151
15152   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
15153   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15154
15155   /* close window and cancel the search */
15156   if (!tree_view->priv->search_custom_entry_set
15157       && (event->keyval == GDK_KEY_Escape ||
15158           event->keyval == GDK_KEY_Tab ||
15159             event->keyval == GDK_KEY_KP_Tab ||
15160             event->keyval == GDK_KEY_ISO_Left_Tab))
15161     {
15162       gtk_tree_view_search_dialog_hide (widget, tree_view,
15163                                         gdk_event_get_device ((GdkEvent *) event));
15164       return TRUE;
15165     }
15166
15167   default_accel = gtk_widget_get_modifier_mask (widget,
15168                                                 GDK_MODIFIER_INTENT_PRIMARY_ACCELERATOR);
15169
15170   /* select previous matching iter */
15171   if (event->keyval == GDK_KEY_Up || event->keyval == GDK_KEY_KP_Up)
15172     {
15173       if (!gtk_tree_view_search_move (widget, tree_view, TRUE))
15174         gtk_widget_error_bell (widget);
15175
15176       retval = TRUE;
15177     }
15178
15179   if (((event->state & (default_accel | GDK_SHIFT_MASK)) == (default_accel | GDK_SHIFT_MASK))
15180       && (event->keyval == GDK_KEY_g || event->keyval == GDK_KEY_G))
15181     {
15182       if (!gtk_tree_view_search_move (widget, tree_view, TRUE))
15183         gtk_widget_error_bell (widget);
15184
15185       retval = TRUE;
15186     }
15187
15188   /* select next matching iter */
15189   if (event->keyval == GDK_KEY_Down || event->keyval == GDK_KEY_KP_Down)
15190     {
15191       if (!gtk_tree_view_search_move (widget, tree_view, FALSE))
15192         gtk_widget_error_bell (widget);
15193
15194       retval = TRUE;
15195     }
15196
15197   if (((event->state & (default_accel | GDK_SHIFT_MASK)) == default_accel)
15198       && (event->keyval == GDK_KEY_g || event->keyval == GDK_KEY_G))
15199     {
15200       if (!gtk_tree_view_search_move (widget, tree_view, FALSE))
15201         gtk_widget_error_bell (widget);
15202
15203       retval = TRUE;
15204     }
15205
15206   /* renew the flush timeout */
15207   if (retval && tree_view->priv->typeselect_flush_timeout
15208       && !tree_view->priv->search_custom_entry_set)
15209     {
15210       g_source_remove (tree_view->priv->typeselect_flush_timeout);
15211       tree_view->priv->typeselect_flush_timeout =
15212         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
15213                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
15214                        tree_view);
15215     }
15216
15217   return retval;
15218 }
15219
15220 /*  this function returns FALSE if there is a search string but
15221  *  nothing was found, and TRUE otherwise.
15222  */
15223 static gboolean
15224 gtk_tree_view_search_move (GtkWidget   *window,
15225                            GtkTreeView *tree_view,
15226                            gboolean     up)
15227 {
15228   gboolean ret;
15229   gint len;
15230   gint count = 0;
15231   const gchar *text;
15232   GtkTreeIter iter;
15233   GtkTreeModel *model;
15234   GtkTreeSelection *selection;
15235
15236   text = gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry));
15237
15238   g_return_val_if_fail (text != NULL, FALSE);
15239
15240   len = strlen (text);
15241
15242   if (up && tree_view->priv->selected_iter == 1)
15243     return strlen (text) < 1;
15244
15245   len = strlen (text);
15246
15247   if (len < 1)
15248     return TRUE;
15249
15250   model = gtk_tree_view_get_model (tree_view);
15251   selection = gtk_tree_view_get_selection (tree_view);
15252
15253   /* search */
15254   gtk_tree_selection_unselect_all (selection);
15255   if (!gtk_tree_model_get_iter_first (model, &iter))
15256     return TRUE;
15257
15258   ret = gtk_tree_view_search_iter (model, selection, &iter, text,
15259                                    &count, up?((tree_view->priv->selected_iter) - 1):((tree_view->priv->selected_iter + 1)));
15260
15261   if (ret)
15262     {
15263       /* found */
15264       tree_view->priv->selected_iter += up?(-1):(1);
15265       return TRUE;
15266     }
15267   else
15268     {
15269       /* return to old iter */
15270       count = 0;
15271       gtk_tree_model_get_iter_first (model, &iter);
15272       gtk_tree_view_search_iter (model, selection,
15273                                  &iter, text,
15274                                  &count, tree_view->priv->selected_iter);
15275       return FALSE;
15276     }
15277 }
15278
15279 static gboolean
15280 gtk_tree_view_search_equal_func (GtkTreeModel *model,
15281                                  gint          column,
15282                                  const gchar  *key,
15283                                  GtkTreeIter  *iter,
15284                                  gpointer      search_data)
15285 {
15286   gboolean retval = TRUE;
15287   const gchar *str;
15288   gchar *normalized_string;
15289   gchar *normalized_key;
15290   gchar *case_normalized_string = NULL;
15291   gchar *case_normalized_key = NULL;
15292   GValue value = G_VALUE_INIT;
15293   GValue transformed = G_VALUE_INIT;
15294
15295   gtk_tree_model_get_value (model, iter, column, &value);
15296
15297   g_value_init (&transformed, G_TYPE_STRING);
15298
15299   if (!g_value_transform (&value, &transformed))
15300     {
15301       g_value_unset (&value);
15302       return TRUE;
15303     }
15304
15305   g_value_unset (&value);
15306
15307   str = g_value_get_string (&transformed);
15308   if (!str)
15309     {
15310       g_value_unset (&transformed);
15311       return TRUE;
15312     }
15313
15314   normalized_string = g_utf8_normalize (str, -1, G_NORMALIZE_ALL);
15315   normalized_key = g_utf8_normalize (key, -1, G_NORMALIZE_ALL);
15316
15317   if (normalized_string && normalized_key)
15318     {
15319       case_normalized_string = g_utf8_casefold (normalized_string, -1);
15320       case_normalized_key = g_utf8_casefold (normalized_key, -1);
15321
15322       if (strncmp (case_normalized_key, case_normalized_string, strlen (case_normalized_key)) == 0)
15323         retval = FALSE;
15324     }
15325
15326   g_value_unset (&transformed);
15327   g_free (normalized_key);
15328   g_free (normalized_string);
15329   g_free (case_normalized_key);
15330   g_free (case_normalized_string);
15331
15332   return retval;
15333 }
15334
15335 static gboolean
15336 gtk_tree_view_search_iter (GtkTreeModel     *model,
15337                            GtkTreeSelection *selection,
15338                            GtkTreeIter      *iter,
15339                            const gchar      *text,
15340                            gint             *count,
15341                            gint              n)
15342 {
15343   GtkRBTree *tree = NULL;
15344   GtkRBNode *node = NULL;
15345   GtkTreePath *path;
15346
15347   GtkTreeView *tree_view = gtk_tree_selection_get_tree_view (selection);
15348
15349   path = gtk_tree_model_get_path (model, iter);
15350   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
15351
15352   do
15353     {
15354       if (! tree_view->priv->search_equal_func (model, tree_view->priv->search_column, text, iter, tree_view->priv->search_user_data))
15355         {
15356           (*count)++;
15357           if (*count == n)
15358             {
15359               gtk_tree_view_scroll_to_cell (tree_view, path, NULL,
15360                                             TRUE, 0.5, 0.0);
15361               gtk_tree_selection_select_iter (selection, iter);
15362               gtk_tree_view_real_set_cursor (tree_view, path, CLAMP_NODE);
15363
15364               if (path)
15365                 gtk_tree_path_free (path);
15366
15367               return TRUE;
15368             }
15369         }
15370
15371       if (node->children)
15372         {
15373           gboolean has_child;
15374           GtkTreeIter tmp;
15375
15376           tree = node->children;
15377           node = _gtk_rbtree_first (tree);
15378
15379           tmp = *iter;
15380           has_child = gtk_tree_model_iter_children (model, iter, &tmp);
15381           gtk_tree_path_down (path);
15382
15383           /* sanity check */
15384           TREE_VIEW_INTERNAL_ASSERT (has_child, FALSE);
15385         }
15386       else
15387         {
15388           gboolean done = FALSE;
15389
15390           do
15391             {
15392               node = _gtk_rbtree_next (tree, node);
15393
15394               if (node)
15395                 {
15396                   gboolean has_next;
15397
15398                   has_next = gtk_tree_model_iter_next (model, iter);
15399
15400                   done = TRUE;
15401                   gtk_tree_path_next (path);
15402
15403                   /* sanity check */
15404                   TREE_VIEW_INTERNAL_ASSERT (has_next, FALSE);
15405                 }
15406               else
15407                 {
15408                   gboolean has_parent;
15409                   GtkTreeIter tmp_iter = *iter;
15410
15411                   node = tree->parent_node;
15412                   tree = tree->parent_tree;
15413
15414                   if (!tree)
15415                     {
15416                       if (path)
15417                         gtk_tree_path_free (path);
15418
15419                       /* we've run out of tree, done with this func */
15420                       return FALSE;
15421                     }
15422
15423                   has_parent = gtk_tree_model_iter_parent (model,
15424                                                            iter,
15425                                                            &tmp_iter);
15426                   gtk_tree_path_up (path);
15427
15428                   /* sanity check */
15429                   TREE_VIEW_INTERNAL_ASSERT (has_parent, FALSE);
15430                 }
15431             }
15432           while (!done);
15433         }
15434     }
15435   while (1);
15436
15437   return FALSE;
15438 }
15439
15440 static void
15441 gtk_tree_view_search_init (GtkWidget   *entry,
15442                            GtkTreeView *tree_view)
15443 {
15444   gint ret;
15445   gint count = 0;
15446   const gchar *text;
15447   GtkTreeIter iter;
15448   GtkTreeModel *model;
15449   GtkTreeSelection *selection;
15450
15451   g_return_if_fail (GTK_IS_ENTRY (entry));
15452   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15453
15454   text = gtk_entry_get_text (GTK_ENTRY (entry));
15455
15456   model = gtk_tree_view_get_model (tree_view);
15457   selection = gtk_tree_view_get_selection (tree_view);
15458
15459   /* search */
15460   gtk_tree_selection_unselect_all (selection);
15461   if (tree_view->priv->typeselect_flush_timeout
15462       && !tree_view->priv->search_custom_entry_set)
15463     {
15464       g_source_remove (tree_view->priv->typeselect_flush_timeout);
15465       tree_view->priv->typeselect_flush_timeout =
15466         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
15467                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
15468                        tree_view);
15469     }
15470
15471   if (*text == '\0')
15472     return;
15473
15474   if (!gtk_tree_model_get_iter_first (model, &iter))
15475     return;
15476
15477   ret = gtk_tree_view_search_iter (model, selection,
15478                                    &iter, text,
15479                                    &count, 1);
15480
15481   if (ret)
15482     tree_view->priv->selected_iter = 1;
15483 }
15484
15485 void
15486 _gtk_tree_view_remove_editable (GtkTreeView       *tree_view,
15487                                 GtkTreeViewColumn *column,
15488                                 GtkCellEditable   *cell_editable)
15489 {
15490   if (tree_view->priv->edited_column == NULL)
15491     return;
15492
15493   g_return_if_fail (column == tree_view->priv->edited_column);
15494
15495   tree_view->priv->edited_column = NULL;
15496
15497   if (gtk_widget_has_focus (GTK_WIDGET (cell_editable)))
15498     gtk_widget_grab_focus (GTK_WIDGET (tree_view));
15499
15500   gtk_container_remove (GTK_CONTAINER (tree_view),
15501                         GTK_WIDGET (cell_editable));
15502
15503   /* FIXME should only redraw a single node */
15504   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15505 }
15506
15507 static gboolean
15508 gtk_tree_view_start_editing (GtkTreeView *tree_view,
15509                              GtkTreePath *cursor_path,
15510                              gboolean     edit_only)
15511 {
15512   GtkTreeIter iter;
15513   GdkRectangle cell_area;
15514   GtkTreeViewColumn *focus_column;
15515   guint flags = 0; /* can be 0, as the flags are primarily for rendering */
15516   gint retval = FALSE;
15517   GtkRBTree *cursor_tree;
15518   GtkRBNode *cursor_node;
15519
15520   g_assert (tree_view->priv->focus_column);
15521   focus_column = tree_view->priv->focus_column;
15522
15523   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
15524     return FALSE;
15525
15526   if (_gtk_tree_view_find_node (tree_view, cursor_path, &cursor_tree, &cursor_node) ||
15527       cursor_node == NULL)
15528     return FALSE;
15529
15530   gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path);
15531
15532   validate_row (tree_view, cursor_tree, cursor_node, &iter, cursor_path);
15533
15534   gtk_tree_view_column_cell_set_cell_data (focus_column,
15535                                            tree_view->priv->model,
15536                                            &iter,
15537                                            GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_PARENT),
15538                                            cursor_node->children ? TRUE : FALSE);
15539   gtk_tree_view_get_cell_area (tree_view,
15540                                cursor_path,
15541                                focus_column,
15542                                &cell_area);
15543
15544   if (gtk_cell_area_activate (gtk_cell_layout_get_area (GTK_CELL_LAYOUT (focus_column)),
15545                               _gtk_tree_view_column_get_context (focus_column),
15546                               GTK_WIDGET (tree_view),
15547                               &cell_area,
15548                               flags, edit_only))
15549     retval = TRUE;
15550
15551   return retval;
15552 }
15553
15554 void
15555 _gtk_tree_view_add_editable (GtkTreeView       *tree_view,
15556                              GtkTreeViewColumn *column,
15557                              GtkTreePath       *path,
15558                              GtkCellEditable   *cell_editable,
15559                              GdkRectangle      *cell_area)
15560 {
15561   gint pre_val = gtk_adjustment_get_value (tree_view->priv->vadjustment);
15562   GtkRequisition requisition;
15563
15564   tree_view->priv->edited_column = column;
15565
15566   gtk_tree_view_real_set_cursor (tree_view, path, CLAMP_NODE);
15567   cell_area->y += pre_val - (int)gtk_adjustment_get_value (tree_view->priv->vadjustment);
15568
15569   gtk_widget_get_preferred_size (GTK_WIDGET (cell_editable),
15570                                  &requisition, NULL);
15571
15572   tree_view->priv->draw_keyfocus = TRUE;
15573
15574   if (requisition.height < cell_area->height)
15575     {
15576       gint diff = cell_area->height - requisition.height;
15577       gtk_tree_view_put (tree_view,
15578                          GTK_WIDGET (cell_editable),
15579                          cell_area->x, cell_area->y + diff/2,
15580                          cell_area->width, requisition.height);
15581     }
15582   else
15583     {
15584       gtk_tree_view_put (tree_view,
15585                          GTK_WIDGET (cell_editable),
15586                          cell_area->x, cell_area->y,
15587                          cell_area->width, cell_area->height);
15588     }
15589 }
15590
15591 static void
15592 gtk_tree_view_stop_editing (GtkTreeView *tree_view,
15593                             gboolean     cancel_editing)
15594 {
15595   GtkTreeViewColumn *column;
15596
15597   if (tree_view->priv->edited_column == NULL)
15598     return;
15599
15600   /*
15601    * This is very evil. We need to do this, because
15602    * gtk_cell_editable_editing_done may trigger gtk_tree_view_row_changed
15603    * later on. If gtk_tree_view_row_changed notices
15604    * tree_view->priv->edited_column != NULL, it'll call
15605    * gtk_tree_view_stop_editing again. Bad things will happen then.
15606    *
15607    * Please read that again if you intend to modify anything here.
15608    */
15609
15610   column = tree_view->priv->edited_column;
15611   gtk_cell_area_stop_editing (gtk_cell_layout_get_area (GTK_CELL_LAYOUT (column)), cancel_editing);
15612   tree_view->priv->edited_column = NULL;
15613 }
15614
15615
15616 /**
15617  * gtk_tree_view_set_hover_selection:
15618  * @tree_view: a #GtkTreeView
15619  * @hover: %TRUE to enable hover selection mode
15620  *
15621  * Enables or disables the hover selection mode of @tree_view.
15622  * Hover selection makes the selected row follow the pointer.
15623  * Currently, this works only for the selection modes 
15624  * %GTK_SELECTION_SINGLE and %GTK_SELECTION_BROWSE.
15625  * 
15626  * Since: 2.6
15627  **/
15628 void     
15629 gtk_tree_view_set_hover_selection (GtkTreeView *tree_view,
15630                                    gboolean     hover)
15631 {
15632   hover = hover != FALSE;
15633
15634   if (hover != tree_view->priv->hover_selection)
15635     {
15636       tree_view->priv->hover_selection = hover;
15637
15638       g_object_notify (G_OBJECT (tree_view), "hover-selection");
15639     }
15640 }
15641
15642 /**
15643  * gtk_tree_view_get_hover_selection:
15644  * @tree_view: a #GtkTreeView
15645  * 
15646  * Returns whether hover selection mode is turned on for @tree_view.
15647  * 
15648  * Return value: %TRUE if @tree_view is in hover selection mode
15649  *
15650  * Since: 2.6 
15651  **/
15652 gboolean 
15653 gtk_tree_view_get_hover_selection (GtkTreeView *tree_view)
15654 {
15655   return tree_view->priv->hover_selection;
15656 }
15657
15658 /**
15659  * gtk_tree_view_set_hover_expand:
15660  * @tree_view: a #GtkTreeView
15661  * @expand: %TRUE to enable hover selection mode
15662  *
15663  * Enables or disables the hover expansion mode of @tree_view.
15664  * Hover expansion makes rows expand or collapse if the pointer 
15665  * moves over them.
15666  * 
15667  * Since: 2.6
15668  **/
15669 void     
15670 gtk_tree_view_set_hover_expand (GtkTreeView *tree_view,
15671                                 gboolean     expand)
15672 {
15673   expand = expand != FALSE;
15674
15675   if (expand != tree_view->priv->hover_expand)
15676     {
15677       tree_view->priv->hover_expand = expand;
15678
15679       g_object_notify (G_OBJECT (tree_view), "hover-expand");
15680     }
15681 }
15682
15683 /**
15684  * gtk_tree_view_get_hover_expand:
15685  * @tree_view: a #GtkTreeView
15686  * 
15687  * Returns whether hover expansion mode is turned on for @tree_view.
15688  * 
15689  * Return value: %TRUE if @tree_view is in hover expansion mode
15690  *
15691  * Since: 2.6 
15692  **/
15693 gboolean 
15694 gtk_tree_view_get_hover_expand (GtkTreeView *tree_view)
15695 {
15696   return tree_view->priv->hover_expand;
15697 }
15698
15699 /**
15700  * gtk_tree_view_set_rubber_banding:
15701  * @tree_view: a #GtkTreeView
15702  * @enable: %TRUE to enable rubber banding
15703  *
15704  * Enables or disables rubber banding in @tree_view.  If the selection mode
15705  * is #GTK_SELECTION_MULTIPLE, rubber banding will allow the user to select
15706  * multiple rows by dragging the mouse.
15707  * 
15708  * Since: 2.10
15709  **/
15710 void
15711 gtk_tree_view_set_rubber_banding (GtkTreeView *tree_view,
15712                                   gboolean     enable)
15713 {
15714   enable = enable != FALSE;
15715
15716   if (enable != tree_view->priv->rubber_banding_enable)
15717     {
15718       tree_view->priv->rubber_banding_enable = enable;
15719
15720       g_object_notify (G_OBJECT (tree_view), "rubber-banding");
15721     }
15722 }
15723
15724 /**
15725  * gtk_tree_view_get_rubber_banding:
15726  * @tree_view: a #GtkTreeView
15727  * 
15728  * Returns whether rubber banding is turned on for @tree_view.  If the
15729  * selection mode is #GTK_SELECTION_MULTIPLE, rubber banding will allow the
15730  * user to select multiple rows by dragging the mouse.
15731  * 
15732  * Return value: %TRUE if rubber banding in @tree_view is enabled.
15733  *
15734  * Since: 2.10
15735  **/
15736 gboolean
15737 gtk_tree_view_get_rubber_banding (GtkTreeView *tree_view)
15738 {
15739   return tree_view->priv->rubber_banding_enable;
15740 }
15741
15742 /**
15743  * gtk_tree_view_is_rubber_banding_active:
15744  * @tree_view: a #GtkTreeView
15745  * 
15746  * Returns whether a rubber banding operation is currently being done
15747  * in @tree_view.
15748  *
15749  * Return value: %TRUE if a rubber banding operation is currently being
15750  * done in @tree_view.
15751  *
15752  * Since: 2.12
15753  **/
15754 gboolean
15755 gtk_tree_view_is_rubber_banding_active (GtkTreeView *tree_view)
15756 {
15757   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15758
15759   if (tree_view->priv->rubber_banding_enable
15760       && tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
15761     return TRUE;
15762
15763   return FALSE;
15764 }
15765
15766 /**
15767  * gtk_tree_view_get_row_separator_func: (skip)
15768  * @tree_view: a #GtkTreeView
15769  * 
15770  * Returns the current row separator function.
15771  * 
15772  * Return value: the current row separator function.
15773  *
15774  * Since: 2.6
15775  **/
15776 GtkTreeViewRowSeparatorFunc 
15777 gtk_tree_view_get_row_separator_func (GtkTreeView *tree_view)
15778 {
15779   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
15780
15781   return tree_view->priv->row_separator_func;
15782 }
15783
15784 /**
15785  * gtk_tree_view_set_row_separator_func:
15786  * @tree_view: a #GtkTreeView
15787  * @func: (allow-none): a #GtkTreeViewRowSeparatorFunc
15788  * @data: (allow-none): user data to pass to @func, or %NULL
15789  * @destroy: (allow-none): destroy notifier for @data, or %NULL
15790  * 
15791  * Sets the row separator function, which is used to determine
15792  * whether a row should be drawn as a separator. If the row separator
15793  * function is %NULL, no separators are drawn. This is the default value.
15794  *
15795  * Since: 2.6
15796  **/
15797 void
15798 gtk_tree_view_set_row_separator_func (GtkTreeView                 *tree_view,
15799                                       GtkTreeViewRowSeparatorFunc  func,
15800                                       gpointer                     data,
15801                                       GDestroyNotify               destroy)
15802 {
15803   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15804
15805   if (tree_view->priv->row_separator_destroy)
15806     tree_view->priv->row_separator_destroy (tree_view->priv->row_separator_data);
15807
15808   tree_view->priv->row_separator_func = func;
15809   tree_view->priv->row_separator_data = data;
15810   tree_view->priv->row_separator_destroy = destroy;
15811
15812   /* Have the tree recalculate heights */
15813   _gtk_rbtree_mark_invalid (tree_view->priv->tree);
15814   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
15815 }
15816
15817   
15818 static void
15819 gtk_tree_view_grab_notify (GtkWidget *widget,
15820                            gboolean   was_grabbed)
15821 {
15822   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
15823
15824   tree_view->priv->in_grab = !was_grabbed;
15825
15826   if (!was_grabbed)
15827     {
15828       tree_view->priv->pressed_button = -1;
15829
15830       if (tree_view->priv->rubber_band_status)
15831         gtk_tree_view_stop_rubber_band (tree_view);
15832     }
15833 }
15834
15835 static void
15836 gtk_tree_view_state_flags_changed (GtkWidget     *widget,
15837                                    GtkStateFlags  previous_state)
15838 {
15839   if (gtk_widget_get_realized (widget))
15840     gtk_tree_view_ensure_background (GTK_TREE_VIEW (widget));
15841
15842   gtk_widget_queue_draw (widget);
15843 }
15844
15845 /**
15846  * gtk_tree_view_get_grid_lines:
15847  * @tree_view: a #GtkTreeView
15848  *
15849  * Returns which grid lines are enabled in @tree_view.
15850  *
15851  * Return value: a #GtkTreeViewGridLines value indicating which grid lines
15852  * are enabled.
15853  *
15854  * Since: 2.10
15855  */
15856 GtkTreeViewGridLines
15857 gtk_tree_view_get_grid_lines (GtkTreeView *tree_view)
15858 {
15859   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
15860
15861   return tree_view->priv->grid_lines;
15862 }
15863
15864 /**
15865  * gtk_tree_view_set_grid_lines:
15866  * @tree_view: a #GtkTreeView
15867  * @grid_lines: a #GtkTreeViewGridLines value indicating which grid lines to
15868  * enable.
15869  *
15870  * Sets which grid lines to draw in @tree_view.
15871  *
15872  * Since: 2.10
15873  */
15874 void
15875 gtk_tree_view_set_grid_lines (GtkTreeView           *tree_view,
15876                               GtkTreeViewGridLines   grid_lines)
15877 {
15878   GtkTreeViewPrivate *priv;
15879   GtkWidget *widget;
15880   GtkTreeViewGridLines old_grid_lines;
15881
15882   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15883
15884   priv = tree_view->priv;
15885   widget = GTK_WIDGET (tree_view);
15886
15887   old_grid_lines = priv->grid_lines;
15888   priv->grid_lines = grid_lines;
15889   
15890   if (gtk_widget_get_realized (widget))
15891     {
15892       if (grid_lines == GTK_TREE_VIEW_GRID_LINES_NONE &&
15893           priv->grid_line_width)
15894         {
15895           priv->grid_line_width = 0;
15896         }
15897       
15898       if (grid_lines != GTK_TREE_VIEW_GRID_LINES_NONE && 
15899           !priv->grid_line_width)
15900         {
15901           gint8 *dash_list;
15902
15903           gtk_widget_style_get (widget,
15904                                 "grid-line-width", &priv->grid_line_width,
15905                                 "grid-line-pattern", (gchar *)&dash_list,
15906                                 NULL);
15907       
15908           if (dash_list)
15909             {
15910               priv->grid_line_dashes[0] = dash_list[0];
15911               if (dash_list[0])
15912                 priv->grid_line_dashes[1] = dash_list[1];
15913               
15914               g_free (dash_list);
15915             }
15916           else
15917             {
15918               priv->grid_line_dashes[0] = 1;
15919               priv->grid_line_dashes[1] = 1;
15920             }
15921         }      
15922     }
15923
15924   if (old_grid_lines != grid_lines)
15925     {
15926       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15927       
15928       g_object_notify (G_OBJECT (tree_view), "enable-grid-lines");
15929     }
15930 }
15931
15932 /**
15933  * gtk_tree_view_get_enable_tree_lines:
15934  * @tree_view: a #GtkTreeView.
15935  *
15936  * Returns whether or not tree lines are drawn in @tree_view.
15937  *
15938  * Return value: %TRUE if tree lines are drawn in @tree_view, %FALSE
15939  * otherwise.
15940  *
15941  * Since: 2.10
15942  */
15943 gboolean
15944 gtk_tree_view_get_enable_tree_lines (GtkTreeView *tree_view)
15945 {
15946   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15947
15948   return tree_view->priv->tree_lines_enabled;
15949 }
15950
15951 /**
15952  * gtk_tree_view_set_enable_tree_lines:
15953  * @tree_view: a #GtkTreeView
15954  * @enabled: %TRUE to enable tree line drawing, %FALSE otherwise.
15955  *
15956  * Sets whether to draw lines interconnecting the expanders in @tree_view.
15957  * This does not have any visible effects for lists.
15958  *
15959  * Since: 2.10
15960  */
15961 void
15962 gtk_tree_view_set_enable_tree_lines (GtkTreeView *tree_view,
15963                                      gboolean     enabled)
15964 {
15965   GtkTreeViewPrivate *priv;
15966   GtkWidget *widget;
15967   gboolean was_enabled;
15968
15969   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15970
15971   enabled = enabled != FALSE;
15972
15973   priv = tree_view->priv;
15974   widget = GTK_WIDGET (tree_view);
15975
15976   was_enabled = priv->tree_lines_enabled;
15977
15978   priv->tree_lines_enabled = enabled;
15979
15980   if (gtk_widget_get_realized (widget))
15981     {
15982       if (!enabled && priv->tree_line_width)
15983         {
15984           priv->tree_line_width = 0;
15985         }
15986       
15987       if (enabled && !priv->tree_line_width)
15988         {
15989           gint8 *dash_list;
15990           gtk_widget_style_get (widget,
15991                                 "tree-line-width", &priv->tree_line_width,
15992                                 "tree-line-pattern", (gchar *)&dash_list,
15993                                 NULL);
15994           
15995           if (dash_list)
15996             {
15997               priv->tree_line_dashes[0] = dash_list[0];
15998               if (dash_list[0])
15999                 priv->tree_line_dashes[1] = dash_list[1];
16000               
16001               g_free (dash_list);
16002             }
16003           else
16004             {
16005               priv->tree_line_dashes[0] = 1;
16006               priv->tree_line_dashes[1] = 1;
16007             }
16008         }
16009     }
16010
16011   if (was_enabled != enabled)
16012     {
16013       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
16014
16015       g_object_notify (G_OBJECT (tree_view), "enable-tree-lines");
16016     }
16017 }
16018
16019
16020 /**
16021  * gtk_tree_view_set_show_expanders:
16022  * @tree_view: a #GtkTreeView
16023  * @enabled: %TRUE to enable expander drawing, %FALSE otherwise.
16024  *
16025  * Sets whether to draw and enable expanders and indent child rows in
16026  * @tree_view.  When disabled there will be no expanders visible in trees
16027  * and there will be no way to expand and collapse rows by default.  Also
16028  * note that hiding the expanders will disable the default indentation.  You
16029  * can set a custom indentation in this case using
16030  * gtk_tree_view_set_level_indentation().
16031  * This does not have any visible effects for lists.
16032  *
16033  * Since: 2.12
16034  */
16035 void
16036 gtk_tree_view_set_show_expanders (GtkTreeView *tree_view,
16037                                   gboolean     enabled)
16038 {
16039   gboolean was_enabled;
16040
16041   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
16042
16043   enabled = enabled != FALSE;
16044   was_enabled = tree_view->priv->show_expanders;
16045
16046   tree_view->priv->show_expanders = enabled == TRUE;
16047
16048   if (enabled != was_enabled)
16049     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
16050 }
16051
16052 /**
16053  * gtk_tree_view_get_show_expanders:
16054  * @tree_view: a #GtkTreeView.
16055  *
16056  * Returns whether or not expanders are drawn in @tree_view.
16057  *
16058  * Return value: %TRUE if expanders are drawn in @tree_view, %FALSE
16059  * otherwise.
16060  *
16061  * Since: 2.12
16062  */
16063 gboolean
16064 gtk_tree_view_get_show_expanders (GtkTreeView *tree_view)
16065 {
16066   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
16067
16068   return tree_view->priv->show_expanders;
16069 }
16070
16071 /**
16072  * gtk_tree_view_set_level_indentation:
16073  * @tree_view: a #GtkTreeView
16074  * @indentation: the amount, in pixels, of extra indentation in @tree_view.
16075  *
16076  * Sets the amount of extra indentation for child levels to use in @tree_view
16077  * in addition to the default indentation.  The value should be specified in
16078  * pixels, a value of 0 disables this feature and in this case only the default
16079  * indentation will be used.
16080  * This does not have any visible effects for lists.
16081  *
16082  * Since: 2.12
16083  */
16084 void
16085 gtk_tree_view_set_level_indentation (GtkTreeView *tree_view,
16086                                      gint         indentation)
16087 {
16088   tree_view->priv->level_indentation = indentation;
16089
16090   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
16091 }
16092
16093 /**
16094  * gtk_tree_view_get_level_indentation:
16095  * @tree_view: a #GtkTreeView.
16096  *
16097  * Returns the amount, in pixels, of extra indentation for child levels
16098  * in @tree_view.
16099  *
16100  * Return value: the amount of extra indentation for child levels in
16101  * @tree_view.  A return value of 0 means that this feature is disabled.
16102  *
16103  * Since: 2.12
16104  */
16105 gint
16106 gtk_tree_view_get_level_indentation (GtkTreeView *tree_view)
16107 {
16108   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
16109
16110   return tree_view->priv->level_indentation;
16111 }
16112
16113 /**
16114  * gtk_tree_view_set_tooltip_row:
16115  * @tree_view: a #GtkTreeView
16116  * @tooltip: a #GtkTooltip
16117  * @path: a #GtkTreePath
16118  *
16119  * Sets the tip area of @tooltip to be the area covered by the row at @path.
16120  * See also gtk_tree_view_set_tooltip_column() for a simpler alternative.
16121  * See also gtk_tooltip_set_tip_area().
16122  *
16123  * Since: 2.12
16124  */
16125 void
16126 gtk_tree_view_set_tooltip_row (GtkTreeView *tree_view,
16127                                GtkTooltip  *tooltip,
16128                                GtkTreePath *path)
16129 {
16130   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
16131   g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
16132
16133   gtk_tree_view_set_tooltip_cell (tree_view, tooltip, path, NULL, NULL);
16134 }
16135
16136 /**
16137  * gtk_tree_view_set_tooltip_cell:
16138  * @tree_view: a #GtkTreeView
16139  * @tooltip: a #GtkTooltip
16140  * @path: (allow-none): a #GtkTreePath or %NULL
16141  * @column: (allow-none): a #GtkTreeViewColumn or %NULL
16142  * @cell: (allow-none): a #GtkCellRenderer or %NULL
16143  *
16144  * Sets the tip area of @tooltip to the area @path, @column and @cell have
16145  * in common.  For example if @path is %NULL and @column is set, the tip
16146  * area will be set to the full area covered by @column.  See also
16147  * gtk_tooltip_set_tip_area().
16148  *
16149  * Note that if @path is not specified and @cell is set and part of a column
16150  * containing the expander, the tooltip might not show and hide at the correct
16151  * position.  In such cases @path must be set to the current node under the
16152  * mouse cursor for this function to operate correctly.
16153  *
16154  * See also gtk_tree_view_set_tooltip_column() for a simpler alternative.
16155  *
16156  * Since: 2.12
16157  */
16158 void
16159 gtk_tree_view_set_tooltip_cell (GtkTreeView       *tree_view,
16160                                 GtkTooltip        *tooltip,
16161                                 GtkTreePath       *path,
16162                                 GtkTreeViewColumn *column,
16163                                 GtkCellRenderer   *cell)
16164 {
16165   GtkAllocation allocation;
16166   GdkRectangle rect;
16167
16168   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
16169   g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
16170   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
16171   g_return_if_fail (cell == NULL || GTK_IS_CELL_RENDERER (cell));
16172
16173   /* Determine x values. */
16174   if (column && cell)
16175     {
16176       GdkRectangle tmp;
16177       gint start, width;
16178
16179       /* We always pass in path here, whether it is NULL or not.
16180        * For cells in expander columns path must be specified so that
16181        * we can correctly account for the indentation.  This also means
16182        * that the tooltip is constrained vertically by the "Determine y
16183        * values" code below; this is not a real problem since cells actually
16184        * don't stretch vertically in constrast to columns.
16185        */
16186       gtk_tree_view_get_cell_area (tree_view, path, column, &tmp);
16187       gtk_tree_view_column_cell_get_position (column, cell, &start, &width);
16188
16189       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
16190                                                          tmp.x + start, 0,
16191                                                          &rect.x, NULL);
16192       rect.width = width;
16193     }
16194   else if (column)
16195     {
16196       GdkRectangle tmp;
16197
16198       gtk_tree_view_get_background_area (tree_view, NULL, column, &tmp);
16199       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
16200                                                          tmp.x, 0,
16201                                                          &rect.x, NULL);
16202       rect.width = tmp.width;
16203     }
16204   else
16205     {
16206       gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
16207       rect.x = 0;
16208       rect.width = allocation.width;
16209     }
16210
16211   /* Determine y values. */
16212   if (path)
16213     {
16214       GdkRectangle tmp;
16215
16216       gtk_tree_view_get_background_area (tree_view, path, NULL, &tmp);
16217       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
16218                                                          0, tmp.y,
16219                                                          NULL, &rect.y);
16220       rect.height = tmp.height;
16221     }
16222   else
16223     {
16224       rect.y = 0;
16225       rect.height = gtk_adjustment_get_page_size (tree_view->priv->vadjustment);
16226     }
16227
16228   gtk_tooltip_set_tip_area (tooltip, &rect);
16229 }
16230
16231 /**
16232  * gtk_tree_view_get_tooltip_context:
16233  * @tree_view: a #GtkTreeView
16234  * @x: (inout): the x coordinate (relative to widget coordinates)
16235  * @y: (inout): the y coordinate (relative to widget coordinates)
16236  * @keyboard_tip: whether this is a keyboard tooltip or not
16237  * @model: (out) (allow-none) (transfer none): a pointer to receive a
16238  *         #GtkTreeModel or %NULL
16239  * @path: (out) (allow-none): a pointer to receive a #GtkTreePath or %NULL
16240  * @iter: (out) (allow-none): a pointer to receive a #GtkTreeIter or %NULL
16241  *
16242  * This function is supposed to be used in a #GtkWidget::query-tooltip
16243  * signal handler for #GtkTreeView.  The @x, @y and @keyboard_tip values
16244  * which are received in the signal handler, should be passed to this
16245  * function without modification.
16246  *
16247  * The return value indicates whether there is a tree view row at the given
16248  * coordinates (%TRUE) or not (%FALSE) for mouse tooltips.  For keyboard
16249  * tooltips the row returned will be the cursor row.  When %TRUE, then any of
16250  * @model, @path and @iter which have been provided will be set to point to
16251  * that row and the corresponding model.  @x and @y will always be converted
16252  * to be relative to @tree_view's bin_window if @keyboard_tooltip is %FALSE.
16253  *
16254  * Return value: whether or not the given tooltip context points to a row.
16255  *
16256  * Since: 2.12
16257  */
16258 gboolean
16259 gtk_tree_view_get_tooltip_context (GtkTreeView   *tree_view,
16260                                    gint          *x,
16261                                    gint          *y,
16262                                    gboolean       keyboard_tip,
16263                                    GtkTreeModel **model,
16264                                    GtkTreePath  **path,
16265                                    GtkTreeIter   *iter)
16266 {
16267   GtkTreePath *tmppath = NULL;
16268
16269   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
16270   g_return_val_if_fail (x != NULL, FALSE);
16271   g_return_val_if_fail (y != NULL, FALSE);
16272
16273   if (keyboard_tip)
16274     {
16275       gtk_tree_view_get_cursor (tree_view, &tmppath, NULL);
16276
16277       if (!tmppath)
16278         return FALSE;
16279     }
16280   else
16281     {
16282       gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, *x, *y,
16283                                                          x, y);
16284
16285       if (!gtk_tree_view_get_path_at_pos (tree_view, *x, *y,
16286                                           &tmppath, NULL, NULL, NULL))
16287         return FALSE;
16288     }
16289
16290   if (model)
16291     *model = gtk_tree_view_get_model (tree_view);
16292
16293   if (iter)
16294     gtk_tree_model_get_iter (gtk_tree_view_get_model (tree_view),
16295                              iter, tmppath);
16296
16297   if (path)
16298     *path = tmppath;
16299   else
16300     gtk_tree_path_free (tmppath);
16301
16302   return TRUE;
16303 }
16304
16305 static gboolean
16306 gtk_tree_view_set_tooltip_query_cb (GtkWidget  *widget,
16307                                     gint        x,
16308                                     gint        y,
16309                                     gboolean    keyboard_tip,
16310                                     GtkTooltip *tooltip,
16311                                     gpointer    data)
16312 {
16313   GValue value = G_VALUE_INIT;
16314   GValue transformed = G_VALUE_INIT;
16315   GtkTreeIter iter;
16316   GtkTreePath *path;
16317   GtkTreeModel *model;
16318   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
16319
16320   if (!gtk_tree_view_get_tooltip_context (GTK_TREE_VIEW (widget),
16321                                           &x, &y,
16322                                           keyboard_tip,
16323                                           &model, &path, &iter))
16324     return FALSE;
16325
16326   gtk_tree_model_get_value (model, &iter,
16327                             tree_view->priv->tooltip_column, &value);
16328
16329   g_value_init (&transformed, G_TYPE_STRING);
16330
16331   if (!g_value_transform (&value, &transformed))
16332     {
16333       g_value_unset (&value);
16334       gtk_tree_path_free (path);
16335
16336       return FALSE;
16337     }
16338
16339   g_value_unset (&value);
16340
16341   if (!g_value_get_string (&transformed))
16342     {
16343       g_value_unset (&transformed);
16344       gtk_tree_path_free (path);
16345
16346       return FALSE;
16347     }
16348
16349   gtk_tooltip_set_markup (tooltip, g_value_get_string (&transformed));
16350   gtk_tree_view_set_tooltip_row (tree_view, tooltip, path);
16351
16352   gtk_tree_path_free (path);
16353   g_value_unset (&transformed);
16354
16355   return TRUE;
16356 }
16357
16358 /**
16359  * gtk_tree_view_set_tooltip_column:
16360  * @tree_view: a #GtkTreeView
16361  * @column: an integer, which is a valid column number for @tree_view's model
16362  *
16363  * If you only plan to have simple (text-only) tooltips on full rows, you
16364  * can use this function to have #GtkTreeView handle these automatically
16365  * for you. @column should be set to the column in @tree_view's model
16366  * containing the tooltip texts, or -1 to disable this feature.
16367  *
16368  * When enabled, #GtkWidget:has-tooltip will be set to %TRUE and
16369  * @tree_view will connect a #GtkWidget::query-tooltip signal handler.
16370  *
16371  * Note that the signal handler sets the text with gtk_tooltip_set_markup(),
16372  * so &amp;, &lt;, etc have to be escaped in the text.
16373  *
16374  * Since: 2.12
16375  */
16376 void
16377 gtk_tree_view_set_tooltip_column (GtkTreeView *tree_view,
16378                                   gint         column)
16379 {
16380   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
16381
16382   if (column == tree_view->priv->tooltip_column)
16383     return;
16384
16385   if (column == -1)
16386     {
16387       g_signal_handlers_disconnect_by_func (tree_view,
16388                                             gtk_tree_view_set_tooltip_query_cb,
16389                                             NULL);
16390       gtk_widget_set_has_tooltip (GTK_WIDGET (tree_view), FALSE);
16391     }
16392   else
16393     {
16394       if (tree_view->priv->tooltip_column == -1)
16395         {
16396           g_signal_connect (tree_view, "query-tooltip",
16397                             G_CALLBACK (gtk_tree_view_set_tooltip_query_cb), NULL);
16398           gtk_widget_set_has_tooltip (GTK_WIDGET (tree_view), TRUE);
16399         }
16400     }
16401
16402   tree_view->priv->tooltip_column = column;
16403   g_object_notify (G_OBJECT (tree_view), "tooltip-column");
16404 }
16405
16406 /**
16407  * gtk_tree_view_get_tooltip_column:
16408  * @tree_view: a #GtkTreeView
16409  *
16410  * Returns the column of @tree_view's model which is being used for
16411  * displaying tooltips on @tree_view's rows.
16412  *
16413  * Return value: the index of the tooltip column that is currently being
16414  * used, or -1 if this is disabled.
16415  *
16416  * Since: 2.12
16417  */
16418 gint
16419 gtk_tree_view_get_tooltip_column (GtkTreeView *tree_view)
16420 {
16421   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
16422
16423   return tree_view->priv->tooltip_column;
16424 }