]> Pileus Git - ~andy/gtk/blob - gtk/gtktreeview.c
treeview: Replace cursor handling by keeping the node
[~andy/gtk] / gtk / gtktreeview.c
1 /* gtktreeview.c
2  * Copyright (C) 2000  Red Hat, Inc.,  Jonathan Blandford <jrb@redhat.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20
21 #include "config.h"
22
23 #include <math.h>
24 #include <string.h>
25
26 #include "gtktreeview.h"
27 #include "gtkrbtree.h"
28 #include "gtktreednd.h"
29 #include "gtktreeprivate.h"
30 #include "gtkcellrenderer.h"
31 #include "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 "gtktypebuiltins.h"
52 #include "gtkmain.h"
53 #include "a11y/gtktreeviewaccessible.h"
54
55
56 /**
57  * SECTION:gtktreeview
58  * @Short_description: A widget for displaying both trees and lists
59  * @Title: GtkTreeView
60  * @See_also: #GtkTreeViewColumn, #GtkTreeSelection, #GtkTreeDnd, #GtkTreeMode,
61  *   #GtkTreeSortable, #GtkTreeModelSort, #GtkListStore, #GtkTreeStore,
62  *   #GtkCellRenderer, #GtkCellEditable, #GtkCellRendererPixbuf,
63  *   #GtkCellRendererText, #GtkCellRendererToggle
64  *
65  * Widget that displays any object that implements the #GtkTreeModel interface.
66  *
67  * Please refer to the <link linkend="TreeWidget">tree widget conceptual
68  * overview</link> for an overview of all the objects and data types related
69  * to the tree widget and how they work together.
70  *
71  * Several different coordinate systems are exposed in the GtkTreeView API.
72  * These are:
73  *
74  * <inlinegraphic fileref="tree-view-coordinates.png" format="PNG"></inlinegraphic>
75  * <variablelist><title>Coordinate systems in GtkTreeView API</title>
76  * <varlistentry><term>Widget coordinates</term>
77  * <listitem>
78  * <para>
79  * Coordinates relative to the widget (usually <literal>widget->window</literal>).
80  * </para>
81  * </listitem>
82  * </varlistentry>
83  * <varlistentry><term>Bin window coordinates</term>
84  * <listitem>
85  * <para>
86  * Coordinates relative to the window that GtkTreeView renders to.
87  * </para>
88  * </listitem>
89  * </varlistentry>
90  * <varlistentry><term>Tree coordinates</term>
91  * <listitem>
92  * <para>
93  * Coordinates relative to the entire scrollable area of GtkTreeView. These
94  * coordinates start at (0, 0) for row 0 of the tree.
95  * </para>
96  * </listitem>
97  * </varlistentry>
98  * </variablelist>
99  *
100  * Several functions are available for converting between the different
101  * coordinate systems.  The most common translations are between widget and bin
102  * window coordinates and between bin window and tree coordinates. For the
103  * former you can use gtk_tree_view_convert_widget_to_bin_window_coords()
104  * (and vice versa), for the latter gtk_tree_view_convert_bin_window_to_tree_coords()
105  * (and vice versa).
106  *
107  * <refsect2 id="GtkTreeView-BUILDER-UI">
108  * <title>GtkTreeView as GtkBuildable</title>
109  * The GtkTreeView implementation of the GtkBuildable interface accepts
110  * #GtkTreeViewColumn objects as &lt;child&gt; elements and exposes the
111  * internal #GtkTreeSelection in UI definitions.
112  * <example>
113  * <title>A UI definition fragment with GtkTreeView</title>
114  * <programlisting><![CDATA[
115  * <object class="GtkTreeView" id="treeview">
116  *   <property name="model">liststore1</property>
117  *   <child>
118  *     <object class="GtkTreeViewColumn" id="test-column">
119  *       <property name="title">Test</property>
120  *       <child>
121  *         <object class="GtkCellRendererText" id="test-renderer"/>
122  *         <attributes>
123  *           <attribute name="text">1</attribute>
124  *         </attributes>
125  *       </child>
126  *     </object>
127  *   </child>
128  *   <child internal-child="selection">
129  *     <object class="GtkTreeSelection" id="selection">
130  *       <signal name="changed" handler="on_treeview_selection_changed"/>
131  *     </object>
132  *   </child>
133  * </object>
134  * ]]></programlisting>
135  * </example>
136  * </refsect2>
137  */
138
139 enum
140 {
141   DRAG_COLUMN_WINDOW_STATE_UNSET = 0,
142   DRAG_COLUMN_WINDOW_STATE_ORIGINAL = 1,
143   DRAG_COLUMN_WINDOW_STATE_ARROW = 2,
144   DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT = 3,
145   DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT = 4
146 };
147
148 enum
149 {
150   RUBBER_BAND_OFF = 0,
151   RUBBER_BAND_MAYBE_START = 1,
152   RUBBER_BAND_ACTIVE = 2
153 };
154
155  /* This lovely little value is used to determine how far away from the title bar
156   * you can move the mouse and still have a column drag work.
157   */
158 #define TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER(tree_view) (10*gtk_tree_view_get_effective_header_height(tree_view))
159
160 #ifdef __GNUC__
161
162 #define TREE_VIEW_INTERNAL_ASSERT(expr, ret)     G_STMT_START{          \
163      if (!(expr))                                                       \
164        {                                                                \
165          g_log (G_LOG_DOMAIN,                                           \
166                 G_LOG_LEVEL_CRITICAL,                                   \
167                 "%s (%s): assertion `%s' failed.\n"                     \
168                 "There is a disparity between the internal view of the GtkTreeView,\n"    \
169                 "and the GtkTreeModel.  This generally means that the model has changed\n"\
170                 "without letting the view know.  Any display from now on is likely to\n"  \
171                 "be incorrect.\n",                                                        \
172                 G_STRLOC,                                               \
173                 G_STRFUNC,                                              \
174                 #expr);                                                 \
175          return ret;                                                    \
176        };                               }G_STMT_END
177
178 #define TREE_VIEW_INTERNAL_ASSERT_VOID(expr)     G_STMT_START{          \
179      if (!(expr))                                                       \
180        {                                                                \
181          g_log (G_LOG_DOMAIN,                                           \
182                 G_LOG_LEVEL_CRITICAL,                                   \
183                 "%s (%s): assertion `%s' failed.\n"                     \
184                 "There is a disparity between the internal view of the GtkTreeView,\n"    \
185                 "and the GtkTreeModel.  This generally means that the model has changed\n"\
186                 "without letting the view know.  Any display from now on is likely to\n"  \
187                 "be incorrect.\n",                                                        \
188                 G_STRLOC,                                               \
189                 G_STRFUNC,                                              \
190                 #expr);                                                 \
191          return;                                                        \
192        };                               }G_STMT_END
193
194 #else
195
196 #define TREE_VIEW_INTERNAL_ASSERT(expr, ret)     G_STMT_START{          \
197      if (!(expr))                                                       \
198        {                                                                \
199          g_log (G_LOG_DOMAIN,                                           \
200                 G_LOG_LEVEL_CRITICAL,                                   \
201                 "file %s: line %d: assertion `%s' failed.\n"       \
202                 "There is a disparity between the internal view of the GtkTreeView,\n"    \
203                 "and the GtkTreeModel.  This generally means that the model has changed\n"\
204                 "without letting the view know.  Any display from now on is likely to\n"  \
205                 "be incorrect.\n",                                                        \
206                 __FILE__,                                               \
207                 __LINE__,                                               \
208                 #expr);                                                 \
209          return ret;                                                    \
210        };                               }G_STMT_END
211
212 #define TREE_VIEW_INTERNAL_ASSERT_VOID(expr)     G_STMT_START{          \
213      if (!(expr))                                                       \
214        {                                                                \
215          g_log (G_LOG_DOMAIN,                                           \
216                 G_LOG_LEVEL_CRITICAL,                                   \
217                 "file %s: line %d: assertion '%s' failed.\n"            \
218                 "There is a disparity between the internal view of the GtkTreeView,\n"    \
219                 "and the GtkTreeModel.  This generally means that the model has changed\n"\
220                 "without letting the view know.  Any display from now on is likely to\n"  \
221                 "be incorrect.\n",                                                        \
222                 __FILE__,                                               \
223                 __LINE__,                                               \
224                 #expr);                                                 \
225          return;                                                        \
226        };                               }G_STMT_END
227 #endif
228
229 #define GTK_TREE_VIEW_PRIORITY_VALIDATE (GDK_PRIORITY_REDRAW + 5)
230 #define GTK_TREE_VIEW_PRIORITY_SCROLL_SYNC (GTK_TREE_VIEW_PRIORITY_VALIDATE + 2)
231 #define GTK_TREE_VIEW_TIME_MS_PER_IDLE 30
232 #define SCROLL_EDGE_SIZE 15
233 #define EXPANDER_EXTRA_PADDING 4
234 #define GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT 5000
235 #define AUTO_EXPAND_TIMEOUT 500
236
237 /* Translate from bin_window coordinates to rbtree (tree coordinates) and
238  * vice versa.
239  */
240 #define TREE_WINDOW_Y_TO_RBTREE_Y(tree_view,y) ((y) + tree_view->priv->dy)
241 #define RBTREE_Y_TO_TREE_WINDOW_Y(tree_view,y) ((y) - tree_view->priv->dy)
242
243 typedef struct _GtkTreeViewColumnReorder GtkTreeViewColumnReorder;
244 struct _GtkTreeViewColumnReorder
245 {
246   gint left_align;
247   gint right_align;
248   GtkTreeViewColumn *left_column;
249   GtkTreeViewColumn *right_column;
250 };
251
252 typedef struct _GtkTreeViewChild GtkTreeViewChild;
253 struct _GtkTreeViewChild
254 {
255   GtkWidget *widget;
256   gint x;
257   gint y;
258   gint width;
259   gint height;
260 };
261
262
263 typedef struct _TreeViewDragInfo TreeViewDragInfo;
264 struct _TreeViewDragInfo
265 {
266   GdkModifierType start_button_mask;
267   GtkTargetList *_unused_source_target_list;
268   GdkDragAction source_actions;
269
270   GtkTargetList *_unused_dest_target_list;
271
272   guint source_set : 1;
273   guint dest_set : 1;
274 };
275
276
277 struct _GtkTreeViewPrivate
278 {
279   GtkTreeModel *model;
280
281   /* tree information */
282   GtkRBTree *tree;
283
284   /* Container info */
285   GList *children;
286   gint width;
287   gint height;
288
289   /* Adjustments */
290   GtkAdjustment *hadjustment;
291   GtkAdjustment *vadjustment;
292   gint           min_display_width;
293   gint           min_display_height;
294
295   /* Sub windows */
296   GdkWindow *bin_window;
297   GdkWindow *header_window;
298
299   /* Scroll position state keeping */
300   GtkTreeRowReference *top_row;
301   gint top_row_dy;
302   /* dy == y pos of top_row + top_row_dy */
303   /* we cache it for simplicity of the code */
304   gint dy;
305
306   guint presize_handler_timer;
307   guint validate_rows_timer;
308   guint scroll_sync_timer;
309
310   /* Indentation and expander layout */
311   gint expander_size;
312   GtkTreeViewColumn *expander_column;
313
314   gint level_indentation;
315
316   /* Key navigation (focus), selection */
317   gint cursor_offset;
318
319   GtkTreeRowReference *anchor;
320   GtkRBNode *cursor_node;
321   GtkRBTree *cursor_tree;
322
323   GtkTreeViewColumn *focus_column;
324
325   /* Current pressed node, previously pressed, prelight */
326   GtkRBNode *button_pressed_node;
327   GtkRBTree *button_pressed_tree;
328
329   gint pressed_button;
330   gint press_start_x;
331   gint press_start_y;
332
333   gint event_last_x;
334   gint event_last_y;
335
336   guint last_button_time;
337   gint last_button_x;
338   gint last_button_y;
339
340   GtkRBNode *prelight_node;
341   GtkRBTree *prelight_tree;
342
343   /* Cell Editing */
344   GtkTreeViewColumn *edited_column;
345
346   /* The node that's currently being collapsed or expanded */
347   GtkRBNode *expanded_collapsed_node;
348   GtkRBTree *expanded_collapsed_tree;
349   guint expand_collapse_timeout;
350
351   /* Auto expand/collapse timeout in hover mode */
352   guint auto_expand_timeout;
353
354   /* Selection information */
355   GtkTreeSelection *selection;
356
357   /* Header information */
358   gint n_columns;
359   GList *columns;
360   gint header_height;
361
362   GtkTreeViewColumnDropFunc column_drop_func;
363   gpointer column_drop_func_data;
364   GDestroyNotify column_drop_func_data_destroy;
365   GList *column_drag_info;
366   GtkTreeViewColumnReorder *cur_reorder;
367
368   gint prev_width_before_expander;
369
370   /* Interactive Header reordering */
371   GdkWindow *drag_window;
372   GdkWindow *drag_highlight_window;
373   GtkTreeViewColumn *drag_column;
374   gint drag_column_x;
375
376   /* Interactive Header Resizing */
377   gint drag_pos;
378   gint x_drag;
379
380   /* Non-interactive Header Resizing, expand flag support */
381   gint prev_width;
382
383   gint last_extra_space;
384   gint last_extra_space_per_column;
385   gint last_number_of_expand_columns;
386
387   /* ATK Hack */
388   GtkTreeDestroyCountFunc destroy_count_func;
389   gpointer destroy_count_data;
390   GDestroyNotify destroy_count_destroy;
391
392   /* Scroll timeout (e.g. during dnd, rubber banding) */
393   guint scroll_timeout;
394
395   /* Row drag-and-drop */
396   GtkTreeRowReference *drag_dest_row;
397   GtkTreeViewDropPosition drag_dest_pos;
398   guint open_dest_timeout;
399
400   /* Rubber banding */
401   gint rubber_band_status;
402   gint rubber_band_x;
403   gint rubber_band_y;
404   gint rubber_band_extend;
405   gint rubber_band_modify;
406
407   GtkRBNode *rubber_band_start_node;
408   GtkRBTree *rubber_band_start_tree;
409
410   GtkRBNode *rubber_band_end_node;
411   GtkRBTree *rubber_band_end_tree;
412
413   /* fixed height */
414   gint fixed_height;
415
416   /* Scroll-to functionality when unrealized */
417   GtkTreeRowReference *scroll_to_path;
418   GtkTreeViewColumn *scroll_to_column;
419   gfloat scroll_to_row_align;
420   gfloat scroll_to_col_align;
421
422   /* Interactive search */
423   gint selected_iter;
424   gint search_column;
425   GtkTreeViewSearchPositionFunc search_position_func;
426   GtkTreeViewSearchEqualFunc search_equal_func;
427   gpointer search_user_data;
428   GDestroyNotify search_destroy;
429   gpointer search_position_user_data;
430   GDestroyNotify search_position_destroy;
431   GtkWidget *search_window;
432   GtkWidget *search_entry;
433   gulong search_entry_changed_id;
434   guint typeselect_flush_timeout;
435
436   /* Grid and tree lines */
437   GtkTreeViewGridLines grid_lines;
438   double grid_line_dashes[2];
439   int grid_line_width;
440
441   gboolean tree_lines_enabled;
442   double tree_line_dashes[2];
443   int tree_line_width;
444
445   /* Row separators */
446   GtkTreeViewRowSeparatorFunc row_separator_func;
447   gpointer row_separator_data;
448   GDestroyNotify row_separator_destroy;
449
450   /* Tooltip support */
451   gint tooltip_column;
452
453   /* Here comes the bitfield */
454   guint scroll_to_use_align : 1;
455
456   guint fixed_height_mode : 1;
457   guint fixed_height_check : 1;
458
459   guint reorderable : 1;
460   guint header_has_focus : 1;
461   guint drag_column_window_state : 3;
462   /* hint to display rows in alternating colors */
463   guint has_rules : 1;
464   guint mark_rows_col_dirty : 1;
465
466   /* for DnD */
467   guint empty_view_drop : 1;
468
469   guint modify_selection_pressed : 1;
470   guint extend_selection_pressed : 1;
471
472   guint init_hadjust_value : 1;
473
474   guint in_top_row_to_dy : 1;
475
476   /* interactive search */
477   guint enable_search : 1;
478   guint disable_popdown : 1;
479   guint search_custom_entry_set : 1;
480   
481   guint hover_selection : 1;
482   guint hover_expand : 1;
483   guint imcontext_changed : 1;
484
485   guint rubber_banding_enable : 1;
486
487   guint in_grab : 1;
488
489   guint post_validation_flag : 1;
490
491   /* Whether our key press handler is to avoid sending an unhandled binding to the search entry */
492   guint search_entry_avoid_unhandled_binding : 1;
493
494   /* GtkScrollablePolicy needs to be checked when
495    * driving the scrollable adjustment values */
496   guint hscroll_policy : 1;
497   guint vscroll_policy : 1;
498
499   /* GtkTreeView flags */
500   guint is_list : 1;
501   guint show_expanders : 1;
502   guint in_column_resize : 1;
503   guint arrow_prelit : 1;
504   guint headers_visible : 1;
505   guint draw_keyfocus : 1;
506   guint model_setup : 1;
507   guint in_column_drag : 1;
508 };
509
510
511 /* Signals */
512 enum
513 {
514   ROW_ACTIVATED,
515   TEST_EXPAND_ROW,
516   TEST_COLLAPSE_ROW,
517   ROW_EXPANDED,
518   ROW_COLLAPSED,
519   COLUMNS_CHANGED,
520   CURSOR_CHANGED,
521   MOVE_CURSOR,
522   SELECT_ALL,
523   UNSELECT_ALL,
524   SELECT_CURSOR_ROW,
525   TOGGLE_CURSOR_ROW,
526   EXPAND_COLLAPSE_CURSOR_ROW,
527   SELECT_CURSOR_PARENT,
528   START_INTERACTIVE_SEARCH,
529   LAST_SIGNAL
530 };
531
532 /* Properties */
533 enum {
534   PROP_0,
535   PROP_MODEL,
536   PROP_HADJUSTMENT,
537   PROP_VADJUSTMENT,
538   PROP_HSCROLL_POLICY,
539   PROP_VSCROLL_POLICY,
540   PROP_HEADERS_VISIBLE,
541   PROP_HEADERS_CLICKABLE,
542   PROP_EXPANDER_COLUMN,
543   PROP_REORDERABLE,
544   PROP_RULES_HINT,
545   PROP_ENABLE_SEARCH,
546   PROP_SEARCH_COLUMN,
547   PROP_FIXED_HEIGHT_MODE,
548   PROP_HOVER_SELECTION,
549   PROP_HOVER_EXPAND,
550   PROP_SHOW_EXPANDERS,
551   PROP_LEVEL_INDENTATION,
552   PROP_RUBBER_BANDING,
553   PROP_ENABLE_GRID_LINES,
554   PROP_ENABLE_TREE_LINES,
555   PROP_TOOLTIP_COLUMN
556 };
557
558 /* object signals */
559 static void     gtk_tree_view_finalize             (GObject          *object);
560 static void     gtk_tree_view_set_property         (GObject         *object,
561                                                     guint            prop_id,
562                                                     const GValue    *value,
563                                                     GParamSpec      *pspec);
564 static void     gtk_tree_view_get_property         (GObject         *object,
565                                                     guint            prop_id,
566                                                     GValue          *value,
567                                                     GParamSpec      *pspec);
568
569 /* gtkwidget signals */
570 static void     gtk_tree_view_destroy              (GtkWidget        *widget);
571 static void     gtk_tree_view_realize              (GtkWidget        *widget);
572 static void     gtk_tree_view_unrealize            (GtkWidget        *widget);
573 static void     gtk_tree_view_map                  (GtkWidget        *widget);
574 static void     gtk_tree_view_get_preferred_width  (GtkWidget        *widget,
575                                                     gint             *minimum,
576                                                     gint             *natural);
577 static void     gtk_tree_view_get_preferred_height (GtkWidget        *widget,
578                                                     gint             *minimum,
579                                                     gint             *natural);
580 static void     gtk_tree_view_size_request         (GtkWidget        *widget,
581                                                     GtkRequisition   *requisition,
582                                                     gboolean          may_validate);
583 static void     gtk_tree_view_size_allocate        (GtkWidget        *widget,
584                                                     GtkAllocation    *allocation);
585 static gboolean gtk_tree_view_draw                 (GtkWidget        *widget,
586                                                     cairo_t          *cr);
587 static gboolean gtk_tree_view_key_press            (GtkWidget        *widget,
588                                                     GdkEventKey      *event);
589 static gboolean gtk_tree_view_key_release          (GtkWidget        *widget,
590                                                     GdkEventKey      *event);
591 static gboolean gtk_tree_view_motion               (GtkWidget        *widget,
592                                                     GdkEventMotion   *event);
593 static gboolean gtk_tree_view_enter_notify         (GtkWidget        *widget,
594                                                     GdkEventCrossing *event);
595 static gboolean gtk_tree_view_leave_notify         (GtkWidget        *widget,
596                                                     GdkEventCrossing *event);
597 static gboolean gtk_tree_view_button_press         (GtkWidget        *widget,
598                                                     GdkEventButton   *event);
599 static gboolean gtk_tree_view_button_release       (GtkWidget        *widget,
600                                                     GdkEventButton   *event);
601 static gboolean gtk_tree_view_grab_broken          (GtkWidget          *widget,
602                                                     GdkEventGrabBroken *event);
603 #if 0
604 static gboolean gtk_tree_view_configure            (GtkWidget         *widget,
605                                                     GdkEventConfigure *event);
606 #endif
607
608 static GtkWidgetPath * gtk_tree_view_get_path_for_child (GtkContainer *container,
609                                                          GtkWidget    *child);
610
611 static void     gtk_tree_view_set_focus_child      (GtkContainer     *container,
612                                                     GtkWidget        *child);
613 static gint     gtk_tree_view_focus_out            (GtkWidget        *widget,
614                                                     GdkEventFocus    *event);
615 static gint     gtk_tree_view_focus                (GtkWidget        *widget,
616                                                     GtkDirectionType  direction);
617 static void     gtk_tree_view_grab_focus           (GtkWidget        *widget);
618 static void     gtk_tree_view_style_updated        (GtkWidget        *widget);
619 static void     gtk_tree_view_grab_notify          (GtkWidget        *widget,
620                                                     gboolean          was_grabbed);
621 static void     gtk_tree_view_state_flags_changed  (GtkWidget        *widget,
622                                                     GtkStateFlags     previous_state);
623
624 /* container signals */
625 static void     gtk_tree_view_remove               (GtkContainer     *container,
626                                                     GtkWidget        *widget);
627 static void     gtk_tree_view_forall               (GtkContainer     *container,
628                                                     gboolean          include_internals,
629                                                     GtkCallback       callback,
630                                                     gpointer          callback_data);
631
632 /* Source side drag signals */
633 static void gtk_tree_view_drag_begin       (GtkWidget        *widget,
634                                             GdkDragContext   *context);
635 static void gtk_tree_view_drag_end         (GtkWidget        *widget,
636                                             GdkDragContext   *context);
637 static void gtk_tree_view_drag_data_get    (GtkWidget        *widget,
638                                             GdkDragContext   *context,
639                                             GtkSelectionData *selection_data,
640                                             guint             info,
641                                             guint             time);
642 static void gtk_tree_view_drag_data_delete (GtkWidget        *widget,
643                                             GdkDragContext   *context);
644
645 /* Target side drag signals */
646 static void     gtk_tree_view_drag_leave         (GtkWidget        *widget,
647                                                   GdkDragContext   *context,
648                                                   guint             time);
649 static gboolean gtk_tree_view_drag_motion        (GtkWidget        *widget,
650                                                   GdkDragContext   *context,
651                                                   gint              x,
652                                                   gint              y,
653                                                   guint             time);
654 static gboolean gtk_tree_view_drag_drop          (GtkWidget        *widget,
655                                                   GdkDragContext   *context,
656                                                   gint              x,
657                                                   gint              y,
658                                                   guint             time);
659 static void     gtk_tree_view_drag_data_received (GtkWidget        *widget,
660                                                   GdkDragContext   *context,
661                                                   gint              x,
662                                                   gint              y,
663                                                   GtkSelectionData *selection_data,
664                                                   guint             info,
665                                                   guint             time);
666
667 /* tree_model signals */
668 static gboolean gtk_tree_view_real_move_cursor            (GtkTreeView     *tree_view,
669                                                            GtkMovementStep  step,
670                                                            gint             count);
671 static gboolean gtk_tree_view_real_select_all             (GtkTreeView     *tree_view);
672 static gboolean gtk_tree_view_real_unselect_all           (GtkTreeView     *tree_view);
673 static gboolean gtk_tree_view_real_select_cursor_row      (GtkTreeView     *tree_view,
674                                                            gboolean         start_editing);
675 static gboolean gtk_tree_view_real_toggle_cursor_row      (GtkTreeView     *tree_view);
676 static gboolean gtk_tree_view_real_expand_collapse_cursor_row (GtkTreeView     *tree_view,
677                                                                gboolean         logical,
678                                                                gboolean         expand,
679                                                                gboolean         open_all);
680 static gboolean gtk_tree_view_real_select_cursor_parent   (GtkTreeView     *tree_view);
681 static void gtk_tree_view_row_changed                     (GtkTreeModel    *model,
682                                                            GtkTreePath     *path,
683                                                            GtkTreeIter     *iter,
684                                                            gpointer         data);
685 static void gtk_tree_view_row_inserted                    (GtkTreeModel    *model,
686                                                            GtkTreePath     *path,
687                                                            GtkTreeIter     *iter,
688                                                            gpointer         data);
689 static void gtk_tree_view_row_has_child_toggled           (GtkTreeModel    *model,
690                                                            GtkTreePath     *path,
691                                                            GtkTreeIter     *iter,
692                                                            gpointer         data);
693 static void gtk_tree_view_row_deleted                     (GtkTreeModel    *model,
694                                                            GtkTreePath     *path,
695                                                            gpointer         data);
696 static void gtk_tree_view_rows_reordered                  (GtkTreeModel    *model,
697                                                            GtkTreePath     *parent,
698                                                            GtkTreeIter     *iter,
699                                                            gint            *new_order,
700                                                            gpointer         data);
701
702 /* Incremental reflow */
703 static gboolean validate_row             (GtkTreeView *tree_view,
704                                           GtkRBTree   *tree,
705                                           GtkRBNode   *node,
706                                           GtkTreeIter *iter,
707                                           GtkTreePath *path);
708 static void     validate_visible_area    (GtkTreeView *tree_view);
709 static gboolean validate_rows_handler    (GtkTreeView *tree_view);
710 static gboolean do_validate_rows         (GtkTreeView *tree_view,
711                                           gboolean     size_request);
712 static gboolean validate_rows            (GtkTreeView *tree_view);
713 static gboolean presize_handler_callback (gpointer     data);
714 static void     install_presize_handler  (GtkTreeView *tree_view);
715 static void     install_scroll_sync_handler (GtkTreeView *tree_view);
716 static void     gtk_tree_view_set_top_row   (GtkTreeView *tree_view,
717                                              GtkTreePath *path,
718                                              gint         offset);
719 static void     gtk_tree_view_dy_to_top_row (GtkTreeView *tree_view);
720 static void     gtk_tree_view_top_row_to_dy (GtkTreeView *tree_view);
721 static void     invalidate_empty_focus      (GtkTreeView *tree_view);
722
723 /* Internal functions */
724 static gboolean gtk_tree_view_is_expander_column             (GtkTreeView        *tree_view,
725                                                               GtkTreeViewColumn  *column);
726 static inline gboolean gtk_tree_view_draw_expanders          (GtkTreeView        *tree_view);
727 static void     gtk_tree_view_add_move_binding               (GtkBindingSet      *binding_set,
728                                                               guint               keyval,
729                                                               guint               modmask,
730                                                               gboolean            add_shifted_binding,
731                                                               GtkMovementStep     step,
732                                                               gint                count);
733 static gint     gtk_tree_view_unref_and_check_selection_tree (GtkTreeView        *tree_view,
734                                                               GtkRBTree          *tree);
735 static void     gtk_tree_view_queue_draw_path                (GtkTreeView        *tree_view,
736                                                               GtkTreePath        *path,
737                                                               const GdkRectangle *clip_rect);
738 static void     gtk_tree_view_queue_draw_arrow               (GtkTreeView        *tree_view,
739                                                               GtkRBTree          *tree,
740                                                               GtkRBNode          *node);
741 static void     gtk_tree_view_draw_arrow                     (GtkTreeView        *tree_view,
742                                                               cairo_t            *cr,
743                                                               GtkRBTree          *tree,
744                                                               GtkRBNode          *node);
745 static void     gtk_tree_view_get_arrow_xrange               (GtkTreeView        *tree_view,
746                                                               GtkRBTree          *tree,
747                                                               gint               *x1,
748                                                               gint               *x2);
749 static gint     gtk_tree_view_new_column_width               (GtkTreeView        *tree_view,
750                                                               gint                i,
751                                                               gint               *x);
752 static void     gtk_tree_view_adjustment_changed             (GtkAdjustment      *adjustment,
753                                                               GtkTreeView        *tree_view);
754 static void     gtk_tree_view_build_tree                     (GtkTreeView        *tree_view,
755                                                               GtkRBTree          *tree,
756                                                               GtkTreeIter        *iter,
757                                                               gint                depth,
758                                                               gboolean            recurse);
759 static void     gtk_tree_view_clamp_node_visible             (GtkTreeView        *tree_view,
760                                                               GtkRBTree          *tree,
761                                                               GtkRBNode          *node);
762 static void     gtk_tree_view_clamp_column_visible           (GtkTreeView        *tree_view,
763                                                               GtkTreeViewColumn  *column,
764                                                               gboolean            focus_to_cell);
765 static gboolean gtk_tree_view_maybe_begin_dragging_row       (GtkTreeView        *tree_view,
766                                                               GdkEventMotion     *event);
767 static void     gtk_tree_view_focus_to_cursor                (GtkTreeView        *tree_view);
768 static void     gtk_tree_view_move_cursor_up_down            (GtkTreeView        *tree_view,
769                                                               gint                count);
770 static void     gtk_tree_view_move_cursor_page_up_down       (GtkTreeView        *tree_view,
771                                                               gint                count);
772 static void     gtk_tree_view_move_cursor_left_right         (GtkTreeView        *tree_view,
773                                                               gint                count);
774 static void     gtk_tree_view_move_cursor_start_end          (GtkTreeView        *tree_view,
775                                                               gint                count);
776 static gboolean gtk_tree_view_real_collapse_row              (GtkTreeView        *tree_view,
777                                                               GtkTreePath        *path,
778                                                               GtkRBTree          *tree,
779                                                               GtkRBNode          *node,
780                                                               gboolean            animate);
781 static gboolean gtk_tree_view_real_expand_row                (GtkTreeView        *tree_view,
782                                                               GtkTreePath        *path,
783                                                               GtkRBTree          *tree,
784                                                               GtkRBNode          *node,
785                                                               gboolean            open_all,
786                                                               gboolean            animate);
787 static void     gtk_tree_view_real_set_cursor                (GtkTreeView        *tree_view,
788                                                               GtkTreePath        *path,
789                                                               gboolean            clear_and_select,
790                                                               gboolean            clamp_node);
791 static gboolean gtk_tree_view_has_can_focus_cell             (GtkTreeView        *tree_view);
792 static void     column_sizing_notify                         (GObject            *object,
793                                                               GParamSpec         *pspec,
794                                                               gpointer            data);
795 static void     gtk_tree_view_stop_rubber_band               (GtkTreeView        *tree_view);
796 static void     update_prelight                              (GtkTreeView        *tree_view,
797                                                               int                 x,
798                                                               int                 y);
799
800 static inline gint gtk_tree_view_get_effective_header_height (GtkTreeView *tree_view);
801
802 static inline gint gtk_tree_view_get_cell_area_y_offset      (GtkTreeView *tree_view,
803                                                               GtkRBTree   *tree,
804                                                               GtkRBNode   *node,
805                                                               gint         vertical_separator);
806 static inline gint gtk_tree_view_get_cell_area_height        (GtkTreeView *tree_view,
807                                                               GtkRBNode   *node,
808                                                               gint         vertical_separator);
809
810 static inline gint gtk_tree_view_get_row_y_offset            (GtkTreeView *tree_view,
811                                                               GtkRBTree   *tree,
812                                                               GtkRBNode   *node);
813 static inline gint gtk_tree_view_get_row_height              (GtkTreeView *tree_view,
814                                                               GtkRBNode   *node);
815
816 /* interactive search */
817 static void     gtk_tree_view_ensure_interactive_directory (GtkTreeView *tree_view);
818 static void     gtk_tree_view_search_dialog_hide        (GtkWidget        *search_dialog,
819                                                          GtkTreeView      *tree_view,
820                                                          GdkDevice        *device);
821 static void     gtk_tree_view_search_position_func      (GtkTreeView      *tree_view,
822                                                          GtkWidget        *search_dialog,
823                                                          gpointer          user_data);
824 static void     gtk_tree_view_search_disable_popdown    (GtkEntry         *entry,
825                                                          GtkMenu          *menu,
826                                                          gpointer          data);
827 static void     gtk_tree_view_search_preedit_changed    (GtkIMContext     *im_context,
828                                                          GtkTreeView      *tree_view);
829 static void     gtk_tree_view_search_activate           (GtkEntry         *entry,
830                                                          GtkTreeView      *tree_view);
831 static gboolean gtk_tree_view_real_search_enable_popdown(gpointer          data);
832 static void     gtk_tree_view_search_enable_popdown     (GtkWidget        *widget,
833                                                          gpointer          data);
834 static gboolean gtk_tree_view_search_delete_event       (GtkWidget        *widget,
835                                                          GdkEventAny      *event,
836                                                          GtkTreeView      *tree_view);
837 static gboolean gtk_tree_view_search_button_press_event (GtkWidget        *widget,
838                                                          GdkEventButton   *event,
839                                                          GtkTreeView      *tree_view);
840 static gboolean gtk_tree_view_search_scroll_event       (GtkWidget        *entry,
841                                                          GdkEventScroll   *event,
842                                                          GtkTreeView      *tree_view);
843 static gboolean gtk_tree_view_search_key_press_event    (GtkWidget        *entry,
844                                                          GdkEventKey      *event,
845                                                          GtkTreeView      *tree_view);
846 static gboolean gtk_tree_view_search_move               (GtkWidget        *window,
847                                                          GtkTreeView      *tree_view,
848                                                          gboolean          up);
849 static gboolean gtk_tree_view_search_equal_func         (GtkTreeModel     *model,
850                                                          gint              column,
851                                                          const gchar      *key,
852                                                          GtkTreeIter      *iter,
853                                                          gpointer          search_data);
854 static gboolean gtk_tree_view_search_iter               (GtkTreeModel     *model,
855                                                          GtkTreeSelection *selection,
856                                                          GtkTreeIter      *iter,
857                                                          const gchar      *text,
858                                                          gint             *count,
859                                                          gint              n);
860 static void     gtk_tree_view_search_init               (GtkWidget        *entry,
861                                                          GtkTreeView      *tree_view);
862 static void     gtk_tree_view_put                       (GtkTreeView      *tree_view,
863                                                          GtkWidget        *child_widget,
864                                                          gint              x,
865                                                          gint              y,
866                                                          gint              width,
867                                                          gint              height);
868 static gboolean gtk_tree_view_start_editing             (GtkTreeView      *tree_view,
869                                                          GtkTreePath      *cursor_path,
870                                                          gboolean          edit_only);
871 static void gtk_tree_view_stop_editing                  (GtkTreeView *tree_view,
872                                                          gboolean     cancel_editing);
873 static gboolean gtk_tree_view_real_start_interactive_search (GtkTreeView *tree_view,
874                                                              GdkDevice   *device,
875                                                              gboolean     keybinding);
876 static gboolean gtk_tree_view_start_interactive_search      (GtkTreeView *tree_view);
877 static GtkTreeViewColumn *gtk_tree_view_get_drop_column (GtkTreeView       *tree_view,
878                                                          GtkTreeViewColumn *column,
879                                                          gint               drop_position);
880
881 /* GtkBuildable */
882 static void     gtk_tree_view_buildable_add_child          (GtkBuildable      *tree_view,
883                                                             GtkBuilder        *builder,
884                                                             GObject           *child,
885                                                             const gchar       *type);
886 static GObject *gtk_tree_view_buildable_get_internal_child (GtkBuildable      *buildable,
887                                                             GtkBuilder        *builder,
888                                                             const gchar       *childname);
889 static void     gtk_tree_view_buildable_init               (GtkBuildableIface *iface);
890
891 static GtkAdjustment *gtk_tree_view_do_get_hadjustment (GtkTreeView   *tree_view);
892 static void           gtk_tree_view_do_set_hadjustment (GtkTreeView   *tree_view,
893                                                         GtkAdjustment *adjustment);
894 static GtkAdjustment *gtk_tree_view_do_get_vadjustment (GtkTreeView   *tree_view);
895 static void           gtk_tree_view_do_set_vadjustment (GtkTreeView   *tree_view,
896                                                         GtkAdjustment *adjustment);
897
898 static gboolean scroll_row_timeout                   (gpointer     data);
899 static void     add_scroll_timeout                   (GtkTreeView *tree_view);
900 static void     remove_scroll_timeout                (GtkTreeView *tree_view);
901
902 static guint tree_view_signals [LAST_SIGNAL] = { 0 };
903
904 \f
905
906 /* GType Methods
907  */
908
909 G_DEFINE_TYPE_WITH_CODE (GtkTreeView, gtk_tree_view, GTK_TYPE_CONTAINER,
910                          G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
911                                                 gtk_tree_view_buildable_init)
912                          G_IMPLEMENT_INTERFACE (GTK_TYPE_SCROLLABLE, NULL))
913
914 static void
915 gtk_tree_view_class_init (GtkTreeViewClass *class)
916 {
917   GObjectClass *o_class;
918   GtkWidgetClass *widget_class;
919   GtkContainerClass *container_class;
920   GtkBindingSet *binding_set;
921
922   binding_set = gtk_binding_set_by_class (class);
923
924   o_class = (GObjectClass *) class;
925   widget_class = (GtkWidgetClass *) class;
926   container_class = (GtkContainerClass *) class;
927
928   /* GObject signals */
929   o_class->set_property = gtk_tree_view_set_property;
930   o_class->get_property = gtk_tree_view_get_property;
931   o_class->finalize = gtk_tree_view_finalize;
932
933   /* GtkWidget signals */
934   widget_class->destroy = gtk_tree_view_destroy;
935   widget_class->map = gtk_tree_view_map;
936   widget_class->realize = gtk_tree_view_realize;
937   widget_class->unrealize = gtk_tree_view_unrealize;
938   widget_class->get_preferred_width = gtk_tree_view_get_preferred_width;
939   widget_class->get_preferred_height = gtk_tree_view_get_preferred_height;
940   widget_class->size_allocate = gtk_tree_view_size_allocate;
941   widget_class->button_press_event = gtk_tree_view_button_press;
942   widget_class->button_release_event = gtk_tree_view_button_release;
943   widget_class->grab_broken_event = gtk_tree_view_grab_broken;
944   /*widget_class->configure_event = gtk_tree_view_configure;*/
945   widget_class->motion_notify_event = gtk_tree_view_motion;
946   widget_class->draw = gtk_tree_view_draw;
947   widget_class->key_press_event = gtk_tree_view_key_press;
948   widget_class->key_release_event = gtk_tree_view_key_release;
949   widget_class->enter_notify_event = gtk_tree_view_enter_notify;
950   widget_class->leave_notify_event = gtk_tree_view_leave_notify;
951   widget_class->focus_out_event = gtk_tree_view_focus_out;
952   widget_class->drag_begin = gtk_tree_view_drag_begin;
953   widget_class->drag_end = gtk_tree_view_drag_end;
954   widget_class->drag_data_get = gtk_tree_view_drag_data_get;
955   widget_class->drag_data_delete = gtk_tree_view_drag_data_delete;
956   widget_class->drag_leave = gtk_tree_view_drag_leave;
957   widget_class->drag_motion = gtk_tree_view_drag_motion;
958   widget_class->drag_drop = gtk_tree_view_drag_drop;
959   widget_class->drag_data_received = gtk_tree_view_drag_data_received;
960   widget_class->focus = gtk_tree_view_focus;
961   widget_class->grab_focus = gtk_tree_view_grab_focus;
962   widget_class->style_updated = gtk_tree_view_style_updated;
963   widget_class->grab_notify = gtk_tree_view_grab_notify;
964   widget_class->state_flags_changed = gtk_tree_view_state_flags_changed;
965
966   /* GtkContainer signals */
967   container_class->remove = gtk_tree_view_remove;
968   container_class->forall = gtk_tree_view_forall;
969   container_class->set_focus_child = gtk_tree_view_set_focus_child;
970   container_class->get_path_for_child = gtk_tree_view_get_path_for_child;
971
972   class->move_cursor = gtk_tree_view_real_move_cursor;
973   class->select_all = gtk_tree_view_real_select_all;
974   class->unselect_all = gtk_tree_view_real_unselect_all;
975   class->select_cursor_row = gtk_tree_view_real_select_cursor_row;
976   class->toggle_cursor_row = gtk_tree_view_real_toggle_cursor_row;
977   class->expand_collapse_cursor_row = gtk_tree_view_real_expand_collapse_cursor_row;
978   class->select_cursor_parent = gtk_tree_view_real_select_cursor_parent;
979   class->start_interactive_search = gtk_tree_view_start_interactive_search;
980
981   /* Properties */
982
983   g_object_class_install_property (o_class,
984                                    PROP_MODEL,
985                                    g_param_spec_object ("model",
986                                                         P_("TreeView Model"),
987                                                         P_("The model for the tree view"),
988                                                         GTK_TYPE_TREE_MODEL,
989                                                         GTK_PARAM_READWRITE));
990
991   g_object_class_override_property (o_class, PROP_HADJUSTMENT,    "hadjustment");
992   g_object_class_override_property (o_class, PROP_VADJUSTMENT,    "vadjustment");
993   g_object_class_override_property (o_class, PROP_HSCROLL_POLICY, "hscroll-policy");
994   g_object_class_override_property (o_class, PROP_VSCROLL_POLICY, "vscroll-policy");
995
996   g_object_class_install_property (o_class,
997                                    PROP_HEADERS_VISIBLE,
998                                    g_param_spec_boolean ("headers-visible",
999                                                          P_("Headers Visible"),
1000                                                          P_("Show the column header buttons"),
1001                                                          TRUE,
1002                                                          GTK_PARAM_READWRITE));
1003
1004   g_object_class_install_property (o_class,
1005                                    PROP_HEADERS_CLICKABLE,
1006                                    g_param_spec_boolean ("headers-clickable",
1007                                                          P_("Headers Clickable"),
1008                                                          P_("Column headers respond to click events"),
1009                                                          TRUE,
1010                                                          GTK_PARAM_READWRITE));
1011
1012   g_object_class_install_property (o_class,
1013                                    PROP_EXPANDER_COLUMN,
1014                                    g_param_spec_object ("expander-column",
1015                                                         P_("Expander Column"),
1016                                                         P_("Set the column for the expander column"),
1017                                                         GTK_TYPE_TREE_VIEW_COLUMN,
1018                                                         GTK_PARAM_READWRITE));
1019
1020   g_object_class_install_property (o_class,
1021                                    PROP_REORDERABLE,
1022                                    g_param_spec_boolean ("reorderable",
1023                                                          P_("Reorderable"),
1024                                                          P_("View is reorderable"),
1025                                                          FALSE,
1026                                                          GTK_PARAM_READWRITE));
1027
1028   g_object_class_install_property (o_class,
1029                                    PROP_RULES_HINT,
1030                                    g_param_spec_boolean ("rules-hint",
1031                                                          P_("Rules Hint"),
1032                                                          P_("Set a hint to the theme engine to draw rows in alternating colors"),
1033                                                          FALSE,
1034                                                          GTK_PARAM_READWRITE));
1035
1036     g_object_class_install_property (o_class,
1037                                      PROP_ENABLE_SEARCH,
1038                                      g_param_spec_boolean ("enable-search",
1039                                                            P_("Enable Search"),
1040                                                            P_("View allows user to search through columns interactively"),
1041                                                            TRUE,
1042                                                            GTK_PARAM_READWRITE));
1043
1044     g_object_class_install_property (o_class,
1045                                      PROP_SEARCH_COLUMN,
1046                                      g_param_spec_int ("search-column",
1047                                                        P_("Search Column"),
1048                                                        P_("Model column to search through during interactive search"),
1049                                                        -1,
1050                                                        G_MAXINT,
1051                                                        -1,
1052                                                        GTK_PARAM_READWRITE));
1053
1054     /**
1055      * GtkTreeView:fixed-height-mode:
1056      *
1057      * Setting the ::fixed-height-mode property to %TRUE speeds up 
1058      * #GtkTreeView by assuming that all rows have the same height. 
1059      * Only enable this option if all rows are the same height.  
1060      * Please see gtk_tree_view_set_fixed_height_mode() for more 
1061      * information on this option.
1062      *
1063      * Since: 2.4
1064      **/
1065     g_object_class_install_property (o_class,
1066                                      PROP_FIXED_HEIGHT_MODE,
1067                                      g_param_spec_boolean ("fixed-height-mode",
1068                                                            P_("Fixed Height Mode"),
1069                                                            P_("Speeds up GtkTreeView by assuming that all rows have the same height"),
1070                                                            FALSE,
1071                                                            GTK_PARAM_READWRITE));
1072     
1073     /**
1074      * GtkTreeView:hover-selection:
1075      * 
1076      * Enables or disables the hover selection mode of @tree_view.
1077      * Hover selection makes the selected row follow the pointer.
1078      * Currently, this works only for the selection modes 
1079      * %GTK_SELECTION_SINGLE and %GTK_SELECTION_BROWSE.
1080      *
1081      * This mode is primarily intended for treeviews in popups, e.g.
1082      * in #GtkComboBox or #GtkEntryCompletion.
1083      *
1084      * Since: 2.6
1085      */
1086     g_object_class_install_property (o_class,
1087                                      PROP_HOVER_SELECTION,
1088                                      g_param_spec_boolean ("hover-selection",
1089                                                            P_("Hover Selection"),
1090                                                            P_("Whether the selection should follow the pointer"),
1091                                                            FALSE,
1092                                                            GTK_PARAM_READWRITE));
1093
1094     /**
1095      * GtkTreeView:hover-expand:
1096      * 
1097      * Enables or disables the hover expansion mode of @tree_view.
1098      * Hover expansion makes rows expand or collapse if the pointer moves 
1099      * over them.
1100      *
1101      * This mode is primarily intended for treeviews in popups, e.g.
1102      * in #GtkComboBox or #GtkEntryCompletion.
1103      *
1104      * Since: 2.6
1105      */
1106     g_object_class_install_property (o_class,
1107                                      PROP_HOVER_EXPAND,
1108                                      g_param_spec_boolean ("hover-expand",
1109                                                            P_("Hover Expand"),
1110                                                            P_("Whether rows should be expanded/collapsed when the pointer moves over them"),
1111                                                            FALSE,
1112                                                            GTK_PARAM_READWRITE));
1113
1114     /**
1115      * GtkTreeView:show-expanders:
1116      *
1117      * %TRUE if the view has expanders.
1118      *
1119      * Since: 2.12
1120      */
1121     g_object_class_install_property (o_class,
1122                                      PROP_SHOW_EXPANDERS,
1123                                      g_param_spec_boolean ("show-expanders",
1124                                                            P_("Show Expanders"),
1125                                                            P_("View has expanders"),
1126                                                            TRUE,
1127                                                            GTK_PARAM_READWRITE));
1128
1129     /**
1130      * GtkTreeView:level-indentation:
1131      *
1132      * Extra indentation for each level.
1133      *
1134      * Since: 2.12
1135      */
1136     g_object_class_install_property (o_class,
1137                                      PROP_LEVEL_INDENTATION,
1138                                      g_param_spec_int ("level-indentation",
1139                                                        P_("Level Indentation"),
1140                                                        P_("Extra indentation for each level"),
1141                                                        0,
1142                                                        G_MAXINT,
1143                                                        0,
1144                                                        GTK_PARAM_READWRITE));
1145
1146     g_object_class_install_property (o_class,
1147                                      PROP_RUBBER_BANDING,
1148                                      g_param_spec_boolean ("rubber-banding",
1149                                                            P_("Rubber Banding"),
1150                                                            P_("Whether to enable selection of multiple items by dragging the mouse pointer"),
1151                                                            FALSE,
1152                                                            GTK_PARAM_READWRITE));
1153
1154     g_object_class_install_property (o_class,
1155                                      PROP_ENABLE_GRID_LINES,
1156                                      g_param_spec_enum ("enable-grid-lines",
1157                                                         P_("Enable Grid Lines"),
1158                                                         P_("Whether grid lines should be drawn in the tree view"),
1159                                                         GTK_TYPE_TREE_VIEW_GRID_LINES,
1160                                                         GTK_TREE_VIEW_GRID_LINES_NONE,
1161                                                         GTK_PARAM_READWRITE));
1162
1163     g_object_class_install_property (o_class,
1164                                      PROP_ENABLE_TREE_LINES,
1165                                      g_param_spec_boolean ("enable-tree-lines",
1166                                                            P_("Enable Tree Lines"),
1167                                                            P_("Whether tree lines should be drawn in the tree view"),
1168                                                            FALSE,
1169                                                            GTK_PARAM_READWRITE));
1170
1171     g_object_class_install_property (o_class,
1172                                      PROP_TOOLTIP_COLUMN,
1173                                      g_param_spec_int ("tooltip-column",
1174                                                        P_("Tooltip Column"),
1175                                                        P_("The column in the model containing the tooltip texts for the rows"),
1176                                                        -1,
1177                                                        G_MAXINT,
1178                                                        -1,
1179                                                        GTK_PARAM_READWRITE));
1180
1181   /* Style properties */
1182 #define _TREE_VIEW_EXPANDER_SIZE 14
1183 #define _TREE_VIEW_VERTICAL_SEPARATOR 2
1184 #define _TREE_VIEW_HORIZONTAL_SEPARATOR 2
1185
1186   gtk_widget_class_install_style_property (widget_class,
1187                                            g_param_spec_int ("expander-size",
1188                                                              P_("Expander Size"),
1189                                                              P_("Size of the expander arrow"),
1190                                                              0,
1191                                                              G_MAXINT,
1192                                                              _TREE_VIEW_EXPANDER_SIZE,
1193                                                              GTK_PARAM_READABLE));
1194
1195   gtk_widget_class_install_style_property (widget_class,
1196                                            g_param_spec_int ("vertical-separator",
1197                                                              P_("Vertical Separator Width"),
1198                                                              P_("Vertical space between cells.  Must be an even number"),
1199                                                              0,
1200                                                              G_MAXINT,
1201                                                              _TREE_VIEW_VERTICAL_SEPARATOR,
1202                                                              GTK_PARAM_READABLE));
1203
1204   gtk_widget_class_install_style_property (widget_class,
1205                                            g_param_spec_int ("horizontal-separator",
1206                                                              P_("Horizontal Separator Width"),
1207                                                              P_("Horizontal space between cells.  Must be an even number"),
1208                                                              0,
1209                                                              G_MAXINT,
1210                                                              _TREE_VIEW_HORIZONTAL_SEPARATOR,
1211                                                              GTK_PARAM_READABLE));
1212
1213   gtk_widget_class_install_style_property (widget_class,
1214                                            g_param_spec_boolean ("allow-rules",
1215                                                                  P_("Allow Rules"),
1216                                                                  P_("Allow drawing of alternating color rows"),
1217                                                                  TRUE,
1218                                                                  GTK_PARAM_READABLE));
1219
1220   gtk_widget_class_install_style_property (widget_class,
1221                                            g_param_spec_boolean ("indent-expanders",
1222                                                                  P_("Indent Expanders"),
1223                                                                  P_("Make the expanders indented"),
1224                                                                  TRUE,
1225                                                                  GTK_PARAM_READABLE));
1226
1227   gtk_widget_class_install_style_property (widget_class,
1228                                            g_param_spec_boxed ("even-row-color",
1229                                                                P_("Even Row Color"),
1230                                                                P_("Color to use for even rows"),
1231                                                                GDK_TYPE_COLOR,
1232                                                                GTK_PARAM_READABLE));
1233
1234   gtk_widget_class_install_style_property (widget_class,
1235                                            g_param_spec_boxed ("odd-row-color",
1236                                                                P_("Odd Row Color"),
1237                                                                P_("Color to use for odd rows"),
1238                                                                GDK_TYPE_COLOR,
1239                                                                GTK_PARAM_READABLE));
1240
1241   gtk_widget_class_install_style_property (widget_class,
1242                                            g_param_spec_int ("grid-line-width",
1243                                                              P_("Grid line width"),
1244                                                              P_("Width, in pixels, of the tree view grid lines"),
1245                                                              0, G_MAXINT, 1,
1246                                                              GTK_PARAM_READABLE));
1247
1248   gtk_widget_class_install_style_property (widget_class,
1249                                            g_param_spec_int ("tree-line-width",
1250                                                              P_("Tree line width"),
1251                                                              P_("Width, in pixels, of the tree view lines"),
1252                                                              0, G_MAXINT, 1,
1253                                                              GTK_PARAM_READABLE));
1254
1255   gtk_widget_class_install_style_property (widget_class,
1256                                            g_param_spec_string ("grid-line-pattern",
1257                                                                 P_("Grid line pattern"),
1258                                                                 P_("Dash pattern used to draw the tree view grid lines"),
1259                                                                 "\1\1",
1260                                                                 GTK_PARAM_READABLE));
1261
1262   gtk_widget_class_install_style_property (widget_class,
1263                                            g_param_spec_string ("tree-line-pattern",
1264                                                                 P_("Tree line pattern"),
1265                                                                 P_("Dash pattern used to draw the tree view lines"),
1266                                                                 "\1\1",
1267                                                                 GTK_PARAM_READABLE));
1268
1269   /* Signals */
1270   /**
1271    * GtkTreeView::row-activated:
1272    * @tree_view: the object on which the signal is emitted
1273    * @path: the #GtkTreePath for the activated row
1274    * @column: the #GtkTreeViewColumn in which the activation occurred
1275    *
1276    * The "row-activated" signal is emitted when the method
1277    * gtk_tree_view_row_activated() is called or the user double clicks 
1278    * a treeview row. It is also emitted when a non-editable row is 
1279    * selected and one of the keys: Space, Shift+Space, Return or 
1280    * Enter is pressed.
1281    * 
1282    * For selection handling refer to the <link linkend="TreeWidget">tree 
1283    * widget conceptual overview</link> as well as #GtkTreeSelection.
1284    */
1285   tree_view_signals[ROW_ACTIVATED] =
1286     g_signal_new (I_("row-activated"),
1287                   G_TYPE_FROM_CLASS (o_class),
1288                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1289                   G_STRUCT_OFFSET (GtkTreeViewClass, row_activated),
1290                   NULL, NULL,
1291                   _gtk_marshal_VOID__BOXED_OBJECT,
1292                   G_TYPE_NONE, 2,
1293                   GTK_TYPE_TREE_PATH,
1294                   GTK_TYPE_TREE_VIEW_COLUMN);
1295
1296   /**
1297    * GtkTreeView::test-expand-row:
1298    * @tree_view: the object on which the signal is emitted
1299    * @iter: the tree iter of the row to expand
1300    * @path: a tree path that points to the row 
1301    * 
1302    * The given row is about to be expanded (show its children nodes). Use this
1303    * signal if you need to control the expandability of individual rows.
1304    *
1305    * Returns: %FALSE to allow expansion, %TRUE to reject
1306    */
1307   tree_view_signals[TEST_EXPAND_ROW] =
1308     g_signal_new (I_("test-expand-row"),
1309                   G_TYPE_FROM_CLASS (o_class),
1310                   G_SIGNAL_RUN_LAST,
1311                   G_STRUCT_OFFSET (GtkTreeViewClass, test_expand_row),
1312                   _gtk_boolean_handled_accumulator, NULL,
1313                   _gtk_marshal_BOOLEAN__BOXED_BOXED,
1314                   G_TYPE_BOOLEAN, 2,
1315                   GTK_TYPE_TREE_ITER,
1316                   GTK_TYPE_TREE_PATH);
1317
1318   /**
1319    * GtkTreeView::test-collapse-row:
1320    * @tree_view: the object on which the signal is emitted
1321    * @iter: the tree iter of the row to collapse
1322    * @path: a tree path that points to the row 
1323    * 
1324    * The given row is about to be collapsed (hide its children nodes). Use this
1325    * signal if you need to control the collapsibility of individual rows.
1326    *
1327    * Returns: %FALSE to allow collapsing, %TRUE to reject
1328    */
1329   tree_view_signals[TEST_COLLAPSE_ROW] =
1330     g_signal_new (I_("test-collapse-row"),
1331                   G_TYPE_FROM_CLASS (o_class),
1332                   G_SIGNAL_RUN_LAST,
1333                   G_STRUCT_OFFSET (GtkTreeViewClass, test_collapse_row),
1334                   _gtk_boolean_handled_accumulator, NULL,
1335                   _gtk_marshal_BOOLEAN__BOXED_BOXED,
1336                   G_TYPE_BOOLEAN, 2,
1337                   GTK_TYPE_TREE_ITER,
1338                   GTK_TYPE_TREE_PATH);
1339
1340   /**
1341    * GtkTreeView::row-expanded:
1342    * @tree_view: the object on which the signal is emitted
1343    * @iter: the tree iter of the expanded row
1344    * @path: a tree path that points to the row 
1345    * 
1346    * The given row has been expanded (child nodes are shown).
1347    */
1348   tree_view_signals[ROW_EXPANDED] =
1349     g_signal_new (I_("row-expanded"),
1350                   G_TYPE_FROM_CLASS (o_class),
1351                   G_SIGNAL_RUN_LAST,
1352                   G_STRUCT_OFFSET (GtkTreeViewClass, row_expanded),
1353                   NULL, NULL,
1354                   _gtk_marshal_VOID__BOXED_BOXED,
1355                   G_TYPE_NONE, 2,
1356                   GTK_TYPE_TREE_ITER,
1357                   GTK_TYPE_TREE_PATH);
1358
1359   /**
1360    * GtkTreeView::row-collapsed:
1361    * @tree_view: the object on which the signal is emitted
1362    * @iter: the tree iter of the collapsed row
1363    * @path: a tree path that points to the row 
1364    * 
1365    * The given row has been collapsed (child nodes are hidden).
1366    */
1367   tree_view_signals[ROW_COLLAPSED] =
1368     g_signal_new (I_("row-collapsed"),
1369                   G_TYPE_FROM_CLASS (o_class),
1370                   G_SIGNAL_RUN_LAST,
1371                   G_STRUCT_OFFSET (GtkTreeViewClass, row_collapsed),
1372                   NULL, NULL,
1373                   _gtk_marshal_VOID__BOXED_BOXED,
1374                   G_TYPE_NONE, 2,
1375                   GTK_TYPE_TREE_ITER,
1376                   GTK_TYPE_TREE_PATH);
1377
1378   /**
1379    * GtkTreeView::columns-changed:
1380    * @tree_view: the object on which the signal is emitted 
1381    * 
1382    * The number of columns of the treeview has changed.
1383    */
1384   tree_view_signals[COLUMNS_CHANGED] =
1385     g_signal_new (I_("columns-changed"),
1386                   G_TYPE_FROM_CLASS (o_class),
1387                   G_SIGNAL_RUN_LAST,
1388                   G_STRUCT_OFFSET (GtkTreeViewClass, columns_changed),
1389                   NULL, NULL,
1390                   _gtk_marshal_VOID__VOID,
1391                   G_TYPE_NONE, 0);
1392
1393   /**
1394    * GtkTreeView::cursor-changed:
1395    * @tree_view: the object on which the signal is emitted
1396    * 
1397    * The position of the cursor (focused cell) has changed.
1398    */
1399   tree_view_signals[CURSOR_CHANGED] =
1400     g_signal_new (I_("cursor-changed"),
1401                   G_TYPE_FROM_CLASS (o_class),
1402                   G_SIGNAL_RUN_LAST,
1403                   G_STRUCT_OFFSET (GtkTreeViewClass, cursor_changed),
1404                   NULL, NULL,
1405                   _gtk_marshal_VOID__VOID,
1406                   G_TYPE_NONE, 0);
1407
1408   tree_view_signals[MOVE_CURSOR] =
1409     g_signal_new (I_("move-cursor"),
1410                   G_TYPE_FROM_CLASS (o_class),
1411                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1412                   G_STRUCT_OFFSET (GtkTreeViewClass, move_cursor),
1413                   NULL, NULL,
1414                   _gtk_marshal_BOOLEAN__ENUM_INT,
1415                   G_TYPE_BOOLEAN, 2,
1416                   GTK_TYPE_MOVEMENT_STEP,
1417                   G_TYPE_INT);
1418
1419   tree_view_signals[SELECT_ALL] =
1420     g_signal_new (I_("select-all"),
1421                   G_TYPE_FROM_CLASS (o_class),
1422                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1423                   G_STRUCT_OFFSET (GtkTreeViewClass, select_all),
1424                   NULL, NULL,
1425                   _gtk_marshal_BOOLEAN__VOID,
1426                   G_TYPE_BOOLEAN, 0);
1427
1428   tree_view_signals[UNSELECT_ALL] =
1429     g_signal_new (I_("unselect-all"),
1430                   G_TYPE_FROM_CLASS (o_class),
1431                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1432                   G_STRUCT_OFFSET (GtkTreeViewClass, unselect_all),
1433                   NULL, NULL,
1434                   _gtk_marshal_BOOLEAN__VOID,
1435                   G_TYPE_BOOLEAN, 0);
1436
1437   tree_view_signals[SELECT_CURSOR_ROW] =
1438     g_signal_new (I_("select-cursor-row"),
1439                   G_TYPE_FROM_CLASS (o_class),
1440                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1441                   G_STRUCT_OFFSET (GtkTreeViewClass, select_cursor_row),
1442                   NULL, NULL,
1443                   _gtk_marshal_BOOLEAN__BOOLEAN,
1444                   G_TYPE_BOOLEAN, 1,
1445                   G_TYPE_BOOLEAN);
1446
1447   tree_view_signals[TOGGLE_CURSOR_ROW] =
1448     g_signal_new (I_("toggle-cursor-row"),
1449                   G_TYPE_FROM_CLASS (o_class),
1450                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1451                   G_STRUCT_OFFSET (GtkTreeViewClass, toggle_cursor_row),
1452                   NULL, NULL,
1453                   _gtk_marshal_BOOLEAN__VOID,
1454                   G_TYPE_BOOLEAN, 0);
1455
1456   tree_view_signals[EXPAND_COLLAPSE_CURSOR_ROW] =
1457     g_signal_new (I_("expand-collapse-cursor-row"),
1458                   G_TYPE_FROM_CLASS (o_class),
1459                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1460                   G_STRUCT_OFFSET (GtkTreeViewClass, expand_collapse_cursor_row),
1461                   NULL, NULL,
1462                   _gtk_marshal_BOOLEAN__BOOLEAN_BOOLEAN_BOOLEAN,
1463                   G_TYPE_BOOLEAN, 3,
1464                   G_TYPE_BOOLEAN,
1465                   G_TYPE_BOOLEAN,
1466                   G_TYPE_BOOLEAN);
1467
1468   tree_view_signals[SELECT_CURSOR_PARENT] =
1469     g_signal_new (I_("select-cursor-parent"),
1470                   G_TYPE_FROM_CLASS (o_class),
1471                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1472                   G_STRUCT_OFFSET (GtkTreeViewClass, select_cursor_parent),
1473                   NULL, NULL,
1474                   _gtk_marshal_BOOLEAN__VOID,
1475                   G_TYPE_BOOLEAN, 0);
1476
1477   tree_view_signals[START_INTERACTIVE_SEARCH] =
1478     g_signal_new (I_("start-interactive-search"),
1479                   G_TYPE_FROM_CLASS (o_class),
1480                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1481                   G_STRUCT_OFFSET (GtkTreeViewClass, start_interactive_search),
1482                   NULL, NULL,
1483                   _gtk_marshal_BOOLEAN__VOID,
1484                   G_TYPE_BOOLEAN, 0);
1485
1486   /* Key bindings */
1487   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Up, 0, TRUE,
1488                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
1489   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Up, 0, TRUE,
1490                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
1491
1492   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Down, 0, TRUE,
1493                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
1494   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Down, 0, TRUE,
1495                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
1496
1497   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_p, GDK_CONTROL_MASK, FALSE,
1498                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
1499
1500   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_n, GDK_CONTROL_MASK, FALSE,
1501                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
1502
1503   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Home, 0, TRUE,
1504                                   GTK_MOVEMENT_BUFFER_ENDS, -1);
1505   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Home, 0, TRUE,
1506                                   GTK_MOVEMENT_BUFFER_ENDS, -1);
1507
1508   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_End, 0, TRUE,
1509                                   GTK_MOVEMENT_BUFFER_ENDS, 1);
1510   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_End, 0, TRUE,
1511                                   GTK_MOVEMENT_BUFFER_ENDS, 1);
1512
1513   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Page_Up, 0, TRUE,
1514                                   GTK_MOVEMENT_PAGES, -1);
1515   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Page_Up, 0, TRUE,
1516                                   GTK_MOVEMENT_PAGES, -1);
1517
1518   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Page_Down, 0, TRUE,
1519                                   GTK_MOVEMENT_PAGES, 1);
1520   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Page_Down, 0, TRUE,
1521                                   GTK_MOVEMENT_PAGES, 1);
1522
1523
1524   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Right, 0, "move-cursor", 2,
1525                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1526                                 G_TYPE_INT, 1);
1527
1528   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Left, 0, "move-cursor", 2,
1529                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1530                                 G_TYPE_INT, -1);
1531
1532   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Right, 0, "move-cursor", 2,
1533                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1534                                 G_TYPE_INT, 1);
1535
1536   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Left, 0, "move-cursor", 2,
1537                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1538                                 G_TYPE_INT, -1);
1539
1540   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Right, GDK_CONTROL_MASK,
1541                                 "move-cursor", 2,
1542                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1543                                 G_TYPE_INT, 1);
1544
1545   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Left, GDK_CONTROL_MASK,
1546                                 "move-cursor", 2,
1547                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1548                                 G_TYPE_INT, -1);
1549
1550   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Right, GDK_CONTROL_MASK,
1551                                 "move-cursor", 2,
1552                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1553                                 G_TYPE_INT, 1);
1554
1555   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Left, GDK_CONTROL_MASK,
1556                                 "move-cursor", 2,
1557                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1558                                 G_TYPE_INT, -1);
1559
1560   gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, GDK_CONTROL_MASK, "toggle-cursor-row", 0);
1561   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Space, GDK_CONTROL_MASK, "toggle-cursor-row", 0);
1562
1563   gtk_binding_entry_add_signal (binding_set, GDK_KEY_a, GDK_CONTROL_MASK, "select-all", 0);
1564   gtk_binding_entry_add_signal (binding_set, GDK_KEY_slash, GDK_CONTROL_MASK, "select-all", 0);
1565
1566   gtk_binding_entry_add_signal (binding_set, GDK_KEY_A, GDK_CONTROL_MASK | GDK_SHIFT_MASK, "unselect-all", 0);
1567   gtk_binding_entry_add_signal (binding_set, GDK_KEY_backslash, GDK_CONTROL_MASK, "unselect-all", 0);
1568
1569   gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, GDK_SHIFT_MASK, "select-cursor-row", 1,
1570                                 G_TYPE_BOOLEAN, TRUE);
1571   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Space, GDK_SHIFT_MASK, "select-cursor-row", 1,
1572                                 G_TYPE_BOOLEAN, TRUE);
1573
1574   gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, 0, "select-cursor-row", 1,
1575                                 G_TYPE_BOOLEAN, TRUE);
1576   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Space, 0, "select-cursor-row", 1,
1577                                 G_TYPE_BOOLEAN, TRUE);
1578   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Return, 0, "select-cursor-row", 1,
1579                                 G_TYPE_BOOLEAN, TRUE);
1580   gtk_binding_entry_add_signal (binding_set, GDK_KEY_ISO_Enter, 0, "select-cursor-row", 1,
1581                                 G_TYPE_BOOLEAN, TRUE);
1582   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Enter, 0, "select-cursor-row", 1,
1583                                 G_TYPE_BOOLEAN, TRUE);
1584
1585   /* expand and collapse rows */
1586   gtk_binding_entry_add_signal (binding_set, GDK_KEY_plus, 0, "expand-collapse-cursor-row", 3,
1587                                 G_TYPE_BOOLEAN, TRUE,
1588                                 G_TYPE_BOOLEAN, TRUE,
1589                                 G_TYPE_BOOLEAN, FALSE);
1590
1591   gtk_binding_entry_add_signal (binding_set, GDK_KEY_asterisk, 0,
1592                                 "expand-collapse-cursor-row", 3,
1593                                 G_TYPE_BOOLEAN, TRUE,
1594                                 G_TYPE_BOOLEAN, TRUE,
1595                                 G_TYPE_BOOLEAN, TRUE);
1596   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Multiply, 0,
1597                                 "expand-collapse-cursor-row", 3,
1598                                 G_TYPE_BOOLEAN, TRUE,
1599                                 G_TYPE_BOOLEAN, TRUE,
1600                                 G_TYPE_BOOLEAN, TRUE);
1601
1602   gtk_binding_entry_add_signal (binding_set, GDK_KEY_slash, 0,
1603                                 "expand-collapse-cursor-row", 3,
1604                                 G_TYPE_BOOLEAN, TRUE,
1605                                 G_TYPE_BOOLEAN, FALSE,
1606                                 G_TYPE_BOOLEAN, FALSE);
1607   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Divide, 0,
1608                                 "expand-collapse-cursor-row", 3,
1609                                 G_TYPE_BOOLEAN, TRUE,
1610                                 G_TYPE_BOOLEAN, FALSE,
1611                                 G_TYPE_BOOLEAN, FALSE);
1612
1613   /* Not doable on US keyboards */
1614   gtk_binding_entry_add_signal (binding_set, GDK_KEY_plus, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1615                                 G_TYPE_BOOLEAN, TRUE,
1616                                 G_TYPE_BOOLEAN, TRUE,
1617                                 G_TYPE_BOOLEAN, TRUE);
1618   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Add, 0, "expand-collapse-cursor-row", 3,
1619                                 G_TYPE_BOOLEAN, TRUE,
1620                                 G_TYPE_BOOLEAN, TRUE,
1621                                 G_TYPE_BOOLEAN, FALSE);
1622   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Add, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1623                                 G_TYPE_BOOLEAN, TRUE,
1624                                 G_TYPE_BOOLEAN, TRUE,
1625                                 G_TYPE_BOOLEAN, TRUE);
1626   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Add, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1627                                 G_TYPE_BOOLEAN, TRUE,
1628                                 G_TYPE_BOOLEAN, TRUE,
1629                                 G_TYPE_BOOLEAN, TRUE);
1630   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Right, GDK_SHIFT_MASK,
1631                                 "expand-collapse-cursor-row", 3,
1632                                 G_TYPE_BOOLEAN, FALSE,
1633                                 G_TYPE_BOOLEAN, TRUE,
1634                                 G_TYPE_BOOLEAN, TRUE);
1635   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Right, GDK_SHIFT_MASK,
1636                                 "expand-collapse-cursor-row", 3,
1637                                 G_TYPE_BOOLEAN, FALSE,
1638                                 G_TYPE_BOOLEAN, TRUE,
1639                                 G_TYPE_BOOLEAN, TRUE);
1640   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Right,
1641                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1642                                 "expand-collapse-cursor-row", 3,
1643                                 G_TYPE_BOOLEAN, FALSE,
1644                                 G_TYPE_BOOLEAN, TRUE,
1645                                 G_TYPE_BOOLEAN, TRUE);
1646   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Right,
1647                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1648                                 "expand-collapse-cursor-row", 3,
1649                                 G_TYPE_BOOLEAN, FALSE,
1650                                 G_TYPE_BOOLEAN, TRUE,
1651                                 G_TYPE_BOOLEAN, TRUE);
1652
1653   gtk_binding_entry_add_signal (binding_set, GDK_KEY_minus, 0, "expand-collapse-cursor-row", 3,
1654                                 G_TYPE_BOOLEAN, TRUE,
1655                                 G_TYPE_BOOLEAN, FALSE,
1656                                 G_TYPE_BOOLEAN, FALSE);
1657   gtk_binding_entry_add_signal (binding_set, GDK_KEY_minus, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1658                                 G_TYPE_BOOLEAN, TRUE,
1659                                 G_TYPE_BOOLEAN, FALSE,
1660                                 G_TYPE_BOOLEAN, TRUE);
1661   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Subtract, 0, "expand-collapse-cursor-row", 3,
1662                                 G_TYPE_BOOLEAN, TRUE,
1663                                 G_TYPE_BOOLEAN, FALSE,
1664                                 G_TYPE_BOOLEAN, FALSE);
1665   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Subtract, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1666                                 G_TYPE_BOOLEAN, TRUE,
1667                                 G_TYPE_BOOLEAN, FALSE,
1668                                 G_TYPE_BOOLEAN, TRUE);
1669   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Left, GDK_SHIFT_MASK,
1670                                 "expand-collapse-cursor-row", 3,
1671                                 G_TYPE_BOOLEAN, FALSE,
1672                                 G_TYPE_BOOLEAN, FALSE,
1673                                 G_TYPE_BOOLEAN, TRUE);
1674   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Left, GDK_SHIFT_MASK,
1675                                 "expand-collapse-cursor-row", 3,
1676                                 G_TYPE_BOOLEAN, FALSE,
1677                                 G_TYPE_BOOLEAN, FALSE,
1678                                 G_TYPE_BOOLEAN, TRUE);
1679   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Left,
1680                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1681                                 "expand-collapse-cursor-row", 3,
1682                                 G_TYPE_BOOLEAN, FALSE,
1683                                 G_TYPE_BOOLEAN, FALSE,
1684                                 G_TYPE_BOOLEAN, TRUE);
1685   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Left,
1686                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1687                                 "expand-collapse-cursor-row", 3,
1688                                 G_TYPE_BOOLEAN, FALSE,
1689                                 G_TYPE_BOOLEAN, FALSE,
1690                                 G_TYPE_BOOLEAN, TRUE);
1691
1692   gtk_binding_entry_add_signal (binding_set, GDK_KEY_BackSpace, 0, "select-cursor-parent", 0);
1693   gtk_binding_entry_add_signal (binding_set, GDK_KEY_BackSpace, GDK_CONTROL_MASK, "select-cursor-parent", 0);
1694
1695   gtk_binding_entry_add_signal (binding_set, GDK_KEY_f, GDK_CONTROL_MASK, "start-interactive-search", 0);
1696
1697   gtk_binding_entry_add_signal (binding_set, GDK_KEY_F, GDK_CONTROL_MASK, "start-interactive-search", 0);
1698
1699   g_type_class_add_private (o_class, sizeof (GtkTreeViewPrivate));
1700
1701   gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_TREE_VIEW_ACCESSIBLE);
1702 }
1703
1704 static void
1705 gtk_tree_view_init (GtkTreeView *tree_view)
1706 {
1707   tree_view->priv = G_TYPE_INSTANCE_GET_PRIVATE (tree_view, GTK_TYPE_TREE_VIEW, GtkTreeViewPrivate);
1708
1709   gtk_widget_set_can_focus (GTK_WIDGET (tree_view), TRUE);
1710   gtk_widget_set_redraw_on_allocate (GTK_WIDGET (tree_view), FALSE);
1711
1712   tree_view->priv->show_expanders = TRUE;
1713   tree_view->priv->draw_keyfocus = TRUE;
1714   tree_view->priv->headers_visible = TRUE;
1715
1716   /* We need some padding */
1717   tree_view->priv->dy = 0;
1718   tree_view->priv->cursor_offset = 0;
1719   tree_view->priv->n_columns = 0;
1720   tree_view->priv->header_height = 1;
1721   tree_view->priv->x_drag = 0;
1722   tree_view->priv->drag_pos = -1;
1723   tree_view->priv->header_has_focus = FALSE;
1724   tree_view->priv->pressed_button = -1;
1725   tree_view->priv->press_start_x = -1;
1726   tree_view->priv->press_start_y = -1;
1727   tree_view->priv->reorderable = FALSE;
1728   tree_view->priv->presize_handler_timer = 0;
1729   tree_view->priv->scroll_sync_timer = 0;
1730   tree_view->priv->fixed_height = -1;
1731   tree_view->priv->fixed_height_mode = FALSE;
1732   tree_view->priv->fixed_height_check = 0;
1733   tree_view->priv->selection = _gtk_tree_selection_new_with_tree_view (tree_view);
1734   tree_view->priv->enable_search = TRUE;
1735   tree_view->priv->search_column = -1;
1736   tree_view->priv->search_position_func = gtk_tree_view_search_position_func;
1737   tree_view->priv->search_equal_func = gtk_tree_view_search_equal_func;
1738   tree_view->priv->search_custom_entry_set = FALSE;
1739   tree_view->priv->typeselect_flush_timeout = 0;
1740   tree_view->priv->init_hadjust_value = TRUE;    
1741   tree_view->priv->width = 0;
1742           
1743   tree_view->priv->hover_selection = FALSE;
1744   tree_view->priv->hover_expand = FALSE;
1745
1746   tree_view->priv->level_indentation = 0;
1747
1748   tree_view->priv->rubber_banding_enable = FALSE;
1749
1750   tree_view->priv->grid_lines = GTK_TREE_VIEW_GRID_LINES_NONE;
1751   tree_view->priv->tree_lines_enabled = FALSE;
1752
1753   tree_view->priv->tooltip_column = -1;
1754
1755   tree_view->priv->post_validation_flag = FALSE;
1756
1757   tree_view->priv->last_button_x = -1;
1758   tree_view->priv->last_button_y = -1;
1759
1760   tree_view->priv->event_last_x = -10000;
1761   tree_view->priv->event_last_y = -10000;
1762
1763   gtk_tree_view_do_set_vadjustment (tree_view, NULL);
1764   gtk_tree_view_do_set_hadjustment (tree_view, NULL);
1765 }
1766
1767 \f
1768
1769 /* GObject Methods
1770  */
1771
1772 static void
1773 gtk_tree_view_set_property (GObject         *object,
1774                             guint            prop_id,
1775                             const GValue    *value,
1776                             GParamSpec      *pspec)
1777 {
1778   GtkTreeView *tree_view;
1779
1780   tree_view = GTK_TREE_VIEW (object);
1781
1782   switch (prop_id)
1783     {
1784     case PROP_MODEL:
1785       gtk_tree_view_set_model (tree_view, g_value_get_object (value));
1786       break;
1787     case PROP_HADJUSTMENT:
1788       gtk_tree_view_do_set_hadjustment (tree_view, g_value_get_object (value));
1789       break;
1790     case PROP_VADJUSTMENT:
1791       gtk_tree_view_do_set_vadjustment (tree_view, g_value_get_object (value));
1792       break;
1793     case PROP_HSCROLL_POLICY:
1794       tree_view->priv->hscroll_policy = g_value_get_enum (value);
1795       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
1796       break;
1797     case PROP_VSCROLL_POLICY:
1798       tree_view->priv->vscroll_policy = g_value_get_enum (value);
1799       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
1800       break;
1801     case PROP_HEADERS_VISIBLE:
1802       gtk_tree_view_set_headers_visible (tree_view, g_value_get_boolean (value));
1803       break;
1804     case PROP_HEADERS_CLICKABLE:
1805       gtk_tree_view_set_headers_clickable (tree_view, g_value_get_boolean (value));
1806       break;
1807     case PROP_EXPANDER_COLUMN:
1808       gtk_tree_view_set_expander_column (tree_view, g_value_get_object (value));
1809       break;
1810     case PROP_REORDERABLE:
1811       gtk_tree_view_set_reorderable (tree_view, g_value_get_boolean (value));
1812       break;
1813     case PROP_RULES_HINT:
1814       gtk_tree_view_set_rules_hint (tree_view, g_value_get_boolean (value));
1815       break;
1816     case PROP_ENABLE_SEARCH:
1817       gtk_tree_view_set_enable_search (tree_view, g_value_get_boolean (value));
1818       break;
1819     case PROP_SEARCH_COLUMN:
1820       gtk_tree_view_set_search_column (tree_view, g_value_get_int (value));
1821       break;
1822     case PROP_FIXED_HEIGHT_MODE:
1823       gtk_tree_view_set_fixed_height_mode (tree_view, g_value_get_boolean (value));
1824       break;
1825     case PROP_HOVER_SELECTION:
1826       tree_view->priv->hover_selection = g_value_get_boolean (value);
1827       break;
1828     case PROP_HOVER_EXPAND:
1829       tree_view->priv->hover_expand = g_value_get_boolean (value);
1830       break;
1831     case PROP_SHOW_EXPANDERS:
1832       gtk_tree_view_set_show_expanders (tree_view, g_value_get_boolean (value));
1833       break;
1834     case PROP_LEVEL_INDENTATION:
1835       tree_view->priv->level_indentation = g_value_get_int (value);
1836       break;
1837     case PROP_RUBBER_BANDING:
1838       tree_view->priv->rubber_banding_enable = g_value_get_boolean (value);
1839       break;
1840     case PROP_ENABLE_GRID_LINES:
1841       gtk_tree_view_set_grid_lines (tree_view, g_value_get_enum (value));
1842       break;
1843     case PROP_ENABLE_TREE_LINES:
1844       gtk_tree_view_set_enable_tree_lines (tree_view, g_value_get_boolean (value));
1845       break;
1846     case PROP_TOOLTIP_COLUMN:
1847       gtk_tree_view_set_tooltip_column (tree_view, g_value_get_int (value));
1848       break;
1849     default:
1850       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1851       break;
1852     }
1853 }
1854
1855 static void
1856 gtk_tree_view_get_property (GObject    *object,
1857                             guint       prop_id,
1858                             GValue     *value,
1859                             GParamSpec *pspec)
1860 {
1861   GtkTreeView *tree_view;
1862
1863   tree_view = GTK_TREE_VIEW (object);
1864
1865   switch (prop_id)
1866     {
1867     case PROP_MODEL:
1868       g_value_set_object (value, tree_view->priv->model);
1869       break;
1870     case PROP_HADJUSTMENT:
1871       g_value_set_object (value, tree_view->priv->hadjustment);
1872       break;
1873     case PROP_VADJUSTMENT:
1874       g_value_set_object (value, tree_view->priv->vadjustment);
1875       break;
1876     case PROP_HSCROLL_POLICY:
1877       g_value_set_enum (value, tree_view->priv->hscroll_policy);
1878       break;
1879     case PROP_VSCROLL_POLICY:
1880       g_value_set_enum (value, tree_view->priv->vscroll_policy);
1881       break;
1882     case PROP_HEADERS_VISIBLE:
1883       g_value_set_boolean (value, gtk_tree_view_get_headers_visible (tree_view));
1884       break;
1885     case PROP_HEADERS_CLICKABLE:
1886       g_value_set_boolean (value, gtk_tree_view_get_headers_clickable (tree_view));
1887       break;
1888     case PROP_EXPANDER_COLUMN:
1889       g_value_set_object (value, tree_view->priv->expander_column);
1890       break;
1891     case PROP_REORDERABLE:
1892       g_value_set_boolean (value, tree_view->priv->reorderable);
1893       break;
1894     case PROP_RULES_HINT:
1895       g_value_set_boolean (value, tree_view->priv->has_rules);
1896       break;
1897     case PROP_ENABLE_SEARCH:
1898       g_value_set_boolean (value, tree_view->priv->enable_search);
1899       break;
1900     case PROP_SEARCH_COLUMN:
1901       g_value_set_int (value, tree_view->priv->search_column);
1902       break;
1903     case PROP_FIXED_HEIGHT_MODE:
1904       g_value_set_boolean (value, tree_view->priv->fixed_height_mode);
1905       break;
1906     case PROP_HOVER_SELECTION:
1907       g_value_set_boolean (value, tree_view->priv->hover_selection);
1908       break;
1909     case PROP_HOVER_EXPAND:
1910       g_value_set_boolean (value, tree_view->priv->hover_expand);
1911       break;
1912     case PROP_SHOW_EXPANDERS:
1913       g_value_set_boolean (value, tree_view->priv->show_expanders);
1914       break;
1915     case PROP_LEVEL_INDENTATION:
1916       g_value_set_int (value, tree_view->priv->level_indentation);
1917       break;
1918     case PROP_RUBBER_BANDING:
1919       g_value_set_boolean (value, tree_view->priv->rubber_banding_enable);
1920       break;
1921     case PROP_ENABLE_GRID_LINES:
1922       g_value_set_enum (value, tree_view->priv->grid_lines);
1923       break;
1924     case PROP_ENABLE_TREE_LINES:
1925       g_value_set_boolean (value, tree_view->priv->tree_lines_enabled);
1926       break;
1927     case PROP_TOOLTIP_COLUMN:
1928       g_value_set_int (value, tree_view->priv->tooltip_column);
1929       break;
1930     default:
1931       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1932       break;
1933     }
1934 }
1935
1936 static void
1937 gtk_tree_view_finalize (GObject *object)
1938 {
1939   G_OBJECT_CLASS (gtk_tree_view_parent_class)->finalize (object);
1940 }
1941
1942
1943 static GtkBuildableIface *parent_buildable_iface;
1944
1945 static void
1946 gtk_tree_view_buildable_init (GtkBuildableIface *iface)
1947 {
1948   parent_buildable_iface = g_type_interface_peek_parent (iface);
1949   iface->add_child = gtk_tree_view_buildable_add_child;
1950   iface->get_internal_child = gtk_tree_view_buildable_get_internal_child;
1951 }
1952
1953 static void
1954 gtk_tree_view_buildable_add_child (GtkBuildable *tree_view,
1955                                    GtkBuilder  *builder,
1956                                    GObject     *child,
1957                                    const gchar *type)
1958 {
1959   gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), GTK_TREE_VIEW_COLUMN (child));
1960 }
1961
1962 static GObject *
1963 gtk_tree_view_buildable_get_internal_child (GtkBuildable      *buildable,
1964                                             GtkBuilder        *builder,
1965                                             const gchar       *childname)
1966 {
1967     if (strcmp (childname, "selection") == 0)
1968       return G_OBJECT (GTK_TREE_VIEW (buildable)->priv->selection);
1969     
1970     return parent_buildable_iface->get_internal_child (buildable,
1971                                                        builder,
1972                                                        childname);
1973 }
1974
1975 /* GtkWidget Methods
1976  */
1977
1978 static void
1979 gtk_tree_view_free_rbtree (GtkTreeView *tree_view)
1980 {
1981   _gtk_rbtree_free (tree_view->priv->tree);
1982   
1983   tree_view->priv->tree = NULL;
1984   tree_view->priv->button_pressed_node = NULL;
1985   tree_view->priv->button_pressed_tree = NULL;
1986   tree_view->priv->prelight_tree = NULL;
1987   tree_view->priv->prelight_node = NULL;
1988   tree_view->priv->expanded_collapsed_node = NULL;
1989   tree_view->priv->expanded_collapsed_tree = NULL;
1990 }
1991
1992 static void
1993 gtk_tree_view_destroy (GtkWidget *widget)
1994 {
1995   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
1996   GList *list;
1997
1998   gtk_tree_view_stop_editing (tree_view, TRUE);
1999
2000   if (tree_view->priv->columns != NULL)
2001     {
2002       list = tree_view->priv->columns;
2003       while (list)
2004         {
2005           GtkTreeViewColumn *column;
2006           column = GTK_TREE_VIEW_COLUMN (list->data);
2007           list = list->next;
2008           gtk_tree_view_remove_column (tree_view, column);
2009         }
2010       tree_view->priv->columns = NULL;
2011     }
2012
2013   if (tree_view->priv->tree != NULL)
2014     {
2015       gtk_tree_view_unref_and_check_selection_tree (tree_view, tree_view->priv->tree);
2016
2017       gtk_tree_view_free_rbtree (tree_view);
2018     }
2019
2020   if (tree_view->priv->selection != NULL)
2021     {
2022       _gtk_tree_selection_set_tree_view (tree_view->priv->selection, NULL);
2023       g_object_unref (tree_view->priv->selection);
2024       tree_view->priv->selection = NULL;
2025     }
2026
2027   if (tree_view->priv->scroll_to_path != NULL)
2028     {
2029       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
2030       tree_view->priv->scroll_to_path = NULL;
2031     }
2032
2033   if (tree_view->priv->drag_dest_row != NULL)
2034     {
2035       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
2036       tree_view->priv->drag_dest_row = NULL;
2037     }
2038
2039   if (tree_view->priv->top_row != NULL)
2040     {
2041       gtk_tree_row_reference_free (tree_view->priv->top_row);
2042       tree_view->priv->top_row = NULL;
2043     }
2044
2045   if (tree_view->priv->column_drop_func_data &&
2046       tree_view->priv->column_drop_func_data_destroy)
2047     {
2048       tree_view->priv->column_drop_func_data_destroy (tree_view->priv->column_drop_func_data);
2049       tree_view->priv->column_drop_func_data = NULL;
2050     }
2051
2052   if (tree_view->priv->destroy_count_destroy &&
2053       tree_view->priv->destroy_count_data)
2054     {
2055       tree_view->priv->destroy_count_destroy (tree_view->priv->destroy_count_data);
2056       tree_view->priv->destroy_count_data = NULL;
2057     }
2058
2059   gtk_tree_row_reference_free (tree_view->priv->anchor);
2060   tree_view->priv->anchor = NULL;
2061
2062   /* destroy interactive search dialog */
2063   if (tree_view->priv->search_window)
2064     {
2065       gtk_widget_destroy (tree_view->priv->search_window);
2066       tree_view->priv->search_window = NULL;
2067       tree_view->priv->search_entry = NULL;
2068       if (tree_view->priv->typeselect_flush_timeout)
2069         {
2070           g_source_remove (tree_view->priv->typeselect_flush_timeout);
2071           tree_view->priv->typeselect_flush_timeout = 0;
2072         }
2073     }
2074
2075   if (tree_view->priv->search_destroy && tree_view->priv->search_user_data)
2076     {
2077       tree_view->priv->search_destroy (tree_view->priv->search_user_data);
2078       tree_view->priv->search_user_data = NULL;
2079     }
2080
2081   if (tree_view->priv->search_position_destroy && tree_view->priv->search_position_user_data)
2082     {
2083       tree_view->priv->search_position_destroy (tree_view->priv->search_position_user_data);
2084       tree_view->priv->search_position_user_data = NULL;
2085     }
2086
2087   if (tree_view->priv->row_separator_destroy && tree_view->priv->row_separator_data)
2088     {
2089       tree_view->priv->row_separator_destroy (tree_view->priv->row_separator_data);
2090       tree_view->priv->row_separator_data = NULL;
2091     }
2092   
2093   gtk_tree_view_set_model (tree_view, NULL);
2094
2095   if (tree_view->priv->hadjustment)
2096     {
2097       g_object_unref (tree_view->priv->hadjustment);
2098       tree_view->priv->hadjustment = NULL;
2099     }
2100   if (tree_view->priv->vadjustment)
2101     {
2102       g_object_unref (tree_view->priv->vadjustment);
2103       tree_view->priv->vadjustment = NULL;
2104     }
2105
2106   GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->destroy (widget);
2107 }
2108
2109 /* GtkWidget::map helper */
2110 static void
2111 gtk_tree_view_map_buttons (GtkTreeView *tree_view)
2112 {
2113   GList *list;
2114
2115   g_return_if_fail (gtk_widget_get_mapped (GTK_WIDGET (tree_view)));
2116
2117   if (tree_view->priv->headers_visible)
2118     {
2119       GtkTreeViewColumn *column;
2120       GtkWidget         *button;
2121       GdkWindow         *window;
2122
2123       for (list = tree_view->priv->columns; list; list = list->next)
2124         {
2125           column = list->data;
2126           button = gtk_tree_view_column_get_button (column);
2127
2128           if (gtk_tree_view_column_get_visible (column) && button)
2129             gtk_widget_show_now (button);
2130
2131           if (gtk_widget_get_visible (button) &&
2132               !gtk_widget_get_mapped (button))
2133             gtk_widget_map (button);
2134         }
2135       for (list = tree_view->priv->columns; list; list = list->next)
2136         {
2137           column = list->data;
2138           if (gtk_tree_view_column_get_visible (column) == FALSE)
2139             continue;
2140
2141           window = _gtk_tree_view_column_get_window (column);
2142           if (gtk_tree_view_column_get_resizable (column))
2143             {
2144               gdk_window_raise (window);
2145               gdk_window_show (window);
2146             }
2147           else
2148             gdk_window_hide (window);
2149         }
2150       gdk_window_show (tree_view->priv->header_window);
2151     }
2152 }
2153
2154 static void
2155 gtk_tree_view_map (GtkWidget *widget)
2156 {
2157   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2158   GList *tmp_list;
2159
2160   gtk_widget_set_mapped (widget, TRUE);
2161
2162   tmp_list = tree_view->priv->children;
2163   while (tmp_list)
2164     {
2165       GtkTreeViewChild *child = tmp_list->data;
2166       tmp_list = tmp_list->next;
2167
2168       if (gtk_widget_get_visible (child->widget))
2169         {
2170           if (!gtk_widget_get_mapped (child->widget))
2171             gtk_widget_map (child->widget);
2172         }
2173     }
2174   gdk_window_show (tree_view->priv->bin_window);
2175
2176   gtk_tree_view_map_buttons (tree_view);
2177
2178   gdk_window_show (gtk_widget_get_window (widget));
2179 }
2180
2181 static void
2182 gtk_tree_view_ensure_background (GtkTreeView *tree_view)
2183 {
2184   GtkStyleContext *context;
2185
2186   context = gtk_widget_get_style_context (GTK_WIDGET (tree_view));
2187
2188   gtk_style_context_save (context);
2189   gtk_style_context_add_class (context, GTK_STYLE_CLASS_VIEW);
2190   gtk_style_context_set_background (context, tree_view->priv->bin_window);
2191   gtk_style_context_restore (context);
2192
2193   gtk_style_context_set_background (context, tree_view->priv->header_window);
2194 }
2195
2196 static void
2197 gtk_tree_view_realize (GtkWidget *widget)
2198 {
2199   GtkAllocation allocation;
2200   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2201   GdkWindow *window;
2202   GdkWindowAttr attributes;
2203   GList *tmp_list;
2204   gint attributes_mask;
2205
2206   gtk_widget_set_realized (widget, TRUE);
2207
2208   gtk_widget_get_allocation (widget, &allocation);
2209
2210   /* Make the main, clipping window */
2211   attributes.window_type = GDK_WINDOW_CHILD;
2212   attributes.x = allocation.x;
2213   attributes.y = allocation.y;
2214   attributes.width = allocation.width;
2215   attributes.height = allocation.height;
2216   attributes.wclass = GDK_INPUT_OUTPUT;
2217   attributes.visual = gtk_widget_get_visual (widget);
2218   attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK;
2219
2220   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
2221
2222   window = gdk_window_new (gtk_widget_get_parent_window (widget),
2223                            &attributes, attributes_mask);
2224   gtk_widget_set_window (widget, window);
2225   gdk_window_set_user_data (window, widget);
2226
2227   gtk_widget_get_allocation (widget, &allocation);
2228
2229   /* Make the window for the tree */
2230   attributes.x = 0;
2231   attributes.y = gtk_tree_view_get_effective_header_height (tree_view);
2232   attributes.width = MAX (tree_view->priv->width, allocation.width);
2233   attributes.height = allocation.height;
2234   attributes.event_mask = (GDK_EXPOSURE_MASK |
2235                            GDK_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   GtkStyleContext *context;
2295   GList *list;
2296
2297   if (priv->scroll_timeout != 0)
2298     {
2299       g_source_remove (priv->scroll_timeout);
2300       priv->scroll_timeout = 0;
2301     }
2302
2303   if (priv->auto_expand_timeout != 0)
2304     {
2305       g_source_remove (priv->auto_expand_timeout);
2306       priv->auto_expand_timeout = 0;
2307     }
2308
2309   if (priv->open_dest_timeout != 0)
2310     {
2311       g_source_remove (priv->open_dest_timeout);
2312       priv->open_dest_timeout = 0;
2313     }
2314
2315   context = gtk_widget_get_style_context (widget);
2316   gtk_style_context_cancel_animations (context, NULL);
2317
2318   if (priv->presize_handler_timer != 0)
2319     {
2320       g_source_remove (priv->presize_handler_timer);
2321       priv->presize_handler_timer = 0;
2322     }
2323
2324   if (priv->validate_rows_timer != 0)
2325     {
2326       g_source_remove (priv->validate_rows_timer);
2327       priv->validate_rows_timer = 0;
2328     }
2329
2330   if (priv->scroll_sync_timer != 0)
2331     {
2332       g_source_remove (priv->scroll_sync_timer);
2333       priv->scroll_sync_timer = 0;
2334     }
2335
2336   if (priv->typeselect_flush_timeout)
2337     {
2338       g_source_remove (priv->typeselect_flush_timeout);
2339       priv->typeselect_flush_timeout = 0;
2340     }
2341   
2342   for (list = priv->columns; list; list = list->next)
2343     _gtk_tree_view_column_unrealize_button (GTK_TREE_VIEW_COLUMN (list->data));
2344
2345   gdk_window_set_user_data (priv->bin_window, NULL);
2346   gdk_window_destroy (priv->bin_window);
2347   priv->bin_window = NULL;
2348
2349   gdk_window_set_user_data (priv->header_window, NULL);
2350   gdk_window_destroy (priv->header_window);
2351   priv->header_window = NULL;
2352
2353   if (priv->drag_window)
2354     {
2355       gdk_window_set_user_data (priv->drag_window, NULL);
2356       gdk_window_destroy (priv->drag_window);
2357       priv->drag_window = NULL;
2358     }
2359
2360   if (priv->drag_highlight_window)
2361     {
2362       gdk_window_set_user_data (priv->drag_highlight_window, NULL);
2363       gdk_window_destroy (priv->drag_highlight_window);
2364       priv->drag_highlight_window = NULL;
2365     }
2366
2367   GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->unrealize (widget);
2368 }
2369
2370 /* GtkWidget::size_request helper */
2371 static void
2372 gtk_tree_view_size_request_columns (GtkTreeView *tree_view)
2373 {
2374   GList *list;
2375
2376   tree_view->priv->header_height = 0;
2377
2378   for (list = tree_view->priv->columns; list; list = list->next)
2379     {
2380       GtkRequisition     requisition;
2381       GtkTreeViewColumn *column = list->data;
2382       GtkWidget         *button = gtk_tree_view_column_get_button (column);
2383
2384       if (button == NULL)
2385         continue;
2386
2387       gtk_widget_get_preferred_size (button, &requisition, NULL);
2388       tree_view->priv->header_height = MAX (tree_view->priv->header_height, requisition.height);
2389     }
2390 }
2391
2392
2393 /* Called only by ::size_request */
2394 static void
2395 gtk_tree_view_update_size (GtkTreeView *tree_view)
2396 {
2397   GList *list;
2398   GtkTreeViewColumn *column;
2399   gint i;
2400
2401   if (tree_view->priv->model == NULL)
2402     {
2403       tree_view->priv->width = 0;
2404       tree_view->priv->prev_width = 0;                   
2405       tree_view->priv->height = 0;
2406       return;
2407     }
2408
2409   tree_view->priv->prev_width = tree_view->priv->width;  
2410   tree_view->priv->width = 0;
2411
2412   /* keep this in sync with size_allocate below */
2413   for (list = tree_view->priv->columns, i = 0; list; list = list->next, i++)
2414     {
2415       column = list->data;
2416       if (!gtk_tree_view_column_get_visible (column))
2417         continue;
2418
2419       tree_view->priv->width += _gtk_tree_view_column_request_width (column);
2420     }
2421
2422   if (tree_view->priv->tree == NULL)
2423     tree_view->priv->height = 0;
2424   else
2425     tree_view->priv->height = tree_view->priv->tree->root->offset;
2426 }
2427
2428 static void
2429 gtk_tree_view_size_request (GtkWidget      *widget,
2430                             GtkRequisition *requisition,
2431                             gboolean        may_validate)
2432 {
2433   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2434
2435   if (may_validate)
2436     {
2437       /* we validate some rows initially just to make sure we have some size.
2438        * In practice, with a lot of static lists, this should get a good width.
2439        */
2440       do_validate_rows (tree_view, FALSE);
2441     }
2442
2443   gtk_tree_view_size_request_columns (tree_view);
2444   gtk_tree_view_update_size (GTK_TREE_VIEW (widget));
2445
2446   requisition->width = tree_view->priv->width;
2447   requisition->height = tree_view->priv->height + gtk_tree_view_get_effective_header_height (tree_view);
2448 }
2449
2450 static void
2451 gtk_tree_view_get_preferred_width (GtkWidget *widget,
2452                                    gint      *minimum,
2453                                    gint      *natural)
2454 {
2455   GtkRequisition requisition;
2456
2457   gtk_tree_view_size_request (widget, &requisition, TRUE);
2458
2459   *minimum = *natural = requisition.width;
2460 }
2461
2462 static void
2463 gtk_tree_view_get_preferred_height (GtkWidget *widget,
2464                                     gint      *minimum,
2465                                     gint      *natural)
2466 {
2467   GtkRequisition requisition;
2468
2469   gtk_tree_view_size_request (widget, &requisition, TRUE);
2470
2471   *minimum = *natural = requisition.height;
2472 }
2473
2474 static int
2475 gtk_tree_view_calculate_width_before_expander (GtkTreeView *tree_view)
2476 {
2477   int width = 0;
2478   GList *list;
2479   gboolean rtl;
2480
2481   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2482   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
2483        list->data != tree_view->priv->expander_column;
2484        list = (rtl ? list->prev : list->next))
2485     {
2486       GtkTreeViewColumn *column = list->data;
2487
2488       width += gtk_tree_view_column_get_width (column);
2489     }
2490
2491   return width;
2492 }
2493
2494 /* GtkWidget::size_allocate helper */
2495 static void
2496 gtk_tree_view_size_allocate_columns (GtkWidget *widget,
2497                                      gboolean  *width_changed)
2498 {
2499   GtkTreeView *tree_view;
2500   GList *list, *first_column, *last_column;
2501   GtkTreeViewColumn *column;
2502   GtkAllocation widget_allocation;
2503   gint width = 0;
2504   gint extra, extra_per_column, extra_for_last;
2505   gint full_requested_width = 0;
2506   gint number_of_expand_columns = 0;
2507   gboolean rtl;
2508   gboolean update_expand;
2509   
2510   tree_view = GTK_TREE_VIEW (widget);
2511
2512   for (last_column = g_list_last (tree_view->priv->columns);
2513        last_column &&
2514        !(gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (last_column->data)));
2515        last_column = last_column->prev)
2516     ;
2517   if (last_column == NULL)
2518     return;
2519
2520   for (first_column = g_list_first (tree_view->priv->columns);
2521        first_column &&
2522        !(gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (first_column->data)));
2523        first_column = first_column->next)
2524     ;
2525
2526   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
2527
2528   /* find out how many extra space and expandable columns we have */
2529   for (list = tree_view->priv->columns; list != last_column->next; list = list->next)
2530     {
2531       column = (GtkTreeViewColumn *)list->data;
2532
2533       if (!gtk_tree_view_column_get_visible (column))
2534         continue;
2535
2536       full_requested_width += _gtk_tree_view_column_request_width (column);
2537
2538       if (gtk_tree_view_column_get_expand (column))
2539         number_of_expand_columns++;
2540     }
2541
2542   /* Only update the expand value if the width of the widget has changed,
2543    * or the number of expand columns has changed, or if there are no expand
2544    * columns, or if we didn't have an size-allocation yet after the
2545    * last validated node.
2546    */
2547   update_expand = (width_changed && *width_changed == TRUE)
2548       || number_of_expand_columns != tree_view->priv->last_number_of_expand_columns
2549       || number_of_expand_columns == 0
2550       || tree_view->priv->post_validation_flag == TRUE;
2551
2552   tree_view->priv->post_validation_flag = FALSE;
2553
2554   gtk_widget_get_allocation (widget, &widget_allocation);
2555   if (!update_expand)
2556     {
2557       extra = tree_view->priv->last_extra_space;
2558       extra_for_last = MAX (widget_allocation.width - full_requested_width - extra, 0);
2559     }
2560   else
2561     {
2562       extra = MAX (widget_allocation.width - full_requested_width, 0);
2563       extra_for_last = 0;
2564
2565       tree_view->priv->last_extra_space = extra;
2566     }
2567
2568   if (number_of_expand_columns > 0)
2569     extra_per_column = extra/number_of_expand_columns;
2570   else
2571     extra_per_column = 0;
2572
2573   if (update_expand)
2574     {
2575       tree_view->priv->last_extra_space_per_column = extra_per_column;
2576       tree_view->priv->last_number_of_expand_columns = number_of_expand_columns;
2577     }
2578
2579   for (list = (rtl ? last_column : first_column); 
2580        list != (rtl ? first_column->prev : last_column->next);
2581        list = (rtl ? list->prev : list->next)) 
2582     {
2583       gint column_width;
2584
2585       column = list->data;
2586
2587       if (!gtk_tree_view_column_get_visible (column))
2588         continue;
2589
2590       /* We need to handle the dragged button specially.
2591        */
2592       if (column == tree_view->priv->drag_column)
2593         {
2594           GtkAllocation drag_allocation;
2595           GtkWidget    *button;
2596
2597           button = gtk_tree_view_column_get_button (tree_view->priv->drag_column);
2598
2599           drag_allocation.x = 0;
2600           drag_allocation.y = 0;
2601           drag_allocation.width = gdk_window_get_width (tree_view->priv->drag_window);
2602           drag_allocation.height = gdk_window_get_height (tree_view->priv->drag_window);
2603           gtk_widget_size_allocate (button, &drag_allocation);
2604           width += drag_allocation.width;
2605           continue;
2606         }
2607
2608       column_width = _gtk_tree_view_column_request_width (column);
2609
2610       if (gtk_tree_view_column_get_expand (column))
2611         {
2612           if (number_of_expand_columns == 1)
2613             {
2614               /* We add the remander to the last column as
2615                * */
2616               column_width += extra;
2617             }
2618           else
2619             {
2620               column_width += extra_per_column;
2621               extra -= extra_per_column;
2622               number_of_expand_columns --;
2623             }
2624         }
2625       else if (number_of_expand_columns == 0 &&
2626                list == last_column)
2627         {
2628           column_width += extra;
2629         }
2630
2631       /* In addition to expand, the last column can get even more
2632        * extra space so all available space is filled up.
2633        */
2634       if (extra_for_last > 0 && list == last_column)
2635         column_width += extra_for_last;
2636
2637       _gtk_tree_view_column_allocate (column, width, column_width);
2638
2639       width += column_width;
2640     }
2641
2642   /* We change the width here.  The user might have been resizing columns,
2643    * which changes the total width of the tree view.  This is of
2644    * importance for getting the horizontal scroll bar right.
2645    */
2646   if (tree_view->priv->width != width)
2647     {
2648       tree_view->priv->width = width;
2649       if (width_changed)
2650         *width_changed = TRUE;
2651     }
2652 }
2653
2654
2655 static void
2656 gtk_tree_view_size_allocate (GtkWidget     *widget,
2657                              GtkAllocation *allocation)
2658 {
2659   GtkAllocation widget_allocation;
2660   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2661   GList *tmp_list;
2662   gboolean width_changed = FALSE;
2663   gint old_width;
2664
2665   gtk_widget_get_allocation (widget, &widget_allocation);
2666   old_width = widget_allocation.width;
2667   if (allocation->width != widget_allocation.width)
2668     width_changed = TRUE;
2669
2670   gtk_widget_set_allocation (widget, allocation);
2671
2672   tmp_list = tree_view->priv->children;
2673
2674   while (tmp_list)
2675     {
2676       GtkAllocation allocation;
2677
2678       GtkTreeViewChild *child = tmp_list->data;
2679       tmp_list = tmp_list->next;
2680
2681       /* totally ignore our child's requisition */
2682       allocation.x = child->x;
2683       allocation.y = child->y;
2684       allocation.width = child->width;
2685       allocation.height = child->height;
2686       gtk_widget_size_allocate (child->widget, &allocation);
2687     }
2688
2689   /* We size-allocate the columns first because the width of the
2690    * tree view (used in updating the adjustments below) might change.
2691    */
2692   gtk_tree_view_size_allocate_columns (widget, &width_changed);
2693
2694   g_object_freeze_notify (G_OBJECT (tree_view->priv->hadjustment));
2695   gtk_adjustment_set_page_size (tree_view->priv->hadjustment,
2696                                 allocation->width);
2697   gtk_adjustment_set_page_increment (tree_view->priv->hadjustment,
2698                                      allocation->width * 0.9);
2699   gtk_adjustment_set_step_increment (tree_view->priv->hadjustment,
2700                                      allocation->width * 0.1);
2701   gtk_adjustment_set_lower (tree_view->priv->hadjustment, 0);
2702   gtk_adjustment_set_upper (tree_view->priv->hadjustment,
2703                             MAX (gtk_adjustment_get_page_size (tree_view->priv->hadjustment),
2704                                  tree_view->priv->width));
2705   g_object_thaw_notify (G_OBJECT (tree_view->priv->hadjustment));
2706
2707   if (gtk_widget_get_direction(widget) == GTK_TEXT_DIR_RTL)   
2708     {
2709       if (allocation->width < tree_view->priv->width)
2710         {
2711           if (tree_view->priv->init_hadjust_value)
2712             {
2713               gtk_adjustment_set_value (tree_view->priv->hadjustment,
2714                                         MAX (tree_view->priv->width -
2715                                              allocation->width, 0));
2716               tree_view->priv->init_hadjust_value = FALSE;
2717             }
2718           else if (allocation->width != old_width)
2719             {
2720               gtk_adjustment_set_value (tree_view->priv->hadjustment,
2721                                         CLAMP (gtk_adjustment_get_value (tree_view->priv->hadjustment) - allocation->width + old_width,
2722                                                0,
2723                                                tree_view->priv->width - allocation->width));
2724             }
2725           else
2726             gtk_adjustment_set_value (tree_view->priv->hadjustment,
2727                                       CLAMP (tree_view->priv->width - (tree_view->priv->prev_width - gtk_adjustment_get_value (tree_view->priv->hadjustment)),
2728                                              0,
2729                                              tree_view->priv->width - allocation->width));
2730         }
2731       else
2732         {
2733           gtk_adjustment_set_value (tree_view->priv->hadjustment, 0);
2734           tree_view->priv->init_hadjust_value = TRUE;
2735         }
2736     }
2737   else
2738     if (gtk_adjustment_get_value (tree_view->priv->hadjustment) + allocation->width > tree_view->priv->width)
2739       gtk_adjustment_set_value (tree_view->priv->hadjustment,
2740                                 MAX (tree_view->priv->width -
2741                                      allocation->width, 0));
2742
2743   g_object_freeze_notify (G_OBJECT (tree_view->priv->vadjustment));
2744   gtk_adjustment_set_page_size (tree_view->priv->vadjustment,
2745                                 allocation->height -
2746                                 gtk_tree_view_get_effective_header_height (tree_view));
2747   gtk_adjustment_set_step_increment (tree_view->priv->vadjustment,
2748                                      gtk_adjustment_get_page_size (tree_view->priv->vadjustment) * 0.1);
2749   gtk_adjustment_set_page_increment (tree_view->priv->vadjustment,
2750                                      gtk_adjustment_get_page_size (tree_view->priv->vadjustment) * 0.9);
2751   gtk_adjustment_set_lower (tree_view->priv->vadjustment, 0);
2752   gtk_adjustment_set_upper (tree_view->priv->vadjustment,
2753                             MAX (gtk_adjustment_get_page_size (tree_view->priv->vadjustment),
2754                                  tree_view->priv->height));
2755   g_object_thaw_notify (G_OBJECT (tree_view->priv->vadjustment));
2756
2757   /* now the adjustments and window sizes are in sync, we can sync toprow/dy again */
2758   if (tree_view->priv->height <= gtk_adjustment_get_page_size (tree_view->priv->vadjustment))
2759     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
2760   else if (gtk_adjustment_get_value (tree_view->priv->vadjustment) + gtk_adjustment_get_page_size (tree_view->priv->vadjustment) > tree_view->priv->height)
2761     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment),
2762                               tree_view->priv->height - gtk_adjustment_get_page_size (tree_view->priv->vadjustment));
2763   else if (gtk_tree_row_reference_valid (tree_view->priv->top_row))
2764     gtk_tree_view_top_row_to_dy (tree_view);
2765   else
2766     gtk_tree_view_dy_to_top_row (tree_view);
2767   
2768   if (gtk_widget_get_realized (widget))
2769     {
2770       gdk_window_move_resize (gtk_widget_get_window (widget),
2771                               allocation->x, allocation->y,
2772                               allocation->width, allocation->height);
2773       gdk_window_move_resize (tree_view->priv->header_window,
2774                               - (gint) gtk_adjustment_get_value (tree_view->priv->hadjustment),
2775                               0,
2776                               MAX (tree_view->priv->width, allocation->width),
2777                               tree_view->priv->header_height);
2778       gdk_window_move_resize (tree_view->priv->bin_window,
2779                               - (gint) gtk_adjustment_get_value (tree_view->priv->hadjustment),
2780                               gtk_tree_view_get_effective_header_height (tree_view),
2781                               MAX (tree_view->priv->width, allocation->width),
2782                               allocation->height - gtk_tree_view_get_effective_header_height (tree_view));
2783
2784       if (tree_view->priv->tree == NULL)
2785         invalidate_empty_focus (tree_view);
2786
2787       if (width_changed && tree_view->priv->expander_column)
2788         {
2789           /* Might seem awkward, but is the best heuristic I could come up
2790            * with.  Only if the width of the columns before the expander
2791            * changes, we will update the prelight status.  It is this
2792            * width that makes the expander move vertically.  Always updating
2793            * prelight status causes trouble with hover selections.
2794            */
2795           gint width_before_expander;
2796
2797           width_before_expander = gtk_tree_view_calculate_width_before_expander (tree_view);
2798
2799           if (tree_view->priv->prev_width_before_expander
2800               != width_before_expander)
2801               update_prelight (tree_view,
2802                                tree_view->priv->event_last_x,
2803                                tree_view->priv->event_last_y);
2804
2805           tree_view->priv->prev_width_before_expander = width_before_expander;
2806         }
2807     }
2808 }
2809
2810 /* Grabs the focus and unsets the GTK_TREE_VIEW_DRAW_KEYFOCUS flag */
2811 static void
2812 grab_focus_and_unset_draw_keyfocus (GtkTreeView *tree_view)
2813 {
2814   GtkWidget *widget = GTK_WIDGET (tree_view);
2815
2816   if (gtk_widget_get_can_focus (widget) && !gtk_widget_has_focus (widget))
2817     gtk_widget_grab_focus (widget);
2818   tree_view->priv->draw_keyfocus = 0;
2819 }
2820
2821 static inline gboolean
2822 row_is_separator (GtkTreeView *tree_view,
2823                   GtkTreeIter *iter,
2824                   GtkTreePath *path)
2825 {
2826   gboolean is_separator = FALSE;
2827
2828   if (tree_view->priv->row_separator_func)
2829     {
2830       GtkTreeIter tmpiter;
2831
2832       if (iter)
2833         tmpiter = *iter;
2834       else
2835         {
2836           if (!gtk_tree_model_get_iter (tree_view->priv->model, &tmpiter, path))
2837             return FALSE;
2838         }
2839
2840       is_separator = tree_view->priv->row_separator_func (tree_view->priv->model,
2841                                                           &tmpiter,
2842                                                           tree_view->priv->row_separator_data);
2843     }
2844
2845   return is_separator;
2846 }
2847
2848 static gboolean
2849 gtk_tree_view_button_press (GtkWidget      *widget,
2850                             GdkEventButton *event)
2851 {
2852   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2853   GList *list;
2854   GtkTreeViewColumn *column = NULL;
2855   gint i;
2856   GdkRectangle background_area;
2857   GdkRectangle cell_area;
2858   gint vertical_separator;
2859   gint horizontal_separator;
2860   gboolean path_is_selectable;
2861   gboolean rtl;
2862
2863   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
2864   gtk_tree_view_stop_editing (tree_view, FALSE);
2865   gtk_widget_style_get (widget,
2866                         "vertical-separator", &vertical_separator,
2867                         "horizontal-separator", &horizontal_separator,
2868                         NULL);
2869
2870   /* Because grab_focus can cause reentrancy, we delay grab_focus until after
2871    * we're done handling the button press.
2872    */
2873
2874   if (event->window == tree_view->priv->bin_window)
2875     {
2876       GtkRBNode *node;
2877       GtkRBTree *tree;
2878       GtkTreePath *path;
2879       gint depth;
2880       gint new_y;
2881       gint y_offset;
2882       gint dval;
2883       gint pre_val, aft_val;
2884       GtkTreeViewColumn *column = NULL;
2885       gint column_handled_click = FALSE;
2886       gboolean row_double_click = FALSE;
2887       gboolean rtl;
2888       gboolean node_selected;
2889       GdkModifierType extend_mod_mask;
2890       GdkModifierType modify_mod_mask;
2891
2892       /* Empty tree? */
2893       if (tree_view->priv->tree == NULL)
2894         {
2895           grab_focus_and_unset_draw_keyfocus (tree_view);
2896           return TRUE;
2897         }
2898
2899       /* are we in an arrow? */
2900       if (tree_view->priv->prelight_node &&
2901           tree_view->priv->arrow_prelit &&
2902           gtk_tree_view_draw_expanders (tree_view))
2903         {
2904           if (event->button == 1)
2905             {
2906               gtk_grab_add (widget);
2907               tree_view->priv->button_pressed_node = tree_view->priv->prelight_node;
2908               tree_view->priv->button_pressed_tree = tree_view->priv->prelight_tree;
2909               gtk_tree_view_queue_draw_arrow (GTK_TREE_VIEW (widget),
2910                                               tree_view->priv->prelight_tree,
2911                                               tree_view->priv->prelight_node);
2912             }
2913
2914           grab_focus_and_unset_draw_keyfocus (tree_view);
2915           return TRUE;
2916         }
2917
2918       /* find the node that was clicked */
2919       new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
2920       if (new_y < 0)
2921         new_y = 0;
2922       y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
2923
2924       if (node == NULL)
2925         {
2926           /* We clicked in dead space */
2927           grab_focus_and_unset_draw_keyfocus (tree_view);
2928           return TRUE;
2929         }
2930
2931       /* Get the path and the node */
2932       path = _gtk_tree_path_new_from_rbtree (tree, node);
2933       path_is_selectable = !row_is_separator (tree_view, NULL, path);
2934
2935       if (!path_is_selectable)
2936         {
2937           gtk_tree_path_free (path);
2938           grab_focus_and_unset_draw_keyfocus (tree_view);
2939           return TRUE;
2940         }
2941
2942       depth = gtk_tree_path_get_depth (path);
2943       background_area.y = y_offset + event->y;
2944       background_area.height = gtk_tree_view_get_row_height (tree_view, node);
2945       background_area.x = 0;
2946
2947
2948       /* Let the column have a chance at selecting it. */
2949       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2950       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
2951            list; list = (rtl ? list->prev : list->next))
2952         {
2953           GtkTreeViewColumn *candidate = list->data;
2954
2955           if (!gtk_tree_view_column_get_visible (candidate))
2956             continue;
2957
2958           background_area.width = gtk_tree_view_column_get_width (candidate);
2959           if ((background_area.x > (gint) event->x) ||
2960               (background_area.x + background_area.width <= (gint) event->x))
2961             {
2962               background_area.x += background_area.width;
2963               continue;
2964             }
2965
2966           /* we found the focus column */
2967           column = candidate;
2968           cell_area = background_area;
2969           cell_area.width -= horizontal_separator;
2970           cell_area.height -= vertical_separator;
2971           cell_area.x += horizontal_separator/2;
2972           cell_area.y += vertical_separator/2;
2973           if (gtk_tree_view_is_expander_column (tree_view, column))
2974             {
2975               if (!rtl)
2976                 cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
2977               cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
2978
2979               if (gtk_tree_view_draw_expanders (tree_view))
2980                 {
2981                   if (!rtl)
2982                     cell_area.x += depth * tree_view->priv->expander_size;
2983                   cell_area.width -= depth * tree_view->priv->expander_size;
2984                 }
2985             }
2986           break;
2987         }
2988
2989       if (column == NULL)
2990         {
2991           gtk_tree_path_free (path);
2992           grab_focus_and_unset_draw_keyfocus (tree_view);
2993           return FALSE;
2994         }
2995
2996       tree_view->priv->focus_column = column;
2997
2998       /* decide if we edit */
2999       if (event->type == GDK_BUTTON_PRESS && event->button == 1 &&
3000           !(event->state & gtk_accelerator_get_default_mod_mask ()))
3001         {
3002           GtkTreePath *anchor;
3003           GtkTreeIter iter;
3004
3005           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
3006           gtk_tree_view_column_cell_set_cell_data (column,
3007                                                    tree_view->priv->model,
3008                                                    &iter,
3009                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
3010                                                    node->children?TRUE:FALSE);
3011
3012           if (tree_view->priv->anchor)
3013             anchor = gtk_tree_row_reference_get_path (tree_view->priv->anchor);
3014           else
3015             anchor = NULL;
3016
3017           if ((anchor && !gtk_tree_path_compare (anchor, path))
3018               || !_gtk_tree_view_column_has_editable_cell (column))
3019             {
3020               GtkCellEditable *cell_editable = NULL;
3021
3022               /* FIXME: get the right flags */
3023               guint flags = 0;
3024
3025               if (_gtk_tree_view_column_cell_event (column,
3026                                                     (GdkEvent *)event,
3027                                                     &cell_area, flags))
3028                 {
3029                   GtkCellArea *area = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (column));
3030                   cell_editable = gtk_cell_area_get_edit_widget (area);
3031
3032                   if (cell_editable != NULL)
3033                     {
3034                       gtk_tree_path_free (path);
3035                       gtk_tree_path_free (anchor);
3036                       return TRUE;
3037                     }
3038                   column_handled_click = TRUE;
3039                 }
3040             }
3041           if (anchor)
3042             gtk_tree_path_free (anchor);
3043         }
3044
3045       extend_mod_mask =
3046         gtk_widget_get_modifier_mask (widget, GDK_MODIFIER_INTENT_EXTEND_SELECTION);
3047
3048       modify_mod_mask =
3049         gtk_widget_get_modifier_mask (widget, GDK_MODIFIER_INTENT_MODIFY_SELECTION);
3050
3051       /* select */
3052       node_selected = GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED);
3053       pre_val = gtk_adjustment_get_value (tree_view->priv->vadjustment);
3054
3055       /* we only handle selection modifications on the first button press
3056        */
3057       if (event->type == GDK_BUTTON_PRESS)
3058         {
3059           GtkCellRenderer *focus_cell;
3060
3061           if ((event->state & modify_mod_mask) == modify_mod_mask)
3062             tree_view->priv->modify_selection_pressed = TRUE;
3063           if ((event->state & extend_mod_mask) == extend_mod_mask)
3064             tree_view->priv->extend_selection_pressed = TRUE;
3065
3066           /* We update the focus cell here, this is also needed if the
3067            * column does not contain an editable cell.  In this case,
3068            * GtkCellArea did not receive the event for processing (and
3069            * could not update the focus cell).
3070            */
3071           focus_cell = _gtk_tree_view_column_get_cell_at_pos (column,
3072                                                               &cell_area,
3073                                                               &background_area,
3074                                                               event->x,
3075                                                               event->y);
3076
3077           if (focus_cell)
3078             gtk_tree_view_column_focus_cell (column, focus_cell);
3079
3080           if (event->state & modify_mod_mask)
3081             {
3082               gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
3083               gtk_tree_view_real_toggle_cursor_row (tree_view);
3084             }
3085           else if (event->state & extend_mod_mask)
3086             {
3087               gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
3088               gtk_tree_view_real_select_cursor_row (tree_view, FALSE);
3089             }
3090           else
3091             {
3092               gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
3093             }
3094
3095           tree_view->priv->modify_selection_pressed = FALSE;
3096           tree_view->priv->extend_selection_pressed = FALSE;
3097         }
3098
3099       /* the treeview may have been scrolled because of _set_cursor,
3100        * correct here
3101        */
3102
3103       aft_val = gtk_adjustment_get_value (tree_view->priv->vadjustment);
3104       dval = pre_val - aft_val;
3105
3106       cell_area.y += dval;
3107       background_area.y += dval;
3108
3109       /* Save press to possibly begin a drag
3110        */
3111       if (!column_handled_click &&
3112           !tree_view->priv->in_grab &&
3113           tree_view->priv->pressed_button < 0)
3114         {
3115           tree_view->priv->pressed_button = event->button;
3116           tree_view->priv->press_start_x = event->x;
3117           tree_view->priv->press_start_y = event->y;
3118
3119           if (tree_view->priv->rubber_banding_enable
3120               && !node_selected
3121               && gtk_tree_selection_get_mode (tree_view->priv->selection) == GTK_SELECTION_MULTIPLE)
3122             {
3123               tree_view->priv->press_start_y += tree_view->priv->dy;
3124               tree_view->priv->rubber_band_x = event->x;
3125               tree_view->priv->rubber_band_y = event->y + tree_view->priv->dy;
3126               tree_view->priv->rubber_band_status = RUBBER_BAND_MAYBE_START;
3127
3128               if ((event->state & modify_mod_mask) == modify_mod_mask)
3129                 tree_view->priv->rubber_band_modify = TRUE;
3130               if ((event->state & extend_mod_mask) == extend_mod_mask)
3131                 tree_view->priv->rubber_band_extend = TRUE;
3132             }
3133         }
3134
3135       /* Test if a double click happened on the same row. */
3136       if (event->button == 1 && event->type == GDK_BUTTON_PRESS)
3137         {
3138           int double_click_time, double_click_distance;
3139
3140           g_object_get (gtk_settings_get_default (),
3141                         "gtk-double-click-time", &double_click_time,
3142                         "gtk-double-click-distance", &double_click_distance,
3143                         NULL);
3144
3145           /* Same conditions as _gdk_event_button_generate */
3146           if (tree_view->priv->last_button_x != -1 &&
3147               (event->time < tree_view->priv->last_button_time + double_click_time) &&
3148               (ABS (event->x - tree_view->priv->last_button_x) <= double_click_distance) &&
3149               (ABS (event->y - tree_view->priv->last_button_y) <= double_click_distance))
3150             {
3151               /* We do no longer compare paths of this row and the
3152                * row clicked previously.  We use the double click
3153                * distance to decide whether this is a valid click,
3154                * allowing the mouse to slightly move over another row.
3155                */
3156               row_double_click = TRUE;
3157
3158               tree_view->priv->last_button_time = 0;
3159               tree_view->priv->last_button_x = -1;
3160               tree_view->priv->last_button_y = -1;
3161             }
3162           else
3163             {
3164               tree_view->priv->last_button_time = event->time;
3165               tree_view->priv->last_button_x = event->x;
3166               tree_view->priv->last_button_y = event->y;
3167             }
3168         }
3169
3170       if (row_double_click)
3171         {
3172           gtk_grab_remove (widget);
3173           gtk_tree_view_row_activated (tree_view, path, column);
3174
3175           if (tree_view->priv->pressed_button == event->button)
3176             tree_view->priv->pressed_button = -1;
3177         }
3178
3179       gtk_tree_path_free (path);
3180
3181       /* If we activated the row through a double click we don't want to grab
3182        * focus back, as moving focus to another widget is pretty common.
3183        */
3184       if (!row_double_click)
3185         grab_focus_and_unset_draw_keyfocus (tree_view);
3186
3187       return TRUE;
3188     }
3189
3190   /* We didn't click in the window.  Let's check to see if we clicked on a column resize window.
3191    */
3192   for (i = 0, list = tree_view->priv->columns; list; list = list->next, i++)
3193     {
3194       column = list->data;
3195       if (event->window == _gtk_tree_view_column_get_window (column) &&
3196           gtk_tree_view_column_get_resizable (column) &&
3197           _gtk_tree_view_column_get_window (column))
3198         {
3199           gpointer drag_data;
3200
3201           if (event->type == GDK_2BUTTON_PRESS &&
3202               gtk_tree_view_column_get_sizing (column) != GTK_TREE_VIEW_COLUMN_AUTOSIZE)
3203             {
3204               _gtk_tree_view_column_set_use_resized_width (column, FALSE);
3205               _gtk_tree_view_column_autosize (tree_view, column);
3206               return TRUE;
3207             }
3208
3209           if (gdk_device_grab (gdk_event_get_device ((GdkEvent*)event),
3210                                _gtk_tree_view_column_get_window (column),
3211                                GDK_OWNERSHIP_NONE,
3212                                FALSE,
3213                                GDK_POINTER_MOTION_HINT_MASK
3214                                 | GDK_BUTTON1_MOTION_MASK
3215                                 | GDK_BUTTON_RELEASE_MASK,
3216                                NULL,
3217                                event->time) != GDK_GRAB_SUCCESS)
3218             return FALSE;
3219
3220           gtk_grab_add (widget);
3221           tree_view->priv->in_column_resize = TRUE;
3222
3223           _gtk_tree_view_column_set_resized_width (column, gtk_tree_view_column_get_width (column) -
3224                                                    tree_view->priv->last_extra_space_per_column);
3225
3226           /* block attached dnd signal handler */
3227           drag_data = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
3228           if (drag_data)
3229             g_signal_handlers_block_matched (widget,
3230                                              G_SIGNAL_MATCH_DATA,
3231                                              0, 0, NULL, NULL,
3232                                              drag_data);
3233
3234           tree_view->priv->drag_pos = i;
3235           tree_view->priv->x_drag = gtk_tree_view_column_get_x_offset (column) + (rtl ? 0 : gtk_tree_view_column_get_width (column));
3236
3237           if (!gtk_widget_has_focus (widget))
3238             gtk_widget_grab_focus (widget);
3239
3240           return TRUE;
3241         }
3242     }
3243   return FALSE;
3244 }
3245
3246 /* GtkWidget::button_release_event helper */
3247 static gboolean
3248 gtk_tree_view_button_release_drag_column (GtkWidget      *widget,
3249                                           GdkEventButton *event)
3250 {
3251   GtkTreeView *tree_view;
3252   GtkWidget *button;
3253   GList *l;
3254   gboolean rtl;
3255   GdkDevice *device, *other;
3256
3257   tree_view = GTK_TREE_VIEW (widget);
3258
3259   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
3260   device = gdk_event_get_device ((GdkEvent*)event);
3261   other = gdk_device_get_associated_device (device);
3262   gdk_device_ungrab (device, event->time);
3263   gdk_device_ungrab (other, event->time);
3264
3265   /* Move the button back */
3266   button = gtk_tree_view_column_get_button (tree_view->priv->drag_column);
3267   g_object_ref (button);
3268   gtk_container_remove (GTK_CONTAINER (tree_view), button);
3269   gtk_widget_set_parent_window (button, tree_view->priv->header_window);
3270   gtk_widget_set_parent (button, GTK_WIDGET (tree_view));
3271   g_object_unref (button);
3272   gtk_widget_queue_resize (widget);
3273   if (gtk_tree_view_column_get_resizable (tree_view->priv->drag_column))
3274     {
3275       gdk_window_raise (_gtk_tree_view_column_get_window (tree_view->priv->drag_column));
3276       gdk_window_show (_gtk_tree_view_column_get_window (tree_view->priv->drag_column));
3277     }
3278   else
3279     gdk_window_hide (_gtk_tree_view_column_get_window (tree_view->priv->drag_column));
3280
3281   gtk_widget_grab_focus (button);
3282
3283   if (rtl)
3284     {
3285       if (tree_view->priv->cur_reorder &&
3286           tree_view->priv->cur_reorder->right_column != tree_view->priv->drag_column)
3287         gtk_tree_view_move_column_after (tree_view, tree_view->priv->drag_column,
3288                                          tree_view->priv->cur_reorder->right_column);
3289     }
3290   else
3291     {
3292       if (tree_view->priv->cur_reorder &&
3293           tree_view->priv->cur_reorder->left_column != tree_view->priv->drag_column)
3294         gtk_tree_view_move_column_after (tree_view, tree_view->priv->drag_column,
3295                                          tree_view->priv->cur_reorder->left_column);
3296     }
3297   tree_view->priv->drag_column = NULL;
3298   gdk_window_hide (tree_view->priv->drag_window);
3299
3300   for (l = tree_view->priv->column_drag_info; l != NULL; l = l->next)
3301     g_slice_free (GtkTreeViewColumnReorder, l->data);
3302   g_list_free (tree_view->priv->column_drag_info);
3303   tree_view->priv->column_drag_info = NULL;
3304   tree_view->priv->cur_reorder = NULL;
3305
3306   if (tree_view->priv->drag_highlight_window)
3307     gdk_window_hide (tree_view->priv->drag_highlight_window);
3308
3309   /* Reset our flags */
3310   tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_UNSET;
3311   tree_view->priv->in_column_drag = FALSE;
3312
3313   return TRUE;
3314 }
3315
3316 /* GtkWidget::button_release_event helper */
3317 static gboolean
3318 gtk_tree_view_button_release_column_resize (GtkWidget      *widget,
3319                                             GdkEventButton *event)
3320 {
3321   GtkTreeView *tree_view;
3322   gpointer drag_data;
3323
3324   tree_view = GTK_TREE_VIEW (widget);
3325
3326   tree_view->priv->drag_pos = -1;
3327
3328   /* unblock attached dnd signal handler */
3329   drag_data = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
3330   if (drag_data)
3331     g_signal_handlers_unblock_matched (widget,
3332                                        G_SIGNAL_MATCH_DATA,
3333                                        0, 0, NULL, NULL,
3334                                        drag_data);
3335
3336   tree_view->priv->in_column_resize = FALSE;
3337   gtk_grab_remove (widget);
3338   gdk_device_ungrab (gdk_event_get_device ((GdkEvent*)event), event->time);
3339   return TRUE;
3340 }
3341
3342 static gboolean
3343 gtk_tree_view_button_release (GtkWidget      *widget,
3344                               GdkEventButton *event)
3345 {
3346   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
3347
3348   if (tree_view->priv->in_column_drag)
3349     return gtk_tree_view_button_release_drag_column (widget, event);
3350
3351   if (tree_view->priv->rubber_band_status)
3352     gtk_tree_view_stop_rubber_band (tree_view);
3353
3354   if (tree_view->priv->pressed_button == event->button)
3355     tree_view->priv->pressed_button = -1;
3356
3357   if (tree_view->priv->in_column_resize)
3358     return gtk_tree_view_button_release_column_resize (widget, event);
3359
3360   if (tree_view->priv->button_pressed_node == NULL)
3361     return FALSE;
3362
3363   if (event->button == 1)
3364     {
3365       if (tree_view->priv->button_pressed_node == tree_view->priv->prelight_node &&
3366           tree_view->priv->arrow_prelit)
3367         {
3368           GtkTreePath *path = NULL;
3369
3370           path = _gtk_tree_path_new_from_rbtree (tree_view->priv->button_pressed_tree,
3371                                                  tree_view->priv->button_pressed_node);
3372           /* Actually activate the node */
3373           if (tree_view->priv->button_pressed_node->children == NULL)
3374             gtk_tree_view_real_expand_row (tree_view, path,
3375                                            tree_view->priv->button_pressed_tree,
3376                                            tree_view->priv->button_pressed_node,
3377                                            FALSE, TRUE);
3378           else
3379             gtk_tree_view_real_collapse_row (GTK_TREE_VIEW (widget), path,
3380                                              tree_view->priv->button_pressed_tree,
3381                                              tree_view->priv->button_pressed_node, TRUE);
3382           gtk_tree_path_free (path);
3383         }
3384
3385       gtk_grab_remove (widget);
3386       tree_view->priv->button_pressed_tree = NULL;
3387       tree_view->priv->button_pressed_node = NULL;
3388     }
3389
3390   return TRUE;
3391 }
3392
3393 static gboolean
3394 gtk_tree_view_grab_broken (GtkWidget          *widget,
3395                            GdkEventGrabBroken *event)
3396 {
3397   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
3398
3399   if (tree_view->priv->in_column_drag)
3400     gtk_tree_view_button_release_drag_column (widget, (GdkEventButton *)event);
3401
3402   if (tree_view->priv->in_column_resize)
3403     gtk_tree_view_button_release_column_resize (widget, (GdkEventButton *)event);
3404
3405   return TRUE;
3406 }
3407
3408 #if 0
3409 static gboolean
3410 gtk_tree_view_configure (GtkWidget *widget,
3411                          GdkEventConfigure *event)
3412 {
3413   GtkTreeView *tree_view;
3414
3415   tree_view = GTK_TREE_VIEW (widget);
3416   tree_view->priv->search_position_func (tree_view, tree_view->priv->search_window);
3417
3418   return FALSE;
3419 }
3420 #endif
3421
3422 /* GtkWidget::motion_event function set.
3423  */
3424
3425 static gboolean
3426 coords_are_over_arrow (GtkTreeView *tree_view,
3427                        GtkRBTree   *tree,
3428                        GtkRBNode   *node,
3429                        /* these are in bin window coords */
3430                        gint         x,
3431                        gint         y)
3432 {
3433   GdkRectangle arrow;
3434   gint x2;
3435
3436   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
3437     return FALSE;
3438
3439   if ((node->flags & GTK_RBNODE_IS_PARENT) == 0)
3440     return FALSE;
3441
3442   arrow.y = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
3443   arrow.height = gtk_tree_view_get_row_height (tree_view, node);
3444
3445   gtk_tree_view_get_arrow_xrange (tree_view, tree, &arrow.x, &x2);
3446
3447   arrow.width = x2 - arrow.x;
3448
3449   return (x >= arrow.x &&
3450           x < (arrow.x + arrow.width) &&
3451           y >= arrow.y &&
3452           y < (arrow.y + arrow.height));
3453 }
3454
3455 static gboolean
3456 auto_expand_timeout (gpointer data)
3457 {
3458   GtkTreeView *tree_view = GTK_TREE_VIEW (data);
3459   GtkTreePath *path;
3460
3461   if (tree_view->priv->prelight_node)
3462     {
3463       path = _gtk_tree_path_new_from_rbtree (tree_view->priv->prelight_tree,
3464                                              tree_view->priv->prelight_node);
3465
3466       if (tree_view->priv->prelight_node->children)
3467         gtk_tree_view_collapse_row (tree_view, path);
3468       else
3469         gtk_tree_view_expand_row (tree_view, path, FALSE);
3470
3471       gtk_tree_path_free (path);
3472     }
3473
3474   tree_view->priv->auto_expand_timeout = 0;
3475
3476   return FALSE;
3477 }
3478
3479 static void
3480 remove_auto_expand_timeout (GtkTreeView *tree_view)
3481 {
3482   if (tree_view->priv->auto_expand_timeout != 0)
3483     {
3484       g_source_remove (tree_view->priv->auto_expand_timeout);
3485       tree_view->priv->auto_expand_timeout = 0;
3486     }
3487 }
3488
3489 static void
3490 do_prelight (GtkTreeView *tree_view,
3491              GtkRBTree   *tree,
3492              GtkRBNode   *node,
3493              /* these are in bin_window coords */
3494              gint         x,
3495              gint         y)
3496 {
3497   if (tree_view->priv->prelight_tree == tree &&
3498       tree_view->priv->prelight_node == node)
3499     {
3500       /*  We are still on the same node,
3501           but we might need to take care of the arrow  */
3502
3503       if (tree && node && gtk_tree_view_draw_expanders (tree_view))
3504         {
3505           gboolean over_arrow;
3506
3507           over_arrow = coords_are_over_arrow (tree_view, tree, node, x, y);
3508
3509           if (over_arrow != tree_view->priv->arrow_prelit)
3510             {
3511               if (over_arrow)
3512                 tree_view->priv->arrow_prelit = TRUE;
3513               else
3514                 tree_view->priv->arrow_prelit = FALSE;
3515
3516               gtk_tree_view_queue_draw_arrow (tree_view, tree, node);
3517             }
3518         }
3519
3520       return;
3521     }
3522
3523   if (tree_view->priv->prelight_tree && tree_view->priv->prelight_node)
3524     {
3525       /*  Unprelight the old node and arrow  */
3526
3527       GTK_RBNODE_UNSET_FLAG (tree_view->priv->prelight_node,
3528                              GTK_RBNODE_IS_PRELIT);
3529
3530       if (tree_view->priv->arrow_prelit
3531           && gtk_tree_view_draw_expanders (tree_view))
3532         {
3533           tree_view->priv->arrow_prelit = FALSE;
3534           
3535           gtk_tree_view_queue_draw_arrow (tree_view,
3536                                           tree_view->priv->prelight_tree,
3537                                           tree_view->priv->prelight_node);
3538         }
3539
3540       _gtk_tree_view_queue_draw_node (tree_view,
3541                                       tree_view->priv->prelight_tree,
3542                                       tree_view->priv->prelight_node,
3543                                       NULL);
3544     }
3545
3546
3547   if (tree_view->priv->hover_expand)
3548     remove_auto_expand_timeout (tree_view);
3549
3550   /*  Set the new prelight values  */
3551   tree_view->priv->prelight_node = node;
3552   tree_view->priv->prelight_tree = tree;
3553
3554   if (!node || !tree)
3555     return;
3556
3557   /*  Prelight the new node and arrow  */
3558
3559   if (gtk_tree_view_draw_expanders (tree_view)
3560       && coords_are_over_arrow (tree_view, tree, node, x, y))
3561     {
3562       tree_view->priv->arrow_prelit = TRUE;
3563
3564       gtk_tree_view_queue_draw_arrow (tree_view, tree, node);
3565     }
3566
3567   GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_PRELIT);
3568
3569   _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
3570
3571   if (tree_view->priv->hover_expand)
3572     {
3573       tree_view->priv->auto_expand_timeout = 
3574         gdk_threads_add_timeout (AUTO_EXPAND_TIMEOUT, auto_expand_timeout, tree_view);
3575     }
3576 }
3577
3578 static void
3579 prelight_or_select (GtkTreeView *tree_view,
3580                     GtkRBTree   *tree,
3581                     GtkRBNode   *node,
3582                     /* these are in bin_window coords */
3583                     gint         x,
3584                     gint         y)
3585 {
3586   GtkSelectionMode mode = gtk_tree_selection_get_mode (tree_view->priv->selection);
3587   
3588   if (tree_view->priv->hover_selection &&
3589       (mode == GTK_SELECTION_SINGLE || mode == GTK_SELECTION_BROWSE) &&
3590       !(tree_view->priv->edited_column &&
3591         gtk_cell_area_get_edit_widget 
3592         (gtk_cell_layout_get_area (GTK_CELL_LAYOUT (tree_view->priv->edited_column)))))
3593     {
3594       if (node)
3595         {
3596           if (!GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
3597             {
3598               GtkTreePath *path;
3599               
3600               path = _gtk_tree_path_new_from_rbtree (tree, node);
3601               gtk_tree_selection_select_path (tree_view->priv->selection, path);
3602               if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
3603                 {
3604                   tree_view->priv->draw_keyfocus = FALSE;
3605                   gtk_tree_view_real_set_cursor (tree_view, path, FALSE, FALSE);
3606                 }
3607               gtk_tree_path_free (path);
3608             }
3609         }
3610
3611       else if (mode == GTK_SELECTION_SINGLE)
3612         gtk_tree_selection_unselect_all (tree_view->priv->selection);
3613     }
3614
3615     do_prelight (tree_view, tree, node, x, y);
3616 }
3617
3618 static void
3619 ensure_unprelighted (GtkTreeView *tree_view)
3620 {
3621   do_prelight (tree_view,
3622                NULL, NULL,
3623                -1000, -1000); /* coords not possibly over an arrow */
3624
3625   g_assert (tree_view->priv->prelight_node == NULL);
3626 }
3627
3628 static void
3629 update_prelight (GtkTreeView *tree_view,
3630                  gint         x,
3631                  gint         y)
3632 {
3633   int new_y;
3634   GtkRBTree *tree;
3635   GtkRBNode *node;
3636
3637   if (tree_view->priv->tree == NULL)
3638     return;
3639
3640   if (x == -10000)
3641     {
3642       ensure_unprelighted (tree_view);
3643       return;
3644     }
3645
3646   new_y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, y);
3647   if (new_y < 0)
3648     new_y = 0;
3649
3650   _gtk_rbtree_find_offset (tree_view->priv->tree,
3651                            new_y, &tree, &node);
3652
3653   if (node)
3654     prelight_or_select (tree_view, tree, node, x, y);
3655 }
3656
3657
3658
3659
3660 /* Our motion arrow is either a box (in the case of the original spot)
3661  * or an arrow.  It is expander_size wide.
3662  */
3663 /*
3664  * 11111111111111
3665  * 01111111111110
3666  * 00111111111100
3667  * 00011111111000
3668  * 00001111110000
3669  * 00000111100000
3670  * 00000111100000
3671  * 00000111100000
3672  * ~ ~ ~ ~ ~ ~ ~
3673  * 00000111100000
3674  * 00000111100000
3675  * 00000111100000
3676  * 00001111110000
3677  * 00011111111000
3678  * 00111111111100
3679  * 01111111111110
3680  * 11111111111111
3681  */
3682
3683 static void
3684 gtk_tree_view_motion_draw_column_motion_arrow (GtkTreeView *tree_view)
3685 {
3686   GtkTreeViewColumnReorder *reorder = tree_view->priv->cur_reorder;
3687   GtkWidget *widget = GTK_WIDGET (tree_view);
3688   cairo_surface_t *mask_image;
3689   cairo_region_t *mask_region;
3690   gint x;
3691   gint y;
3692   gint width;
3693   gint height;
3694   gint arrow_type = DRAG_COLUMN_WINDOW_STATE_UNSET;
3695   GdkWindowAttr attributes;
3696   guint attributes_mask;
3697   cairo_t *cr;
3698
3699   if (!reorder ||
3700       reorder->left_column == tree_view->priv->drag_column ||
3701       reorder->right_column == tree_view->priv->drag_column)
3702     arrow_type = DRAG_COLUMN_WINDOW_STATE_ORIGINAL;
3703   else if (reorder->left_column || reorder->right_column)
3704     {
3705       GtkAllocation left_allocation, right_allocation;
3706       GdkRectangle visible_rect;
3707       GtkWidget *button;
3708
3709       gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
3710       if (reorder->left_column)
3711         {
3712           button = gtk_tree_view_column_get_button (reorder->left_column);
3713           gtk_widget_get_allocation (button, &left_allocation);
3714           x = left_allocation.x + left_allocation.width;
3715         }
3716       else
3717         {
3718           button = gtk_tree_view_column_get_button (reorder->right_column);
3719           gtk_widget_get_allocation (button, &right_allocation);
3720           x = right_allocation.x;
3721         }
3722
3723       if (x < visible_rect.x)
3724         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT;
3725       else if (x > visible_rect.x + visible_rect.width)
3726         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT;
3727       else
3728         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW;
3729     }
3730
3731   /* We want to draw the rectangle over the initial location. */
3732   if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ORIGINAL)
3733     {
3734       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ORIGINAL)
3735         {
3736           GtkAllocation drag_allocation;
3737           GtkWidget    *button;
3738
3739           if (tree_view->priv->drag_highlight_window)
3740             {
3741               gdk_window_set_user_data (tree_view->priv->drag_highlight_window,
3742                                         NULL);
3743               gdk_window_destroy (tree_view->priv->drag_highlight_window);
3744             }
3745
3746           button = gtk_tree_view_column_get_button (tree_view->priv->drag_column);
3747           attributes.window_type = GDK_WINDOW_CHILD;
3748           attributes.wclass = GDK_INPUT_OUTPUT;
3749           attributes.x = tree_view->priv->drag_column_x;
3750           attributes.y = 0;
3751           gtk_widget_get_allocation (button, &drag_allocation);
3752           width = attributes.width = drag_allocation.width;
3753           height = attributes.height = drag_allocation.height;
3754           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
3755           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3756           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
3757           tree_view->priv->drag_highlight_window = gdk_window_new (tree_view->priv->header_window, &attributes, attributes_mask);
3758           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
3759
3760           mask_image = cairo_image_surface_create (CAIRO_FORMAT_A1, width, height);
3761           cr = cairo_create (mask_image);
3762
3763           cairo_rectangle (cr, 1, 1, width - 2, height - 2);
3764           cairo_stroke (cr);
3765           cairo_destroy (cr);
3766
3767           mask_region = gdk_cairo_region_create_from_surface (mask_image);
3768           gdk_window_shape_combine_region (tree_view->priv->drag_highlight_window,
3769                                            mask_region, 0, 0);
3770
3771           cairo_region_destroy (mask_region);
3772           cairo_surface_destroy (mask_image);
3773
3774           tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_ORIGINAL;
3775         }
3776     }
3777   else if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW)
3778     {
3779       GtkAllocation button_allocation;
3780       GtkWidget    *button;
3781
3782       width = tree_view->priv->expander_size;
3783
3784       /* Get x, y, width, height of arrow */
3785       gdk_window_get_origin (tree_view->priv->header_window, &x, &y);
3786       if (reorder->left_column)
3787         {
3788           button = gtk_tree_view_column_get_button (reorder->left_column);
3789           gtk_widget_get_allocation (button, &button_allocation);
3790           x += button_allocation.x + button_allocation.width - width/2;
3791           height = button_allocation.height;
3792         }
3793       else
3794         {
3795           button = gtk_tree_view_column_get_button (reorder->right_column);
3796           gtk_widget_get_allocation (button, &button_allocation);
3797           x += button_allocation.x - width/2;
3798           height = button_allocation.height;
3799         }
3800       y -= tree_view->priv->expander_size/2; /* The arrow takes up only half the space */
3801       height += tree_view->priv->expander_size;
3802
3803       /* Create the new window */
3804       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW)
3805         {
3806           if (tree_view->priv->drag_highlight_window)
3807             {
3808               gdk_window_set_user_data (tree_view->priv->drag_highlight_window,
3809                                         NULL);
3810               gdk_window_destroy (tree_view->priv->drag_highlight_window);
3811             }
3812
3813           attributes.window_type = GDK_WINDOW_TEMP;
3814           attributes.wclass = GDK_INPUT_OUTPUT;
3815           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
3816           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3817           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
3818           attributes.x = x;
3819           attributes.y = y;
3820           attributes.width = width;
3821           attributes.height = height;
3822           tree_view->priv->drag_highlight_window = gdk_window_new (gtk_widget_get_root_window (widget),
3823                                                                    &attributes, attributes_mask);
3824           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
3825
3826           mask_image = cairo_image_surface_create (CAIRO_FORMAT_A1, width, height);
3827
3828           cr = cairo_create (mask_image);
3829           cairo_move_to (cr, 0, 0);
3830           cairo_line_to (cr, width, 0);
3831           cairo_line_to (cr, width / 2., width / 2);
3832           cairo_move_to (cr, 0, height);
3833           cairo_line_to (cr, width, height);
3834           cairo_line_to (cr, width / 2., height - width / 2.);
3835           cairo_fill (cr);
3836           cairo_destroy (cr);
3837
3838           mask_region = gdk_cairo_region_create_from_surface (mask_image);
3839           gdk_window_shape_combine_region (tree_view->priv->drag_highlight_window,
3840                                            mask_region, 0, 0);
3841
3842           cairo_region_destroy (mask_region);
3843           cairo_surface_destroy (mask_image);
3844         }
3845
3846       tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_ARROW;
3847       gdk_window_move (tree_view->priv->drag_highlight_window, x, y);
3848     }
3849   else if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT ||
3850            arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
3851     {
3852       GtkAllocation allocation;
3853       GtkWidget    *button;
3854
3855       width = tree_view->priv->expander_size;
3856
3857       /* Get x, y, width, height of arrow */
3858       width = width/2; /* remember, the arrow only takes half the available width */
3859       gdk_window_get_origin (gtk_widget_get_window (widget),
3860                              &x, &y);
3861       if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
3862         {
3863           gtk_widget_get_allocation (widget, &allocation);
3864           x += allocation.width - width;
3865         }
3866
3867       if (reorder->left_column)
3868         {
3869           button = gtk_tree_view_column_get_button (reorder->left_column);
3870           gtk_widget_get_allocation (button, &allocation);
3871           height = allocation.height;
3872         }
3873       else
3874         {
3875           button = gtk_tree_view_column_get_button (reorder->right_column);
3876           gtk_widget_get_allocation (button, &allocation);
3877           height = allocation.height;
3878         }
3879
3880       y -= tree_view->priv->expander_size;
3881       height += 2*tree_view->priv->expander_size;
3882
3883       /* Create the new window */
3884       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT &&
3885           tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
3886         {
3887           if (tree_view->priv->drag_highlight_window)
3888             {
3889               gdk_window_set_user_data (tree_view->priv->drag_highlight_window,
3890                                         NULL);
3891               gdk_window_destroy (tree_view->priv->drag_highlight_window);
3892             }
3893
3894           attributes.window_type = GDK_WINDOW_TEMP;
3895           attributes.wclass = GDK_INPUT_OUTPUT;
3896           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
3897           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3898           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
3899           attributes.x = x;
3900           attributes.y = y;
3901           attributes.width = width;
3902           attributes.height = height;
3903           tree_view->priv->drag_highlight_window = gdk_window_new (NULL, &attributes, attributes_mask);
3904           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
3905
3906           mask_image = cairo_image_surface_create (CAIRO_FORMAT_A1, width, height);
3907
3908           cr = cairo_create (mask_image);
3909           /* mirror if we're on the left */
3910           if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT)
3911             {
3912               cairo_translate (cr, width, 0);
3913               cairo_scale (cr, -1, 1);
3914             }
3915           cairo_move_to (cr, 0, 0);
3916           cairo_line_to (cr, width, width);
3917           cairo_line_to (cr, 0, tree_view->priv->expander_size);
3918           cairo_move_to (cr, 0, height);
3919           cairo_line_to (cr, width, height - width);
3920           cairo_line_to (cr, 0, height - tree_view->priv->expander_size);
3921           cairo_fill (cr);
3922           cairo_destroy (cr);
3923
3924           mask_region = gdk_cairo_region_create_from_surface (mask_image);
3925           gdk_window_shape_combine_region (tree_view->priv->drag_highlight_window,
3926                                            mask_region, 0, 0);
3927
3928           cairo_region_destroy (mask_region);
3929           cairo_surface_destroy (mask_image);
3930         }
3931
3932       tree_view->priv->drag_column_window_state = arrow_type;
3933       gdk_window_move (tree_view->priv->drag_highlight_window, x, y);
3934    }
3935   else
3936     {
3937       g_warning (G_STRLOC"Invalid GtkTreeViewColumnReorder struct");
3938       gdk_window_hide (tree_view->priv->drag_highlight_window);
3939       return;
3940     }
3941
3942   gdk_window_show (tree_view->priv->drag_highlight_window);
3943   gdk_window_raise (tree_view->priv->drag_highlight_window);
3944 }
3945
3946 static gboolean
3947 gtk_tree_view_motion_resize_column (GtkWidget      *widget,
3948                                     GdkEventMotion *event)
3949 {
3950   gint x;
3951   gint new_width;
3952   GtkTreeViewColumn *column;
3953   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
3954
3955   column = gtk_tree_view_get_column (tree_view, tree_view->priv->drag_pos);
3956
3957   if (event->is_hint || event->window != gtk_widget_get_window (widget))
3958     gdk_window_get_device_position (gtk_widget_get_window (widget),
3959                                     gdk_event_get_device ((GdkEvent *) event),
3960                                     &x, NULL, NULL);
3961   else
3962     x = event->x;
3963
3964   if (tree_view->priv->hadjustment)
3965     x += gtk_adjustment_get_value (tree_view->priv->hadjustment);
3966
3967   new_width = gtk_tree_view_new_column_width (tree_view,
3968                                               tree_view->priv->drag_pos, &x);
3969   if (x != tree_view->priv->x_drag &&
3970       (new_width != gtk_tree_view_column_get_fixed_width (column)))
3971     {
3972       _gtk_tree_view_column_set_use_resized_width (column, TRUE);
3973
3974       if (gtk_tree_view_column_get_expand (column))
3975         new_width -= tree_view->priv->last_extra_space_per_column;
3976
3977       _gtk_tree_view_column_set_resized_width (column, new_width);
3978
3979
3980       gtk_widget_queue_resize (widget);
3981     }
3982
3983   return FALSE;
3984 }
3985
3986
3987 static void
3988 gtk_tree_view_update_current_reorder (GtkTreeView *tree_view,
3989                                       GdkEvent    *event)
3990 {
3991   GtkTreeViewColumnReorder *reorder = NULL;
3992   GList *list;
3993   gint mouse_x;
3994
3995   gdk_window_get_device_position (tree_view->priv->header_window,
3996                                   gdk_event_get_device (event),
3997                                   &mouse_x, NULL, NULL);
3998   for (list = tree_view->priv->column_drag_info; list; list = list->next)
3999     {
4000       reorder = (GtkTreeViewColumnReorder *) list->data;
4001       if (mouse_x >= reorder->left_align && mouse_x < reorder->right_align)
4002         break;
4003       reorder = NULL;
4004     }
4005
4006   /*  if (reorder && reorder == tree_view->priv->cur_reorder)
4007       return;*/
4008
4009   tree_view->priv->cur_reorder = reorder;
4010   gtk_tree_view_motion_draw_column_motion_arrow (tree_view);
4011 }
4012
4013 static void
4014 gtk_tree_view_vertical_autoscroll (GtkTreeView *tree_view)
4015 {
4016   GdkRectangle visible_rect;
4017   gint y;
4018   gint offset;
4019
4020   gdk_window_get_device_position (tree_view->priv->bin_window,
4021                                   gdk_device_manager_get_client_pointer (
4022                                     gdk_display_get_device_manager (
4023                                       gtk_widget_get_display (GTK_WIDGET (tree_view)))),
4024                                   NULL, &y, NULL);
4025   y += tree_view->priv->dy;
4026
4027   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
4028
4029   /* see if we are near the edge. */
4030   offset = y - (visible_rect.y + 2 * SCROLL_EDGE_SIZE);
4031   if (offset > 0)
4032     {
4033       offset = y - (visible_rect.y + visible_rect.height - 2 * SCROLL_EDGE_SIZE);
4034       if (offset < 0)
4035         return;
4036     }
4037
4038   gtk_adjustment_set_value (tree_view->priv->vadjustment,
4039                             MAX (gtk_adjustment_get_value (tree_view->priv->vadjustment) + offset, 0.0));
4040 }
4041
4042 static gboolean
4043 gtk_tree_view_horizontal_autoscroll (GtkTreeView *tree_view,
4044                                      GdkEvent    *event)
4045 {
4046   GdkRectangle visible_rect;
4047   gint x;
4048   gint offset;
4049
4050   gdk_window_get_device_position (tree_view->priv->bin_window,
4051                                   gdk_event_get_device (event),
4052                                   &x, NULL, NULL);
4053
4054   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
4055
4056   /* See if we are near the edge. */
4057   offset = x - (visible_rect.x + SCROLL_EDGE_SIZE);
4058   if (offset > 0)
4059     {
4060       offset = x - (visible_rect.x + visible_rect.width - SCROLL_EDGE_SIZE);
4061       if (offset < 0)
4062         return TRUE;
4063     }
4064   offset = offset/3;
4065
4066   gtk_adjustment_set_value (tree_view->priv->hadjustment,
4067                             MAX (gtk_adjustment_get_value (tree_view->priv->hadjustment) + offset, 0.0));
4068
4069   return TRUE;
4070
4071 }
4072
4073 static gboolean
4074 gtk_tree_view_motion_drag_column (GtkWidget      *widget,
4075                                   GdkEventMotion *event)
4076 {
4077   GtkAllocation allocation, button_allocation;
4078   GtkTreeView *tree_view = (GtkTreeView *) widget;
4079   GtkTreeViewColumn *column = tree_view->priv->drag_column;
4080   GtkWidget *button;
4081   gint x, y;
4082
4083   /* Sanity Check */
4084   if ((column == NULL) ||
4085       (event->window != tree_view->priv->drag_window))
4086     return FALSE;
4087
4088   button = gtk_tree_view_column_get_button (column);
4089
4090   /* Handle moving the header */
4091   gdk_window_get_position (tree_view->priv->drag_window, &x, &y);
4092   gtk_widget_get_allocation (widget, &allocation);
4093   gtk_widget_get_allocation (button, &button_allocation);
4094   x = CLAMP (x + (gint)event->x - _gtk_tree_view_column_get_drag_x (column), 0,
4095              MAX (tree_view->priv->width, allocation.width) - button_allocation.width);
4096   gdk_window_move (tree_view->priv->drag_window, x, y);
4097   
4098   /* autoscroll, if needed */
4099   gtk_tree_view_horizontal_autoscroll (tree_view, (GdkEvent *) event);
4100   /* Update the current reorder position and arrow; */
4101   gtk_tree_view_update_current_reorder (tree_view, (GdkEvent *) event);
4102
4103   return TRUE;
4104 }
4105
4106 static void
4107 gtk_tree_view_stop_rubber_band (GtkTreeView *tree_view)
4108 {
4109   remove_scroll_timeout (tree_view);
4110   gtk_grab_remove (GTK_WIDGET (tree_view));
4111
4112   if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
4113     {
4114       GtkTreePath *tmp_path;
4115
4116       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
4117
4118       /* The anchor path should be set to the start path */
4119       tmp_path = _gtk_tree_path_new_from_rbtree (tree_view->priv->rubber_band_start_tree,
4120                                                  tree_view->priv->rubber_band_start_node);
4121
4122       if (tree_view->priv->anchor)
4123         gtk_tree_row_reference_free (tree_view->priv->anchor);
4124
4125       tree_view->priv->anchor =
4126         gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
4127                                           tree_view->priv->model,
4128                                           tmp_path);
4129
4130       gtk_tree_path_free (tmp_path);
4131
4132       /* ... and the cursor to the end path */
4133       tmp_path = _gtk_tree_path_new_from_rbtree (tree_view->priv->rubber_band_end_tree,
4134                                                  tree_view->priv->rubber_band_end_node);
4135       gtk_tree_view_real_set_cursor (GTK_TREE_VIEW (tree_view), tmp_path, FALSE, FALSE);
4136       gtk_tree_path_free (tmp_path);
4137
4138       _gtk_tree_selection_emit_changed (tree_view->priv->selection);
4139     }
4140
4141   /* Clear status variables */
4142   tree_view->priv->rubber_band_status = RUBBER_BAND_OFF;
4143   tree_view->priv->rubber_band_extend = FALSE;
4144   tree_view->priv->rubber_band_modify = FALSE;
4145
4146   tree_view->priv->rubber_band_start_node = NULL;
4147   tree_view->priv->rubber_band_start_tree = NULL;
4148   tree_view->priv->rubber_band_end_node = NULL;
4149   tree_view->priv->rubber_band_end_tree = NULL;
4150 }
4151
4152 static void
4153 gtk_tree_view_update_rubber_band_selection_range (GtkTreeView *tree_view,
4154                                                  GtkRBTree   *start_tree,
4155                                                  GtkRBNode   *start_node,
4156                                                  GtkRBTree   *end_tree,
4157                                                  GtkRBNode   *end_node,
4158                                                  gboolean     select,
4159                                                  gboolean     skip_start,
4160                                                  gboolean     skip_end)
4161 {
4162   if (start_node == end_node)
4163     return;
4164
4165   /* We skip the first node and jump inside the loop */
4166   if (skip_start)
4167     goto skip_first;
4168
4169   do
4170     {
4171       /* Small optimization by assuming insensitive nodes are never
4172        * selected.
4173        */
4174       if (!GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
4175         {
4176           GtkTreePath *path;
4177           gboolean selectable;
4178
4179           path = _gtk_tree_path_new_from_rbtree (start_tree, start_node);
4180           selectable = _gtk_tree_selection_row_is_selectable (tree_view->priv->selection, start_node, path);
4181           gtk_tree_path_free (path);
4182
4183           if (!selectable)
4184             goto node_not_selectable;
4185         }
4186
4187       if (select)
4188         {
4189           if (tree_view->priv->rubber_band_extend)
4190             GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4191           else if (tree_view->priv->rubber_band_modify)
4192             {
4193               /* Toggle the selection state */
4194               if (GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
4195                 GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4196               else
4197                 GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4198             }
4199           else
4200             GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4201         }
4202       else
4203         {
4204           /* Mirror the above */
4205           if (tree_view->priv->rubber_band_extend)
4206             GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4207           else if (tree_view->priv->rubber_band_modify)
4208             {
4209               /* Toggle the selection state */
4210               if (GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
4211                 GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4212               else
4213                 GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4214             }
4215           else
4216             GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4217         }
4218
4219       _gtk_tree_view_queue_draw_node (tree_view, start_tree, start_node, NULL);
4220
4221 node_not_selectable:
4222       if (start_node == end_node)
4223         break;
4224
4225 skip_first:
4226
4227       if (start_node->children)
4228         {
4229           start_tree = start_node->children;
4230           start_node = _gtk_rbtree_first (start_tree);
4231         }
4232       else
4233         {
4234           _gtk_rbtree_next_full (start_tree, start_node, &start_tree, &start_node);
4235
4236           if (!start_tree)
4237             /* Ran out of tree */
4238             break;
4239         }
4240
4241       if (skip_end && start_node == end_node)
4242         break;
4243     }
4244   while (TRUE);
4245 }
4246
4247 static void
4248 gtk_tree_view_update_rubber_band_selection (GtkTreeView *tree_view)
4249 {
4250   GtkRBTree *start_tree, *end_tree;
4251   GtkRBNode *start_node, *end_node;
4252
4253   _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);
4254   _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);
4255
4256   /* Handle the start area first */
4257   if (!tree_view->priv->rubber_band_start_node)
4258     {
4259       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4260                                                        start_tree,
4261                                                        start_node,
4262                                                        end_tree,
4263                                                        end_node,
4264                                                        TRUE,
4265                                                        FALSE,
4266                                                        FALSE);
4267     }
4268   else if (_gtk_rbtree_node_find_offset (start_tree, start_node) <
4269            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_start_tree, tree_view->priv->rubber_band_start_node))
4270     {
4271       /* New node is above the old one; selection became bigger */
4272       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4273                                                        start_tree,
4274                                                        start_node,
4275                                                        tree_view->priv->rubber_band_start_tree,
4276                                                        tree_view->priv->rubber_band_start_node,
4277                                                        TRUE,
4278                                                        FALSE,
4279                                                        TRUE);
4280     }
4281   else if (_gtk_rbtree_node_find_offset (start_tree, start_node) >
4282            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_start_tree, tree_view->priv->rubber_band_start_node))
4283     {
4284       /* New node is below the old one; selection became smaller */
4285       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4286                                                        tree_view->priv->rubber_band_start_tree,
4287                                                        tree_view->priv->rubber_band_start_node,
4288                                                        start_tree,
4289                                                        start_node,
4290                                                        FALSE,
4291                                                        FALSE,
4292                                                        TRUE);
4293     }
4294
4295   tree_view->priv->rubber_band_start_tree = start_tree;
4296   tree_view->priv->rubber_band_start_node = start_node;
4297
4298   /* Next, handle the end area */
4299   if (!tree_view->priv->rubber_band_end_node)
4300     {
4301       /* In the event this happens, start_node was also NULL; this case is
4302        * handled above.
4303        */
4304     }
4305   else if (!end_node)
4306     {
4307       /* Find the last node in the tree */
4308       _gtk_rbtree_find_offset (tree_view->priv->tree, tree_view->priv->height - 1,
4309                                &end_tree, &end_node);
4310
4311       /* Selection reached end of the tree */
4312       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4313                                                        tree_view->priv->rubber_band_end_tree,
4314                                                        tree_view->priv->rubber_band_end_node,
4315                                                        end_tree,
4316                                                        end_node,
4317                                                        TRUE,
4318                                                        TRUE,
4319                                                        FALSE);
4320     }
4321   else if (_gtk_rbtree_node_find_offset (end_tree, end_node) >
4322            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_end_tree, tree_view->priv->rubber_band_end_node))
4323     {
4324       /* New node is below the old one; selection became bigger */
4325       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4326                                                        tree_view->priv->rubber_band_end_tree,
4327                                                        tree_view->priv->rubber_band_end_node,
4328                                                        end_tree,
4329                                                        end_node,
4330                                                        TRUE,
4331                                                        TRUE,
4332                                                        FALSE);
4333     }
4334   else if (_gtk_rbtree_node_find_offset (end_tree, end_node) <
4335            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_end_tree, tree_view->priv->rubber_band_end_node))
4336     {
4337       /* New node is above the old one; selection became smaller */
4338       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4339                                                        end_tree,
4340                                                        end_node,
4341                                                        tree_view->priv->rubber_band_end_tree,
4342                                                        tree_view->priv->rubber_band_end_node,
4343                                                        FALSE,
4344                                                        TRUE,
4345                                                        FALSE);
4346     }
4347
4348   tree_view->priv->rubber_band_end_tree = end_tree;
4349   tree_view->priv->rubber_band_end_node = end_node;
4350 }
4351
4352 static void
4353 gtk_tree_view_update_rubber_band (GtkTreeView *tree_view)
4354 {
4355   gint x, y;
4356   GdkRectangle old_area;
4357   GdkRectangle new_area;
4358   GdkRectangle common;
4359   cairo_region_t *invalid_region;
4360
4361   old_area.x = MIN (tree_view->priv->press_start_x, tree_view->priv->rubber_band_x);
4362   old_area.y = MIN (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y) - tree_view->priv->dy;
4363   old_area.width = ABS (tree_view->priv->rubber_band_x - tree_view->priv->press_start_x) + 1;
4364   old_area.height = ABS (tree_view->priv->rubber_band_y - tree_view->priv->press_start_y) + 1;
4365
4366   gdk_window_get_device_position (tree_view->priv->bin_window,
4367                                   gdk_device_manager_get_client_pointer (
4368                                     gdk_display_get_device_manager (
4369                                       gtk_widget_get_display (GTK_WIDGET (tree_view)))),
4370                                   &x, &y, NULL);
4371
4372   x = MAX (x, 0);
4373   y = MAX (y, 0) + tree_view->priv->dy;
4374
4375   new_area.x = MIN (tree_view->priv->press_start_x, x);
4376   new_area.y = MIN (tree_view->priv->press_start_y, y) - tree_view->priv->dy;
4377   new_area.width = ABS (x - tree_view->priv->press_start_x) + 1;
4378   new_area.height = ABS (y - tree_view->priv->press_start_y) + 1;
4379
4380   invalid_region = cairo_region_create_rectangle (&old_area);
4381   cairo_region_union_rectangle (invalid_region, &new_area);
4382
4383   gdk_rectangle_intersect (&old_area, &new_area, &common);
4384   if (common.width > 2 && common.height > 2)
4385     {
4386       cairo_region_t *common_region;
4387
4388       /* make sure the border is invalidated */
4389       common.x += 1;
4390       common.y += 1;
4391       common.width -= 2;
4392       common.height -= 2;
4393
4394       common_region = cairo_region_create_rectangle (&common);
4395
4396       cairo_region_subtract (invalid_region, common_region);
4397       cairo_region_destroy (common_region);
4398     }
4399
4400   gdk_window_invalidate_region (tree_view->priv->bin_window, invalid_region, TRUE);
4401
4402   cairo_region_destroy (invalid_region);
4403
4404   tree_view->priv->rubber_band_x = x;
4405   tree_view->priv->rubber_band_y = y;
4406
4407   gtk_tree_view_update_rubber_band_selection (tree_view);
4408 }
4409
4410 static void
4411 gtk_tree_view_paint_rubber_band (GtkTreeView  *tree_view,
4412                                  cairo_t      *cr)
4413 {
4414   GdkRectangle rect;
4415   GtkStyleContext *context;
4416
4417   cairo_save (cr);
4418
4419   context = gtk_widget_get_style_context (GTK_WIDGET (tree_view));
4420
4421   gtk_style_context_save (context);
4422   gtk_style_context_add_class (context, GTK_STYLE_CLASS_RUBBERBAND);
4423
4424   rect.x = MIN (tree_view->priv->press_start_x, tree_view->priv->rubber_band_x);
4425   rect.y = MIN (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y) - tree_view->priv->dy;
4426   rect.width = ABS (tree_view->priv->press_start_x - tree_view->priv->rubber_band_x) + 1;
4427   rect.height = ABS (tree_view->priv->press_start_y - tree_view->priv->rubber_band_y) + 1;
4428
4429   gdk_cairo_rectangle (cr, &rect);
4430   cairo_clip (cr);
4431
4432   gtk_render_background (context, cr,
4433                          rect.x, rect.y,
4434                          rect.width, rect.height);
4435   gtk_render_frame (context, cr,
4436                     rect.x, rect.y,
4437                     rect.width, rect.height);
4438
4439   gtk_style_context_restore (context);
4440   cairo_restore (cr);
4441 }
4442
4443 static gboolean
4444 gtk_tree_view_motion_bin_window (GtkWidget      *widget,
4445                                  GdkEventMotion *event)
4446 {
4447   GtkTreeView *tree_view;
4448   GtkRBTree *tree;
4449   GtkRBNode *node;
4450   gint new_y;
4451
4452   tree_view = (GtkTreeView *) widget;
4453
4454   if (tree_view->priv->tree == NULL)
4455     return FALSE;
4456
4457   if (tree_view->priv->rubber_band_status == RUBBER_BAND_MAYBE_START)
4458     {
4459       gtk_grab_add (GTK_WIDGET (tree_view));
4460       gtk_tree_view_update_rubber_band (tree_view);
4461
4462       tree_view->priv->rubber_band_status = RUBBER_BAND_ACTIVE;
4463     }
4464   else if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
4465     {
4466       gtk_tree_view_update_rubber_band (tree_view);
4467
4468       add_scroll_timeout (tree_view);
4469     }
4470
4471   /* only check for an initiated drag when a button is pressed */
4472   if (tree_view->priv->pressed_button >= 0
4473       && !tree_view->priv->rubber_band_status)
4474     gtk_tree_view_maybe_begin_dragging_row (tree_view, event);
4475
4476   new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
4477   if (new_y < 0)
4478     new_y = 0;
4479
4480   _gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
4481
4482   /* If we are currently pressing down a button, we don't want to prelight anything else. */
4483   if ((tree_view->priv->button_pressed_node != NULL) &&
4484       (tree_view->priv->button_pressed_node != node))
4485     node = NULL;
4486
4487   tree_view->priv->event_last_x = event->x;
4488   tree_view->priv->event_last_y = event->y;
4489
4490   prelight_or_select (tree_view, tree, node, event->x, event->y);
4491
4492   return TRUE;
4493 }
4494
4495 static gboolean
4496 gtk_tree_view_motion (GtkWidget      *widget,
4497                       GdkEventMotion *event)
4498 {
4499   GtkTreeView *tree_view;
4500
4501   tree_view = (GtkTreeView *) widget;
4502
4503   /* Resizing a column */
4504   if (tree_view->priv->in_column_resize)
4505     return gtk_tree_view_motion_resize_column (widget, event);
4506
4507   /* Drag column */
4508   if (tree_view->priv->in_column_drag)
4509     return gtk_tree_view_motion_drag_column (widget, event);
4510
4511   /* Sanity check it */
4512   if (event->window == tree_view->priv->bin_window)
4513     return gtk_tree_view_motion_bin_window (widget, event);
4514
4515   return FALSE;
4516 }
4517
4518 /* Invalidate the focus rectangle near the edge of the bin_window; used when
4519  * the tree is empty.
4520  */
4521 static void
4522 invalidate_empty_focus (GtkTreeView *tree_view)
4523 {
4524   GdkRectangle area;
4525
4526   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
4527     return;
4528
4529   area.x = 0;
4530   area.y = 0;
4531   area.width = gdk_window_get_width (tree_view->priv->bin_window);
4532   area.height = gdk_window_get_height (tree_view->priv->bin_window);
4533   gdk_window_invalidate_rect (tree_view->priv->bin_window, &area, FALSE);
4534 }
4535
4536 /* Draws a focus rectangle near the edge of the bin_window; used when the tree
4537  * is empty.
4538  */
4539 static void
4540 draw_empty_focus (GtkTreeView *tree_view, cairo_t *cr)
4541 {
4542   GtkWidget *widget = GTK_WIDGET (tree_view);
4543   gint w, h;
4544
4545   if (!gtk_widget_has_visible_focus (widget))
4546     return;
4547
4548   w = gdk_window_get_width (tree_view->priv->bin_window) - 2;
4549   h = gdk_window_get_height (tree_view->priv->bin_window) - 2;
4550
4551   if (w > 0 && h > 0)
4552     {
4553       GtkStyleContext *context;
4554       GtkStateFlags state;
4555
4556       context = gtk_widget_get_style_context (widget);
4557       state = gtk_widget_get_state_flags (widget);
4558
4559       gtk_style_context_save (context);
4560       gtk_style_context_set_state (context, state);
4561
4562       gtk_render_focus (context, cr, 1, 1, w, h);
4563
4564       gtk_style_context_restore (context);
4565     }
4566 }
4567
4568 typedef enum {
4569   GTK_TREE_VIEW_GRID_LINE,
4570   GTK_TREE_VIEW_TREE_LINE,
4571   GTK_TREE_VIEW_FOREGROUND_LINE
4572 } GtkTreeViewLineType;
4573
4574 static void
4575 gtk_tree_view_draw_line (GtkTreeView         *tree_view,
4576                          cairo_t             *cr,
4577                          GtkTreeViewLineType  type,
4578                          int                  x1,
4579                          int                  y1,
4580                          int                  x2,
4581                          int                  y2)
4582 {
4583   cairo_save (cr);
4584
4585   switch (type)
4586     {
4587     case GTK_TREE_VIEW_TREE_LINE:
4588       cairo_set_source_rgb (cr, 0, 0, 0);
4589       cairo_set_line_width (cr, tree_view->priv->tree_line_width);
4590       if (tree_view->priv->tree_line_dashes[0])
4591         cairo_set_dash (cr, 
4592                         tree_view->priv->tree_line_dashes,
4593                         2, 0.5);
4594       break;
4595     case GTK_TREE_VIEW_GRID_LINE:
4596       cairo_set_source_rgb (cr, 0, 0, 0);
4597       cairo_set_line_width (cr, tree_view->priv->grid_line_width);
4598       if (tree_view->priv->grid_line_dashes[0])
4599         cairo_set_dash (cr, 
4600                         tree_view->priv->grid_line_dashes,
4601                         2, 0.5);
4602       break;
4603     default:
4604       g_assert_not_reached ();
4605       /* fall through */
4606     case GTK_TREE_VIEW_FOREGROUND_LINE:
4607       {
4608         GtkStyleContext *context;
4609         GtkStateFlags state;
4610         GdkRGBA color;
4611
4612         context = gtk_widget_get_style_context (GTK_WIDGET (tree_view));
4613         state = gtk_widget_get_state_flags (GTK_WIDGET (tree_view));
4614
4615         cairo_set_line_width (cr, 1.0);
4616         gtk_style_context_get_color (context, state, &color);
4617         gdk_cairo_set_source_rgba (cr, &color);
4618       }
4619
4620       break;
4621     }
4622
4623   cairo_move_to (cr, x1 + 0.5, y1 + 0.5);
4624   cairo_line_to (cr, x2 + 0.5, y2 + 0.5);
4625   cairo_stroke (cr);
4626
4627   cairo_restore (cr);
4628 }
4629                          
4630 static void
4631 gtk_tree_view_draw_grid_lines (GtkTreeView    *tree_view,
4632                                cairo_t        *cr,
4633                                gint            n_visible_columns)
4634 {
4635   GList *list = tree_view->priv->columns;
4636   gint i = 0;
4637   gint current_x = 0;
4638
4639   if (tree_view->priv->grid_lines != GTK_TREE_VIEW_GRID_LINES_VERTICAL
4640       && tree_view->priv->grid_lines != GTK_TREE_VIEW_GRID_LINES_BOTH)
4641     return;
4642
4643   /* Only draw the lines for visible rows and columns */
4644   for (list = tree_view->priv->columns; list; list = list->next, i++)
4645     {
4646       GtkTreeViewColumn *column = list->data;
4647
4648       /* We don't want a line for the last column */
4649       if (i == n_visible_columns - 1)
4650         break;
4651
4652       if (!gtk_tree_view_column_get_visible (column))
4653         continue;
4654
4655       current_x += gtk_tree_view_column_get_width (column);
4656
4657       gtk_tree_view_draw_line (tree_view, cr,
4658                                GTK_TREE_VIEW_GRID_LINE,
4659                                current_x - 1, 0,
4660                                current_x - 1, tree_view->priv->height);
4661     }
4662 }
4663
4664 /* Warning: Very scary function.
4665  * Modify at your own risk
4666  *
4667  * KEEP IN SYNC WITH gtk_tree_view_create_row_drag_icon()!
4668  * FIXME: It's not...
4669  */
4670 static gboolean
4671 gtk_tree_view_bin_draw (GtkWidget      *widget,
4672                         cairo_t        *cr)
4673 {
4674   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
4675   GtkTreePath *path;
4676   GtkRBTree *tree;
4677   GList *list;
4678   GtkRBNode *node;
4679   GtkRBNode *drag_highlight = NULL;
4680   GtkRBTree *drag_highlight_tree = NULL;
4681   GtkTreeIter iter;
4682   gint new_y;
4683   gint y_offset, cell_offset;
4684   gint max_height;
4685   gint depth;
4686   GdkRectangle background_area;
4687   GdkRectangle cell_area;
4688   GdkRectangle clip;
4689   guint flags;
4690   gint highlight_x;
4691   gint expander_cell_width;
4692   gint bin_window_width;
4693   gint bin_window_height;
4694   GtkTreePath *drag_dest_path;
4695   GList *first_column, *last_column;
4696   gint vertical_separator;
4697   gint horizontal_separator;
4698   gint focus_line_width;
4699   gboolean allow_rules;
4700   gboolean has_can_focus_cell;
4701   gboolean rtl;
4702   gint n_visible_columns;
4703   gint grid_line_width;
4704   gboolean draw_vgrid_lines, draw_hgrid_lines;
4705   GtkStyleContext *context;
4706   GtkStateFlags state;
4707   gboolean parity;
4708
4709   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
4710   context = gtk_widget_get_style_context (widget);
4711   state = gtk_widget_get_state_flags (widget);
4712
4713   gtk_widget_style_get (widget,
4714                         "horizontal-separator", &horizontal_separator,
4715                         "vertical-separator", &vertical_separator,
4716                         "allow-rules", &allow_rules,
4717                         "focus-line-width", &focus_line_width,
4718                         NULL);
4719
4720   if (tree_view->priv->tree == NULL)
4721     {
4722       draw_empty_focus (tree_view, cr);
4723       return TRUE;
4724     }
4725
4726   bin_window_width = gdk_window_get_width (tree_view->priv->bin_window);
4727   bin_window_height = gdk_window_get_height (tree_view->priv->bin_window);
4728   cairo_rectangle (cr, 0, 0, bin_window_width, bin_window_height);
4729   cairo_clip (cr);
4730   if (!gdk_cairo_get_clip_rectangle (cr, &clip))
4731     return TRUE;
4732
4733   new_y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, clip.y);
4734
4735   if (new_y < 0)
4736     new_y = 0;
4737   y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
4738
4739   if (tree_view->priv->height < bin_window_height)
4740     {
4741       gtk_style_context_save (context);
4742       gtk_style_context_set_state (context, state);
4743       gtk_style_context_add_class (context, GTK_STYLE_CLASS_CELL);
4744
4745       gtk_render_background (context, cr,
4746                              0, tree_view->priv->height,
4747                              bin_window_width,
4748                              bin_window_height - tree_view->priv->height);
4749
4750       gtk_style_context_restore (context);
4751     }
4752
4753   if (node == NULL)
4754     return TRUE;
4755
4756   /* find the path for the node */
4757   path = _gtk_tree_path_new_from_rbtree (tree, node);
4758   gtk_tree_model_get_iter (tree_view->priv->model,
4759                            &iter,
4760                            path);
4761   depth = gtk_tree_path_get_depth (path);
4762   gtk_tree_path_free (path);
4763   
4764   drag_dest_path = NULL;
4765
4766   if (tree_view->priv->drag_dest_row)
4767     drag_dest_path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
4768
4769   if (drag_dest_path)
4770     _gtk_tree_view_find_node (tree_view, drag_dest_path,
4771                               &drag_highlight_tree, &drag_highlight);
4772
4773   draw_vgrid_lines =
4774     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_VERTICAL
4775     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
4776   draw_hgrid_lines =
4777     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_HORIZONTAL
4778     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
4779
4780   if (draw_vgrid_lines || draw_hgrid_lines)
4781     gtk_widget_style_get (widget, "grid-line-width", &grid_line_width, NULL);
4782   
4783   n_visible_columns = 0;
4784   for (list = tree_view->priv->columns; list; list = list->next)
4785     {
4786       if (!gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (list->data)))
4787         continue;
4788       n_visible_columns ++;
4789     }
4790
4791   /* Find the last column */
4792   for (last_column = g_list_last (tree_view->priv->columns);
4793        last_column &&
4794        !(gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (last_column->data)));
4795        last_column = last_column->prev)
4796     ;
4797
4798   /* and the first */
4799   for (first_column = g_list_first (tree_view->priv->columns);
4800        first_column &&
4801        !(gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (first_column->data)));
4802        first_column = first_column->next)
4803     ;
4804
4805   /* Actually process the expose event.  To do this, we want to
4806    * start at the first node of the event, and walk the tree in
4807    * order, drawing each successive node.
4808    */
4809   
4810   parity = !(_gtk_rbtree_node_get_index (tree, node) % 2);
4811
4812   do
4813     {
4814       gboolean is_separator = FALSE;
4815       gboolean is_first = FALSE;
4816       gboolean is_last = FALSE;
4817       gint n_col = 0;
4818
4819       parity = !parity;
4820       is_separator = row_is_separator (tree_view, &iter, NULL);
4821
4822       max_height = gtk_tree_view_get_row_height (tree_view, node);
4823
4824       cell_offset = 0;
4825       highlight_x = 0; /* should match x coord of first cell */
4826       expander_cell_width = 0;
4827
4828       background_area.y = y_offset + clip.y;
4829       background_area.height = max_height;
4830
4831       flags = 0;
4832
4833       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PRELIT))
4834         flags |= GTK_CELL_RENDERER_PRELIT;
4835
4836       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
4837         flags |= GTK_CELL_RENDERER_SELECTED;
4838
4839       /* we *need* to set cell data on all cells before the call
4840        * to _has_can_focus_cell, else _has_can_focus_cell() does not
4841        * return a correct value.
4842        */
4843       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
4844            list;
4845            list = (rtl ? list->prev : list->next))
4846         {
4847           GtkTreeViewColumn *column = list->data;
4848           gtk_tree_view_column_cell_set_cell_data (column,
4849                                                    tree_view->priv->model,
4850                                                    &iter,
4851                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
4852                                                    node->children?TRUE:FALSE);
4853         }
4854
4855       has_can_focus_cell = gtk_tree_view_has_can_focus_cell (tree_view);
4856
4857       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
4858            list;
4859            list = (rtl ? list->prev : list->next))
4860         {
4861           GtkTreeViewColumn *column = list->data;
4862           GtkRegionFlags row_flags = 0, column_flags = 0;
4863           GtkStateFlags state = 0;
4864           gint width;
4865           gboolean draw_focus;
4866
4867           if (!gtk_tree_view_column_get_visible (column))
4868             continue;
4869
4870           n_col++;
4871           width = gtk_tree_view_column_get_width (column);
4872
4873           if (cell_offset > clip.x + clip.width ||
4874               cell_offset + width < clip.x)
4875             {
4876               cell_offset += width;
4877               continue;
4878             }
4879
4880           if (gtk_tree_view_column_get_sort_indicator (column))
4881             flags |= GTK_CELL_RENDERER_SORTED;
4882           else
4883             flags &= ~GTK_CELL_RENDERER_SORTED;
4884
4885           if (tree_view->priv->cursor_node == node)
4886             flags |= GTK_CELL_RENDERER_FOCUSED;
4887           else
4888             flags &= ~GTK_CELL_RENDERER_FOCUSED;
4889
4890           background_area.x = cell_offset;
4891           background_area.width = width;
4892
4893           cell_area = background_area;
4894           cell_area.y += vertical_separator / 2;
4895           cell_area.x += horizontal_separator / 2;
4896           cell_area.height -= vertical_separator;
4897           cell_area.width -= horizontal_separator;
4898
4899           if (draw_vgrid_lines)
4900             {
4901               if (list == first_column)
4902                 {
4903                   cell_area.width -= grid_line_width / 2;
4904                 }
4905               else if (list == last_column)
4906                 {
4907                   cell_area.x += grid_line_width / 2;
4908                   cell_area.width -= grid_line_width / 2;
4909                 }
4910               else
4911                 {
4912                   cell_area.x += grid_line_width / 2;
4913                   cell_area.width -= grid_line_width;
4914                 }
4915             }
4916
4917           if (draw_hgrid_lines)
4918             {
4919               cell_area.y += grid_line_width / 2;
4920               cell_area.height -= grid_line_width;
4921             }
4922
4923           if (!gdk_rectangle_intersect (&clip, &background_area, NULL))
4924             {
4925               cell_offset += gtk_tree_view_column_get_width (column);
4926               continue;
4927             }
4928
4929           gtk_tree_view_column_cell_set_cell_data (column,
4930                                                    tree_view->priv->model,
4931                                                    &iter,
4932                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
4933                                                    node->children?TRUE:FALSE);
4934
4935           /* Select the detail for drawing the cell.  relevant
4936            * factors are parity, sortedness, and whether to
4937            * display rules.
4938            */
4939           if (allow_rules && tree_view->priv->has_rules)
4940             {
4941               if (parity)
4942                 row_flags |= GTK_REGION_ODD;
4943               else
4944                 row_flags |= GTK_REGION_EVEN;
4945             }
4946
4947           if ((flags & GTK_CELL_RENDERER_SORTED) &&
4948               n_visible_columns >= 3)
4949             column_flags |= GTK_REGION_SORTED;
4950
4951           is_first = (rtl ? !list->next : !list->prev);
4952           is_last = (rtl ? !list->prev : !list->next);
4953
4954           if (is_first)
4955             column_flags |= GTK_REGION_FIRST;
4956
4957           if (is_last)
4958             column_flags |= GTK_REGION_LAST;
4959
4960           if ((n_col % 2) == 0)
4961             column_flags |= GTK_REGION_EVEN;
4962           else
4963             column_flags |= GTK_REGION_ODD;
4964
4965           gtk_style_context_save (context);
4966
4967           state = gtk_cell_renderer_get_state (NULL, widget, flags);
4968           gtk_style_context_set_state (context, state);
4969
4970           gtk_style_context_add_class (context, GTK_STYLE_CLASS_CELL);
4971           gtk_style_context_add_region (context, GTK_STYLE_REGION_ROW, row_flags);
4972           gtk_style_context_add_region (context, GTK_STYLE_REGION_COLUMN, column_flags);
4973
4974           if (node == tree_view->priv->cursor_node && has_can_focus_cell
4975               && ((column == tree_view->priv->focus_column
4976                    && tree_view->priv->draw_keyfocus &&
4977                    gtk_widget_has_visible_focus (widget))
4978                   || (column == tree_view->priv->edited_column)))
4979             draw_focus = TRUE;
4980           else
4981             draw_focus = FALSE;
4982
4983           /* Draw background */
4984           gtk_render_background (context, cr,
4985                                  background_area.x,
4986                                  background_area.y,
4987                                  background_area.width,
4988                                  background_area.height);
4989
4990           /* Draw frame */
4991           gtk_render_frame (context, cr,
4992                             background_area.x,
4993                             background_area.y,
4994                             background_area.width,
4995                             background_area.height);
4996
4997           if (gtk_tree_view_is_expander_column (tree_view, column))
4998             {
4999               if (!rtl)
5000                 cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
5001               cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
5002
5003               if (gtk_tree_view_draw_expanders (tree_view))
5004                 {
5005                   if (!rtl)
5006                     cell_area.x += depth * tree_view->priv->expander_size;
5007                   cell_area.width -= depth * tree_view->priv->expander_size;
5008                 }
5009
5010               /* If we have an expander column, the highlight underline
5011                * starts with that column, so that it indicates which
5012                * level of the tree we're dropping at.
5013                */
5014               highlight_x = cell_area.x;
5015               expander_cell_width = cell_area.width;
5016
5017               if (is_separator)
5018                 {
5019                   gtk_style_context_save (context);
5020                   gtk_style_context_add_class (context, GTK_STYLE_CLASS_SEPARATOR);
5021
5022                   gtk_render_line (context, cr,
5023                                    cell_area.x,
5024                                    cell_area.y + cell_area.height / 2,
5025                                    cell_area.x + cell_area.width,
5026                                    cell_area.y + cell_area.height / 2);
5027
5028                   gtk_style_context_restore (context);
5029                 }
5030               else
5031                 {
5032                   _gtk_tree_view_column_cell_render (column,
5033                                                      cr,
5034                                                      &background_area,
5035                                                      &cell_area,
5036                                                      flags,
5037                                                      draw_focus);
5038                 }
5039
5040               if (gtk_tree_view_draw_expanders (tree_view)
5041                   && (node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT)
5042                 {
5043                   gtk_tree_view_draw_arrow (GTK_TREE_VIEW (widget),
5044                                             cr,
5045                                             tree,
5046                                             node);
5047                 }
5048             }
5049           else
5050             {
5051               if (is_separator)
5052                 {
5053                   gtk_style_context_save (context);
5054                   gtk_style_context_add_class (context, GTK_STYLE_CLASS_SEPARATOR);
5055
5056                   gtk_render_line (context, cr,
5057                                    cell_area.x,
5058                                    cell_area.y + cell_area.height / 2,
5059                                    cell_area.x + cell_area.width,
5060                                    cell_area.y + cell_area.height / 2);
5061
5062                   gtk_style_context_restore (context);
5063                 }
5064               else
5065                 _gtk_tree_view_column_cell_render (column,
5066                                                    cr,
5067                                                    &background_area,
5068                                                    &cell_area,
5069                                                    flags,
5070                                                    draw_focus);
5071             }
5072
5073           if (draw_hgrid_lines)
5074             {
5075               if (background_area.y > 0)
5076                 gtk_tree_view_draw_line (tree_view, cr,
5077                                          GTK_TREE_VIEW_GRID_LINE,
5078                                          background_area.x, background_area.y,
5079                                          background_area.x + background_area.width,
5080                                          background_area.y);
5081
5082               if (y_offset + max_height >= clip.height)
5083                 gtk_tree_view_draw_line (tree_view, cr,
5084                                          GTK_TREE_VIEW_GRID_LINE,
5085                                          background_area.x, background_area.y + max_height,
5086                                          background_area.x + background_area.width,
5087                                          background_area.y + max_height);
5088             }
5089
5090           if (gtk_tree_view_is_expander_column (tree_view, column) &&
5091               tree_view->priv->tree_lines_enabled)
5092             {
5093               gint x = background_area.x;
5094               gint mult = rtl ? -1 : 1;
5095               gint y0 = background_area.y;
5096               gint y1 = background_area.y + background_area.height/2;
5097               gint y2 = background_area.y + background_area.height;
5098
5099               if (rtl)
5100                 x += background_area.width - 1;
5101
5102               if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT
5103                   && depth > 1)
5104                 {
5105                   gtk_tree_view_draw_line (tree_view, cr,
5106                                            GTK_TREE_VIEW_TREE_LINE,
5107                                            x + tree_view->priv->expander_size * (depth - 1.5) * mult,
5108                                            y1,
5109                                            x + tree_view->priv->expander_size * (depth - 1.1) * mult,
5110                                            y1);
5111                 }
5112               else if (depth > 1)
5113                 {
5114                   gtk_tree_view_draw_line (tree_view, cr,
5115                                            GTK_TREE_VIEW_TREE_LINE,
5116                                            x + tree_view->priv->expander_size * (depth - 1.5) * mult,
5117                                            y1,
5118                                            x + tree_view->priv->expander_size * (depth - 0.5) * mult,
5119                                            y1);
5120                 }
5121
5122               if (depth > 1)
5123                 {
5124                   gint i;
5125                   GtkRBNode *tmp_node;
5126                   GtkRBTree *tmp_tree;
5127
5128                   if (!_gtk_rbtree_next (tree, node))
5129                     gtk_tree_view_draw_line (tree_view, cr,
5130                                              GTK_TREE_VIEW_TREE_LINE,
5131                                              x + tree_view->priv->expander_size * (depth - 1.5) * mult,
5132                                              y0,
5133                                              x + tree_view->priv->expander_size * (depth - 1.5) * mult,
5134                                              y1);
5135                   else
5136                     gtk_tree_view_draw_line (tree_view, cr,
5137                                              GTK_TREE_VIEW_TREE_LINE,
5138                                              x + tree_view->priv->expander_size * (depth - 1.5) * mult,
5139                                              y0,
5140                                              x + tree_view->priv->expander_size * (depth - 1.5) * mult,
5141                                              y2);
5142
5143                   tmp_node = tree->parent_node;
5144                   tmp_tree = tree->parent_tree;
5145
5146                   for (i = depth - 2; i > 0; i--)
5147                     {
5148                       if (_gtk_rbtree_next (tmp_tree, tmp_node))
5149                         gtk_tree_view_draw_line (tree_view, cr,
5150                                                  GTK_TREE_VIEW_TREE_LINE,
5151                                                  x + tree_view->priv->expander_size * (i - 0.5) * mult,
5152                                                  y0,
5153                                                  x + tree_view->priv->expander_size * (i - 0.5) * mult,
5154                                                  y2);
5155
5156                       tmp_node = tmp_tree->parent_node;
5157                       tmp_tree = tmp_tree->parent_tree;
5158                     }
5159                 }
5160             }
5161
5162           gtk_style_context_restore (context);
5163           cell_offset += gtk_tree_view_column_get_width (column);
5164         }
5165
5166       if (node == drag_highlight)
5167         {
5168           /* Draw indicator for the drop
5169            */
5170           gint highlight_y = -1;
5171           GtkRBTree *tree = NULL;
5172           GtkRBNode *node = NULL;
5173
5174           switch (tree_view->priv->drag_dest_pos)
5175             {
5176             case GTK_TREE_VIEW_DROP_BEFORE:
5177               highlight_y = background_area.y - 1;
5178               if (highlight_y < 0)
5179                       highlight_y = 0;
5180               break;
5181
5182             case GTK_TREE_VIEW_DROP_AFTER:
5183               highlight_y = background_area.y + background_area.height - 1;
5184               break;
5185
5186             case GTK_TREE_VIEW_DROP_INTO_OR_BEFORE:
5187             case GTK_TREE_VIEW_DROP_INTO_OR_AFTER:
5188               _gtk_tree_view_find_node (tree_view, drag_dest_path, &tree, &node);
5189
5190               if (tree == NULL)
5191                 break;
5192
5193               gtk_render_focus (context, cr,
5194                                 0, gtk_tree_view_get_row_y_offset (tree_view, tree, node)
5195                                    - focus_line_width / 2,
5196                                 gdk_window_get_width (tree_view->priv->bin_window),
5197                                 gtk_tree_view_get_row_height (tree_view, node)
5198                                    - focus_line_width + 1);
5199               break;
5200             }
5201
5202           if (highlight_y >= 0)
5203             {
5204               gtk_tree_view_draw_line (tree_view, cr,
5205                                        GTK_TREE_VIEW_FOREGROUND_LINE,
5206                                        rtl ? highlight_x + expander_cell_width : highlight_x,
5207                                        highlight_y,
5208                                        rtl ? 0 : bin_window_width,
5209                                        highlight_y);
5210             }
5211         }
5212
5213       /* draw the big row-spanning focus rectangle, if needed */
5214       if (!has_can_focus_cell && node == tree_view->priv->cursor_node &&
5215           tree_view->priv->draw_keyfocus &&
5216           gtk_widget_has_visible_focus (widget))
5217         {
5218           gint tmp_y, tmp_height;
5219           GtkStateFlags focus_rect_state = 0;
5220
5221           gtk_style_context_save (context);
5222
5223           focus_rect_state = gtk_cell_renderer_get_state (NULL, widget, flags);
5224           gtk_style_context_set_state (context, focus_rect_state);
5225
5226           if (draw_hgrid_lines)
5227             {
5228               tmp_y = gtk_tree_view_get_row_y_offset (tree_view, tree, node) + grid_line_width / 2;
5229               tmp_height = gtk_tree_view_get_row_height (tree_view, node) - grid_line_width;
5230             }
5231           else
5232             {
5233               tmp_y = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
5234               tmp_height = gtk_tree_view_get_row_height (tree_view, node);
5235             }
5236
5237           gtk_render_focus (context, cr,
5238                             0, tmp_y,
5239                             gdk_window_get_width (tree_view->priv->bin_window),
5240                             tmp_height);
5241
5242           gtk_style_context_restore (context);
5243         }
5244
5245       y_offset += max_height;
5246       if (node->children)
5247         {
5248           GtkTreeIter parent = iter;
5249           gboolean has_child;
5250
5251           tree = node->children;
5252           node = _gtk_rbtree_first (tree);
5253
5254           has_child = gtk_tree_model_iter_children (tree_view->priv->model,
5255                                                     &iter,
5256                                                     &parent);
5257           depth++;
5258
5259           /* Sanity Check! */
5260           TREE_VIEW_INTERNAL_ASSERT (has_child, FALSE);
5261         }
5262       else
5263         {
5264           gboolean done = FALSE;
5265
5266           do
5267             {
5268               node = _gtk_rbtree_next (tree, node);
5269               if (node != NULL)
5270                 {
5271                   gboolean has_next = gtk_tree_model_iter_next (tree_view->priv->model, &iter);
5272                   done = TRUE;
5273
5274                   /* Sanity Check! */
5275                   TREE_VIEW_INTERNAL_ASSERT (has_next, FALSE);
5276                 }
5277               else
5278                 {
5279                   GtkTreeIter parent_iter = iter;
5280                   gboolean has_parent;
5281
5282                   node = tree->parent_node;
5283                   tree = tree->parent_tree;
5284                   if (tree == NULL)
5285                     /* we should go to done to free some memory */
5286                     goto done;
5287                   has_parent = gtk_tree_model_iter_parent (tree_view->priv->model,
5288                                                            &iter,
5289                                                            &parent_iter);
5290                   depth--;
5291
5292                   /* Sanity check */
5293                   TREE_VIEW_INTERNAL_ASSERT (has_parent, FALSE);
5294                 }
5295             }
5296           while (!done);
5297         }
5298     }
5299   while (y_offset < clip.height);
5300
5301 done:
5302   gtk_tree_view_draw_grid_lines (tree_view, cr, n_visible_columns);
5303
5304   if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
5305     gtk_tree_view_paint_rubber_band (tree_view, cr);
5306
5307   if (drag_dest_path)
5308     gtk_tree_path_free (drag_dest_path);
5309
5310   return FALSE;
5311 }
5312
5313 static gboolean
5314 gtk_tree_view_draw (GtkWidget *widget,
5315                     cairo_t   *cr)
5316 {
5317   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
5318   GtkWidget   *button;
5319
5320   if (gtk_cairo_should_draw_window (cr, tree_view->priv->bin_window))
5321     {
5322       GtkStyleContext *context;
5323       GList *tmp_list;
5324
5325       context = gtk_widget_get_style_context (widget);
5326
5327       cairo_save (cr);
5328
5329       gtk_style_context_save (context);
5330       gtk_style_context_add_class (context, GTK_STYLE_CLASS_VIEW);
5331
5332       gtk_cairo_transform_to_window (cr, widget, tree_view->priv->bin_window);
5333
5334       gtk_tree_view_bin_draw (widget, cr);
5335
5336       gtk_style_context_restore (context);
5337       cairo_restore (cr);
5338
5339       /* We can't just chain up to Container::draw as it will try to send the
5340        * event to the headers, so we handle propagating it to our children
5341        * (eg. widgets being edited) ourselves.
5342        */
5343       tmp_list = tree_view->priv->children;
5344       while (tmp_list)
5345         {
5346           GtkTreeViewChild *child = tmp_list->data;
5347           tmp_list = tmp_list->next;
5348
5349           gtk_container_propagate_draw (GTK_CONTAINER (tree_view), child->widget, cr);
5350         }
5351     }
5352
5353   if (gtk_cairo_should_draw_window (cr, tree_view->priv->header_window))
5354     {
5355       GList *list;
5356       
5357       for (list = tree_view->priv->columns; list != NULL; list = list->next)
5358         {
5359           GtkTreeViewColumn *column = list->data;
5360
5361           if (column == tree_view->priv->drag_column)
5362             continue;
5363
5364           if (gtk_tree_view_column_get_visible (column))
5365             {
5366               button = gtk_tree_view_column_get_button (column);
5367               gtk_container_propagate_draw (GTK_CONTAINER (tree_view),
5368                                             button, cr);
5369             }
5370         }
5371     }
5372   
5373   if (tree_view->priv->drag_window &&
5374       gtk_cairo_should_draw_window (cr, tree_view->priv->drag_window))
5375     {
5376       button = gtk_tree_view_column_get_button (tree_view->priv->drag_column);
5377       gtk_container_propagate_draw (GTK_CONTAINER (tree_view),
5378                                     button, cr);
5379     }
5380
5381   return FALSE;
5382 }
5383
5384 enum
5385 {
5386   DROP_HOME,
5387   DROP_RIGHT,
5388   DROP_LEFT,
5389   DROP_END
5390 };
5391
5392 /* returns 0x1 when no column has been found -- yes it's hackish */
5393 static GtkTreeViewColumn *
5394 gtk_tree_view_get_drop_column (GtkTreeView       *tree_view,
5395                                GtkTreeViewColumn *column,
5396                                gint               drop_position)
5397 {
5398   GtkTreeViewColumn *left_column = NULL;
5399   GtkTreeViewColumn *cur_column = NULL;
5400   GList *tmp_list;
5401
5402   if (!gtk_tree_view_column_get_reorderable (column))
5403     return (GtkTreeViewColumn *)0x1;
5404
5405   switch (drop_position)
5406     {
5407       case DROP_HOME:
5408         /* find first column where we can drop */
5409         tmp_list = tree_view->priv->columns;
5410         if (column == GTK_TREE_VIEW_COLUMN (tmp_list->data))
5411           return (GtkTreeViewColumn *)0x1;
5412
5413         while (tmp_list)
5414           {
5415             g_assert (tmp_list);
5416
5417             cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5418             tmp_list = tmp_list->next;
5419
5420             if (left_column &&
5421                 gtk_tree_view_column_get_visible (left_column) == FALSE)
5422               continue;
5423
5424             if (!tree_view->priv->column_drop_func)
5425               return left_column;
5426
5427             if (!tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5428               {
5429                 left_column = cur_column;
5430                 continue;
5431               }
5432
5433             return left_column;
5434           }
5435
5436         if (!tree_view->priv->column_drop_func)
5437           return left_column;
5438
5439         if (tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data))
5440           return left_column;
5441         else
5442           return (GtkTreeViewColumn *)0x1;
5443         break;
5444
5445       case DROP_RIGHT:
5446         /* find first column after column where we can drop */
5447         tmp_list = tree_view->priv->columns;
5448
5449         for (; tmp_list; tmp_list = tmp_list->next)
5450           if (GTK_TREE_VIEW_COLUMN (tmp_list->data) == column)
5451             break;
5452
5453         if (!tmp_list || !tmp_list->next)
5454           return (GtkTreeViewColumn *)0x1;
5455
5456         tmp_list = tmp_list->next;
5457         left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5458         tmp_list = tmp_list->next;
5459
5460         while (tmp_list)
5461           {
5462             g_assert (tmp_list);
5463
5464             cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5465             tmp_list = tmp_list->next;
5466
5467             if (left_column &&
5468                 gtk_tree_view_column_get_visible (left_column) == FALSE)
5469               {
5470                 left_column = cur_column;
5471                 if (tmp_list)
5472                   tmp_list = tmp_list->next;
5473                 continue;
5474               }
5475
5476             if (!tree_view->priv->column_drop_func)
5477               return left_column;
5478
5479             if (!tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5480               {
5481                 left_column = cur_column;
5482                 continue;
5483               }
5484
5485             return left_column;
5486           }
5487
5488         if (!tree_view->priv->column_drop_func)
5489           return left_column;
5490
5491         if (tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data))
5492           return left_column;
5493         else
5494           return (GtkTreeViewColumn *)0x1;
5495         break;
5496
5497       case DROP_LEFT:
5498         /* find first column before column where we can drop */
5499         tmp_list = tree_view->priv->columns;
5500
5501         for (; tmp_list; tmp_list = tmp_list->next)
5502           if (GTK_TREE_VIEW_COLUMN (tmp_list->data) == column)
5503             break;
5504
5505         if (!tmp_list || !tmp_list->prev)
5506           return (GtkTreeViewColumn *)0x1;
5507
5508         tmp_list = tmp_list->prev;
5509         cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5510         tmp_list = tmp_list->prev;
5511
5512         while (tmp_list)
5513           {
5514             g_assert (tmp_list);
5515
5516             left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5517
5518             if (left_column &&
5519                 gtk_tree_view_column_get_visible (left_column) == FALSE)
5520               {
5521                 /*if (!tmp_list->prev)
5522                   return (GtkTreeViewColumn *)0x1;
5523                   */
5524 /*
5525                 cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->prev->data);
5526                 tmp_list = tmp_list->prev->prev;
5527                 continue;*/
5528
5529                 cur_column = left_column;
5530                 if (tmp_list)
5531                   tmp_list = tmp_list->prev;
5532                 continue;
5533               }
5534
5535             if (!tree_view->priv->column_drop_func)
5536               return left_column;
5537
5538             if (tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5539               return left_column;
5540
5541             cur_column = left_column;
5542             tmp_list = tmp_list->prev;
5543           }
5544
5545         if (!tree_view->priv->column_drop_func)
5546           return NULL;
5547
5548         if (tree_view->priv->column_drop_func (tree_view, column, NULL, cur_column, tree_view->priv->column_drop_func_data))
5549           return NULL;
5550         else
5551           return (GtkTreeViewColumn *)0x1;
5552         break;
5553
5554       case DROP_END:
5555         /* same as DROP_HOME case, but doing it backwards */
5556         tmp_list = g_list_last (tree_view->priv->columns);
5557         cur_column = NULL;
5558
5559         if (column == GTK_TREE_VIEW_COLUMN (tmp_list->data))
5560           return (GtkTreeViewColumn *)0x1;
5561
5562         while (tmp_list)
5563           {
5564             g_assert (tmp_list);
5565
5566             left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5567
5568             if (left_column &&
5569                 gtk_tree_view_column_get_visible (left_column) == FALSE)
5570               {
5571                 cur_column = left_column;
5572                 tmp_list = tmp_list->prev;
5573               }
5574
5575             if (!tree_view->priv->column_drop_func)
5576               return left_column;
5577
5578             if (tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5579               return left_column;
5580
5581             cur_column = left_column;
5582             tmp_list = tmp_list->prev;
5583           }
5584
5585         if (!tree_view->priv->column_drop_func)
5586           return NULL;
5587
5588         if (tree_view->priv->column_drop_func (tree_view, column, NULL, cur_column, tree_view->priv->column_drop_func_data))
5589           return NULL;
5590         else
5591           return (GtkTreeViewColumn *)0x1;
5592         break;
5593     }
5594
5595   return (GtkTreeViewColumn *)0x1;
5596 }
5597
5598 static gboolean
5599 gtk_tree_view_key_press (GtkWidget   *widget,
5600                          GdkEventKey *event)
5601 {
5602   GtkTreeView *tree_view = (GtkTreeView *) widget;
5603   GtkWidget   *button;
5604
5605   if (tree_view->priv->rubber_band_status)
5606     {
5607       if (event->keyval == GDK_KEY_Escape)
5608         gtk_tree_view_stop_rubber_band (tree_view);
5609
5610       return TRUE;
5611     }
5612
5613   if (tree_view->priv->in_column_drag)
5614     {
5615       if (event->keyval == GDK_KEY_Escape)
5616         {
5617           tree_view->priv->cur_reorder = NULL;
5618           gtk_tree_view_button_release_drag_column (widget, NULL);
5619         }
5620       return TRUE;
5621     }
5622
5623   if (tree_view->priv->headers_visible)
5624     {
5625       GList *focus_column;
5626       gboolean rtl;
5627
5628       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
5629
5630       for (focus_column = tree_view->priv->columns;
5631            focus_column;
5632            focus_column = focus_column->next)
5633         {
5634           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
5635           
5636           button = gtk_tree_view_column_get_button (column);
5637           if (gtk_widget_has_focus (button))
5638             break;
5639         }
5640
5641       if (focus_column &&
5642           (event->state & GDK_SHIFT_MASK) && (event->state & GDK_MOD1_MASK) &&
5643           (event->keyval == GDK_KEY_Left || event->keyval == GDK_KEY_KP_Left
5644            || event->keyval == GDK_KEY_Right || event->keyval == GDK_KEY_KP_Right))
5645         {
5646           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
5647           gint max_width, min_width;
5648
5649           if (!gtk_tree_view_column_get_resizable (column))
5650             {
5651               gtk_widget_error_bell (widget);
5652               return TRUE;
5653             }
5654
5655           if (event->keyval == (rtl ? GDK_KEY_Right : GDK_KEY_Left)
5656               || event->keyval == (rtl ? GDK_KEY_KP_Right : GDK_KEY_KP_Left))
5657             {
5658               GtkRequisition button_req;
5659               gint old_width = _gtk_tree_view_column_get_resized_width (column);
5660               gint new_width;
5661
5662               button = gtk_tree_view_column_get_button (column);
5663
5664               gtk_widget_get_preferred_size (button, &button_req, NULL);
5665
5666               new_width = MAX (old_width, gtk_tree_view_column_get_width (column));
5667               new_width -= 2;
5668               if (new_width < 0)
5669                 new_width = 0;
5670
5671               _gtk_tree_view_column_set_resized_width (column, new_width);
5672
5673               min_width = gtk_tree_view_column_get_min_width (column);
5674               if (min_width == -1)
5675                 new_width = MAX (button_req.width, new_width);
5676               else
5677                 {
5678                   new_width = MAX (min_width, new_width);
5679                 }
5680
5681               max_width = gtk_tree_view_column_get_max_width (column);
5682               if (max_width != -1)
5683                 new_width = MIN (new_width, max_width);
5684
5685               _gtk_tree_view_column_set_use_resized_width (column, TRUE);
5686
5687               if (new_width != old_width)
5688                 {
5689                   _gtk_tree_view_column_set_resized_width (column, new_width);
5690                   gtk_widget_queue_resize (widget);
5691                 }
5692               else
5693                 gtk_widget_error_bell (widget);
5694             }
5695           else if (event->keyval == (rtl ? GDK_KEY_Left : GDK_KEY_Right)
5696                    || event->keyval == (rtl ? GDK_KEY_KP_Left : GDK_KEY_KP_Right))
5697             {
5698               gint old_width = _gtk_tree_view_column_get_resized_width (column);
5699               gint new_width;
5700
5701               new_width = MAX (old_width, gtk_tree_view_column_get_width (column));
5702               new_width += 2;
5703
5704               max_width = gtk_tree_view_column_get_max_width (column);
5705               if (max_width != -1)
5706                 new_width = MIN (new_width, max_width);
5707
5708               _gtk_tree_view_column_set_use_resized_width (column, TRUE);
5709
5710               if (new_width != old_width)
5711                 {
5712                   _gtk_tree_view_column_set_resized_width (column, new_width);
5713                   gtk_widget_queue_resize (widget);
5714                 }
5715               else
5716                 gtk_widget_error_bell (widget);
5717             }
5718
5719           return TRUE;
5720         }
5721
5722       if (focus_column &&
5723           (event->state & GDK_MOD1_MASK) &&
5724           (event->keyval == GDK_KEY_Left || event->keyval == GDK_KEY_KP_Left
5725            || event->keyval == GDK_KEY_Right || event->keyval == GDK_KEY_KP_Right
5726            || event->keyval == GDK_KEY_Home || event->keyval == GDK_KEY_KP_Home
5727            || event->keyval == GDK_KEY_End || event->keyval == GDK_KEY_KP_End))
5728         {
5729           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
5730
5731           if (event->keyval == (rtl ? GDK_KEY_Right : GDK_KEY_Left)
5732               || event->keyval == (rtl ? GDK_KEY_KP_Right : GDK_KEY_KP_Left))
5733             {
5734               GtkTreeViewColumn *col;
5735               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_LEFT);
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 == (rtl ? GDK_KEY_Left : GDK_KEY_Right)
5742                    || event->keyval == (rtl ? GDK_KEY_KP_Left : GDK_KEY_KP_Right))
5743             {
5744               GtkTreeViewColumn *col;
5745               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_RIGHT);
5746               if (col != (GtkTreeViewColumn *)0x1)
5747                 gtk_tree_view_move_column_after (tree_view, column, col);
5748               else
5749                 gtk_widget_error_bell (widget);
5750             }
5751           else if (event->keyval == GDK_KEY_Home || event->keyval == GDK_KEY_KP_Home)
5752             {
5753               GtkTreeViewColumn *col;
5754               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_HOME);
5755               if (col != (GtkTreeViewColumn *)0x1)
5756                 gtk_tree_view_move_column_after (tree_view, column, col);
5757               else
5758                 gtk_widget_error_bell (widget);
5759             }
5760           else if (event->keyval == GDK_KEY_End || event->keyval == GDK_KEY_KP_End)
5761             {
5762               GtkTreeViewColumn *col;
5763               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_END);
5764               if (col != (GtkTreeViewColumn *)0x1)
5765                 gtk_tree_view_move_column_after (tree_view, column, col);
5766               else
5767                 gtk_widget_error_bell (widget);
5768             }
5769
5770           return TRUE;
5771         }
5772     }
5773
5774   /* Chain up to the parent class.  It handles the keybindings. */
5775   if (GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->key_press_event (widget, event))
5776     return TRUE;
5777
5778   if (tree_view->priv->search_entry_avoid_unhandled_binding)
5779     {
5780       tree_view->priv->search_entry_avoid_unhandled_binding = FALSE;
5781       return FALSE;
5782     }
5783
5784   /* We pass the event to the search_entry.  If its text changes, then we start
5785    * the typeahead find capabilities. */
5786   if (gtk_widget_has_focus (GTK_WIDGET (tree_view))
5787       && tree_view->priv->enable_search
5788       && !tree_view->priv->search_custom_entry_set)
5789     {
5790       GdkEvent *new_event;
5791       char *old_text;
5792       const char *new_text;
5793       gboolean retval;
5794       GdkScreen *screen;
5795       gboolean text_modified;
5796       gulong popup_menu_id;
5797
5798       gtk_tree_view_ensure_interactive_directory (tree_view);
5799
5800       /* Make a copy of the current text */
5801       old_text = g_strdup (gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry)));
5802       new_event = gdk_event_copy ((GdkEvent *) event);
5803       g_object_unref (((GdkEventKey *) new_event)->window);
5804       ((GdkEventKey *) new_event)->window = g_object_ref (gtk_widget_get_window (tree_view->priv->search_window));
5805       gtk_widget_realize (tree_view->priv->search_window);
5806
5807       popup_menu_id = g_signal_connect (tree_view->priv->search_entry, 
5808                                         "popup-menu", G_CALLBACK (gtk_true),
5809                                         NULL);
5810
5811       /* Move the entry off screen */
5812       screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
5813       gtk_window_move (GTK_WINDOW (tree_view->priv->search_window),
5814                        gdk_screen_get_width (screen) + 1,
5815                        gdk_screen_get_height (screen) + 1);
5816       gtk_widget_show (tree_view->priv->search_window);
5817
5818       /* Send the event to the window.  If the preedit_changed signal is emitted
5819        * during this event, we will set priv->imcontext_changed  */
5820       tree_view->priv->imcontext_changed = FALSE;
5821       retval = gtk_widget_event (tree_view->priv->search_window, new_event);
5822       gdk_event_free (new_event);
5823       gtk_widget_hide (tree_view->priv->search_window);
5824
5825       g_signal_handler_disconnect (tree_view->priv->search_entry, 
5826                                    popup_menu_id);
5827
5828       /* We check to make sure that the entry tried to handle the text, and that
5829        * the text has changed.
5830        */
5831       new_text = gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry));
5832       text_modified = strcmp (old_text, new_text) != 0;
5833       g_free (old_text);
5834       if (tree_view->priv->imcontext_changed ||    /* we're in a preedit */
5835           (retval && text_modified))               /* ...or the text was modified */
5836         {
5837           if (gtk_tree_view_real_start_interactive_search (tree_view,
5838                                                            gdk_event_get_device ((GdkEvent *) event),
5839                                                            FALSE))
5840             {
5841               gtk_widget_grab_focus (GTK_WIDGET (tree_view));
5842               return TRUE;
5843             }
5844           else
5845             {
5846               gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
5847               return FALSE;
5848             }
5849         }
5850     }
5851
5852   return FALSE;
5853 }
5854
5855 static gboolean
5856 gtk_tree_view_key_release (GtkWidget   *widget,
5857                            GdkEventKey *event)
5858 {
5859   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
5860
5861   if (tree_view->priv->rubber_band_status)
5862     return TRUE;
5863
5864   return GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->key_release_event (widget, event);
5865 }
5866
5867 /* FIXME Is this function necessary? Can I get an enter_notify event
5868  * w/o either an expose event or a mouse motion event?
5869  */
5870 static gboolean
5871 gtk_tree_view_enter_notify (GtkWidget        *widget,
5872                             GdkEventCrossing *event)
5873 {
5874   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
5875   GtkRBTree *tree;
5876   GtkRBNode *node;
5877   gint new_y;
5878
5879   /* Sanity check it */
5880   if (event->window != tree_view->priv->bin_window)
5881     return FALSE;
5882
5883   if (tree_view->priv->tree == NULL)
5884     return FALSE;
5885
5886   if (event->mode == GDK_CROSSING_GRAB ||
5887       event->mode == GDK_CROSSING_GTK_GRAB ||
5888       event->mode == GDK_CROSSING_GTK_UNGRAB ||
5889       event->mode == GDK_CROSSING_STATE_CHANGED)
5890     return TRUE;
5891
5892   /* find the node internally */
5893   new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
5894   if (new_y < 0)
5895     new_y = 0;
5896   _gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
5897
5898   tree_view->priv->event_last_x = event->x;
5899   tree_view->priv->event_last_y = event->y;
5900
5901   if ((tree_view->priv->button_pressed_node == NULL) ||
5902       (tree_view->priv->button_pressed_node == node))
5903     prelight_or_select (tree_view, tree, node, event->x, event->y);
5904
5905   return TRUE;
5906 }
5907
5908 static gboolean
5909 gtk_tree_view_leave_notify (GtkWidget        *widget,
5910                             GdkEventCrossing *event)
5911 {
5912   GtkTreeView *tree_view;
5913
5914   if (event->mode == GDK_CROSSING_GRAB ||
5915       event->mode == GDK_CROSSING_GTK_GRAB ||
5916       event->mode == GDK_CROSSING_GTK_UNGRAB)
5917     return TRUE;
5918
5919   tree_view = GTK_TREE_VIEW (widget);
5920
5921   if (tree_view->priv->prelight_node)
5922     _gtk_tree_view_queue_draw_node (tree_view,
5923                                    tree_view->priv->prelight_tree,
5924                                    tree_view->priv->prelight_node,
5925                                    NULL);
5926
5927   tree_view->priv->event_last_x = -10000;
5928   tree_view->priv->event_last_y = -10000;
5929
5930   prelight_or_select (tree_view,
5931                       NULL, NULL,
5932                       -1000, -1000); /* coords not possibly over an arrow */
5933
5934   return TRUE;
5935 }
5936
5937
5938 static gint
5939 gtk_tree_view_focus_out (GtkWidget     *widget,
5940                          GdkEventFocus *event)
5941 {
5942   GtkTreeView *tree_view;
5943
5944   tree_view = GTK_TREE_VIEW (widget);
5945
5946   gtk_widget_queue_draw (widget);
5947
5948   /* destroy interactive search dialog */
5949   if (tree_view->priv->search_window)
5950     gtk_tree_view_search_dialog_hide (tree_view->priv->search_window, tree_view,
5951                                       gdk_event_get_device ((GdkEvent *) event));
5952
5953   return FALSE;
5954 }
5955
5956
5957 /* Incremental Reflow
5958  */
5959
5960 static void
5961 gtk_tree_view_node_queue_redraw (GtkTreeView *tree_view,
5962                                  GtkRBTree   *tree,
5963                                  GtkRBNode   *node)
5964 {
5965   GtkAllocation allocation;
5966   gint y;
5967
5968   y = _gtk_rbtree_node_find_offset (tree, node)
5969     - gtk_adjustment_get_value (tree_view->priv->vadjustment)
5970     + gtk_tree_view_get_effective_header_height (tree_view);
5971
5972   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
5973   gtk_widget_queue_draw_area (GTK_WIDGET (tree_view),
5974                               0, y,
5975                               allocation.width,
5976                               GTK_RBNODE_GET_HEIGHT (node));
5977 }
5978
5979 static gboolean
5980 node_is_visible (GtkTreeView *tree_view,
5981                  GtkRBTree   *tree,
5982                  GtkRBNode   *node)
5983 {
5984   int y;
5985   int height;
5986
5987   y = _gtk_rbtree_node_find_offset (tree, node);
5988   height = gtk_tree_view_get_row_height (tree_view, node);
5989
5990   if (y >= gtk_adjustment_get_value (tree_view->priv->vadjustment) &&
5991       y + height <= (gtk_adjustment_get_value (tree_view->priv->vadjustment)
5992                      + gtk_adjustment_get_page_size (tree_view->priv->vadjustment)))
5993     return TRUE;
5994
5995   return FALSE;
5996 }
5997
5998 /* Returns TRUE if it updated the size
5999  */
6000 static gboolean
6001 validate_row (GtkTreeView *tree_view,
6002               GtkRBTree   *tree,
6003               GtkRBNode   *node,
6004               GtkTreeIter *iter,
6005               GtkTreePath *path)
6006 {
6007   GtkTreeViewColumn *column;
6008   GList *list, *first_column, *last_column;
6009   gint height = 0;
6010   gint horizontal_separator;
6011   gint vertical_separator;
6012   gint depth = gtk_tree_path_get_depth (path);
6013   gboolean retval = FALSE;
6014   gboolean is_separator = FALSE;
6015   gboolean draw_vgrid_lines, draw_hgrid_lines;
6016   gint focus_pad;
6017   gint grid_line_width;
6018   gboolean wide_separators;
6019   gint separator_height;
6020
6021   /* double check the row needs validating */
6022   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) &&
6023       ! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6024     return FALSE;
6025
6026   is_separator = row_is_separator (tree_view, iter, NULL);
6027
6028   gtk_widget_style_get (GTK_WIDGET (tree_view),
6029                         "focus-padding", &focus_pad,
6030                         "horizontal-separator", &horizontal_separator,
6031                         "vertical-separator", &vertical_separator,
6032                         "grid-line-width", &grid_line_width,
6033                         "wide-separators",  &wide_separators,
6034                         "separator-height", &separator_height,
6035                         NULL);
6036   
6037   draw_vgrid_lines =
6038     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_VERTICAL
6039     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
6040   draw_hgrid_lines =
6041     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_HORIZONTAL
6042     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
6043
6044   for (last_column = g_list_last (tree_view->priv->columns);
6045        last_column &&
6046        !(gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (last_column->data)));
6047        last_column = last_column->prev)
6048     ;
6049
6050   for (first_column = g_list_first (tree_view->priv->columns);
6051        first_column &&
6052        !(gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (first_column->data)));
6053        first_column = first_column->next)
6054     ;
6055
6056   for (list = tree_view->priv->columns; list; list = list->next)
6057     {
6058       gint padding = 0;
6059       gint original_width;
6060       gint new_width;
6061       gint row_height;
6062
6063       column = list->data;
6064
6065       if (!gtk_tree_view_column_get_visible (column))
6066         continue;
6067
6068       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID) && 
6069           !_gtk_tree_view_column_cell_get_dirty (column))
6070         continue;
6071
6072       original_width = _gtk_tree_view_column_get_requested_width (column);
6073
6074       gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, iter,
6075                                                GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
6076                                                node->children?TRUE:FALSE);
6077       gtk_tree_view_column_cell_get_size (column,
6078                                           NULL, NULL, NULL,
6079                                           NULL, &row_height);
6080
6081       if (!is_separator)
6082         {
6083           row_height += vertical_separator;
6084           height = MAX (height, row_height);
6085           height = MAX (height, tree_view->priv->expander_size);
6086         }
6087       else
6088         {
6089           if (wide_separators)
6090             height = separator_height + 2 * focus_pad;
6091           else
6092             height = 2 + 2 * focus_pad;
6093         }
6094
6095       if (gtk_tree_view_is_expander_column (tree_view, column))
6096         {
6097           padding += horizontal_separator + (depth - 1) * tree_view->priv->level_indentation;
6098
6099           if (gtk_tree_view_draw_expanders (tree_view))
6100             padding += depth * tree_view->priv->expander_size;
6101         }
6102       else
6103         padding += horizontal_separator;
6104
6105       if (draw_vgrid_lines)
6106         {
6107           if (list->data == first_column || list->data == last_column)
6108             padding += grid_line_width / 2.0;
6109           else
6110             padding += grid_line_width;
6111         }
6112
6113       /* Update the padding for the column */
6114       _gtk_tree_view_column_push_padding (column, padding);
6115       new_width = _gtk_tree_view_column_get_requested_width (column);
6116
6117       if (new_width > original_width)
6118         retval = TRUE;
6119     }
6120
6121   if (draw_hgrid_lines)
6122     height += grid_line_width;
6123
6124   if (height != GTK_RBNODE_GET_HEIGHT (node))
6125     {
6126       retval = TRUE;
6127       _gtk_rbtree_node_set_height (tree, node, height);
6128     }
6129   _gtk_rbtree_node_mark_valid (tree, node);
6130   tree_view->priv->post_validation_flag = TRUE;
6131
6132   return retval;
6133 }
6134
6135
6136 static void
6137 validate_visible_area (GtkTreeView *tree_view)
6138 {
6139   GtkAllocation allocation;
6140   GtkTreePath *path = NULL;
6141   GtkTreePath *above_path = NULL;
6142   GtkTreeIter iter;
6143   GtkRBTree *tree = NULL;
6144   GtkRBNode *node = NULL;
6145   gboolean need_redraw = FALSE;
6146   gboolean size_changed = FALSE;
6147   gint total_height;
6148   gint area_above = 0;
6149   gint area_below = 0;
6150
6151   if (tree_view->priv->tree == NULL)
6152     return;
6153
6154   if (! GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID) &&
6155       tree_view->priv->scroll_to_path == NULL)
6156     return;
6157
6158   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
6159   total_height = allocation.height - gtk_tree_view_get_effective_header_height (tree_view);
6160
6161   if (total_height == 0)
6162     return;
6163
6164   /* First, we check to see if we need to scroll anywhere
6165    */
6166   if (tree_view->priv->scroll_to_path)
6167     {
6168       path = gtk_tree_row_reference_get_path (tree_view->priv->scroll_to_path);
6169       if (path && !_gtk_tree_view_find_node (tree_view, path, &tree, &node))
6170         {
6171           /* we are going to scroll, and will update dy */
6172           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6173           if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6174               GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6175             {
6176               _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
6177               if (validate_row (tree_view, tree, node, &iter, path))
6178                 size_changed = TRUE;
6179             }
6180
6181           if (tree_view->priv->scroll_to_use_align)
6182             {
6183               gint height = gtk_tree_view_get_row_height (tree_view, node);
6184               area_above = (total_height - height) *
6185                 tree_view->priv->scroll_to_row_align;
6186               area_below = total_height - area_above - height;
6187               area_above = MAX (area_above, 0);
6188               area_below = MAX (area_below, 0);
6189             }
6190           else
6191             {
6192               /* two cases:
6193                * 1) row not visible
6194                * 2) row visible
6195                */
6196               gint dy;
6197               gint height = gtk_tree_view_get_row_height (tree_view, node);
6198
6199               dy = _gtk_rbtree_node_find_offset (tree, node);
6200
6201               if (dy >= gtk_adjustment_get_value (tree_view->priv->vadjustment) &&
6202                   dy + height <= (gtk_adjustment_get_value (tree_view->priv->vadjustment)
6203                                   + gtk_adjustment_get_page_size (tree_view->priv->vadjustment)))
6204                 {
6205                   /* row visible: keep the row at the same position */
6206                   area_above = dy - gtk_adjustment_get_value (tree_view->priv->vadjustment);
6207                   area_below = (gtk_adjustment_get_value (tree_view->priv->vadjustment) +
6208                                 gtk_adjustment_get_page_size (tree_view->priv->vadjustment))
6209                                - dy - height;
6210                 }
6211               else
6212                 {
6213                   /* row not visible */
6214                   if (dy >= 0
6215                       && dy + height <= gtk_adjustment_get_page_size (tree_view->priv->vadjustment))
6216                     {
6217                       /* row at the beginning -- fixed */
6218                       area_above = dy;
6219                       area_below = gtk_adjustment_get_page_size (tree_view->priv->vadjustment)
6220                                    - area_above - height;
6221                     }
6222                   else if (dy >= (gtk_adjustment_get_upper (tree_view->priv->vadjustment) -
6223                                   gtk_adjustment_get_page_size (tree_view->priv->vadjustment)))
6224                     {
6225                       /* row at the end -- fixed */
6226                       area_above = dy - (gtk_adjustment_get_upper (tree_view->priv->vadjustment) -
6227                                    gtk_adjustment_get_page_size (tree_view->priv->vadjustment));
6228                       area_below = gtk_adjustment_get_page_size (tree_view->priv->vadjustment) -
6229                                    area_above - height;
6230
6231                       if (area_below < 0)
6232                         {
6233                           area_above = gtk_adjustment_get_page_size (tree_view->priv->vadjustment) - height;
6234                           area_below = 0;
6235                         }
6236                     }
6237                   else
6238                     {
6239                       /* row somewhere in the middle, bring it to the top
6240                        * of the view
6241                        */
6242                       area_above = 0;
6243                       area_below = total_height - height;
6244                     }
6245                 }
6246             }
6247         }
6248       else
6249         /* the scroll to isn't valid; ignore it.
6250          */
6251         {
6252           if (tree_view->priv->scroll_to_path && !path)
6253             {
6254               gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
6255               tree_view->priv->scroll_to_path = NULL;
6256             }
6257           if (path)
6258             gtk_tree_path_free (path);
6259           path = NULL;
6260         }      
6261     }
6262
6263   /* We didn't have a scroll_to set, so we just handle things normally
6264    */
6265   if (path == NULL)
6266     {
6267       gint offset;
6268
6269       offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
6270                                         TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, 0),
6271                                         &tree, &node);
6272       if (node == NULL)
6273         {
6274           /* In this case, nothing has been validated */
6275           path = gtk_tree_path_new_first ();
6276           _gtk_tree_view_find_node (tree_view, path, &tree, &node);
6277         }
6278       else
6279         {
6280           path = _gtk_tree_path_new_from_rbtree (tree, node);
6281           total_height += offset;
6282         }
6283
6284       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6285
6286       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6287           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6288         {
6289           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
6290           if (validate_row (tree_view, tree, node, &iter, path))
6291             size_changed = TRUE;
6292         }
6293       area_above = 0;
6294       area_below = total_height - gtk_tree_view_get_row_height (tree_view, node);
6295     }
6296
6297   above_path = gtk_tree_path_copy (path);
6298
6299   /* if we do not validate any row above the new top_row, we will make sure
6300    * that the row immediately above top_row has been validated. (if we do not
6301    * do this, _gtk_rbtree_find_offset will find the row above top_row, because
6302    * when invalidated that row's height will be zero. and this will mess up
6303    * scrolling).
6304    */
6305   if (area_above == 0)
6306     {
6307       GtkRBTree *tmptree;
6308       GtkRBNode *tmpnode;
6309
6310       _gtk_tree_view_find_node (tree_view, above_path, &tmptree, &tmpnode);
6311       _gtk_rbtree_prev_full (tmptree, tmpnode, &tmptree, &tmpnode);
6312
6313       if (tmpnode)
6314         {
6315           GtkTreePath *tmppath;
6316           GtkTreeIter tmpiter;
6317
6318           tmppath = _gtk_tree_path_new_from_rbtree (tmptree, tmpnode);
6319           gtk_tree_model_get_iter (tree_view->priv->model, &tmpiter, tmppath);
6320
6321           if (GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_INVALID) ||
6322               GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_COLUMN_INVALID))
6323             {
6324               _gtk_tree_view_queue_draw_node (tree_view, tmptree, tmpnode, NULL);
6325               if (validate_row (tree_view, tmptree, tmpnode, &tmpiter, tmppath))
6326                 size_changed = TRUE;
6327             }
6328
6329           gtk_tree_path_free (tmppath);
6330         }
6331     }
6332
6333   /* Now, we walk forwards and backwards, measuring rows. Unfortunately,
6334    * backwards is much slower then forward, as there is no iter_prev function.
6335    * We go forwards first in case we run out of tree.  Then we go backwards to
6336    * fill out the top.
6337    */
6338   while (node && area_below > 0)
6339     {
6340       if (node->children)
6341         {
6342           GtkTreeIter parent = iter;
6343           gboolean has_child;
6344
6345           tree = node->children;
6346           node = _gtk_rbtree_first (tree);
6347
6348           has_child = gtk_tree_model_iter_children (tree_view->priv->model,
6349                                                     &iter,
6350                                                     &parent);
6351           TREE_VIEW_INTERNAL_ASSERT_VOID (has_child);
6352           gtk_tree_path_down (path);
6353         }
6354       else
6355         {
6356           gboolean done = FALSE;
6357           do
6358             {
6359               node = _gtk_rbtree_next (tree, node);
6360               if (node != NULL)
6361                 {
6362                   gboolean has_next = gtk_tree_model_iter_next (tree_view->priv->model, &iter);
6363                   done = TRUE;
6364                   gtk_tree_path_next (path);
6365
6366                   /* Sanity Check! */
6367                   TREE_VIEW_INTERNAL_ASSERT_VOID (has_next);
6368                 }
6369               else
6370                 {
6371                   GtkTreeIter parent_iter = iter;
6372                   gboolean has_parent;
6373
6374                   node = tree->parent_node;
6375                   tree = tree->parent_tree;
6376                   if (tree == NULL)
6377                     break;
6378                   has_parent = gtk_tree_model_iter_parent (tree_view->priv->model,
6379                                                            &iter,
6380                                                            &parent_iter);
6381                   gtk_tree_path_up (path);
6382
6383                   /* Sanity check */
6384                   TREE_VIEW_INTERNAL_ASSERT_VOID (has_parent);
6385                 }
6386             }
6387           while (!done);
6388         }
6389
6390       if (!node)
6391         break;
6392
6393       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6394           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6395         {
6396           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
6397           if (validate_row (tree_view, tree, node, &iter, path))
6398               size_changed = TRUE;
6399         }
6400
6401       area_below -= gtk_tree_view_get_row_height (tree_view, node);
6402     }
6403   gtk_tree_path_free (path);
6404
6405   /* If we ran out of tree, and have extra area_below left, we need to add it
6406    * to area_above */
6407   if (area_below > 0)
6408     area_above += area_below;
6409
6410   _gtk_tree_view_find_node (tree_view, above_path, &tree, &node);
6411
6412   /* We walk backwards */
6413   while (area_above > 0)
6414     {
6415       _gtk_rbtree_prev_full (tree, node, &tree, &node);
6416
6417       /* Always find the new path in the tree.  We cannot just assume
6418        * a gtk_tree_path_prev() is enough here, as there might be children
6419        * in between this node and the previous sibling node.  If this
6420        * appears to be a performance hotspot in profiles, we can look into
6421        * intrigate logic for keeping path, node and iter in sync like
6422        * we do for forward walks.  (Which will be hard because of the lacking
6423        * iter_prev).
6424        */
6425
6426       if (node == NULL)
6427         break;
6428
6429       gtk_tree_path_free (above_path);
6430       above_path = _gtk_tree_path_new_from_rbtree (tree, node);
6431
6432       gtk_tree_model_get_iter (tree_view->priv->model, &iter, above_path);
6433
6434       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6435           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6436         {
6437           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
6438           if (validate_row (tree_view, tree, node, &iter, above_path))
6439             size_changed = TRUE;
6440         }
6441       area_above -= gtk_tree_view_get_row_height (tree_view, node);
6442     }
6443
6444   /* if we scrolled to a path, we need to set the dy here,
6445    * and sync the top row accordingly
6446    */
6447   if (tree_view->priv->scroll_to_path)
6448     {
6449       gtk_tree_view_set_top_row (tree_view, above_path, -area_above);
6450       gtk_tree_view_top_row_to_dy (tree_view);
6451
6452       need_redraw = TRUE;
6453     }
6454   else if (tree_view->priv->height <= gtk_adjustment_get_page_size (tree_view->priv->vadjustment))
6455     {
6456       /* when we are not scrolling, we should never set dy to something
6457        * else than zero. we update top_row to be in sync with dy = 0.
6458        */
6459       gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
6460       gtk_tree_view_dy_to_top_row (tree_view);
6461     }
6462   else if (gtk_adjustment_get_value (tree_view->priv->vadjustment) + gtk_adjustment_get_page_size (tree_view->priv->vadjustment) > tree_view->priv->height)
6463     {
6464       gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), tree_view->priv->height - gtk_adjustment_get_page_size (tree_view->priv->vadjustment));
6465       gtk_tree_view_dy_to_top_row (tree_view);
6466     }
6467   else
6468     gtk_tree_view_top_row_to_dy (tree_view);
6469
6470   /* update width/height and queue a resize */
6471   if (size_changed)
6472     {
6473       GtkRequisition requisition;
6474
6475       /* We temporarily guess a size, under the assumption that it will be the
6476        * same when we get our next size_allocate.  If we don't do this, we'll be
6477        * in an inconsistent state if we call top_row_to_dy. */
6478
6479       gtk_widget_get_preferred_size (GTK_WIDGET (tree_view),
6480                                      &requisition, NULL);
6481       gtk_adjustment_set_upper (tree_view->priv->hadjustment,
6482                                 MAX (gtk_adjustment_get_upper (tree_view->priv->hadjustment), requisition.width));
6483       gtk_adjustment_set_upper (tree_view->priv->vadjustment,
6484                                 MAX (gtk_adjustment_get_upper (tree_view->priv->vadjustment), requisition.height));
6485       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6486     }
6487
6488   if (tree_view->priv->scroll_to_path)
6489     {
6490       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
6491       tree_view->priv->scroll_to_path = NULL;
6492     }
6493
6494   if (above_path)
6495     gtk_tree_path_free (above_path);
6496
6497   if (tree_view->priv->scroll_to_column)
6498     {
6499       tree_view->priv->scroll_to_column = NULL;
6500     }
6501   if (need_redraw)
6502     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
6503 }
6504
6505 static void
6506 initialize_fixed_height_mode (GtkTreeView *tree_view)
6507 {
6508   if (!tree_view->priv->tree)
6509     return;
6510
6511   if (tree_view->priv->fixed_height < 0)
6512     {
6513       GtkTreeIter iter;
6514       GtkTreePath *path;
6515
6516       GtkRBTree *tree = NULL;
6517       GtkRBNode *node = NULL;
6518
6519       tree = tree_view->priv->tree;
6520       node = tree->root;
6521
6522       path = _gtk_tree_path_new_from_rbtree (tree, node);
6523       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6524
6525       validate_row (tree_view, tree, node, &iter, path);
6526
6527       gtk_tree_path_free (path);
6528
6529       tree_view->priv->fixed_height = gtk_tree_view_get_row_height (tree_view, node);
6530     }
6531
6532    _gtk_rbtree_set_fixed_height (tree_view->priv->tree,
6533                                  tree_view->priv->fixed_height, TRUE);
6534 }
6535
6536 /* Our strategy for finding nodes to validate is a little convoluted.  We find
6537  * the left-most uninvalidated node.  We then try walking right, validating
6538  * nodes.  Once we find a valid node, we repeat the previous process of finding
6539  * the first invalid node.
6540  */
6541
6542 static gboolean
6543 do_validate_rows (GtkTreeView *tree_view, gboolean queue_resize)
6544 {
6545   GtkRBTree *tree = NULL;
6546   GtkRBNode *node = NULL;
6547   gboolean validated_area = FALSE;
6548   gint retval = TRUE;
6549   GtkTreePath *path = NULL;
6550   GtkTreeIter iter;
6551   GTimer *timer;
6552   gint i = 0;
6553
6554   gint y = -1;
6555   gint prev_height = -1;
6556   gboolean fixed_height = TRUE;
6557
6558   g_assert (tree_view);
6559
6560   if (tree_view->priv->tree == NULL)
6561       return FALSE;
6562
6563   if (tree_view->priv->fixed_height_mode)
6564     {
6565       if (tree_view->priv->fixed_height < 0)
6566         initialize_fixed_height_mode (tree_view);
6567
6568       return FALSE;
6569     }
6570
6571   timer = g_timer_new ();
6572   g_timer_start (timer);
6573
6574   do
6575     {
6576       gboolean changed = FALSE;
6577
6578       if (! GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID))
6579         {
6580           retval = FALSE;
6581           goto done;
6582         }
6583
6584       if (path != NULL)
6585         {
6586           node = _gtk_rbtree_next (tree, node);
6587           if (node != NULL)
6588             {
6589               TREE_VIEW_INTERNAL_ASSERT (gtk_tree_model_iter_next (tree_view->priv->model, &iter), FALSE);
6590               gtk_tree_path_next (path);
6591             }
6592           else
6593             {
6594               gtk_tree_path_free (path);
6595               path = NULL;
6596             }
6597         }
6598
6599       if (path == NULL)
6600         {
6601           tree = tree_view->priv->tree;
6602           node = tree_view->priv->tree->root;
6603
6604           g_assert (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_DESCENDANTS_INVALID));
6605
6606           do
6607             {
6608               if (!_gtk_rbtree_is_nil (node->left) &&
6609                   GTK_RBNODE_FLAG_SET (node->left, GTK_RBNODE_DESCENDANTS_INVALID))
6610                 {
6611                   node = node->left;
6612                 }
6613               else if (!_gtk_rbtree_is_nil (node->right) &&
6614                        GTK_RBNODE_FLAG_SET (node->right, GTK_RBNODE_DESCENDANTS_INVALID))
6615                 {
6616                   node = node->right;
6617                 }
6618               else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6619                        GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6620                 {
6621                   break;
6622                 }
6623               else if (node->children != NULL)
6624                 {
6625                   tree = node->children;
6626                   node = tree->root;
6627                 }
6628               else
6629                 /* RBTree corruption!  All bad */
6630                 g_assert_not_reached ();
6631             }
6632           while (TRUE);
6633           path = _gtk_tree_path_new_from_rbtree (tree, node);
6634           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6635         }
6636
6637       changed = validate_row (tree_view, tree, node, &iter, path);
6638       validated_area = changed || validated_area;
6639
6640       if (changed)
6641         {
6642           gint offset = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
6643
6644           if (y == -1 || y > offset)
6645             y = offset;
6646         }
6647
6648       if (!tree_view->priv->fixed_height_check)
6649         {
6650           gint height;
6651
6652           height = gtk_tree_view_get_row_height (tree_view, node);
6653           if (prev_height < 0)
6654             prev_height = height;
6655           else if (prev_height != height)
6656             fixed_height = FALSE;
6657         }
6658
6659       i++;
6660     }
6661   while (g_timer_elapsed (timer, NULL) < GTK_TREE_VIEW_TIME_MS_PER_IDLE / 1000.);
6662
6663   if (!tree_view->priv->fixed_height_check)
6664    {
6665      if (fixed_height)
6666        _gtk_rbtree_set_fixed_height (tree_view->priv->tree, prev_height, FALSE);
6667
6668      tree_view->priv->fixed_height_check = 1;
6669    }
6670   
6671  done:
6672   if (validated_area)
6673     {
6674       GtkRequisition requisition;
6675
6676       /* We temporarily guess a size, under the assumption that it will be the
6677        * same when we get our next size_allocate.  If we don't do this, we'll be
6678        * in an inconsistent state when we call top_row_to_dy. */
6679
6680       /* FIXME: This is called from size_request, for some reason it is not infinitely
6681        * recursing, we cannot call gtk_widget_get_preferred_size() here because that's
6682        * not allowed (from inside ->get_preferred_width/height() implementations, one
6683        * should call the vfuncs directly). However what is desired here is the full
6684        * size including any margins and limited by any alignment (i.e. after 
6685        * GtkWidget:adjust_size_request() is called).
6686        *
6687        * Currently bypassing this but the real solution is to not update the scroll adjustments
6688        * untill we've recieved an allocation (never update scroll adjustments from size-requests).
6689        */
6690       gtk_tree_view_size_request (GTK_WIDGET (tree_view), &requisition, FALSE);
6691
6692       /* If rows above the current position have changed height, this has
6693        * affected the current view and thus needs a redraw.
6694        */
6695       if (y != -1 && y < gtk_adjustment_get_value (tree_view->priv->vadjustment))
6696         gtk_widget_queue_draw (GTK_WIDGET (tree_view));
6697
6698       gtk_adjustment_set_upper (tree_view->priv->hadjustment,
6699                                 MAX (gtk_adjustment_get_upper (tree_view->priv->hadjustment), requisition.width));
6700       gtk_adjustment_set_upper (tree_view->priv->vadjustment,
6701                                 MAX (gtk_adjustment_get_upper (tree_view->priv->vadjustment), requisition.height));
6702
6703       if (queue_resize)
6704         gtk_widget_queue_resize_no_redraw (GTK_WIDGET (tree_view));
6705     }
6706
6707   if (path) gtk_tree_path_free (path);
6708   g_timer_destroy (timer);
6709
6710   return retval;
6711 }
6712
6713 static gboolean
6714 validate_rows (GtkTreeView *tree_view)
6715 {
6716   gboolean retval;
6717   
6718   retval = do_validate_rows (tree_view, TRUE);
6719   
6720   if (! retval && tree_view->priv->validate_rows_timer)
6721     {
6722       g_source_remove (tree_view->priv->validate_rows_timer);
6723       tree_view->priv->validate_rows_timer = 0;
6724     }
6725
6726   return retval;
6727 }
6728
6729 static gboolean
6730 validate_rows_handler (GtkTreeView *tree_view)
6731 {
6732   gboolean retval;
6733
6734   retval = do_validate_rows (tree_view, TRUE);
6735   if (! retval && tree_view->priv->validate_rows_timer)
6736     {
6737       g_source_remove (tree_view->priv->validate_rows_timer);
6738       tree_view->priv->validate_rows_timer = 0;
6739     }
6740
6741   return retval;
6742 }
6743
6744 static gboolean
6745 do_presize_handler (GtkTreeView *tree_view)
6746 {
6747   if (tree_view->priv->mark_rows_col_dirty)
6748     {
6749       if (tree_view->priv->tree)
6750         _gtk_rbtree_column_invalid (tree_view->priv->tree);
6751       tree_view->priv->mark_rows_col_dirty = FALSE;
6752     }
6753   validate_visible_area (tree_view);
6754   tree_view->priv->presize_handler_timer = 0;
6755
6756   if (tree_view->priv->fixed_height_mode)
6757     {
6758       GtkRequisition requisition;
6759
6760       gtk_widget_get_preferred_size (GTK_WIDGET (tree_view),
6761                                      &requisition, NULL);
6762
6763       gtk_adjustment_set_upper (tree_view->priv->hadjustment,
6764                                 MAX (gtk_adjustment_get_upper (tree_view->priv->hadjustment), requisition.width));
6765       gtk_adjustment_set_upper (tree_view->priv->vadjustment,
6766                                 MAX (gtk_adjustment_get_upper (tree_view->priv->vadjustment), requisition.height));
6767       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6768     }
6769                    
6770   return FALSE;
6771 }
6772
6773 static gboolean
6774 presize_handler_callback (gpointer data)
6775 {
6776   do_presize_handler (GTK_TREE_VIEW (data));
6777                    
6778   return FALSE;
6779 }
6780
6781 static void
6782 install_presize_handler (GtkTreeView *tree_view)
6783 {
6784   if (! gtk_widget_get_realized (GTK_WIDGET (tree_view)))
6785     return;
6786
6787   if (! tree_view->priv->presize_handler_timer)
6788     {
6789       tree_view->priv->presize_handler_timer =
6790         gdk_threads_add_idle_full (GTK_PRIORITY_RESIZE - 2, presize_handler_callback, tree_view, NULL);
6791     }
6792   if (! tree_view->priv->validate_rows_timer)
6793     {
6794       tree_view->priv->validate_rows_timer =
6795         gdk_threads_add_idle_full (GTK_TREE_VIEW_PRIORITY_VALIDATE, (GSourceFunc) validate_rows_handler, tree_view, NULL);
6796     }
6797 }
6798
6799 static void
6800 gtk_tree_view_bin_process_updates (GtkTreeView *tree_view)
6801 {
6802   /* Prior to drawing, we make sure the visible area is validated. */
6803   if (tree_view->priv->presize_handler_timer)
6804     {
6805       g_source_remove (tree_view->priv->presize_handler_timer);
6806       tree_view->priv->presize_handler_timer = 0;
6807
6808       do_presize_handler (tree_view);
6809     }
6810
6811   gdk_window_process_updates (tree_view->priv->bin_window, TRUE);
6812 }
6813
6814 static gboolean
6815 scroll_sync_handler (GtkTreeView *tree_view)
6816 {
6817   if (tree_view->priv->height <= gtk_adjustment_get_page_size (tree_view->priv->vadjustment))
6818     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
6819   else if (gtk_tree_row_reference_valid (tree_view->priv->top_row))
6820     gtk_tree_view_top_row_to_dy (tree_view);
6821   else
6822     gtk_tree_view_dy_to_top_row (tree_view);
6823
6824   tree_view->priv->scroll_sync_timer = 0;
6825
6826   return FALSE;
6827 }
6828
6829 static void
6830 install_scroll_sync_handler (GtkTreeView *tree_view)
6831 {
6832   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
6833     return;
6834
6835   if (!tree_view->priv->scroll_sync_timer)
6836     {
6837       tree_view->priv->scroll_sync_timer =
6838         gdk_threads_add_idle_full (GTK_TREE_VIEW_PRIORITY_SCROLL_SYNC, (GSourceFunc) scroll_sync_handler, tree_view, NULL);
6839     }
6840 }
6841
6842 static void
6843 gtk_tree_view_set_top_row (GtkTreeView *tree_view,
6844                            GtkTreePath *path,
6845                            gint         offset)
6846 {
6847   gtk_tree_row_reference_free (tree_view->priv->top_row);
6848
6849   if (!path)
6850     {
6851       tree_view->priv->top_row = NULL;
6852       tree_view->priv->top_row_dy = 0;
6853     }
6854   else
6855     {
6856       tree_view->priv->top_row = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
6857       tree_view->priv->top_row_dy = offset;
6858     }
6859 }
6860
6861 /* Always call this iff dy is in the visible range.  If the tree is empty, then
6862  * it's set to be NULL, and top_row_dy is 0;
6863  */
6864 static void
6865 gtk_tree_view_dy_to_top_row (GtkTreeView *tree_view)
6866 {
6867   gint offset;
6868   GtkTreePath *path;
6869   GtkRBTree *tree;
6870   GtkRBNode *node;
6871
6872   if (tree_view->priv->tree == NULL)
6873     {
6874       gtk_tree_view_set_top_row (tree_view, NULL, 0);
6875     }
6876   else
6877     {
6878       offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
6879                                         tree_view->priv->dy,
6880                                         &tree, &node);
6881
6882       if (tree == NULL)
6883         {
6884           gtk_tree_view_set_top_row (tree_view, NULL, 0);
6885         }
6886       else
6887         {
6888           path = _gtk_tree_path_new_from_rbtree (tree, node);
6889           gtk_tree_view_set_top_row (tree_view, path, offset);
6890           gtk_tree_path_free (path);
6891         }
6892     }
6893 }
6894
6895 static void
6896 gtk_tree_view_top_row_to_dy (GtkTreeView *tree_view)
6897 {
6898   GtkTreePath *path;
6899   GtkRBTree *tree;
6900   GtkRBNode *node;
6901   int new_dy;
6902
6903   /* Avoid recursive calls */
6904   if (tree_view->priv->in_top_row_to_dy)
6905     return;
6906
6907   if (tree_view->priv->top_row)
6908     path = gtk_tree_row_reference_get_path (tree_view->priv->top_row);
6909   else
6910     path = NULL;
6911
6912   if (!path)
6913     tree = NULL;
6914   else
6915     _gtk_tree_view_find_node (tree_view, path, &tree, &node);
6916
6917   if (path)
6918     gtk_tree_path_free (path);
6919
6920   if (tree == NULL)
6921     {
6922       /* keep dy and set new toprow */
6923       gtk_tree_row_reference_free (tree_view->priv->top_row);
6924       tree_view->priv->top_row = NULL;
6925       tree_view->priv->top_row_dy = 0;
6926       /* DO NOT install the idle handler */
6927       gtk_tree_view_dy_to_top_row (tree_view);
6928       return;
6929     }
6930
6931   if (gtk_tree_view_get_row_height (tree_view, node)
6932       < tree_view->priv->top_row_dy)
6933     {
6934       /* new top row -- do NOT install the idle handler */
6935       gtk_tree_view_dy_to_top_row (tree_view);
6936       return;
6937     }
6938
6939   new_dy = _gtk_rbtree_node_find_offset (tree, node);
6940   new_dy += tree_view->priv->top_row_dy;
6941
6942   if (new_dy + gtk_adjustment_get_page_size (tree_view->priv->vadjustment) > tree_view->priv->height)
6943     new_dy = tree_view->priv->height - gtk_adjustment_get_page_size (tree_view->priv->vadjustment);
6944
6945   new_dy = MAX (0, new_dy);
6946
6947   tree_view->priv->in_top_row_to_dy = TRUE;
6948   gtk_adjustment_set_value (tree_view->priv->vadjustment, (gdouble)new_dy);
6949   tree_view->priv->in_top_row_to_dy = FALSE;
6950 }
6951
6952
6953 void
6954 _gtk_tree_view_install_mark_rows_col_dirty (GtkTreeView *tree_view,
6955                                             gboolean     install_handler)
6956 {
6957   tree_view->priv->mark_rows_col_dirty = TRUE;
6958
6959   if (install_handler)
6960     install_presize_handler (tree_view);
6961 }
6962
6963 /*
6964  * This function works synchronously (due to the while (validate_rows...)
6965  * loop).
6966  *
6967  * There was a check for column_type != GTK_TREE_VIEW_COLUMN_AUTOSIZE
6968  * here. You now need to check that yourself.
6969  */
6970 void
6971 _gtk_tree_view_column_autosize (GtkTreeView *tree_view,
6972                                 GtkTreeViewColumn *column)
6973 {
6974   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
6975   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (column));
6976
6977   _gtk_tree_view_column_cell_set_dirty (column, FALSE);
6978
6979   do_presize_handler (tree_view);
6980   while (validate_rows (tree_view));
6981
6982   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6983 }
6984
6985 /* Drag-and-drop */
6986
6987 static void
6988 set_source_row (GdkDragContext *context,
6989                 GtkTreeModel   *model,
6990                 GtkTreePath    *source_row)
6991 {
6992   g_object_set_data_full (G_OBJECT (context),
6993                           I_("gtk-tree-view-source-row"),
6994                           source_row ? gtk_tree_row_reference_new (model, source_row) : NULL,
6995                           (GDestroyNotify) (source_row ? gtk_tree_row_reference_free : NULL));
6996 }
6997
6998 static GtkTreePath*
6999 get_source_row (GdkDragContext *context)
7000 {
7001   GtkTreeRowReference *ref =
7002     g_object_get_data (G_OBJECT (context), "gtk-tree-view-source-row");
7003
7004   if (ref)
7005     return gtk_tree_row_reference_get_path (ref);
7006   else
7007     return NULL;
7008 }
7009
7010 typedef struct
7011 {
7012   GtkTreeRowReference *dest_row;
7013   guint                path_down_mode   : 1;
7014   guint                empty_view_drop  : 1;
7015   guint                drop_append_mode : 1;
7016 }
7017 DestRow;
7018
7019 static void
7020 dest_row_free (gpointer data)
7021 {
7022   DestRow *dr = (DestRow *)data;
7023
7024   gtk_tree_row_reference_free (dr->dest_row);
7025   g_slice_free (DestRow, dr);
7026 }
7027
7028 static void
7029 set_dest_row (GdkDragContext *context,
7030               GtkTreeModel   *model,
7031               GtkTreePath    *dest_row,
7032               gboolean        path_down_mode,
7033               gboolean        empty_view_drop,
7034               gboolean        drop_append_mode)
7035 {
7036   DestRow *dr;
7037
7038   if (!dest_row)
7039     {
7040       g_object_set_data_full (G_OBJECT (context), I_("gtk-tree-view-dest-row"),
7041                               NULL, NULL);
7042       return;
7043     }
7044
7045   dr = g_slice_new (DestRow);
7046
7047   dr->dest_row = gtk_tree_row_reference_new (model, dest_row);
7048   dr->path_down_mode = path_down_mode != FALSE;
7049   dr->empty_view_drop = empty_view_drop != FALSE;
7050   dr->drop_append_mode = drop_append_mode != FALSE;
7051
7052   g_object_set_data_full (G_OBJECT (context), I_("gtk-tree-view-dest-row"),
7053                           dr, (GDestroyNotify) dest_row_free);
7054 }
7055
7056 static GtkTreePath*
7057 get_dest_row (GdkDragContext *context,
7058               gboolean       *path_down_mode)
7059 {
7060   DestRow *dr =
7061     g_object_get_data (G_OBJECT (context), "gtk-tree-view-dest-row");
7062
7063   if (dr)
7064     {
7065       GtkTreePath *path = NULL;
7066
7067       if (path_down_mode)
7068         *path_down_mode = dr->path_down_mode;
7069
7070       if (dr->dest_row)
7071         path = gtk_tree_row_reference_get_path (dr->dest_row);
7072       else if (dr->empty_view_drop)
7073         path = gtk_tree_path_new_from_indices (0, -1);
7074       else
7075         path = NULL;
7076
7077       if (path && dr->drop_append_mode)
7078         gtk_tree_path_next (path);
7079
7080       return path;
7081     }
7082   else
7083     return NULL;
7084 }
7085
7086 /* Get/set whether drag_motion requested the drag data and
7087  * drag_data_received should thus not actually insert the data,
7088  * since the data doesn't result from a drop.
7089  */
7090 static void
7091 set_status_pending (GdkDragContext *context,
7092                     GdkDragAction   suggested_action)
7093 {
7094   g_object_set_data (G_OBJECT (context),
7095                      I_("gtk-tree-view-status-pending"),
7096                      GINT_TO_POINTER (suggested_action));
7097 }
7098
7099 static GdkDragAction
7100 get_status_pending (GdkDragContext *context)
7101 {
7102   return GPOINTER_TO_INT (g_object_get_data (G_OBJECT (context),
7103                                              "gtk-tree-view-status-pending"));
7104 }
7105
7106 static TreeViewDragInfo*
7107 get_info (GtkTreeView *tree_view)
7108 {
7109   return g_object_get_data (G_OBJECT (tree_view), "gtk-tree-view-drag-info");
7110 }
7111
7112 static void
7113 destroy_info (TreeViewDragInfo *di)
7114 {
7115   g_slice_free (TreeViewDragInfo, di);
7116 }
7117
7118 static TreeViewDragInfo*
7119 ensure_info (GtkTreeView *tree_view)
7120 {
7121   TreeViewDragInfo *di;
7122
7123   di = get_info (tree_view);
7124
7125   if (di == NULL)
7126     {
7127       di = g_slice_new0 (TreeViewDragInfo);
7128
7129       g_object_set_data_full (G_OBJECT (tree_view),
7130                               I_("gtk-tree-view-drag-info"),
7131                               di,
7132                               (GDestroyNotify) destroy_info);
7133     }
7134
7135   return di;
7136 }
7137
7138 static void
7139 remove_info (GtkTreeView *tree_view)
7140 {
7141   g_object_set_data (G_OBJECT (tree_view), I_("gtk-tree-view-drag-info"), NULL);
7142 }
7143
7144 #if 0
7145 static gint
7146 drag_scan_timeout (gpointer data)
7147 {
7148   GtkTreeView *tree_view;
7149   gint x, y;
7150   GdkModifierType state;
7151   GtkTreePath *path = NULL;
7152   GtkTreeViewColumn *column = NULL;
7153   GdkRectangle visible_rect;
7154
7155   GDK_THREADS_ENTER ();
7156
7157   tree_view = GTK_TREE_VIEW (data);
7158
7159   gdk_window_get_device_position (tree_view->priv->bin_window,
7160                                   gdk_device_manager_get_client_pointer (
7161                                     gdk_display_get_device_manager (
7162                                       gtk_widget_get_display (GTK_WIDGET (tree_view)))),
7163                                   &x, &y, &state);
7164
7165   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
7166
7167   /* See if we are near the edge. */
7168   if ((x - visible_rect.x) < SCROLL_EDGE_SIZE ||
7169       (visible_rect.x + visible_rect.width - x) < SCROLL_EDGE_SIZE ||
7170       (y - visible_rect.y) < SCROLL_EDGE_SIZE ||
7171       (visible_rect.y + visible_rect.height - y) < SCROLL_EDGE_SIZE)
7172     {
7173       gtk_tree_view_get_path_at_pos (tree_view,
7174                                      tree_view->priv->bin_window,
7175                                      x, y,
7176                                      &path,
7177                                      &column,
7178                                      NULL,
7179                                      NULL);
7180
7181       if (path != NULL)
7182         {
7183           gtk_tree_view_scroll_to_cell (tree_view,
7184                                         path,
7185                                         column,
7186                                         TRUE,
7187                                         0.5, 0.5);
7188
7189           gtk_tree_path_free (path);
7190         }
7191     }
7192
7193   GDK_THREADS_LEAVE ();
7194
7195   return TRUE;
7196 }
7197 #endif /* 0 */
7198
7199 static void
7200 add_scroll_timeout (GtkTreeView *tree_view)
7201 {
7202   if (tree_view->priv->scroll_timeout == 0)
7203     {
7204       tree_view->priv->scroll_timeout =
7205         gdk_threads_add_timeout (150, scroll_row_timeout, tree_view);
7206     }
7207 }
7208
7209 static void
7210 remove_scroll_timeout (GtkTreeView *tree_view)
7211 {
7212   if (tree_view->priv->scroll_timeout != 0)
7213     {
7214       g_source_remove (tree_view->priv->scroll_timeout);
7215       tree_view->priv->scroll_timeout = 0;
7216     }
7217 }
7218
7219 static gboolean
7220 check_model_dnd (GtkTreeModel *model,
7221                  GType         required_iface,
7222                  const gchar  *signal)
7223 {
7224   if (model == NULL || !G_TYPE_CHECK_INSTANCE_TYPE ((model), required_iface))
7225     {
7226       g_warning ("You must override the default '%s' handler "
7227                  "on GtkTreeView when using models that don't support "
7228                  "the %s interface and enabling drag-and-drop. The simplest way to do this "
7229                  "is to connect to '%s' and call "
7230                  "g_signal_stop_emission_by_name() in your signal handler to prevent "
7231                  "the default handler from running. Look at the source code "
7232                  "for the default handler in gtktreeview.c to get an idea what "
7233                  "your handler should do. (gtktreeview.c is in the GTK source "
7234                  "code.) If you're using GTK from a language other than C, "
7235                  "there may be a more natural way to override default handlers, e.g. via derivation.",
7236                  signal, g_type_name (required_iface), signal);
7237       return FALSE;
7238     }
7239   else
7240     return TRUE;
7241 }
7242
7243 static void
7244 remove_open_timeout (GtkTreeView *tree_view)
7245 {
7246   if (tree_view->priv->open_dest_timeout != 0)
7247     {
7248       g_source_remove (tree_view->priv->open_dest_timeout);
7249       tree_view->priv->open_dest_timeout = 0;
7250     }
7251 }
7252
7253
7254 static gint
7255 open_row_timeout (gpointer data)
7256 {
7257   GtkTreeView *tree_view = data;
7258   GtkTreePath *dest_path = NULL;
7259   GtkTreeViewDropPosition pos;
7260   gboolean result = FALSE;
7261
7262   gtk_tree_view_get_drag_dest_row (tree_view,
7263                                    &dest_path,
7264                                    &pos);
7265
7266   if (dest_path &&
7267       (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
7268        pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
7269     {
7270       gtk_tree_view_expand_row (tree_view, dest_path, FALSE);
7271       tree_view->priv->open_dest_timeout = 0;
7272
7273       gtk_tree_path_free (dest_path);
7274     }
7275   else
7276     {
7277       if (dest_path)
7278         gtk_tree_path_free (dest_path);
7279
7280       result = TRUE;
7281     }
7282
7283   return result;
7284 }
7285
7286 static gboolean
7287 scroll_row_timeout (gpointer data)
7288 {
7289   GtkTreeView *tree_view = data;
7290
7291   gtk_tree_view_vertical_autoscroll (tree_view);
7292
7293   if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
7294     gtk_tree_view_update_rubber_band (tree_view);
7295
7296   return TRUE;
7297 }
7298
7299 /* Returns TRUE if event should not be propagated to parent widgets */
7300 static gboolean
7301 set_destination_row (GtkTreeView    *tree_view,
7302                      GdkDragContext *context,
7303                      /* coordinates relative to the widget */
7304                      gint            x,
7305                      gint            y,
7306                      GdkDragAction  *suggested_action,
7307                      GdkAtom        *target)
7308 {
7309   GtkTreePath *path = NULL;
7310   GtkTreeViewDropPosition pos;
7311   GtkTreeViewDropPosition old_pos;
7312   TreeViewDragInfo *di;
7313   GtkWidget *widget;
7314   GtkTreePath *old_dest_path = NULL;
7315   gboolean can_drop = FALSE;
7316
7317   *suggested_action = 0;
7318   *target = GDK_NONE;
7319
7320   widget = GTK_WIDGET (tree_view);
7321
7322   di = get_info (tree_view);
7323
7324   if (di == NULL || y - gtk_tree_view_get_effective_header_height (tree_view) < 0)
7325     {
7326       /* someone unset us as a drag dest, note that if
7327        * we return FALSE drag_leave isn't called
7328        */
7329
7330       gtk_tree_view_set_drag_dest_row (tree_view,
7331                                        NULL,
7332                                        GTK_TREE_VIEW_DROP_BEFORE);
7333
7334       remove_scroll_timeout (GTK_TREE_VIEW (widget));
7335       remove_open_timeout (GTK_TREE_VIEW (widget));
7336
7337       return FALSE; /* no longer a drop site */
7338     }
7339
7340   *target = gtk_drag_dest_find_target (widget, context,
7341                                        gtk_drag_dest_get_target_list (widget));
7342   if (*target == GDK_NONE)
7343     {
7344       return FALSE;
7345     }
7346
7347   if (!gtk_tree_view_get_dest_row_at_pos (tree_view,
7348                                           x, y,
7349                                           &path,
7350                                           &pos))
7351     {
7352       gint n_children;
7353       GtkTreeModel *model;
7354
7355       remove_open_timeout (tree_view);
7356
7357       /* the row got dropped on empty space, let's setup a special case
7358        */
7359
7360       if (path)
7361         gtk_tree_path_free (path);
7362
7363       model = gtk_tree_view_get_model (tree_view);
7364
7365       n_children = gtk_tree_model_iter_n_children (model, NULL);
7366       if (n_children)
7367         {
7368           pos = GTK_TREE_VIEW_DROP_AFTER;
7369           path = gtk_tree_path_new_from_indices (n_children - 1, -1);
7370         }
7371       else
7372         {
7373           pos = GTK_TREE_VIEW_DROP_BEFORE;
7374           path = gtk_tree_path_new_from_indices (0, -1);
7375         }
7376
7377       can_drop = TRUE;
7378
7379       goto out;
7380     }
7381
7382   g_assert (path);
7383
7384   /* If we left the current row's "open" zone, unset the timeout for
7385    * opening the row
7386    */
7387   gtk_tree_view_get_drag_dest_row (tree_view,
7388                                    &old_dest_path,
7389                                    &old_pos);
7390
7391   if (old_dest_path &&
7392       (gtk_tree_path_compare (path, old_dest_path) != 0 ||
7393        !(pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
7394          pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE)))
7395     remove_open_timeout (tree_view);
7396
7397   if (old_dest_path)
7398     gtk_tree_path_free (old_dest_path);
7399
7400   if (TRUE /* FIXME if the location droppable predicate */)
7401     {
7402       can_drop = TRUE;
7403     }
7404
7405 out:
7406   if (can_drop)
7407     {
7408       GtkWidget *source_widget;
7409
7410       *suggested_action = gdk_drag_context_get_suggested_action (context);
7411       source_widget = gtk_drag_get_source_widget (context);
7412
7413       if (source_widget == widget)
7414         {
7415           /* Default to MOVE, unless the user has
7416            * pressed ctrl or shift to affect available actions
7417            */
7418           if ((gdk_drag_context_get_actions (context) & GDK_ACTION_MOVE) != 0)
7419             *suggested_action = GDK_ACTION_MOVE;
7420         }
7421
7422       gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7423                                        path, pos);
7424     }
7425   else
7426     {
7427       /* can't drop here */
7428       remove_open_timeout (tree_view);
7429
7430       gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7431                                        NULL,
7432                                        GTK_TREE_VIEW_DROP_BEFORE);
7433     }
7434
7435   if (path)
7436     gtk_tree_path_free (path);
7437
7438   return TRUE;
7439 }
7440
7441 static GtkTreePath*
7442 get_logical_dest_row (GtkTreeView *tree_view,
7443                       gboolean    *path_down_mode,
7444                       gboolean    *drop_append_mode)
7445 {
7446   /* adjust path to point to the row the drop goes in front of */
7447   GtkTreePath *path = NULL;
7448   GtkTreeViewDropPosition pos;
7449
7450   g_return_val_if_fail (path_down_mode != NULL, NULL);
7451   g_return_val_if_fail (drop_append_mode != NULL, NULL);
7452
7453   *path_down_mode = FALSE;
7454   *drop_append_mode = 0;
7455
7456   gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
7457
7458   if (path == NULL)
7459     return NULL;
7460
7461   if (pos == GTK_TREE_VIEW_DROP_BEFORE)
7462     ; /* do nothing */
7463   else if (pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE ||
7464            pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER)
7465     *path_down_mode = TRUE;
7466   else
7467     {
7468       GtkTreeIter iter;
7469       GtkTreeModel *model = gtk_tree_view_get_model (tree_view);
7470
7471       g_assert (pos == GTK_TREE_VIEW_DROP_AFTER);
7472
7473       if (!gtk_tree_model_get_iter (model, &iter, path) ||
7474           !gtk_tree_model_iter_next (model, &iter))
7475         *drop_append_mode = 1;
7476       else
7477         {
7478           *drop_append_mode = 0;
7479           gtk_tree_path_next (path);
7480         }
7481     }
7482
7483   return path;
7484 }
7485
7486 static gboolean
7487 gtk_tree_view_maybe_begin_dragging_row (GtkTreeView      *tree_view,
7488                                         GdkEventMotion   *event)
7489 {
7490   GtkWidget *widget = GTK_WIDGET (tree_view);
7491   GdkDragContext *context;
7492   TreeViewDragInfo *di;
7493   GtkTreePath *path = NULL;
7494   gint button;
7495   gint cell_x, cell_y;
7496   GtkTreeModel *model;
7497   gboolean retval = FALSE;
7498
7499   di = get_info (tree_view);
7500
7501   if (di == NULL || !di->source_set)
7502     goto out;
7503
7504   if (tree_view->priv->pressed_button < 0)
7505     goto out;
7506
7507   if (!gtk_drag_check_threshold (widget,
7508                                  tree_view->priv->press_start_x,
7509                                  tree_view->priv->press_start_y,
7510                                  event->x, event->y))
7511     goto out;
7512
7513   model = gtk_tree_view_get_model (tree_view);
7514
7515   if (model == NULL)
7516     goto out;
7517
7518   button = tree_view->priv->pressed_button;
7519   tree_view->priv->pressed_button = -1;
7520
7521   gtk_tree_view_get_path_at_pos (tree_view,
7522                                  tree_view->priv->press_start_x,
7523                                  tree_view->priv->press_start_y,
7524                                  &path,
7525                                  NULL,
7526                                  &cell_x,
7527                                  &cell_y);
7528
7529   if (path == NULL)
7530     goto out;
7531
7532   if (!GTK_IS_TREE_DRAG_SOURCE (model) ||
7533       !gtk_tree_drag_source_row_draggable (GTK_TREE_DRAG_SOURCE (model),
7534                                            path))
7535     goto out;
7536
7537   if (!(GDK_BUTTON1_MASK << (button - 1) & di->start_button_mask))
7538     goto out;
7539
7540   /* Now we can begin the drag */
7541
7542   retval = TRUE;
7543
7544   context = gtk_drag_begin (widget,
7545                             gtk_drag_source_get_target_list (widget),
7546                             di->source_actions,
7547                             button,
7548                             (GdkEvent*)event);
7549
7550   set_source_row (context, model, path);
7551
7552  out:
7553   if (path)
7554     gtk_tree_path_free (path);
7555
7556   return retval;
7557 }
7558
7559
7560 static void
7561 gtk_tree_view_drag_begin (GtkWidget      *widget,
7562                           GdkDragContext *context)
7563 {
7564   GtkTreeView *tree_view;
7565   GtkTreePath *path = NULL;
7566   gint cell_x, cell_y;
7567   cairo_surface_t *row_pix;
7568   TreeViewDragInfo *di;
7569
7570   tree_view = GTK_TREE_VIEW (widget);
7571
7572   /* if the user uses a custom DND source impl, we don't set the icon here */
7573   di = get_info (tree_view);
7574
7575   if (di == NULL || !di->source_set)
7576     return;
7577
7578   gtk_tree_view_get_path_at_pos (tree_view,
7579                                  tree_view->priv->press_start_x,
7580                                  tree_view->priv->press_start_y,
7581                                  &path,
7582                                  NULL,
7583                                  &cell_x,
7584                                  &cell_y);
7585
7586   /* If path is NULL, there's nothing we can drag.  For now, we silently
7587    * bail out.  Actually, dragging should not be possible from an empty
7588    * tree view, but there's no way we can cancel that from here.
7589    * Automatically unsetting the tree view as drag source for empty models
7590    * is something that would likely break other people's code ...
7591    */
7592   if (!path)
7593     return;
7594
7595   row_pix = gtk_tree_view_create_row_drag_icon (tree_view,
7596                                                 path);
7597   cairo_surface_set_device_offset (row_pix,
7598                                    /* the + 1 is for the black border in the icon */
7599                                    - (tree_view->priv->press_start_x + 1),
7600                                    - (cell_y + 1));
7601
7602   gtk_drag_set_icon_surface (context, row_pix);
7603
7604   cairo_surface_destroy (row_pix);
7605   gtk_tree_path_free (path);
7606 }
7607
7608 static void
7609 gtk_tree_view_drag_end (GtkWidget      *widget,
7610                         GdkDragContext *context)
7611 {
7612   /* do nothing */
7613 }
7614
7615 /* Default signal implementations for the drag signals */
7616 static void
7617 gtk_tree_view_drag_data_get (GtkWidget        *widget,
7618                              GdkDragContext   *context,
7619                              GtkSelectionData *selection_data,
7620                              guint             info,
7621                              guint             time)
7622 {
7623   GtkTreeView *tree_view;
7624   GtkTreeModel *model;
7625   TreeViewDragInfo *di;
7626   GtkTreePath *source_row;
7627
7628   tree_view = GTK_TREE_VIEW (widget);
7629
7630   model = gtk_tree_view_get_model (tree_view);
7631
7632   if (model == NULL)
7633     return;
7634
7635   di = get_info (GTK_TREE_VIEW (widget));
7636
7637   if (di == NULL)
7638     return;
7639
7640   source_row = get_source_row (context);
7641
7642   if (source_row == NULL)
7643     return;
7644
7645   /* We can implement the GTK_TREE_MODEL_ROW target generically for
7646    * any model; for DragSource models there are some other targets
7647    * we also support.
7648    */
7649
7650   if (GTK_IS_TREE_DRAG_SOURCE (model) &&
7651       gtk_tree_drag_source_drag_data_get (GTK_TREE_DRAG_SOURCE (model),
7652                                           source_row,
7653                                           selection_data))
7654     goto done;
7655
7656   /* If drag_data_get does nothing, try providing row data. */
7657   if (gtk_selection_data_get_target (selection_data) == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
7658     {
7659       gtk_tree_set_row_drag_data (selection_data,
7660                                   model,
7661                                   source_row);
7662     }
7663
7664  done:
7665   gtk_tree_path_free (source_row);
7666 }
7667
7668
7669 static void
7670 gtk_tree_view_drag_data_delete (GtkWidget      *widget,
7671                                 GdkDragContext *context)
7672 {
7673   TreeViewDragInfo *di;
7674   GtkTreeModel *model;
7675   GtkTreeView *tree_view;
7676   GtkTreePath *source_row;
7677
7678   tree_view = GTK_TREE_VIEW (widget);
7679   model = gtk_tree_view_get_model (tree_view);
7680
7681   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_SOURCE, "drag_data_delete"))
7682     return;
7683
7684   di = get_info (tree_view);
7685
7686   if (di == NULL)
7687     return;
7688
7689   source_row = get_source_row (context);
7690
7691   if (source_row == NULL)
7692     return;
7693
7694   gtk_tree_drag_source_drag_data_delete (GTK_TREE_DRAG_SOURCE (model),
7695                                          source_row);
7696
7697   gtk_tree_path_free (source_row);
7698
7699   set_source_row (context, NULL, NULL);
7700 }
7701
7702 static void
7703 gtk_tree_view_drag_leave (GtkWidget      *widget,
7704                           GdkDragContext *context,
7705                           guint             time)
7706 {
7707   /* unset any highlight row */
7708   gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7709                                    NULL,
7710                                    GTK_TREE_VIEW_DROP_BEFORE);
7711
7712   remove_scroll_timeout (GTK_TREE_VIEW (widget));
7713   remove_open_timeout (GTK_TREE_VIEW (widget));
7714 }
7715
7716
7717 static gboolean
7718 gtk_tree_view_drag_motion (GtkWidget        *widget,
7719                            GdkDragContext   *context,
7720                            /* coordinates relative to the widget */
7721                            gint              x,
7722                            gint              y,
7723                            guint             time)
7724 {
7725   gboolean empty;
7726   GtkTreePath *path = NULL;
7727   GtkTreeViewDropPosition pos;
7728   GtkTreeView *tree_view;
7729   GdkDragAction suggested_action = 0;
7730   GdkAtom target;
7731
7732   tree_view = GTK_TREE_VIEW (widget);
7733
7734   if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
7735     return FALSE;
7736
7737   gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
7738
7739   /* we only know this *after* set_desination_row */
7740   empty = tree_view->priv->empty_view_drop;
7741
7742   if (path == NULL && !empty)
7743     {
7744       /* Can't drop here. */
7745       gdk_drag_status (context, 0, time);
7746     }
7747   else
7748     {
7749       if (tree_view->priv->open_dest_timeout == 0 &&
7750           (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
7751            pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
7752         {
7753           tree_view->priv->open_dest_timeout =
7754             gdk_threads_add_timeout (AUTO_EXPAND_TIMEOUT, open_row_timeout, tree_view);
7755         }
7756       else
7757         {
7758           add_scroll_timeout (tree_view);
7759         }
7760
7761       if (target == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
7762         {
7763           /* Request data so we can use the source row when
7764            * determining whether to accept the drop
7765            */
7766           set_status_pending (context, suggested_action);
7767           gtk_drag_get_data (widget, context, target, time);
7768         }
7769       else
7770         {
7771           set_status_pending (context, 0);
7772           gdk_drag_status (context, suggested_action, time);
7773         }
7774     }
7775
7776   if (path)
7777     gtk_tree_path_free (path);
7778
7779   return TRUE;
7780 }
7781
7782
7783 static gboolean
7784 gtk_tree_view_drag_drop (GtkWidget        *widget,
7785                          GdkDragContext   *context,
7786                          /* coordinates relative to the widget */
7787                          gint              x,
7788                          gint              y,
7789                          guint             time)
7790 {
7791   GtkTreeView *tree_view;
7792   GtkTreePath *path;
7793   GdkDragAction suggested_action = 0;
7794   GdkAtom target = GDK_NONE;
7795   TreeViewDragInfo *di;
7796   GtkTreeModel *model;
7797   gboolean path_down_mode;
7798   gboolean drop_append_mode;
7799
7800   tree_view = GTK_TREE_VIEW (widget);
7801
7802   model = gtk_tree_view_get_model (tree_view);
7803
7804   remove_scroll_timeout (GTK_TREE_VIEW (widget));
7805   remove_open_timeout (GTK_TREE_VIEW (widget));
7806
7807   di = get_info (tree_view);
7808
7809   if (di == NULL)
7810     return FALSE;
7811
7812   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_drop"))
7813     return FALSE;
7814
7815   if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
7816     return FALSE;
7817
7818   path = get_logical_dest_row (tree_view, &path_down_mode, &drop_append_mode);
7819
7820   if (target != GDK_NONE && path != NULL)
7821     {
7822       /* in case a motion had requested drag data, change things so we
7823        * treat drag data receives as a drop.
7824        */
7825       set_status_pending (context, 0);
7826       set_dest_row (context, model, path,
7827                     path_down_mode, tree_view->priv->empty_view_drop,
7828                     drop_append_mode);
7829     }
7830
7831   if (path)
7832     gtk_tree_path_free (path);
7833
7834   /* Unset this thing */
7835   gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7836                                    NULL,
7837                                    GTK_TREE_VIEW_DROP_BEFORE);
7838
7839   if (target != GDK_NONE)
7840     {
7841       gtk_drag_get_data (widget, context, target, time);
7842       return TRUE;
7843     }
7844   else
7845     return FALSE;
7846 }
7847
7848 static void
7849 gtk_tree_view_drag_data_received (GtkWidget        *widget,
7850                                   GdkDragContext   *context,
7851                                   /* coordinates relative to the widget */
7852                                   gint              x,
7853                                   gint              y,
7854                                   GtkSelectionData *selection_data,
7855                                   guint             info,
7856                                   guint             time)
7857 {
7858   GtkTreePath *path;
7859   TreeViewDragInfo *di;
7860   gboolean accepted = FALSE;
7861   GtkTreeModel *model;
7862   GtkTreeView *tree_view;
7863   GtkTreePath *dest_row;
7864   GdkDragAction suggested_action;
7865   gboolean path_down_mode;
7866   gboolean drop_append_mode;
7867
7868   tree_view = GTK_TREE_VIEW (widget);
7869
7870   model = gtk_tree_view_get_model (tree_view);
7871
7872   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_data_received"))
7873     return;
7874
7875   di = get_info (tree_view);
7876
7877   if (di == NULL)
7878     return;
7879
7880   suggested_action = get_status_pending (context);
7881
7882   if (suggested_action)
7883     {
7884       /* We are getting this data due to a request in drag_motion,
7885        * rather than due to a request in drag_drop, so we are just
7886        * supposed to call drag_status, not actually paste in the
7887        * data.
7888        */
7889       path = get_logical_dest_row (tree_view, &path_down_mode,
7890                                    &drop_append_mode);
7891
7892       if (path == NULL)
7893         suggested_action = 0;
7894       else if (path_down_mode)
7895         gtk_tree_path_down (path);
7896
7897       if (suggested_action)
7898         {
7899           if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
7900                                                      path,
7901                                                      selection_data))
7902             {
7903               if (path_down_mode)
7904                 {
7905                   path_down_mode = FALSE;
7906                   gtk_tree_path_up (path);
7907
7908                   if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
7909                                                              path,
7910                                                              selection_data))
7911                     suggested_action = 0;
7912                 }
7913               else
7914                 suggested_action = 0;
7915             }
7916         }
7917
7918       gdk_drag_status (context, suggested_action, time);
7919
7920       if (path)
7921         gtk_tree_path_free (path);
7922
7923       /* If you can't drop, remove user drop indicator until the next motion */
7924       if (suggested_action == 0)
7925         gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7926                                          NULL,
7927                                          GTK_TREE_VIEW_DROP_BEFORE);
7928
7929       return;
7930     }
7931
7932   dest_row = get_dest_row (context, &path_down_mode);
7933
7934   if (dest_row == NULL)
7935     return;
7936
7937   if (gtk_selection_data_get_length (selection_data) >= 0)
7938     {
7939       if (path_down_mode)
7940         {
7941           gtk_tree_path_down (dest_row);
7942           if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
7943                                                      dest_row, selection_data))
7944             gtk_tree_path_up (dest_row);
7945         }
7946     }
7947
7948   if (gtk_selection_data_get_length (selection_data) >= 0)
7949     {
7950       if (gtk_tree_drag_dest_drag_data_received (GTK_TREE_DRAG_DEST (model),
7951                                                  dest_row,
7952                                                  selection_data))
7953         accepted = TRUE;
7954     }
7955
7956   gtk_drag_finish (context,
7957                    accepted,
7958                    (gdk_drag_context_get_selected_action (context) == GDK_ACTION_MOVE),
7959                    time);
7960
7961   if (gtk_tree_path_get_depth (dest_row) == 1 &&
7962       gtk_tree_path_get_indices (dest_row)[0] == 0 &&
7963       gtk_tree_model_iter_n_children (tree_view->priv->model, NULL) != 0)
7964     {
7965       /* special special case drag to "0", scroll to first item */
7966       if (!tree_view->priv->scroll_to_path)
7967         gtk_tree_view_scroll_to_cell (tree_view, dest_row, NULL, FALSE, 0.0, 0.0);
7968     }
7969
7970   gtk_tree_path_free (dest_row);
7971
7972   /* drop dest_row */
7973   set_dest_row (context, NULL, NULL, FALSE, FALSE, FALSE);
7974 }
7975
7976
7977
7978 /* GtkContainer Methods
7979  */
7980
7981
7982 static void
7983 gtk_tree_view_remove (GtkContainer *container,
7984                       GtkWidget    *widget)
7985 {
7986   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
7987   GtkTreeViewChild *child = NULL;
7988   GList *tmp_list;
7989
7990   tmp_list = tree_view->priv->children;
7991   while (tmp_list)
7992     {
7993       child = tmp_list->data;
7994       if (child->widget == widget)
7995         {
7996           gtk_widget_unparent (widget);
7997
7998           tree_view->priv->children = g_list_remove_link (tree_view->priv->children, tmp_list);
7999           g_list_free_1 (tmp_list);
8000           g_slice_free (GtkTreeViewChild, child);
8001           return;
8002         }
8003
8004       tmp_list = tmp_list->next;
8005     }
8006
8007   tmp_list = tree_view->priv->columns;
8008
8009   while (tmp_list)
8010     {
8011       GtkTreeViewColumn *column;
8012       GtkWidget         *button;
8013
8014       column = tmp_list->data;
8015       button = gtk_tree_view_column_get_button (column);
8016
8017       if (button == widget)
8018         {
8019           gtk_widget_unparent (widget);
8020           return;
8021         }
8022       tmp_list = tmp_list->next;
8023     }
8024 }
8025
8026 static void
8027 gtk_tree_view_forall (GtkContainer *container,
8028                       gboolean      include_internals,
8029                       GtkCallback   callback,
8030                       gpointer      callback_data)
8031 {
8032   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
8033   GtkTreeViewChild *child = NULL;
8034   GtkTreeViewColumn *column;
8035   GtkWidget *button;
8036   GList *tmp_list;
8037
8038   tmp_list = tree_view->priv->children;
8039   while (tmp_list)
8040     {
8041       child = tmp_list->data;
8042       tmp_list = tmp_list->next;
8043
8044       (* callback) (child->widget, callback_data);
8045     }
8046   if (include_internals == FALSE)
8047     return;
8048
8049   for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
8050     {
8051       column = tmp_list->data;
8052       button = gtk_tree_view_column_get_button (column);
8053
8054       if (button)
8055         (* callback) (button, callback_data);
8056     }
8057 }
8058
8059 /* Returns TRUE is any of the columns contains a cell that can-focus.
8060  * If this is not the case, a column-spanning focus rectangle will be
8061  * drawn.
8062  */
8063 static gboolean
8064 gtk_tree_view_has_can_focus_cell (GtkTreeView *tree_view)
8065 {
8066   GList *list;
8067
8068   for (list = tree_view->priv->columns; list; list = list->next)
8069     {
8070       GtkTreeViewColumn *column = list->data;
8071
8072       if (!gtk_tree_view_column_get_visible (column))
8073         continue;
8074       if (gtk_cell_area_is_activatable (gtk_cell_layout_get_area (GTK_CELL_LAYOUT (column))))
8075         return TRUE;
8076     }
8077
8078   return FALSE;
8079 }
8080
8081 static void
8082 column_sizing_notify (GObject    *object,
8083                       GParamSpec *pspec,
8084                       gpointer    data)
8085 {
8086   GtkTreeViewColumn *c = GTK_TREE_VIEW_COLUMN (object);
8087
8088   if (gtk_tree_view_column_get_sizing (c) != GTK_TREE_VIEW_COLUMN_FIXED)
8089     /* disable fixed height mode */
8090     g_object_set (data, "fixed-height-mode", FALSE, NULL);
8091 }
8092
8093 /**
8094  * gtk_tree_view_set_fixed_height_mode:
8095  * @tree_view: a #GtkTreeView 
8096  * @enable: %TRUE to enable fixed height mode
8097  * 
8098  * Enables or disables the fixed height mode of @tree_view. 
8099  * Fixed height mode speeds up #GtkTreeView by assuming that all 
8100  * rows have the same height. 
8101  * Only enable this option if all rows are the same height and all
8102  * columns are of type %GTK_TREE_VIEW_COLUMN_FIXED.
8103  *
8104  * Since: 2.6 
8105  **/
8106 void
8107 gtk_tree_view_set_fixed_height_mode (GtkTreeView *tree_view,
8108                                      gboolean     enable)
8109 {
8110   GList *l;
8111   
8112   enable = enable != FALSE;
8113
8114   if (enable == tree_view->priv->fixed_height_mode)
8115     return;
8116
8117   if (!enable)
8118     {
8119       tree_view->priv->fixed_height_mode = 0;
8120       tree_view->priv->fixed_height = -1;
8121
8122       /* force a revalidation */
8123       install_presize_handler (tree_view);
8124     }
8125   else 
8126     {
8127       /* make sure all columns are of type FIXED */
8128       for (l = tree_view->priv->columns; l; l = l->next)
8129         {
8130           GtkTreeViewColumn *c = l->data;
8131           
8132           g_return_if_fail (gtk_tree_view_column_get_sizing (c) == GTK_TREE_VIEW_COLUMN_FIXED);
8133         }
8134       
8135       /* yes, we really have to do this is in a separate loop */
8136       for (l = tree_view->priv->columns; l; l = l->next)
8137         g_signal_connect (l->data, "notify::sizing",
8138                           G_CALLBACK (column_sizing_notify), tree_view);
8139       
8140       tree_view->priv->fixed_height_mode = 1;
8141       tree_view->priv->fixed_height = -1;
8142       
8143       if (tree_view->priv->tree)
8144         initialize_fixed_height_mode (tree_view);
8145     }
8146
8147   g_object_notify (G_OBJECT (tree_view), "fixed-height-mode");
8148 }
8149
8150 /**
8151  * gtk_tree_view_get_fixed_height_mode:
8152  * @tree_view: a #GtkTreeView
8153  * 
8154  * Returns whether fixed height mode is turned on for @tree_view.
8155  * 
8156  * Return value: %TRUE if @tree_view is in fixed height mode
8157  * 
8158  * Since: 2.6
8159  **/
8160 gboolean
8161 gtk_tree_view_get_fixed_height_mode (GtkTreeView *tree_view)
8162 {
8163   return tree_view->priv->fixed_height_mode;
8164 }
8165
8166 /* Returns TRUE if the focus is within the headers, after the focus operation is
8167  * done
8168  */
8169 static gboolean
8170 gtk_tree_view_header_focus (GtkTreeView      *tree_view,
8171                             GtkDirectionType  dir,
8172                             gboolean          clamp_column_visible)
8173 {
8174   GtkTreeViewColumn *column;
8175   GtkWidget *focus_child;
8176   GtkWidget *button;
8177   GList *last_column, *first_column;
8178   GList *tmp_list;
8179   gboolean rtl;
8180
8181   if (! tree_view->priv->headers_visible)
8182     return FALSE;
8183
8184   focus_child = gtk_container_get_focus_child (GTK_CONTAINER (tree_view));
8185
8186   first_column = tree_view->priv->columns;
8187   while (first_column)
8188     {
8189       column = GTK_TREE_VIEW_COLUMN (first_column->data);
8190       button = gtk_tree_view_column_get_button (column);
8191
8192       if (gtk_widget_get_can_focus (button) &&
8193           gtk_tree_view_column_get_visible (column) &&
8194           (gtk_tree_view_column_get_clickable (column) ||
8195            gtk_tree_view_column_get_reorderable (column)))
8196         break;
8197       first_column = first_column->next;
8198     }
8199
8200   /* No headers are visible, or are focusable.  We can't focus in or out.
8201    */
8202   if (first_column == NULL)
8203     return FALSE;
8204
8205   last_column = g_list_last (tree_view->priv->columns);
8206   while (last_column)
8207     {
8208       column = GTK_TREE_VIEW_COLUMN (last_column->data);
8209       button = gtk_tree_view_column_get_button (column);
8210
8211       if (gtk_widget_get_can_focus (button) &&
8212           gtk_tree_view_column_get_visible (column) &&
8213           (gtk_tree_view_column_get_clickable (column) ||
8214            gtk_tree_view_column_get_reorderable (column)))
8215         break;
8216       last_column = last_column->prev;
8217     }
8218
8219
8220   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
8221
8222   switch (dir)
8223     {
8224     case GTK_DIR_TAB_BACKWARD:
8225     case GTK_DIR_TAB_FORWARD:
8226     case GTK_DIR_UP:
8227     case GTK_DIR_DOWN:
8228       if (focus_child == NULL)
8229         {
8230           if (tree_view->priv->focus_column != NULL)
8231             button = gtk_tree_view_column_get_button (tree_view->priv->focus_column);
8232           else 
8233             button = NULL;
8234
8235           if (button && gtk_widget_get_can_focus (button))
8236             focus_child = button;
8237           else
8238             focus_child = gtk_tree_view_column_get_button (GTK_TREE_VIEW_COLUMN (first_column->data));
8239
8240           gtk_widget_grab_focus (focus_child);
8241           break;
8242         }
8243       return FALSE;
8244
8245     case GTK_DIR_LEFT:
8246     case GTK_DIR_RIGHT:
8247       if (focus_child == NULL)
8248         {
8249           if (tree_view->priv->focus_column != NULL)
8250             focus_child = gtk_tree_view_column_get_button (tree_view->priv->focus_column);
8251           else if (dir == GTK_DIR_LEFT)
8252             focus_child = gtk_tree_view_column_get_button (GTK_TREE_VIEW_COLUMN (last_column->data));
8253           else
8254             focus_child = gtk_tree_view_column_get_button (GTK_TREE_VIEW_COLUMN (first_column->data));
8255
8256           gtk_widget_grab_focus (focus_child);
8257           break;
8258         }
8259
8260       if (gtk_widget_child_focus (focus_child, dir))
8261         {
8262           /* The focus moves inside the button. */
8263           /* This is probably a great example of bad UI */
8264           break;
8265         }
8266
8267       /* We need to move the focus among the row of buttons. */
8268       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
8269         if (gtk_tree_view_column_get_button (GTK_TREE_VIEW_COLUMN (tmp_list->data)) == focus_child)
8270           break;
8271
8272       if ((tmp_list == first_column && dir == (rtl ? GTK_DIR_RIGHT : GTK_DIR_LEFT))
8273           || (tmp_list == last_column && dir == (rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT)))
8274         {
8275           gtk_widget_error_bell (GTK_WIDGET (tree_view));
8276           break;
8277         }
8278
8279       while (tmp_list)
8280         {
8281           GtkTreeViewColumn *column;
8282           GtkWidget         *button;
8283
8284           if (dir == (rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT))
8285             tmp_list = tmp_list->next;
8286           else
8287             tmp_list = tmp_list->prev;
8288
8289           if (tmp_list == NULL)
8290             {
8291               g_warning ("Internal button not found");
8292               break;
8293             }
8294           column = tmp_list->data;
8295           button = gtk_tree_view_column_get_button (column);
8296           if (button &&
8297               gtk_tree_view_column_get_visible (column) &&
8298               gtk_widget_get_can_focus (button))
8299             {
8300               focus_child = button;
8301               gtk_widget_grab_focus (button);
8302               break;
8303             }
8304         }
8305       break;
8306     default:
8307       g_assert_not_reached ();
8308       break;
8309     }
8310
8311   /* if focus child is non-null, we assume it's been set to the current focus child
8312    */
8313   if (focus_child)
8314     {
8315       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
8316         if (gtk_tree_view_column_get_button (GTK_TREE_VIEW_COLUMN (tmp_list->data)) == focus_child)
8317           {
8318             tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
8319             break;
8320           }
8321
8322       if (clamp_column_visible)
8323         {
8324           gtk_tree_view_clamp_column_visible (tree_view,
8325                                               tree_view->priv->focus_column,
8326                                               FALSE);
8327         }
8328     }
8329
8330   return (focus_child != NULL);
8331 }
8332
8333 /* This function returns in 'path' the first focusable path, if the given path
8334  * is already focusable, it's the returned one.
8335  */
8336 static gboolean
8337 search_first_focusable_path (GtkTreeView  *tree_view,
8338                              GtkTreePath **path,
8339                              gboolean      search_forward,
8340                              GtkRBTree   **new_tree,
8341                              GtkRBNode   **new_node)
8342 {
8343   GtkRBTree *tree = NULL;
8344   GtkRBNode *node = NULL;
8345
8346   if (!path || !*path)
8347     return FALSE;
8348
8349   _gtk_tree_view_find_node (tree_view, *path, &tree, &node);
8350
8351   if (!tree || !node)
8352     return FALSE;
8353
8354   while (node && row_is_separator (tree_view, NULL, *path))
8355     {
8356       if (search_forward)
8357         _gtk_rbtree_next_full (tree, node, &tree, &node);
8358       else
8359         _gtk_rbtree_prev_full (tree, node, &tree, &node);
8360
8361       if (*path)
8362         gtk_tree_path_free (*path);
8363
8364       if (node)
8365         *path = _gtk_tree_path_new_from_rbtree (tree, node);
8366       else
8367         *path = NULL;
8368     }
8369
8370   if (new_tree)
8371     *new_tree = tree;
8372
8373   if (new_node)
8374     *new_node = node;
8375
8376   return (*path != NULL);
8377 }
8378
8379 static gint
8380 gtk_tree_view_focus (GtkWidget        *widget,
8381                      GtkDirectionType  direction)
8382 {
8383   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
8384   GtkContainer *container = GTK_CONTAINER (widget);
8385   GtkWidget *focus_child;
8386
8387   if (!gtk_widget_is_sensitive (widget) || !gtk_widget_get_can_focus (widget))
8388     return FALSE;
8389
8390   focus_child = gtk_container_get_focus_child (container);
8391
8392   gtk_tree_view_stop_editing (GTK_TREE_VIEW (widget), FALSE);
8393   /* Case 1.  Headers currently have focus. */
8394   if (focus_child)
8395     {
8396       switch (direction)
8397         {
8398         case GTK_DIR_LEFT:
8399         case GTK_DIR_RIGHT:
8400           gtk_tree_view_header_focus (tree_view, direction, TRUE);
8401           return TRUE;
8402         case GTK_DIR_TAB_BACKWARD:
8403         case GTK_DIR_UP:
8404           return FALSE;
8405         case GTK_DIR_TAB_FORWARD:
8406         case GTK_DIR_DOWN:
8407           gtk_widget_grab_focus (widget);
8408           return TRUE;
8409         default:
8410           g_assert_not_reached ();
8411           return FALSE;
8412         }
8413     }
8414
8415   /* Case 2. We don't have focus at all. */
8416   if (!gtk_widget_has_focus (widget))
8417     {
8418       gtk_widget_grab_focus (widget);
8419       return TRUE;
8420     }
8421
8422   /* Case 3. We have focus already. */
8423   if (direction == GTK_DIR_TAB_BACKWARD)
8424     return (gtk_tree_view_header_focus (tree_view, direction, FALSE));
8425   else if (direction == GTK_DIR_TAB_FORWARD)
8426     return FALSE;
8427
8428   /* Other directions caught by the keybindings */
8429   gtk_widget_grab_focus (widget);
8430   return TRUE;
8431 }
8432
8433 static void
8434 gtk_tree_view_grab_focus (GtkWidget *widget)
8435 {
8436   GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->grab_focus (widget);
8437
8438   gtk_tree_view_focus_to_cursor (GTK_TREE_VIEW (widget));
8439 }
8440
8441 static void
8442 gtk_tree_view_style_updated (GtkWidget *widget)
8443 {
8444   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
8445   GList *list;
8446   GtkTreeViewColumn *column;
8447
8448   GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->style_updated (widget);
8449
8450   if (gtk_widget_get_realized (widget))
8451     {
8452       gtk_tree_view_ensure_background (tree_view);
8453
8454       gtk_tree_view_set_grid_lines (tree_view, tree_view->priv->grid_lines);
8455       gtk_tree_view_set_enable_tree_lines (tree_view, tree_view->priv->tree_lines_enabled);
8456     }
8457
8458   gtk_widget_style_get (widget,
8459                         "expander-size", &tree_view->priv->expander_size,
8460                         NULL);
8461   tree_view->priv->expander_size += EXPANDER_EXTRA_PADDING;
8462
8463   for (list = tree_view->priv->columns; list; list = list->next)
8464     {
8465       column = list->data;
8466       _gtk_tree_view_column_cell_set_dirty (column, TRUE);
8467     }
8468
8469   tree_view->priv->fixed_height = -1;
8470   _gtk_rbtree_mark_invalid (tree_view->priv->tree);
8471
8472   gtk_widget_queue_resize (widget);
8473 }
8474
8475
8476 static void
8477 gtk_tree_view_set_focus_child (GtkContainer *container,
8478                                GtkWidget    *child)
8479 {
8480   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
8481   GList *list;
8482
8483   for (list = tree_view->priv->columns; list; list = list->next)
8484     {
8485       if (gtk_tree_view_column_get_button (GTK_TREE_VIEW_COLUMN (list->data)) == child)
8486         {
8487           tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (list->data);
8488           break;
8489         }
8490     }
8491
8492   GTK_CONTAINER_CLASS (gtk_tree_view_parent_class)->set_focus_child (container, child);
8493 }
8494
8495 static GtkWidgetPath *
8496 gtk_tree_view_get_path_for_child (GtkContainer *container,
8497                                   GtkWidget    *child)
8498 {
8499   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
8500   GtkWidgetPath *path;
8501   gboolean rtl;
8502   GList *list;
8503   gint n_col = 0;
8504
8505   path = GTK_CONTAINER_CLASS (gtk_tree_view_parent_class)->get_path_for_child (container, child);
8506   rtl = (gtk_widget_get_direction (GTK_WIDGET (container)) == GTK_TEXT_DIR_RTL);
8507
8508   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
8509        list;
8510        list = (rtl ? list->prev : list->next))
8511     {
8512       GtkTreeViewColumn *column = list->data;
8513       GtkRegionFlags flags = 0;
8514
8515       if (!gtk_tree_view_column_get_visible (column))
8516         continue;
8517
8518       n_col++;
8519
8520       if (gtk_tree_view_column_get_widget (column) != child &&
8521           gtk_tree_view_column_get_button (column) != child)
8522         continue;
8523
8524       if ((n_col % 2) == 0)
8525         flags |= GTK_REGION_EVEN;
8526       else
8527         flags |= GTK_REGION_ODD;
8528
8529       if (n_col == 1)
8530         flags |= GTK_REGION_FIRST;
8531
8532       if ((rtl && !list->prev) ||
8533           (!rtl && !list->next))
8534         flags |= GTK_REGION_LAST;
8535
8536       gtk_widget_path_iter_add_region (path, -1, GTK_STYLE_REGION_COLUMN_HEADER, flags);
8537       break;
8538     }
8539
8540   gtk_widget_path_append_for_widget (path, child);
8541
8542   return path;
8543 }
8544
8545 static gboolean
8546 gtk_tree_view_real_move_cursor (GtkTreeView       *tree_view,
8547                                 GtkMovementStep    step,
8548                                 gint               count)
8549 {
8550   GdkModifierType state;
8551
8552   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
8553   g_return_val_if_fail (step == GTK_MOVEMENT_LOGICAL_POSITIONS ||
8554                         step == GTK_MOVEMENT_VISUAL_POSITIONS ||
8555                         step == GTK_MOVEMENT_DISPLAY_LINES ||
8556                         step == GTK_MOVEMENT_PAGES ||
8557                         step == GTK_MOVEMENT_BUFFER_ENDS, FALSE);
8558
8559   if (tree_view->priv->tree == NULL)
8560     return FALSE;
8561   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
8562     return FALSE;
8563
8564   gtk_tree_view_stop_editing (tree_view, FALSE);
8565   tree_view->priv->draw_keyfocus = TRUE;
8566   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
8567
8568   if (gtk_get_current_event_state (&state))
8569     {
8570       GdkModifierType extend_mod_mask;
8571       GdkModifierType modify_mod_mask;
8572
8573       extend_mod_mask =
8574         gtk_widget_get_modifier_mask (GTK_WIDGET (tree_view),
8575                                       GDK_MODIFIER_INTENT_EXTEND_SELECTION);
8576
8577       modify_mod_mask =
8578         gtk_widget_get_modifier_mask (GTK_WIDGET (tree_view),
8579                                       GDK_MODIFIER_INTENT_MODIFY_SELECTION);
8580
8581       if ((state & modify_mod_mask) == modify_mod_mask)
8582         tree_view->priv->modify_selection_pressed = TRUE;
8583       if ((state & extend_mod_mask) == extend_mod_mask)
8584         tree_view->priv->extend_selection_pressed = TRUE;
8585     }
8586   /* else we assume not pressed */
8587
8588   switch (step)
8589     {
8590       /* currently we make no distinction.  When we go bi-di, we need to */
8591     case GTK_MOVEMENT_LOGICAL_POSITIONS:
8592     case GTK_MOVEMENT_VISUAL_POSITIONS:
8593       gtk_tree_view_move_cursor_left_right (tree_view, count);
8594       break;
8595     case GTK_MOVEMENT_DISPLAY_LINES:
8596       gtk_tree_view_move_cursor_up_down (tree_view, count);
8597       break;
8598     case GTK_MOVEMENT_PAGES:
8599       gtk_tree_view_move_cursor_page_up_down (tree_view, count);
8600       break;
8601     case GTK_MOVEMENT_BUFFER_ENDS:
8602       gtk_tree_view_move_cursor_start_end (tree_view, count);
8603       break;
8604     default:
8605       g_assert_not_reached ();
8606     }
8607
8608   tree_view->priv->modify_selection_pressed = FALSE;
8609   tree_view->priv->extend_selection_pressed = FALSE;
8610
8611   return TRUE;
8612 }
8613
8614 static void
8615 gtk_tree_view_put (GtkTreeView *tree_view,
8616                    GtkWidget   *child_widget,
8617                    /* in bin_window coordinates */
8618                    gint         x,
8619                    gint         y,
8620                    gint         width,
8621                    gint         height)
8622 {
8623   GtkTreeViewChild *child;
8624   
8625   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8626   g_return_if_fail (GTK_IS_WIDGET (child_widget));
8627
8628   child = g_slice_new (GtkTreeViewChild);
8629
8630   child->widget = child_widget;
8631   child->x = x;
8632   child->y = y;
8633   child->width = width;
8634   child->height = height;
8635
8636   tree_view->priv->children = g_list_append (tree_view->priv->children, child);
8637
8638   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
8639     gtk_widget_set_parent_window (child->widget, tree_view->priv->bin_window);
8640   
8641   gtk_widget_set_parent (child_widget, GTK_WIDGET (tree_view));
8642 }
8643
8644 void
8645 _gtk_tree_view_child_move_resize (GtkTreeView *tree_view,
8646                                   GtkWidget   *widget,
8647                                   /* in tree coordinates */
8648                                   gint         x,
8649                                   gint         y,
8650                                   gint         width,
8651                                   gint         height)
8652 {
8653   GtkTreeViewChild *child = NULL;
8654   GList *list;
8655   GdkRectangle allocation;
8656
8657   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8658   g_return_if_fail (GTK_IS_WIDGET (widget));
8659
8660   for (list = tree_view->priv->children; list; list = list->next)
8661     {
8662       if (((GtkTreeViewChild *)list->data)->widget == widget)
8663         {
8664           child = list->data;
8665           break;
8666         }
8667     }
8668   if (child == NULL)
8669     return;
8670
8671   allocation.x = child->x = x;
8672   allocation.y = child->y = y;
8673   allocation.width = child->width = width;
8674   allocation.height = child->height = height;
8675
8676   if (gtk_widget_get_realized (widget))
8677     gtk_widget_size_allocate (widget, &allocation);
8678 }
8679
8680
8681 /* TreeModel Callbacks
8682  */
8683
8684 static void
8685 gtk_tree_view_row_changed (GtkTreeModel *model,
8686                            GtkTreePath  *path,
8687                            GtkTreeIter  *iter,
8688                            gpointer      data)
8689 {
8690   GtkTreeView *tree_view = (GtkTreeView *)data;
8691   GtkRBTree *tree;
8692   GtkRBNode *node;
8693   gboolean free_path = FALSE;
8694   GList *list;
8695   GtkTreePath *cursor_path;
8696
8697   g_return_if_fail (path != NULL || iter != NULL);
8698
8699   if (tree_view->priv->cursor_node != NULL)
8700     cursor_path = _gtk_tree_path_new_from_rbtree (tree_view->priv->cursor_tree,
8701                                                   tree_view->priv->cursor_node);
8702   else
8703     cursor_path = NULL;
8704
8705   if (tree_view->priv->edited_column &&
8706       (cursor_path == NULL || gtk_tree_path_compare (cursor_path, path) == 0))
8707     gtk_tree_view_stop_editing (tree_view, TRUE);
8708
8709   if (cursor_path != NULL)
8710     gtk_tree_path_free (cursor_path);
8711
8712   if (path == NULL)
8713     {
8714       path = gtk_tree_model_get_path (model, iter);
8715       free_path = TRUE;
8716     }
8717   else if (iter == NULL)
8718     gtk_tree_model_get_iter (model, iter, path);
8719
8720   if (_gtk_tree_view_find_node (tree_view,
8721                                 path,
8722                                 &tree,
8723                                 &node))
8724     /* We aren't actually showing the node */
8725     goto done;
8726
8727   if (tree == NULL)
8728     goto done;
8729
8730   if (tree_view->priv->fixed_height_mode
8731       && tree_view->priv->fixed_height >= 0)
8732     {
8733       _gtk_rbtree_node_set_height (tree, node, tree_view->priv->fixed_height);
8734       if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
8735         gtk_tree_view_node_queue_redraw (tree_view, tree, node);
8736     }
8737   else
8738     {
8739       _gtk_rbtree_node_mark_invalid (tree, node);
8740       for (list = tree_view->priv->columns; list; list = list->next)
8741         {
8742           GtkTreeViewColumn *column;
8743
8744           column = list->data;
8745           if (!gtk_tree_view_column_get_visible (column))
8746             continue;
8747
8748           if (gtk_tree_view_column_get_sizing (column) == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
8749             {
8750               _gtk_tree_view_column_cell_set_dirty (column, TRUE);
8751             }
8752         }
8753     }
8754
8755  done:
8756   if (!tree_view->priv->fixed_height_mode &&
8757       gtk_widget_get_realized (GTK_WIDGET (tree_view)))
8758     install_presize_handler (tree_view);
8759   if (free_path)
8760     gtk_tree_path_free (path);
8761 }
8762
8763 static void
8764 gtk_tree_view_row_inserted (GtkTreeModel *model,
8765                             GtkTreePath  *path,
8766                             GtkTreeIter  *iter,
8767                             gpointer      data)
8768 {
8769   GtkTreeView *tree_view = (GtkTreeView *) data;
8770   gint *indices;
8771   GtkRBTree *tree;
8772   GtkRBNode *tmpnode = NULL;
8773   gint depth;
8774   gint i = 0;
8775   gint height;
8776   gboolean free_path = FALSE;
8777   gboolean node_visible = TRUE;
8778
8779   g_return_if_fail (path != NULL || iter != NULL);
8780
8781   if (tree_view->priv->fixed_height_mode
8782       && tree_view->priv->fixed_height >= 0)
8783     height = tree_view->priv->fixed_height;
8784   else
8785     height = 0;
8786
8787   if (path == NULL)
8788     {
8789       path = gtk_tree_model_get_path (model, iter);
8790       free_path = TRUE;
8791     }
8792   else if (iter == NULL)
8793     gtk_tree_model_get_iter (model, iter, path);
8794
8795   if (tree_view->priv->tree == NULL)
8796     tree_view->priv->tree = _gtk_rbtree_new ();
8797
8798   tree = tree_view->priv->tree;
8799
8800   /* Update all row-references */
8801   gtk_tree_row_reference_inserted (G_OBJECT (data), path);
8802   depth = gtk_tree_path_get_depth (path);
8803   indices = gtk_tree_path_get_indices (path);
8804
8805   /* First, find the parent tree */
8806   while (i < depth - 1)
8807     {
8808       if (tree == NULL)
8809         {
8810           /* We aren't showing the node */
8811           node_visible = FALSE;
8812           goto done;
8813         }
8814
8815       tmpnode = _gtk_rbtree_find_count (tree, indices[i] + 1);
8816       if (tmpnode == NULL)
8817         {
8818           g_warning ("A node was inserted with a parent that's not in the tree.\n" \
8819                      "This possibly means that a GtkTreeModel inserted a child node\n" \
8820                      "before the parent was inserted.");
8821           goto done;
8822         }
8823       else if (!GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_IS_PARENT))
8824         {
8825           /* FIXME enforce correct behavior on model, probably */
8826           /* In theory, the model should have emitted has_child_toggled here.  We
8827            * try to catch it anyway, just to be safe, in case the model hasn't.
8828            */
8829           GtkTreePath *tmppath = _gtk_tree_path_new_from_rbtree (tree, tmpnode);
8830           gtk_tree_view_row_has_child_toggled (model, tmppath, NULL, data);
8831           gtk_tree_path_free (tmppath);
8832           goto done;
8833         }
8834
8835       tree = tmpnode->children;
8836       i++;
8837     }
8838
8839   if (tree == NULL)
8840     {
8841       node_visible = FALSE;
8842       goto done;
8843     }
8844
8845   /* ref the node */
8846   gtk_tree_model_ref_node (tree_view->priv->model, iter);
8847   if (indices[depth - 1] == 0)
8848     {
8849       tmpnode = _gtk_rbtree_find_count (tree, 1);
8850       tmpnode = _gtk_rbtree_insert_before (tree, tmpnode, height, FALSE);
8851     }
8852   else
8853     {
8854       tmpnode = _gtk_rbtree_find_count (tree, indices[depth - 1]);
8855       tmpnode = _gtk_rbtree_insert_after (tree, tmpnode, height, FALSE);
8856     }
8857
8858  done:
8859   if (height > 0)
8860     {
8861       if (tree)
8862         _gtk_rbtree_node_mark_valid (tree, tmpnode);
8863
8864       if (node_visible && node_is_visible (tree_view, tree, tmpnode))
8865         gtk_widget_queue_resize (GTK_WIDGET (tree_view));
8866       else
8867         gtk_widget_queue_resize_no_redraw (GTK_WIDGET (tree_view));
8868     }
8869   else
8870     install_presize_handler (tree_view);
8871   if (free_path)
8872     gtk_tree_path_free (path);
8873 }
8874
8875 static void
8876 gtk_tree_view_row_has_child_toggled (GtkTreeModel *model,
8877                                      GtkTreePath  *path,
8878                                      GtkTreeIter  *iter,
8879                                      gpointer      data)
8880 {
8881   GtkTreeView *tree_view = (GtkTreeView *)data;
8882   GtkTreeIter real_iter;
8883   gboolean has_child;
8884   GtkRBTree *tree;
8885   GtkRBNode *node;
8886   gboolean free_path = FALSE;
8887
8888   g_return_if_fail (path != NULL || iter != NULL);
8889
8890   if (iter)
8891     real_iter = *iter;
8892
8893   if (path == NULL)
8894     {
8895       path = gtk_tree_model_get_path (model, iter);
8896       free_path = TRUE;
8897     }
8898   else if (iter == NULL)
8899     gtk_tree_model_get_iter (model, &real_iter, path);
8900
8901   if (_gtk_tree_view_find_node (tree_view,
8902                                 path,
8903                                 &tree,
8904                                 &node))
8905     /* We aren't actually showing the node */
8906     goto done;
8907
8908   if (tree == NULL)
8909     goto done;
8910
8911   has_child = gtk_tree_model_iter_has_child (model, &real_iter);
8912   /* Sanity check.
8913    */
8914   if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT) == has_child)
8915     goto done;
8916
8917   if (has_child)
8918     GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_PARENT);
8919   else
8920     GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_PARENT);
8921
8922   if (has_child && tree_view->priv->is_list)
8923     {
8924       tree_view->priv->is_list = FALSE;
8925       if (tree_view->priv->show_expanders)
8926         {
8927           GList *list;
8928
8929           for (list = tree_view->priv->columns; list; list = list->next)
8930             if (gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (list->data)))
8931               {
8932                 _gtk_tree_view_column_cell_set_dirty (GTK_TREE_VIEW_COLUMN (list->data), TRUE);
8933                 break;
8934               }
8935         }
8936       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
8937     }
8938   else
8939     {
8940       _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
8941     }
8942
8943  done:
8944   if (free_path)
8945     gtk_tree_path_free (path);
8946 }
8947
8948 static void
8949 count_children_helper (GtkRBTree *tree,
8950                        GtkRBNode *node,
8951                        gpointer   data)
8952 {
8953   if (node->children)
8954     _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, data);
8955   (*((gint *)data))++;
8956 }
8957
8958 static void
8959 check_selection_helper (GtkRBTree *tree,
8960                         GtkRBNode *node,
8961                         gpointer   data)
8962 {
8963   gint *value = (gint *)data;
8964
8965   *value = GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED);
8966
8967   if (node->children && !*value)
8968     _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, check_selection_helper, data);
8969 }
8970
8971 static void
8972 gtk_tree_view_row_deleted (GtkTreeModel *model,
8973                            GtkTreePath  *path,
8974                            gpointer      data)
8975 {
8976   GtkTreeView *tree_view = (GtkTreeView *)data;
8977   GtkRBTree *tree;
8978   GtkRBNode *node;
8979   GList *list;
8980   gint selection_changed = FALSE;
8981   GtkStyleContext *context;
8982
8983   g_return_if_fail (path != NULL);
8984
8985   gtk_tree_row_reference_deleted (G_OBJECT (data), path);
8986
8987   if (_gtk_tree_view_find_node (tree_view, path, &tree, &node))
8988     return;
8989
8990   if (tree == NULL)
8991     return;
8992
8993   /* check if the selection has been changed */
8994   _gtk_rbtree_traverse (tree, node, G_POST_ORDER,
8995                         check_selection_helper, &selection_changed);
8996
8997   for (list = tree_view->priv->columns; list; list = list->next)
8998     if (gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (list->data)) &&
8999         gtk_tree_view_column_get_sizing (GTK_TREE_VIEW_COLUMN (list->data)) == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
9000       _gtk_tree_view_column_cell_set_dirty ((GtkTreeViewColumn *)list->data, TRUE);
9001
9002   /* Ensure we don't have a dangling pointer to a dead node */
9003   ensure_unprelighted (tree_view);
9004
9005   /* Cancel editting if we've started */
9006   gtk_tree_view_stop_editing (tree_view, TRUE);
9007
9008   if (tree_view->priv->destroy_count_func)
9009     {
9010       gint child_count = 0;
9011       if (node->children)
9012         _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, &child_count);
9013       tree_view->priv->destroy_count_func (tree_view, path, child_count, tree_view->priv->destroy_count_data);
9014     }
9015
9016   if (tree->root->count == 1)
9017     {
9018       if (tree_view->priv->tree == tree)
9019         tree_view->priv->tree = NULL;
9020
9021       _gtk_tree_view_accessible_remove (tree_view, tree, NULL);
9022       _gtk_rbtree_remove (tree);
9023     }
9024   else
9025     {
9026       _gtk_tree_view_accessible_remove (tree_view, tree, node);
9027       _gtk_rbtree_remove_node (tree, node);
9028     }
9029
9030   if (! gtk_tree_row_reference_valid (tree_view->priv->top_row))
9031     {
9032       gtk_tree_row_reference_free (tree_view->priv->top_row);
9033       tree_view->priv->top_row = NULL;
9034     }
9035
9036   /* Cancel any ongoing animation happening within the row */
9037   context = gtk_widget_get_style_context (GTK_WIDGET (tree_view));
9038   gtk_style_context_cancel_animations (context, node);
9039
9040   install_scroll_sync_handler (tree_view);
9041
9042   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
9043
9044   if (selection_changed)
9045     g_signal_emit_by_name (tree_view->priv->selection, "changed");
9046 }
9047
9048 static void
9049 gtk_tree_view_rows_reordered (GtkTreeModel *model,
9050                               GtkTreePath  *parent,
9051                               GtkTreeIter  *iter,
9052                               gint         *new_order,
9053                               gpointer      data)
9054 {
9055   GtkTreeView *tree_view = GTK_TREE_VIEW (data);
9056   GtkRBTree *tree;
9057   GtkRBNode *node;
9058   gint len;
9059
9060   len = gtk_tree_model_iter_n_children (model, iter);
9061
9062   if (len < 2)
9063     return;
9064
9065   gtk_tree_row_reference_reordered (G_OBJECT (data),
9066                                     parent,
9067                                     iter,
9068                                     new_order);
9069
9070   if (_gtk_tree_view_find_node (tree_view,
9071                                 parent,
9072                                 &tree,
9073                                 &node))
9074     return;
9075
9076   /* We need to special case the parent path */
9077   if (tree == NULL)
9078     tree = tree_view->priv->tree;
9079   else
9080     tree = node->children;
9081
9082   if (tree == NULL)
9083     return;
9084
9085   if (tree_view->priv->edited_column)
9086     gtk_tree_view_stop_editing (tree_view, TRUE);
9087
9088   /* we need to be unprelighted */
9089   ensure_unprelighted (tree_view);
9090
9091   _gtk_rbtree_reorder (tree, new_order, len);
9092
9093   _gtk_tree_view_accessible_reorder (tree_view);
9094
9095   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
9096
9097   gtk_tree_view_dy_to_top_row (tree_view);
9098 }
9099
9100
9101 /* Internal tree functions
9102  */
9103
9104
9105 static void
9106 gtk_tree_view_get_background_xrange (GtkTreeView       *tree_view,
9107                                      GtkRBTree         *tree,
9108                                      GtkTreeViewColumn *column,
9109                                      gint              *x1,
9110                                      gint              *x2)
9111 {
9112   GtkTreeViewColumn *tmp_column = NULL;
9113   gint total_width;
9114   GList *list;
9115   gboolean rtl;
9116
9117   if (x1)
9118     *x1 = 0;
9119
9120   if (x2)
9121     *x2 = 0;
9122
9123   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
9124
9125   total_width = 0;
9126   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
9127        list;
9128        list = (rtl ? list->prev : list->next))
9129     {
9130       tmp_column = list->data;
9131
9132       if (tmp_column == column)
9133         break;
9134
9135       if (gtk_tree_view_column_get_visible (tmp_column))
9136         total_width += gtk_tree_view_column_get_width (tmp_column);
9137     }
9138
9139   if (tmp_column != column)
9140     {
9141       g_warning (G_STRLOC": passed-in column isn't in the tree");
9142       return;
9143     }
9144
9145   if (x1)
9146     *x1 = total_width;
9147
9148   if (x2)
9149     {
9150       if (gtk_tree_view_column_get_visible (column))
9151         *x2 = total_width + gtk_tree_view_column_get_width (column);
9152       else
9153         *x2 = total_width; /* width of 0 */
9154     }
9155 }
9156
9157 static void
9158 gtk_tree_view_get_arrow_xrange (GtkTreeView *tree_view,
9159                                 GtkRBTree   *tree,
9160                                 gint        *x1,
9161                                 gint        *x2)
9162 {
9163   gint x_offset = 0;
9164   GList *list;
9165   GtkTreeViewColumn *tmp_column = NULL;
9166   gint total_width;
9167   gboolean indent_expanders;
9168   gboolean rtl;
9169
9170   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
9171
9172   total_width = 0;
9173   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
9174        list;
9175        list = (rtl ? list->prev : list->next))
9176     {
9177       tmp_column = list->data;
9178
9179       if (gtk_tree_view_is_expander_column (tree_view, tmp_column))
9180         {
9181           if (rtl)
9182             x_offset = total_width + gtk_tree_view_column_get_width (tmp_column) - tree_view->priv->expander_size;
9183           else
9184             x_offset = total_width;
9185           break;
9186         }
9187
9188       if (gtk_tree_view_column_get_visible (tmp_column))
9189         total_width += gtk_tree_view_column_get_width (tmp_column);
9190     }
9191
9192   gtk_widget_style_get (GTK_WIDGET (tree_view),
9193                         "indent-expanders", &indent_expanders,
9194                         NULL);
9195
9196   if (indent_expanders)
9197     {
9198       if (rtl)
9199         x_offset -= tree_view->priv->expander_size * _gtk_rbtree_get_depth (tree);
9200       else
9201         x_offset += tree_view->priv->expander_size * _gtk_rbtree_get_depth (tree);
9202     }
9203
9204   *x1 = x_offset;
9205
9206   if (tmp_column &&
9207       gtk_tree_view_column_get_visible (tmp_column))
9208     /* +1 because x2 isn't included in the range. */
9209     *x2 = *x1 + tree_view->priv->expander_size + 1;
9210   else
9211     *x2 = *x1;
9212 }
9213
9214 static void
9215 gtk_tree_view_build_tree (GtkTreeView *tree_view,
9216                           GtkRBTree   *tree,
9217                           GtkTreeIter *iter,
9218                           gint         depth,
9219                           gboolean     recurse)
9220 {
9221   GtkRBNode *temp = NULL;
9222   GtkTreePath *path = NULL;
9223
9224   do
9225     {
9226       gtk_tree_model_ref_node (tree_view->priv->model, iter);
9227       temp = _gtk_rbtree_insert_after (tree, temp, 0, FALSE);
9228
9229       if (tree_view->priv->fixed_height > 0)
9230         {
9231           if (GTK_RBNODE_FLAG_SET (temp, GTK_RBNODE_INVALID))
9232             {
9233               _gtk_rbtree_node_set_height (tree, temp, tree_view->priv->fixed_height);
9234               _gtk_rbtree_node_mark_valid (tree, temp);
9235             }
9236         }
9237
9238       if (tree_view->priv->is_list)
9239         continue;
9240
9241       if (recurse)
9242         {
9243           GtkTreeIter child;
9244
9245           if (!path)
9246             path = gtk_tree_model_get_path (tree_view->priv->model, iter);
9247           else
9248             gtk_tree_path_next (path);
9249
9250           if (gtk_tree_model_iter_children (tree_view->priv->model, &child, iter))
9251             {
9252               gboolean expand;
9253
9254               g_signal_emit (tree_view, tree_view_signals[TEST_EXPAND_ROW], 0, iter, path, &expand);
9255
9256               if (gtk_tree_model_iter_has_child (tree_view->priv->model, iter)
9257                   && !expand)
9258                 {
9259                   temp->children = _gtk_rbtree_new ();
9260                   temp->children->parent_tree = tree;
9261                   temp->children->parent_node = temp;
9262                   gtk_tree_view_build_tree (tree_view, temp->children, &child, depth + 1, recurse);
9263                 }
9264             }
9265         }
9266
9267       if (gtk_tree_model_iter_has_child (tree_view->priv->model, iter))
9268         {
9269           if ((temp->flags&GTK_RBNODE_IS_PARENT) != GTK_RBNODE_IS_PARENT)
9270             temp->flags ^= GTK_RBNODE_IS_PARENT;
9271         }
9272     }
9273   while (gtk_tree_model_iter_next (tree_view->priv->model, iter));
9274
9275   if (path)
9276     gtk_tree_path_free (path);
9277 }
9278
9279 /* Make sure the node is visible vertically */
9280 static void
9281 gtk_tree_view_clamp_node_visible (GtkTreeView *tree_view,
9282                                   GtkRBTree   *tree,
9283                                   GtkRBNode   *node)
9284 {
9285   gint node_dy, height;
9286   GtkTreePath *path = NULL;
9287
9288   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
9289     return;
9290
9291   /* just return if the node is visible, avoiding a costly expose */
9292   node_dy = _gtk_rbtree_node_find_offset (tree, node);
9293   height = gtk_tree_view_get_row_height (tree_view, node);
9294   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID)
9295       && node_dy >= gtk_adjustment_get_value (tree_view->priv->vadjustment)
9296       && node_dy + height <= (gtk_adjustment_get_value (tree_view->priv->vadjustment)
9297                               + gtk_adjustment_get_page_size (tree_view->priv->vadjustment)))
9298     return;
9299
9300   path = _gtk_tree_path_new_from_rbtree (tree, node);
9301   if (path)
9302     {
9303       /* We process updates because we want to clear old selected items when we scroll.
9304        * if this is removed, we get a "selection streak" at the bottom. */
9305       gtk_tree_view_bin_process_updates (tree_view);
9306
9307       gtk_tree_view_scroll_to_cell (tree_view, path, NULL, FALSE, 0.0, 0.0);
9308       gtk_tree_path_free (path);
9309     }
9310 }
9311
9312 static void
9313 gtk_tree_view_clamp_column_visible (GtkTreeView       *tree_view,
9314                                     GtkTreeViewColumn *column,
9315                                     gboolean           focus_to_cell)
9316 {
9317   GtkAllocation allocation;
9318   gint x, width;
9319
9320   if (column == NULL)
9321     return;
9322
9323   gtk_widget_get_allocation (gtk_tree_view_column_get_button (column), &allocation);
9324   x = allocation.x;
9325   width = allocation.width;
9326
9327   if (width > gtk_adjustment_get_page_size (tree_view->priv->hadjustment))
9328     {
9329       /* The column is larger than the horizontal page size.  If the
9330        * column has cells which can be focussed individually, then we make
9331        * sure the cell which gets focus is fully visible (if even the
9332        * focus cell is bigger than the page size, we make sure the
9333        * left-hand side of the cell is visible).
9334        *
9335        * If the column does not have an activatable cell, we
9336        * make sure the left-hand side of the column is visible.
9337        */
9338
9339       if (focus_to_cell && gtk_tree_view_has_can_focus_cell (tree_view))
9340         {
9341           GtkCellArea *cell_area;
9342           GtkCellRenderer *focus_cell;
9343
9344           cell_area = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (column));
9345           focus_cell = gtk_cell_area_get_focus_cell (cell_area);
9346
9347           if (gtk_tree_view_column_cell_get_position (column, focus_cell,
9348                                                       &x, &width))
9349             {
9350               if (width < gtk_adjustment_get_page_size (tree_view->priv->hadjustment))
9351                 {
9352                   if (gtk_adjustment_get_value (tree_view->priv->hadjustment) + gtk_adjustment_get_page_size (tree_view->priv->hadjustment) < x + width)
9353                     gtk_adjustment_set_value (tree_view->priv->hadjustment,
9354                                               x + width - gtk_adjustment_get_page_size (tree_view->priv->hadjustment));
9355                   else if (gtk_adjustment_get_value (tree_view->priv->hadjustment) > x)
9356                     gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
9357                 }
9358             }
9359         }
9360
9361       gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
9362     }
9363   else
9364     {
9365       if ((gtk_adjustment_get_value (tree_view->priv->hadjustment) + gtk_adjustment_get_page_size (tree_view->priv->hadjustment)) < (x + width))
9366           gtk_adjustment_set_value (tree_view->priv->hadjustment,
9367                                     x + width - gtk_adjustment_get_page_size (tree_view->priv->hadjustment));
9368       else if (gtk_adjustment_get_value (tree_view->priv->hadjustment) > x)
9369         gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
9370   }
9371 }
9372
9373 /* This function could be more efficient.  I'll optimize it if profiling seems
9374  * to imply that it is important */
9375 GtkTreePath *
9376 _gtk_tree_path_new_from_rbtree (GtkRBTree   *tree,
9377                                 GtkRBNode   *node)
9378 {
9379   GtkTreePath *path;
9380   GtkRBTree *tmp_tree;
9381   GtkRBNode *tmp_node, *last;
9382   gint count;
9383
9384   path = gtk_tree_path_new ();
9385
9386   g_return_val_if_fail (node != NULL, path);
9387
9388   count = 1 + node->left->count;
9389
9390   last = node;
9391   tmp_node = node->parent;
9392   tmp_tree = tree;
9393   while (tmp_tree)
9394     {
9395       while (!_gtk_rbtree_is_nil (tmp_node))
9396         {
9397           if (tmp_node->right == last)
9398             count += 1 + tmp_node->left->count;
9399           last = tmp_node;
9400           tmp_node = tmp_node->parent;
9401         }
9402       gtk_tree_path_prepend_index (path, count - 1);
9403       last = tmp_tree->parent_node;
9404       tmp_tree = tmp_tree->parent_tree;
9405       if (last)
9406         {
9407           count = 1 + last->left->count;
9408           tmp_node = last->parent;
9409         }
9410     }
9411   return path;
9412 }
9413
9414 /* Returns TRUE if we ran out of tree before finding the path.  If the path is
9415  * invalid (ie. points to a node that's not in the tree), *tree and *node are
9416  * both set to NULL.
9417  */
9418 gboolean
9419 _gtk_tree_view_find_node (GtkTreeView  *tree_view,
9420                           GtkTreePath  *path,
9421                           GtkRBTree   **tree,
9422                           GtkRBNode   **node)
9423 {
9424   GtkRBNode *tmpnode = NULL;
9425   GtkRBTree *tmptree = tree_view->priv->tree;
9426   gint *indices = gtk_tree_path_get_indices (path);
9427   gint depth = gtk_tree_path_get_depth (path);
9428   gint i = 0;
9429
9430   *node = NULL;
9431   *tree = NULL;
9432
9433   if (depth == 0 || tmptree == NULL)
9434     return FALSE;
9435   do
9436     {
9437       tmpnode = _gtk_rbtree_find_count (tmptree, indices[i] + 1);
9438       ++i;
9439       if (tmpnode == NULL)
9440         {
9441           *tree = NULL;
9442           *node = NULL;
9443           return FALSE;
9444         }
9445       if (i >= depth)
9446         {
9447           *tree = tmptree;
9448           *node = tmpnode;
9449           return FALSE;
9450         }
9451       *tree = tmptree;
9452       *node = tmpnode;
9453       tmptree = tmpnode->children;
9454       if (tmptree == NULL)
9455         return TRUE;
9456     }
9457   while (1);
9458 }
9459
9460 static gboolean
9461 gtk_tree_view_is_expander_column (GtkTreeView       *tree_view,
9462                                   GtkTreeViewColumn *column)
9463 {
9464   GList *list;
9465
9466   if (tree_view->priv->is_list)
9467     return FALSE;
9468
9469   if (tree_view->priv->expander_column != NULL)
9470     {
9471       if (tree_view->priv->expander_column == column)
9472         return TRUE;
9473       return FALSE;
9474     }
9475   else
9476     {
9477       for (list = tree_view->priv->columns;
9478            list;
9479            list = list->next)
9480         if (gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (list->data)))
9481           break;
9482       if (list && list->data == column)
9483         return TRUE;
9484     }
9485   return FALSE;
9486 }
9487
9488 static inline gboolean
9489 gtk_tree_view_draw_expanders (GtkTreeView *tree_view)
9490 {
9491   if (!tree_view->priv->is_list && tree_view->priv->show_expanders)
9492     return TRUE;
9493   /* else */
9494   return FALSE;
9495 }
9496
9497 static void
9498 gtk_tree_view_add_move_binding (GtkBindingSet  *binding_set,
9499                                 guint           keyval,
9500                                 guint           modmask,
9501                                 gboolean        add_shifted_binding,
9502                                 GtkMovementStep step,
9503                                 gint            count)
9504 {
9505   
9506   gtk_binding_entry_add_signal (binding_set, keyval, modmask,
9507                                 "move-cursor", 2,
9508                                 G_TYPE_ENUM, step,
9509                                 G_TYPE_INT, count);
9510
9511   if (add_shifted_binding)
9512     gtk_binding_entry_add_signal (binding_set, keyval, GDK_SHIFT_MASK,
9513                                   "move-cursor", 2,
9514                                   G_TYPE_ENUM, step,
9515                                   G_TYPE_INT, count);
9516
9517   if ((modmask & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
9518    return;
9519
9520   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK | GDK_SHIFT_MASK,
9521                                 "move-cursor", 2,
9522                                 G_TYPE_ENUM, step,
9523                                 G_TYPE_INT, count);
9524
9525   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK,
9526                                 "move-cursor", 2,
9527                                 G_TYPE_ENUM, step,
9528                                 G_TYPE_INT, count);
9529 }
9530
9531 static gint
9532 gtk_tree_view_unref_tree_helper (GtkTreeModel *model,
9533                                  GtkTreeIter  *iter,
9534                                  GtkRBTree    *tree,
9535                                  GtkRBNode    *node)
9536 {
9537   gint retval = FALSE;
9538   do
9539     {
9540       g_return_val_if_fail (node != NULL, FALSE);
9541
9542       if (node->children)
9543         {
9544           GtkTreeIter child;
9545           GtkRBTree *new_tree;
9546           GtkRBNode *new_node;
9547
9548           new_tree = node->children;
9549           new_node = _gtk_rbtree_first (new_tree);
9550
9551           if (!gtk_tree_model_iter_children (model, &child, iter))
9552             return FALSE;
9553
9554           retval = retval || gtk_tree_view_unref_tree_helper (model, &child, new_tree, new_node);
9555         }
9556
9557       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
9558         retval = TRUE;
9559       gtk_tree_model_unref_node (model, iter);
9560       node = _gtk_rbtree_next (tree, node);
9561     }
9562   while (gtk_tree_model_iter_next (model, iter));
9563
9564   return retval;
9565 }
9566
9567 static gint
9568 gtk_tree_view_unref_and_check_selection_tree (GtkTreeView *tree_view,
9569                                               GtkRBTree   *tree)
9570 {
9571   GtkTreeIter iter;
9572   GtkTreePath *path;
9573   GtkRBNode *node;
9574   gint retval;
9575
9576   if (!tree)
9577     return FALSE;
9578
9579   node = _gtk_rbtree_first (tree);
9580
9581   g_return_val_if_fail (node != NULL, FALSE);
9582   path = _gtk_tree_path_new_from_rbtree (tree, node);
9583   gtk_tree_model_get_iter (GTK_TREE_MODEL (tree_view->priv->model),
9584                            &iter, path);
9585   retval = gtk_tree_view_unref_tree_helper (GTK_TREE_MODEL (tree_view->priv->model), &iter, tree, node);
9586   gtk_tree_path_free (path);
9587
9588   return retval;
9589 }
9590
9591 static void
9592 gtk_tree_view_set_column_drag_info (GtkTreeView       *tree_view,
9593                                     GtkTreeViewColumn *column)
9594 {
9595   GtkTreeViewColumn *left_column;
9596   GtkTreeViewColumn *cur_column = NULL;
9597   GtkTreeViewColumnReorder *reorder;
9598   gboolean rtl;
9599   GList *tmp_list;
9600   gint left;
9601
9602   /* We want to precalculate the motion list such that we know what column slots
9603    * are available.
9604    */
9605   left_column = NULL;
9606   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
9607
9608   /* First, identify all possible drop spots */
9609   if (rtl)
9610     tmp_list = g_list_last (tree_view->priv->columns);
9611   else
9612     tmp_list = g_list_first (tree_view->priv->columns);
9613
9614   while (tmp_list)
9615     {
9616       cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
9617       tmp_list = rtl?g_list_previous (tmp_list):g_list_next (tmp_list);
9618
9619       if (gtk_tree_view_column_get_visible (cur_column) == FALSE)
9620         continue;
9621
9622       /* If it's not the column moving and func tells us to skip over the column, we continue. */
9623       if (left_column != column && cur_column != column &&
9624           tree_view->priv->column_drop_func &&
9625           ! tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
9626         {
9627           left_column = cur_column;
9628           continue;
9629         }
9630       reorder = g_slice_new0 (GtkTreeViewColumnReorder);
9631       reorder->left_column = left_column;
9632       left_column = reorder->right_column = cur_column;
9633
9634       tree_view->priv->column_drag_info = g_list_append (tree_view->priv->column_drag_info, reorder);
9635     }
9636
9637   /* Add the last one */
9638   if (tree_view->priv->column_drop_func == NULL ||
9639       ((left_column != column) &&
9640        tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data)))
9641     {
9642       reorder = g_slice_new0 (GtkTreeViewColumnReorder);
9643       reorder->left_column = left_column;
9644       reorder->right_column = NULL;
9645       tree_view->priv->column_drag_info = g_list_append (tree_view->priv->column_drag_info, reorder);
9646     }
9647
9648   /* We quickly check to see if it even makes sense to reorder columns. */
9649   /* If there is nothing that can be moved, then we return */
9650
9651   if (tree_view->priv->column_drag_info == NULL)
9652     return;
9653
9654   /* We know there are always 2 slots possbile, as you can always return column. */
9655   /* If that's all there is, return */
9656   if (tree_view->priv->column_drag_info->next == NULL || 
9657       (tree_view->priv->column_drag_info->next->next == NULL &&
9658        ((GtkTreeViewColumnReorder *)tree_view->priv->column_drag_info->data)->right_column == column &&
9659        ((GtkTreeViewColumnReorder *)tree_view->priv->column_drag_info->next->data)->left_column == column))
9660     {
9661       for (tmp_list = tree_view->priv->column_drag_info; tmp_list; tmp_list = tmp_list->next)
9662         g_slice_free (GtkTreeViewColumnReorder, tmp_list->data);
9663       g_list_free (tree_view->priv->column_drag_info);
9664       tree_view->priv->column_drag_info = NULL;
9665       return;
9666     }
9667   /* We fill in the ranges for the columns, now that we've isolated them */
9668   left = - TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER (tree_view);
9669
9670   for (tmp_list = tree_view->priv->column_drag_info; tmp_list; tmp_list = tmp_list->next)
9671     {
9672       reorder = (GtkTreeViewColumnReorder *) tmp_list->data;
9673
9674       reorder->left_align = left;
9675       if (tmp_list->next != NULL)
9676         {
9677           GtkAllocation right_allocation, left_allocation;
9678           GtkWidget    *left_button, *right_button;
9679
9680           g_assert (tmp_list->next->data);
9681
9682           right_button = gtk_tree_view_column_get_button (reorder->right_column);
9683           left_button  = gtk_tree_view_column_get_button
9684             (((GtkTreeViewColumnReorder *)tmp_list->next->data)->left_column);
9685
9686           gtk_widget_get_allocation (right_button, &right_allocation);
9687           gtk_widget_get_allocation (left_button, &left_allocation);
9688           left = reorder->right_align = (right_allocation.x + right_allocation.width + left_allocation.x) / 2;
9689         }
9690       else
9691         {
9692           reorder->right_align = gdk_window_get_width (tree_view->priv->header_window)
9693                                  + TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER (tree_view);
9694         }
9695     }
9696 }
9697
9698 void
9699 _gtk_tree_view_column_start_drag (GtkTreeView       *tree_view,
9700                                   GtkTreeViewColumn *column,
9701                                   GdkDevice         *device)
9702 {
9703   GdkEvent *send_event;
9704   GtkAllocation allocation;
9705   GtkAllocation button_allocation;
9706   GdkScreen *screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
9707   GtkWidget *button;
9708   GdkDevice *pointer, *keyboard;
9709
9710   g_return_if_fail (tree_view->priv->column_drag_info == NULL);
9711   g_return_if_fail (tree_view->priv->cur_reorder == NULL);
9712
9713   gtk_tree_view_set_column_drag_info (tree_view, column);
9714
9715   if (tree_view->priv->column_drag_info == NULL)
9716     return;
9717
9718   button = gtk_tree_view_column_get_button (column);
9719
9720   if (tree_view->priv->drag_window == NULL)
9721     {
9722       GdkWindowAttr attributes;
9723       guint attributes_mask;
9724
9725       gtk_widget_get_allocation (button, &button_allocation);
9726
9727       attributes.window_type = GDK_WINDOW_CHILD;
9728       attributes.wclass = GDK_INPUT_OUTPUT;
9729       attributes.x = button_allocation.x;
9730       attributes.y = 0;
9731       attributes.width = button_allocation.width;
9732       attributes.height = button_allocation.height;
9733       attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
9734       attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
9735       attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
9736
9737       tree_view->priv->drag_window = gdk_window_new (tree_view->priv->bin_window,
9738                                                      &attributes,
9739                                                      attributes_mask);
9740       gdk_window_set_user_data (tree_view->priv->drag_window, GTK_WIDGET (tree_view));
9741     }
9742
9743   if (gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD)
9744     {
9745       keyboard = device;
9746       pointer = gdk_device_get_associated_device (device);
9747     }
9748   else
9749     {
9750       pointer = device;
9751       keyboard = gdk_device_get_associated_device (device);
9752     }
9753
9754   gdk_device_ungrab (pointer, GDK_CURRENT_TIME);
9755   gdk_device_ungrab (keyboard, GDK_CURRENT_TIME);
9756
9757   gtk_grab_remove (button);
9758
9759   send_event = gdk_event_new (GDK_LEAVE_NOTIFY);
9760   send_event->crossing.send_event = TRUE;
9761   send_event->crossing.window = g_object_ref (gtk_button_get_event_window (GTK_BUTTON (button)));
9762   send_event->crossing.subwindow = NULL;
9763   send_event->crossing.detail = GDK_NOTIFY_ANCESTOR;
9764   send_event->crossing.time = GDK_CURRENT_TIME;
9765   gdk_event_set_device (send_event, device);
9766
9767   gtk_propagate_event (button, send_event);
9768   gdk_event_free (send_event);
9769
9770   send_event = gdk_event_new (GDK_BUTTON_RELEASE);
9771   send_event->button.window = g_object_ref (gdk_screen_get_root_window (screen));
9772   send_event->button.send_event = TRUE;
9773   send_event->button.time = GDK_CURRENT_TIME;
9774   send_event->button.x = -1;
9775   send_event->button.y = -1;
9776   send_event->button.axes = NULL;
9777   send_event->button.state = 0;
9778   send_event->button.button = 1;
9779   send_event->button.x_root = 0;
9780   send_event->button.y_root = 0;
9781   gdk_event_set_device (send_event, device);
9782
9783   gtk_propagate_event (button, send_event);
9784   gdk_event_free (send_event);
9785
9786   /* Kids, don't try this at home */
9787   g_object_ref (button);
9788   gtk_container_remove (GTK_CONTAINER (tree_view), button);
9789   gtk_widget_set_parent_window (button, tree_view->priv->drag_window);
9790   gtk_widget_set_parent (button, GTK_WIDGET (tree_view));
9791   g_object_unref (button);
9792
9793   gtk_widget_get_allocation (button, &button_allocation);
9794   tree_view->priv->drag_column_x = button_allocation.x;
9795   allocation = button_allocation;
9796   allocation.x = 0;
9797   gtk_widget_size_allocate (button, &allocation);
9798   gtk_widget_set_parent_window (button, tree_view->priv->drag_window);
9799
9800   tree_view->priv->drag_column = column;
9801   gdk_window_show (tree_view->priv->drag_window);
9802
9803   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
9804   while (gtk_events_pending ())
9805     gtk_main_iteration ();
9806
9807   tree_view->priv->in_column_drag = TRUE;
9808
9809   gdk_device_grab (pointer,
9810                    tree_view->priv->drag_window,
9811                    GDK_OWNERSHIP_NONE,
9812                    FALSE,
9813                    GDK_POINTER_MOTION_MASK|GDK_BUTTON_RELEASE_MASK,
9814                    NULL,
9815                    GDK_CURRENT_TIME);
9816   gdk_device_grab (keyboard,
9817                    tree_view->priv->drag_window,
9818                    GDK_OWNERSHIP_NONE,
9819                    FALSE,
9820                    GDK_KEY_PRESS_MASK|GDK_KEY_RELEASE_MASK,
9821                    NULL,
9822                    GDK_CURRENT_TIME);
9823 }
9824
9825 static void
9826 gtk_tree_view_queue_draw_arrow (GtkTreeView        *tree_view,
9827                                 GtkRBTree          *tree,
9828                                 GtkRBNode          *node)
9829 {
9830   GtkAllocation allocation;
9831   GdkRectangle rect;
9832
9833   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
9834     return;
9835
9836   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
9837   rect.x = 0;
9838   rect.width = MAX (tree_view->priv->expander_size, MAX (tree_view->priv->width, allocation.width));
9839
9840   rect.y = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
9841   rect.height = gtk_tree_view_get_row_height (tree_view, node);
9842
9843   gdk_window_invalidate_rect (tree_view->priv->bin_window, &rect, TRUE);
9844 }
9845
9846 void
9847 _gtk_tree_view_queue_draw_node (GtkTreeView        *tree_view,
9848                                 GtkRBTree          *tree,
9849                                 GtkRBNode          *node,
9850                                 const GdkRectangle *clip_rect)
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 = MAX (tree_view->priv->width, allocation.width);
9861
9862   rect.y = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
9863   rect.height = gtk_tree_view_get_row_height (tree_view, node);
9864
9865   if (clip_rect)
9866     {
9867       GdkRectangle new_rect;
9868
9869       gdk_rectangle_intersect (clip_rect, &rect, &new_rect);
9870
9871       gdk_window_invalidate_rect (tree_view->priv->bin_window, &new_rect, TRUE);
9872     }
9873   else
9874     {
9875       gdk_window_invalidate_rect (tree_view->priv->bin_window, &rect, TRUE);
9876     }
9877 }
9878
9879 static inline gint
9880 gtk_tree_view_get_effective_header_height (GtkTreeView *tree_view)
9881 {
9882   if (tree_view->priv->headers_visible)
9883     return tree_view->priv->header_height;
9884   /* else */
9885   return 0;
9886 }
9887
9888 gint
9889 _gtk_tree_view_get_header_height (GtkTreeView *tree_view)
9890 {
9891   return tree_view->priv->header_height;
9892 }
9893
9894 void
9895 _gtk_tree_view_get_row_separator_func (GtkTreeView                 *tree_view,
9896                                        GtkTreeViewRowSeparatorFunc *func,
9897                                        gpointer                    *data)
9898 {
9899   *func = tree_view->priv->row_separator_func;
9900   *data = tree_view->priv->row_separator_data;
9901 }
9902
9903 GtkTreePath *
9904 _gtk_tree_view_get_anchor_path (GtkTreeView *tree_view)
9905 {
9906   if (tree_view->priv->anchor)
9907     return gtk_tree_row_reference_get_path (tree_view->priv->anchor);
9908
9909   return NULL;
9910 }
9911
9912 void
9913 _gtk_tree_view_set_anchor_path (GtkTreeView *tree_view,
9914                                 GtkTreePath *anchor_path)
9915 {
9916   if (tree_view->priv->anchor)
9917     {
9918       gtk_tree_row_reference_free (tree_view->priv->anchor);
9919       tree_view->priv->anchor = NULL;
9920     }
9921
9922   if (anchor_path && tree_view->priv->model)
9923     tree_view->priv->anchor =
9924       gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), 
9925                                         tree_view->priv->model, anchor_path);
9926 }
9927
9928 GtkRBTree *
9929 _gtk_tree_view_get_rbtree (GtkTreeView *tree_view)
9930 {
9931   return tree_view->priv->tree;
9932 }
9933
9934 GdkWindow *
9935 _gtk_tree_view_get_header_window (GtkTreeView *tree_view)
9936 {
9937   return tree_view->priv->header_window;
9938 }
9939
9940 void
9941 _gtk_tree_view_set_focus_column (GtkTreeView       *tree_view,
9942                                  GtkTreeViewColumn *column)
9943 {
9944   tree_view->priv->focus_column = column;
9945 }
9946
9947
9948 static void
9949 gtk_tree_view_queue_draw_path (GtkTreeView        *tree_view,
9950                                GtkTreePath        *path,
9951                                const GdkRectangle *clip_rect)
9952 {
9953   GtkRBTree *tree = NULL;
9954   GtkRBNode *node = NULL;
9955
9956   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
9957
9958   if (tree)
9959     _gtk_tree_view_queue_draw_node (tree_view, tree, node, clip_rect);
9960 }
9961
9962 /* x and y are the mouse position
9963  */
9964 static void
9965 gtk_tree_view_draw_arrow (GtkTreeView *tree_view,
9966                           cairo_t     *cr,
9967                           GtkRBTree   *tree,
9968                           GtkRBNode   *node)
9969 {
9970   GdkRectangle area;
9971   GtkStateFlags state = 0;
9972   GtkStyleContext *context;
9973   GtkWidget *widget;
9974   gint x_offset = 0;
9975   gint x2;
9976   gint vertical_separator;
9977   gint expander_size;
9978   GtkCellRendererState flags;
9979
9980   widget = GTK_WIDGET (tree_view);
9981   context = gtk_widget_get_style_context (widget);
9982
9983   gtk_widget_style_get (widget,
9984                         "vertical-separator", &vertical_separator,
9985                         NULL);
9986   expander_size = tree_view->priv->expander_size - EXPANDER_EXTRA_PADDING;
9987
9988   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
9989     return;
9990
9991   gtk_tree_view_get_arrow_xrange (tree_view, tree, &x_offset, &x2);
9992
9993   area.x = x_offset;
9994   area.y = gtk_tree_view_get_cell_area_y_offset (tree_view, tree, node,
9995                                                  vertical_separator);
9996   area.width = expander_size;
9997   area.height = gtk_tree_view_get_cell_area_height (tree_view, node,
9998                                                     vertical_separator);
9999
10000   if (!gtk_widget_get_sensitive (widget))
10001     state |= GTK_STATE_FLAG_INSENSITIVE;
10002   else
10003     {
10004       flags = 0;
10005
10006       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
10007         flags |= GTK_CELL_RENDERER_SELECTED;
10008
10009       state = gtk_cell_renderer_get_state (NULL, widget, flags);
10010
10011       if (node == tree_view->priv->prelight_node &&
10012           tree_view->priv->arrow_prelit)
10013         state |= GTK_STATE_FLAG_PRELIGHT;
10014     }
10015
10016   if (node->children != NULL)
10017     state |= GTK_STATE_FLAG_ACTIVE;
10018
10019   gtk_style_context_save (context);
10020
10021   gtk_style_context_set_state (context, state);
10022   gtk_style_context_add_class (context, GTK_STYLE_CLASS_EXPANDER);
10023
10024   gtk_style_context_push_animatable_region (context, node);
10025
10026   gtk_render_expander (context, cr,
10027                        area.x, area.y,
10028                        area.width, area.height);
10029
10030   gtk_style_context_pop_animatable_region (context);
10031   gtk_style_context_restore (context);
10032 }
10033
10034 static void
10035 gtk_tree_view_focus_to_cursor (GtkTreeView *tree_view)
10036
10037 {
10038   GtkTreePath *cursor_path;
10039
10040   if ((tree_view->priv->tree == NULL) ||
10041       (! gtk_widget_get_realized (GTK_WIDGET (tree_view))))
10042     return;
10043
10044   cursor_path = NULL;
10045   if (tree_view->priv->cursor_node)
10046     cursor_path = _gtk_tree_path_new_from_rbtree (tree_view->priv->cursor_tree,
10047                                                   tree_view->priv->cursor_node);
10048
10049   if (cursor_path == NULL)
10050     {
10051       /* Consult the selection before defaulting to the
10052        * first focusable element
10053        */
10054       GList *selected_rows;
10055       GtkTreeModel *model;
10056       GtkTreeSelection *selection;
10057
10058       selection = gtk_tree_view_get_selection (tree_view);
10059       selected_rows = gtk_tree_selection_get_selected_rows (selection, &model);
10060
10061       if (selected_rows)
10062         {
10063           cursor_path = gtk_tree_path_copy((const GtkTreePath *)(selected_rows->data));
10064           g_list_foreach (selected_rows, (GFunc)gtk_tree_path_free, NULL);
10065           g_list_free (selected_rows);
10066         }
10067       else
10068         {
10069           cursor_path = gtk_tree_path_new_first ();
10070           search_first_focusable_path (tree_view, &cursor_path,
10071                                        TRUE, NULL, NULL);
10072         }
10073
10074       if (cursor_path)
10075         {
10076           if (gtk_tree_selection_get_mode (tree_view->priv->selection) == GTK_SELECTION_MULTIPLE)
10077             gtk_tree_view_real_set_cursor (tree_view, cursor_path, FALSE, FALSE);
10078           else
10079             gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE);
10080         }
10081     }
10082
10083   if (cursor_path)
10084     {
10085       tree_view->priv->draw_keyfocus = TRUE;
10086
10087       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10088       gtk_tree_path_free (cursor_path);
10089
10090       if (tree_view->priv->focus_column == NULL)
10091         {
10092           GList *list;
10093           for (list = tree_view->priv->columns; list; list = list->next)
10094             {
10095               if (gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (list->data)))
10096                 {
10097                   GtkCellArea *cell_area;
10098
10099                   tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (list->data);
10100
10101                   /* This happens when the treeview initially grabs focus and there
10102                    * is no column in focus, here we explicitly focus into the first cell */
10103                   cell_area = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (tree_view->priv->focus_column));
10104                   if (!gtk_cell_area_get_focus_cell (cell_area))
10105                     {
10106                       gboolean rtl;
10107
10108                       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
10109                       gtk_cell_area_focus (cell_area,
10110                                            rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT);
10111                     }
10112
10113                   break;
10114                 }
10115             }
10116         }
10117     }
10118 }
10119
10120 static void
10121 gtk_tree_view_move_cursor_up_down (GtkTreeView *tree_view,
10122                                    gint         count)
10123 {
10124   gint selection_count;
10125   GtkRBTree *new_cursor_tree = NULL;
10126   GtkRBNode *new_cursor_node = NULL;
10127   GtkTreePath *cursor_path = NULL;
10128   gboolean grab_focus = TRUE;
10129   gboolean selectable;
10130   GtkDirectionType direction;
10131   GtkCellArea *cell_area = NULL;
10132   GtkCellRenderer *last_focus_cell = NULL;
10133   GtkTreeIter iter;
10134
10135   if (! gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10136     return;
10137
10138   if (tree_view->priv->cursor_node == NULL)
10139     return;
10140
10141   cursor_path = _gtk_tree_path_new_from_rbtree (tree_view->priv->cursor_tree,
10142                                                 tree_view->priv->cursor_node);
10143
10144   direction = count < 0 ? GTK_DIR_UP : GTK_DIR_DOWN;
10145
10146   if (tree_view->priv->focus_column)
10147     cell_area = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (tree_view->priv->focus_column));
10148
10149   /* If focus stays in the area for this row, then just return for this round */
10150   if (cell_area && (count == -1 || count == 1) &&
10151       gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path))
10152     {
10153       gtk_tree_view_column_cell_set_cell_data (tree_view->priv->focus_column,
10154                                                tree_view->priv->model,
10155                                                &iter,
10156                                                GTK_RBNODE_FLAG_SET (tree_view->priv->cursor_node, GTK_RBNODE_IS_PARENT),
10157                                                tree_view->priv->cursor_node->children ? TRUE : FALSE);
10158
10159       /* Save the last cell that had focus, if we hit the end of the view we'll give
10160        * focus back to it. */
10161       last_focus_cell = gtk_cell_area_get_focus_cell (cell_area);
10162
10163       /* If focus stays in the area, no need to change the cursor row */
10164       if (gtk_cell_area_focus (cell_area, direction))
10165         return;
10166     }
10167
10168   selection_count = gtk_tree_selection_count_selected_rows (tree_view->priv->selection);
10169   selectable = _gtk_tree_selection_row_is_selectable (tree_view->priv->selection,
10170                                                       tree_view->priv->cursor_node,
10171                                                       cursor_path);
10172
10173   if (selection_count == 0
10174       && gtk_tree_selection_get_mode (tree_view->priv->selection) != GTK_SELECTION_NONE
10175       && !tree_view->priv->modify_selection_pressed
10176       && selectable)
10177     {
10178       /* Don't move the cursor, but just select the current node */
10179       new_cursor_tree = tree_view->priv->cursor_tree;
10180       new_cursor_node = tree_view->priv->cursor_node;
10181     }
10182   else
10183     {
10184       if (count == -1)
10185         _gtk_rbtree_prev_full (tree_view->priv->cursor_tree, tree_view->priv->cursor_node,
10186                                &new_cursor_tree, &new_cursor_node);
10187       else
10188         _gtk_rbtree_next_full (tree_view->priv->cursor_tree, tree_view->priv->cursor_node,
10189                                &new_cursor_tree, &new_cursor_node);
10190     }
10191
10192   gtk_tree_path_free (cursor_path);
10193
10194   if (new_cursor_node)
10195     {
10196       cursor_path = _gtk_tree_path_new_from_rbtree (new_cursor_tree, new_cursor_node);
10197
10198       search_first_focusable_path (tree_view, &cursor_path,
10199                                    (count != -1),
10200                                    &new_cursor_tree,
10201                                    &new_cursor_node);
10202
10203       if (cursor_path)
10204         gtk_tree_path_free (cursor_path);
10205     }
10206
10207   /*
10208    * If the list has only one item and multi-selection is set then select
10209    * the row (if not yet selected).
10210    */
10211   if (gtk_tree_selection_get_mode (tree_view->priv->selection) == GTK_SELECTION_MULTIPLE &&
10212       new_cursor_node == NULL)
10213     {
10214       if (count == -1)
10215         _gtk_rbtree_next_full (tree_view->priv->cursor_tree, tree_view->priv->cursor_node,
10216                                &new_cursor_tree, &new_cursor_node);
10217       else
10218         _gtk_rbtree_prev_full (tree_view->priv->cursor_tree, tree_view->priv->cursor_node,
10219                                &new_cursor_tree, &new_cursor_node);
10220
10221       if (new_cursor_node == NULL
10222           && !GTK_RBNODE_FLAG_SET (tree_view->priv->cursor_node, GTK_RBNODE_IS_SELECTED))
10223         {
10224           new_cursor_node = tree_view->priv->cursor_node;
10225           new_cursor_tree = tree_view->priv->cursor_tree;
10226         }
10227       else
10228         {
10229           new_cursor_tree = NULL;
10230           new_cursor_node = NULL;
10231         }
10232     }
10233
10234   if (new_cursor_node)
10235     {
10236       cursor_path = _gtk_tree_path_new_from_rbtree (new_cursor_tree, new_cursor_node);
10237       gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, TRUE);
10238       gtk_tree_path_free (cursor_path);
10239
10240       /* Give focus to the area in the new row */
10241       if (cell_area)
10242         gtk_cell_area_focus (cell_area, direction);
10243     }
10244   else
10245     {
10246       gtk_tree_view_clamp_node_visible (tree_view, 
10247                                         tree_view->priv->cursor_tree,
10248                                         tree_view->priv->cursor_node);
10249
10250       if (!tree_view->priv->extend_selection_pressed)
10251         {
10252           if (! gtk_widget_keynav_failed (GTK_WIDGET (tree_view),
10253                                           count < 0 ?
10254                                           GTK_DIR_UP : GTK_DIR_DOWN))
10255             {
10256               GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (tree_view));
10257
10258               if (toplevel)
10259                 gtk_widget_child_focus (toplevel,
10260                                         count < 0 ?
10261                                         GTK_DIR_TAB_BACKWARD :
10262                                         GTK_DIR_TAB_FORWARD);
10263
10264               grab_focus = FALSE;
10265             }
10266         }
10267       else
10268         {
10269           gtk_widget_error_bell (GTK_WIDGET (tree_view));
10270         }
10271
10272       if (cell_area)
10273         gtk_cell_area_set_focus_cell (cell_area, last_focus_cell);
10274     }
10275
10276   if (grab_focus)
10277     gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10278 }
10279
10280 static void
10281 gtk_tree_view_move_cursor_page_up_down (GtkTreeView *tree_view,
10282                                         gint         count)
10283 {
10284   GtkTreePath *old_cursor_path = NULL;
10285   GtkTreePath *cursor_path = NULL;
10286   GtkRBTree *start_cursor_tree = NULL;
10287   GtkRBNode *start_cursor_node = NULL;
10288   GtkRBTree *cursor_tree;
10289   GtkRBNode *cursor_node;
10290   gint y;
10291   gint window_y;
10292   gint vertical_separator;
10293
10294   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10295     return;
10296
10297   if (tree_view->priv->cursor_node == NULL)
10298     return;
10299
10300   old_cursor_path = _gtk_tree_path_new_from_rbtree (tree_view->priv->cursor_tree,
10301                                                     tree_view->priv->cursor_node);
10302
10303   gtk_widget_style_get (GTK_WIDGET (tree_view), "vertical-separator", &vertical_separator, NULL);
10304
10305   y = _gtk_rbtree_node_find_offset (tree_view->priv->cursor_tree, tree_view->priv->cursor_node);
10306   window_y = RBTREE_Y_TO_TREE_WINDOW_Y (tree_view, y);
10307   y += tree_view->priv->cursor_offset;
10308   y += count * (int)gtk_adjustment_get_page_increment (tree_view->priv->vadjustment);
10309   y = CLAMP (y, (gint)gtk_adjustment_get_lower (tree_view->priv->vadjustment),  (gint)gtk_adjustment_get_upper (tree_view->priv->vadjustment) - vertical_separator);
10310
10311   if (y >= tree_view->priv->height)
10312     y = tree_view->priv->height - 1;
10313
10314   tree_view->priv->cursor_offset =
10315     _gtk_rbtree_find_offset (tree_view->priv->tree, y,
10316                              &cursor_tree, &cursor_node);
10317
10318   if (cursor_tree == NULL)
10319     {
10320       /* FIXME: we lost the cursor.  Should we try to get one? */
10321       gtk_tree_path_free (old_cursor_path);
10322       return;
10323     }
10324
10325   if (tree_view->priv->cursor_offset
10326       > gtk_tree_view_get_row_height (tree_view, cursor_node))
10327     {
10328       _gtk_rbtree_next_full (cursor_tree, cursor_node,
10329                              &cursor_tree, &cursor_node);
10330       tree_view->priv->cursor_offset -= gtk_tree_view_get_row_height (tree_view, cursor_node);
10331     }
10332
10333   y -= tree_view->priv->cursor_offset;
10334   cursor_path = _gtk_tree_path_new_from_rbtree (cursor_tree, cursor_node);
10335
10336   start_cursor_tree = cursor_tree;
10337   start_cursor_node = cursor_node;
10338
10339   if (! search_first_focusable_path (tree_view, &cursor_path,
10340                                      (count != -1),
10341                                      &cursor_tree, &cursor_node))
10342     {
10343       /* It looks like we reached the end of the view without finding
10344        * a focusable row.  We will step backwards to find the last
10345        * focusable row.
10346        */
10347       cursor_tree = start_cursor_tree;
10348       cursor_node = start_cursor_node;
10349       cursor_path = _gtk_tree_path_new_from_rbtree (cursor_tree, cursor_node);
10350
10351       search_first_focusable_path (tree_view, &cursor_path,
10352                                    (count == -1),
10353                                    &cursor_tree, &cursor_node);
10354     }
10355
10356   if (!cursor_path)
10357     goto cleanup;
10358
10359   /* update y */
10360   y = _gtk_rbtree_node_find_offset (cursor_tree, cursor_node);
10361
10362   gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE);
10363
10364   y -= window_y;
10365   gtk_tree_view_scroll_to_point (tree_view, -1, y);
10366   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10367   _gtk_tree_view_queue_draw_node (tree_view, cursor_tree, cursor_node, NULL);
10368
10369   if (!gtk_tree_path_compare (old_cursor_path, cursor_path))
10370     gtk_widget_error_bell (GTK_WIDGET (tree_view));
10371
10372   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10373
10374 cleanup:
10375   gtk_tree_path_free (old_cursor_path);
10376   gtk_tree_path_free (cursor_path);
10377 }
10378
10379 static void
10380 gtk_tree_view_move_cursor_left_right (GtkTreeView *tree_view,
10381                                       gint         count)
10382 {
10383   GtkTreePath *cursor_path = NULL;
10384   GtkTreeViewColumn *column;
10385   GtkTreeIter iter;
10386   GList *list;
10387   gboolean found_column = FALSE;
10388   gboolean rtl;
10389   GtkDirectionType direction;
10390   GtkCellArea     *cell_area;
10391   GtkCellRenderer *last_focus_cell = NULL;
10392   GtkCellArea     *last_focus_area = NULL;
10393
10394   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
10395
10396   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10397     return;
10398
10399   if (tree_view->priv->cursor_node == NULL)
10400     return;
10401
10402   cursor_path = _gtk_tree_path_new_from_rbtree (tree_view->priv->cursor_tree,
10403                                                 tree_view->priv->cursor_node);
10404
10405   if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path) == FALSE)
10406     {
10407       gtk_tree_path_free (cursor_path);
10408       return;
10409     }
10410   gtk_tree_path_free (cursor_path);
10411
10412   list = rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns);
10413   if (tree_view->priv->focus_column)
10414     {
10415       /* Save the cell/area we are moving focus from, if moving the cursor
10416        * by one step hits the end we'll set focus back here */
10417       last_focus_area = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (tree_view->priv->focus_column));
10418       last_focus_cell = gtk_cell_area_get_focus_cell (last_focus_area);
10419
10420       for (; list; list = (rtl ? list->prev : list->next))
10421         {
10422           if (list->data == tree_view->priv->focus_column)
10423             break;
10424         }
10425     }
10426
10427   direction = count > 0 ? GTK_DIR_RIGHT : GTK_DIR_LEFT;
10428
10429   while (list)
10430     {
10431       column = list->data;
10432       if (gtk_tree_view_column_get_visible (column) == FALSE)
10433         goto loop_end;
10434
10435       gtk_tree_view_column_cell_set_cell_data (column,
10436                                                tree_view->priv->model,
10437                                                &iter,
10438                                                GTK_RBNODE_FLAG_SET (tree_view->priv->cursor_node, GTK_RBNODE_IS_PARENT),
10439                                                tree_view->priv->cursor_node->children ? TRUE : FALSE);
10440
10441       cell_area = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (column));
10442       if (gtk_cell_area_focus (cell_area, direction))
10443         {
10444           tree_view->priv->focus_column = column;
10445           found_column = TRUE;
10446           break;
10447         }
10448
10449     loop_end:
10450       if (count == 1)
10451         list = rtl ? list->prev : list->next;
10452       else
10453         list = rtl ? list->next : list->prev;
10454     }
10455
10456   if (found_column)
10457     {
10458       if (!gtk_tree_view_has_can_focus_cell (tree_view))
10459         _gtk_tree_view_queue_draw_node (tree_view,
10460                                         tree_view->priv->cursor_tree,
10461                                         tree_view->priv->cursor_node,
10462                                         NULL);
10463       g_signal_emit (tree_view, tree_view_signals[CURSOR_CHANGED], 0);
10464       gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10465     }
10466   else
10467     {
10468       gtk_widget_error_bell (GTK_WIDGET (tree_view));
10469
10470       if (last_focus_area)
10471         gtk_cell_area_set_focus_cell (last_focus_area, last_focus_cell);
10472     }
10473
10474   gtk_tree_view_clamp_column_visible (tree_view,
10475                                       tree_view->priv->focus_column, TRUE);
10476 }
10477
10478 static void
10479 gtk_tree_view_move_cursor_start_end (GtkTreeView *tree_view,
10480                                      gint         count)
10481 {
10482   GtkRBTree *cursor_tree;
10483   GtkRBNode *cursor_node;
10484   GtkTreePath *path;
10485   GtkTreePath *old_path;
10486
10487   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10488     return;
10489
10490   g_return_if_fail (tree_view->priv->tree != NULL);
10491
10492   gtk_tree_view_get_cursor (tree_view, &old_path, NULL);
10493
10494   cursor_tree = tree_view->priv->tree;
10495
10496   if (count == -1)
10497     {
10498       cursor_node = _gtk_rbtree_first (cursor_tree);
10499
10500       /* Now go forward to find the first focusable row. */
10501       path = _gtk_tree_path_new_from_rbtree (cursor_tree, cursor_node);
10502       search_first_focusable_path (tree_view, &path,
10503                                    TRUE, &cursor_tree, &cursor_node);
10504     }
10505   else
10506     {
10507       cursor_node = cursor_tree->root;
10508
10509       do
10510         {
10511           while (cursor_node && !_gtk_rbtree_is_nil (cursor_node->right))
10512             cursor_node = cursor_node->right;
10513           if (cursor_node->children == NULL)
10514             break;
10515
10516           cursor_tree = cursor_node->children;
10517           cursor_node = cursor_tree->root;
10518         }
10519       while (1);
10520
10521       /* Now go backwards to find last focusable row. */
10522       path = _gtk_tree_path_new_from_rbtree (cursor_tree, cursor_node);
10523       search_first_focusable_path (tree_view, &path,
10524                                    FALSE, &cursor_tree, &cursor_node);
10525     }
10526
10527   if (!path)
10528     goto cleanup;
10529
10530   if (gtk_tree_path_compare (old_path, path))
10531     {
10532       gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
10533       gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10534     }
10535   else
10536     {
10537       gtk_widget_error_bell (GTK_WIDGET (tree_view));
10538     }
10539
10540 cleanup:
10541   gtk_tree_path_free (old_path);
10542   gtk_tree_path_free (path);
10543 }
10544
10545 static gboolean
10546 gtk_tree_view_real_select_all (GtkTreeView *tree_view)
10547 {
10548   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10549     return FALSE;
10550
10551   if (gtk_tree_selection_get_mode (tree_view->priv->selection) != GTK_SELECTION_MULTIPLE)
10552     return FALSE;
10553
10554   gtk_tree_selection_select_all (tree_view->priv->selection);
10555
10556   return TRUE;
10557 }
10558
10559 static gboolean
10560 gtk_tree_view_real_unselect_all (GtkTreeView *tree_view)
10561 {
10562   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10563     return FALSE;
10564
10565   if (gtk_tree_selection_get_mode (tree_view->priv->selection) != GTK_SELECTION_MULTIPLE)
10566     return FALSE;
10567
10568   gtk_tree_selection_unselect_all (tree_view->priv->selection);
10569
10570   return TRUE;
10571 }
10572
10573 static gboolean
10574 gtk_tree_view_real_select_cursor_row (GtkTreeView *tree_view,
10575                                       gboolean     start_editing)
10576 {
10577   GtkRBTree *new_tree = NULL;
10578   GtkRBNode *new_node = NULL;
10579   GtkRBTree *cursor_tree = NULL;
10580   GtkRBNode *cursor_node = NULL;
10581   GtkTreePath *cursor_path = NULL;
10582   GtkTreeSelectMode mode = 0;
10583
10584   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10585     return FALSE;
10586
10587   if (tree_view->priv->cursor_node == NULL)
10588     return FALSE;
10589
10590   cursor_path = _gtk_tree_path_new_from_rbtree (tree_view->priv->cursor_tree,
10591                                                 tree_view->priv->cursor_node);
10592
10593   _gtk_tree_view_find_node (tree_view, cursor_path,
10594                             &cursor_tree, &cursor_node);
10595
10596   if (cursor_tree == NULL)
10597     {
10598       gtk_tree_path_free (cursor_path);
10599       return FALSE;
10600     }
10601
10602   if (!tree_view->priv->extend_selection_pressed && start_editing &&
10603       tree_view->priv->focus_column)
10604     {
10605       if (gtk_tree_view_start_editing (tree_view, cursor_path, FALSE))
10606         {
10607           gtk_tree_path_free (cursor_path);
10608           return TRUE;
10609         }
10610     }
10611
10612   if (tree_view->priv->modify_selection_pressed)
10613     mode |= GTK_TREE_SELECT_MODE_TOGGLE;
10614   if (tree_view->priv->extend_selection_pressed)
10615     mode |= GTK_TREE_SELECT_MODE_EXTEND;
10616
10617   _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
10618                                             cursor_node,
10619                                             cursor_tree,
10620                                             cursor_path,
10621                                             mode,
10622                                             FALSE);
10623
10624   /* We bail out if the original (tree, node) don't exist anymore after
10625    * handling the selection-changed callback.  We do return TRUE because
10626    * the key press has been handled at this point.
10627    */
10628   _gtk_tree_view_find_node (tree_view, cursor_path, &new_tree, &new_node);
10629
10630   if (cursor_tree != new_tree || cursor_node != new_node)
10631     return FALSE;
10632
10633   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10634
10635   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10636   _gtk_tree_view_queue_draw_node (tree_view, cursor_tree, cursor_node, NULL);
10637
10638   if (!tree_view->priv->extend_selection_pressed)
10639     gtk_tree_view_row_activated (tree_view, cursor_path,
10640                                  tree_view->priv->focus_column);
10641     
10642   gtk_tree_path_free (cursor_path);
10643
10644   return TRUE;
10645 }
10646
10647 static gboolean
10648 gtk_tree_view_real_toggle_cursor_row (GtkTreeView *tree_view)
10649 {
10650   GtkRBTree *new_tree = NULL;
10651   GtkRBNode *new_node = NULL;
10652   GtkRBTree *cursor_tree = NULL;
10653   GtkRBNode *cursor_node = NULL;
10654   GtkTreePath *cursor_path = NULL;
10655
10656   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10657     return FALSE;
10658
10659   if (tree_view->priv->cursor_node == NULL)
10660     return FALSE;
10661
10662   cursor_path = _gtk_tree_path_new_from_rbtree (tree_view->priv->cursor_tree,
10663                                                 tree_view->priv->cursor_node);
10664
10665   _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
10666                                             cursor_node,
10667                                             cursor_tree,
10668                                             cursor_path,
10669                                             GTK_TREE_SELECT_MODE_TOGGLE,
10670                                             FALSE);
10671
10672   /* We bail out if the original (tree, node) don't exist anymore after
10673    * handling the selection-changed callback.  We do return TRUE because
10674    * the key press has been handled at this point.
10675    */
10676   _gtk_tree_view_find_node (tree_view, cursor_path, &new_tree, &new_node);
10677
10678   if (tree_view->priv->cursor_node != new_node)
10679     return FALSE;
10680
10681   gtk_tree_view_clamp_node_visible (tree_view,
10682                                     tree_view->priv->cursor_tree,
10683                                     tree_view->priv->cursor_node);
10684
10685   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10686   gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10687   gtk_tree_path_free (cursor_path);
10688
10689   return TRUE;
10690 }
10691
10692 static gboolean
10693 gtk_tree_view_real_expand_collapse_cursor_row (GtkTreeView *tree_view,
10694                                                gboolean     logical,
10695                                                gboolean     expand,
10696                                                gboolean     open_all)
10697 {
10698   GtkTreePath *cursor_path = NULL;
10699
10700   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10701     return FALSE;
10702
10703   if (tree_view->priv->cursor_node == NULL)
10704     return FALSE;
10705
10706   cursor_path = _gtk_tree_path_new_from_rbtree (tree_view->priv->cursor_tree,
10707                                                 tree_view->priv->cursor_node);
10708
10709   /* Don't handle the event if we aren't an expander */
10710   if (!GTK_RBNODE_FLAG_SET (tree_view->priv->cursor_node, GTK_RBNODE_IS_PARENT))
10711     return FALSE;
10712
10713   if (!logical
10714       && gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL)
10715     expand = !expand;
10716
10717   if (expand)
10718     gtk_tree_view_real_expand_row (tree_view,
10719                                    cursor_path,
10720                                    tree_view->priv->cursor_tree,
10721                                    tree_view->priv->cursor_node,
10722                                    open_all,
10723                                    TRUE);
10724   else
10725     gtk_tree_view_real_collapse_row (tree_view,
10726                                      cursor_path,
10727                                      tree_view->priv->cursor_tree,
10728                                      tree_view->priv->cursor_node,
10729                                      TRUE);
10730
10731   gtk_tree_path_free (cursor_path);
10732
10733   return TRUE;
10734 }
10735
10736 static gboolean
10737 gtk_tree_view_real_select_cursor_parent (GtkTreeView *tree_view)
10738 {
10739   GtkTreePath *cursor_path = NULL;
10740   GdkModifierType state;
10741
10742   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10743     goto out;
10744
10745   if (tree_view->priv->cursor_node == NULL)
10746     goto out;
10747
10748   cursor_path = _gtk_tree_path_new_from_rbtree (tree_view->priv->cursor_tree,
10749                                                 tree_view->priv->cursor_node);
10750
10751   if (tree_view->priv->cursor_tree->parent_node)
10752     {
10753       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10754
10755       gtk_tree_path_up (cursor_path);
10756
10757       if (gtk_get_current_event_state (&state))
10758         {
10759           GdkModifierType modify_mod_mask;
10760
10761           modify_mod_mask =
10762             gtk_widget_get_modifier_mask (GTK_WIDGET (tree_view),
10763                                           GDK_MODIFIER_INTENT_MODIFY_SELECTION);
10764
10765           if ((state & modify_mod_mask) == modify_mod_mask)
10766             tree_view->priv->modify_selection_pressed = TRUE;
10767         }
10768
10769       gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, TRUE);
10770       gtk_tree_path_free (cursor_path);
10771
10772       gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10773
10774       tree_view->priv->modify_selection_pressed = FALSE;
10775
10776       return TRUE;
10777     }
10778
10779  out:
10780
10781   tree_view->priv->search_entry_avoid_unhandled_binding = TRUE;
10782   return FALSE;
10783 }
10784
10785 static gboolean
10786 gtk_tree_view_search_entry_flush_timeout (GtkTreeView *tree_view)
10787 {
10788   gtk_tree_view_search_dialog_hide (tree_view->priv->search_window, tree_view, NULL);
10789   tree_view->priv->typeselect_flush_timeout = 0;
10790
10791   return FALSE;
10792 }
10793
10794 /* Cut and paste from gtkwindow.c */
10795 static void
10796 send_focus_change (GtkWidget *widget,
10797                    GdkDevice *device,
10798                    gboolean   in)
10799 {
10800   GdkDeviceManager *device_manager;
10801   GList *devices, *d;
10802
10803   device_manager = gdk_display_get_device_manager (gtk_widget_get_display (widget));
10804   devices = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER);
10805   devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_SLAVE));
10806   devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_FLOATING));
10807
10808   for (d = devices; d; d = d->next)
10809     {
10810       GdkDevice *dev = d->data;
10811       GdkEvent *fevent;
10812       GdkWindow *window;
10813
10814       if (gdk_device_get_source (dev) != GDK_SOURCE_KEYBOARD)
10815         continue;
10816
10817       window = gtk_widget_get_window (widget);
10818
10819       /* Skip non-master keyboards that haven't
10820        * selected for events from this window
10821        */
10822       if (gdk_device_get_device_type (dev) != GDK_DEVICE_TYPE_MASTER &&
10823           !gdk_window_get_device_events (window, dev))
10824         continue;
10825
10826       fevent = gdk_event_new (GDK_FOCUS_CHANGE);
10827
10828       fevent->focus_change.type = GDK_FOCUS_CHANGE;
10829       fevent->focus_change.window = g_object_ref (window);
10830       fevent->focus_change.in = in;
10831       gdk_event_set_device (fevent, device);
10832
10833       gtk_widget_send_focus_change (widget, fevent);
10834
10835       gdk_event_free (fevent);
10836     }
10837
10838   g_list_free (devices);
10839 }
10840
10841 static void
10842 gtk_tree_view_ensure_interactive_directory (GtkTreeView *tree_view)
10843 {
10844   GtkWidget *frame, *vbox, *toplevel;
10845   GdkScreen *screen;
10846
10847   if (tree_view->priv->search_custom_entry_set)
10848     return;
10849
10850   toplevel = gtk_widget_get_toplevel (GTK_WIDGET (tree_view));
10851   screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
10852
10853    if (tree_view->priv->search_window != NULL)
10854      {
10855        if (gtk_window_has_group (GTK_WINDOW (toplevel)))
10856          gtk_window_group_add_window (gtk_window_get_group (GTK_WINDOW (toplevel)),
10857                                       GTK_WINDOW (tree_view->priv->search_window));
10858        else if (gtk_window_has_group (GTK_WINDOW (tree_view->priv->search_window)))
10859          gtk_window_group_remove_window (gtk_window_get_group (GTK_WINDOW (tree_view->priv->search_window)),
10860                                          GTK_WINDOW (tree_view->priv->search_window));
10861
10862        gtk_window_set_screen (GTK_WINDOW (tree_view->priv->search_window), screen);
10863
10864        return;
10865      }
10866    
10867   tree_view->priv->search_window = gtk_window_new (GTK_WINDOW_POPUP);
10868   gtk_window_set_screen (GTK_WINDOW (tree_view->priv->search_window), screen);
10869
10870   if (gtk_window_has_group (GTK_WINDOW (toplevel)))
10871     gtk_window_group_add_window (gtk_window_get_group (GTK_WINDOW (toplevel)),
10872                                  GTK_WINDOW (tree_view->priv->search_window));
10873
10874   gtk_window_set_type_hint (GTK_WINDOW (tree_view->priv->search_window),
10875                             GDK_WINDOW_TYPE_HINT_UTILITY);
10876   gtk_window_set_modal (GTK_WINDOW (tree_view->priv->search_window), TRUE);
10877   g_signal_connect (tree_view->priv->search_window, "delete-event",
10878                     G_CALLBACK (gtk_tree_view_search_delete_event),
10879                     tree_view);
10880   g_signal_connect (tree_view->priv->search_window, "key-press-event",
10881                     G_CALLBACK (gtk_tree_view_search_key_press_event),
10882                     tree_view);
10883   g_signal_connect (tree_view->priv->search_window, "button-press-event",
10884                     G_CALLBACK (gtk_tree_view_search_button_press_event),
10885                     tree_view);
10886   g_signal_connect (tree_view->priv->search_window, "scroll-event",
10887                     G_CALLBACK (gtk_tree_view_search_scroll_event),
10888                     tree_view);
10889
10890   frame = gtk_frame_new (NULL);
10891   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
10892   gtk_widget_show (frame);
10893   gtk_container_add (GTK_CONTAINER (tree_view->priv->search_window), frame);
10894
10895   vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
10896   gtk_widget_show (vbox);
10897   gtk_container_add (GTK_CONTAINER (frame), vbox);
10898   gtk_container_set_border_width (GTK_CONTAINER (vbox), 3);
10899
10900   /* add entry */
10901   tree_view->priv->search_entry = gtk_entry_new ();
10902   gtk_widget_show (tree_view->priv->search_entry);
10903   g_signal_connect (tree_view->priv->search_entry, "populate-popup",
10904                     G_CALLBACK (gtk_tree_view_search_disable_popdown),
10905                     tree_view);
10906   g_signal_connect (tree_view->priv->search_entry,
10907                     "activate", G_CALLBACK (gtk_tree_view_search_activate),
10908                     tree_view);
10909
10910   g_signal_connect (_gtk_entry_get_im_context (GTK_ENTRY (tree_view->priv->search_entry)),
10911                     "preedit-changed",
10912                     G_CALLBACK (gtk_tree_view_search_preedit_changed),
10913                     tree_view);
10914
10915   gtk_container_add (GTK_CONTAINER (vbox),
10916                      tree_view->priv->search_entry);
10917
10918   gtk_widget_realize (tree_view->priv->search_entry);
10919 }
10920
10921 /* Pops up the interactive search entry.  If keybinding is TRUE then the user
10922  * started this by typing the start_interactive_search keybinding.  Otherwise, it came from 
10923  */
10924 static gboolean
10925 gtk_tree_view_real_start_interactive_search (GtkTreeView *tree_view,
10926                                              GdkDevice   *device,
10927                                              gboolean     keybinding)
10928 {
10929   /* We only start interactive search if we have focus or the columns
10930    * have focus.  If one of our children have focus, we don't want to
10931    * start the search.
10932    */
10933   GList *list;
10934   gboolean found_focus = FALSE;
10935   GtkWidgetClass *entry_parent_class;
10936   
10937   if (!tree_view->priv->enable_search && !keybinding)
10938     return FALSE;
10939
10940   if (tree_view->priv->search_custom_entry_set)
10941     return FALSE;
10942
10943   if (tree_view->priv->search_window != NULL &&
10944       gtk_widget_get_visible (tree_view->priv->search_window))
10945     return TRUE;
10946
10947   for (list = tree_view->priv->columns; list; list = list->next)
10948     {
10949       GtkTreeViewColumn *column;
10950       GtkWidget         *button;
10951
10952       column = list->data;
10953       if (!gtk_tree_view_column_get_visible (column))
10954         continue;
10955
10956       button = gtk_tree_view_column_get_button (column);
10957       if (gtk_widget_has_focus (button))
10958         {
10959           found_focus = TRUE;
10960           break;
10961         }
10962     }
10963   
10964   if (gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10965     found_focus = TRUE;
10966
10967   if (!found_focus)
10968     return FALSE;
10969
10970   if (tree_view->priv->search_column < 0)
10971     return FALSE;
10972
10973   gtk_tree_view_ensure_interactive_directory (tree_view);
10974
10975   if (keybinding)
10976     gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
10977
10978   /* done, show it */
10979   tree_view->priv->search_position_func (tree_view, tree_view->priv->search_window, tree_view->priv->search_position_user_data);
10980   gtk_widget_show (tree_view->priv->search_window);
10981   if (tree_view->priv->search_entry_changed_id == 0)
10982     {
10983       tree_view->priv->search_entry_changed_id =
10984         g_signal_connect (tree_view->priv->search_entry, "changed",
10985                           G_CALLBACK (gtk_tree_view_search_init),
10986                           tree_view);
10987     }
10988
10989   tree_view->priv->typeselect_flush_timeout =
10990     gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
10991                    (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
10992                    tree_view);
10993
10994   /* Grab focus will select all the text.  We don't want that to happen, so we
10995    * call the parent instance and bypass the selection change.  This is probably
10996    * really non-kosher. */
10997   entry_parent_class = g_type_class_peek_parent (GTK_ENTRY_GET_CLASS (tree_view->priv->search_entry));
10998   (entry_parent_class->grab_focus) (tree_view->priv->search_entry);
10999
11000   /* send focus-in event */
11001   send_focus_change (tree_view->priv->search_entry, device, TRUE);
11002
11003   /* search first matching iter */
11004   gtk_tree_view_search_init (tree_view->priv->search_entry, tree_view);
11005
11006   return TRUE;
11007 }
11008
11009 static gboolean
11010 gtk_tree_view_start_interactive_search (GtkTreeView *tree_view)
11011 {
11012   return gtk_tree_view_real_start_interactive_search (tree_view,
11013                                                       gtk_get_current_event_device (),
11014                                                       TRUE);
11015 }
11016
11017 /* this function returns the new width of the column being resized given
11018  * the column and x position of the cursor; the x cursor position is passed
11019  * in as a pointer and automagicly corrected if it's beyond min/max limits
11020  */
11021 static gint
11022 gtk_tree_view_new_column_width (GtkTreeView *tree_view,
11023                                 gint       i,
11024                                 gint      *x)
11025 {
11026   GtkAllocation allocation;
11027   GtkTreeViewColumn *column;
11028   GtkRequisition button_req;
11029   gint max_width, min_width;
11030   gint width;
11031   gboolean rtl;
11032
11033   /* first translate the x position from widget->window
11034    * to clist->clist_window
11035    */
11036   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
11037   column = g_list_nth (tree_view->priv->columns, i)->data;
11038   gtk_widget_get_allocation (gtk_tree_view_column_get_button (column), &allocation);
11039   width = rtl ? (allocation.x + allocation.width - *x) : (*x - allocation.x);
11040
11041   /* Clamp down the value */
11042   min_width = gtk_tree_view_column_get_min_width (column);
11043   if (min_width == -1)
11044     {
11045       gtk_widget_get_preferred_size (gtk_tree_view_column_get_button (column), &button_req, NULL);
11046       width = MAX (button_req.width, width);
11047     }
11048   else
11049     width = MAX (min_width, width);
11050
11051   max_width = gtk_tree_view_column_get_max_width (column);
11052   if (max_width != -1)
11053     width = MIN (width, max_width);
11054
11055   *x = rtl ? (allocation.x + allocation.width - width) : (allocation.x + width);
11056
11057   return width;
11058 }
11059
11060
11061 /* FIXME this adjust_allocation is a big cut-and-paste from
11062  * GtkCList, needs to be some "official" way to do this
11063  * factored out.
11064  */
11065 typedef struct
11066 {
11067   GdkWindow *window;
11068   int dx;
11069   int dy;
11070 } ScrollData;
11071
11072 /* The window to which widget->window is relative */
11073 #define ALLOCATION_WINDOW(widget)               \
11074    (!gtk_widget_get_has_window (widget) ?                   \
11075     gtk_widget_get_window (widget) :                        \
11076     gdk_window_get_parent (gtk_widget_get_window (widget)))
11077
11078 static void
11079 adjust_allocation_recurse (GtkWidget *widget,
11080                            gpointer   data)
11081 {
11082   GtkAllocation allocation;
11083   ScrollData *scroll_data = data;
11084
11085   /* Need to really size allocate instead of just poking
11086    * into widget->allocation if the widget is not realized.
11087    * FIXME someone figure out why this was.
11088    */
11089   gtk_widget_get_allocation (widget, &allocation);
11090   if (!gtk_widget_get_realized (widget))
11091     {
11092       if (gtk_widget_get_visible (widget))
11093         {
11094           GdkRectangle tmp_rectangle = allocation;
11095           tmp_rectangle.x += scroll_data->dx;
11096           tmp_rectangle.y += scroll_data->dy;
11097           
11098           gtk_widget_size_allocate (widget, &tmp_rectangle);
11099         }
11100     }
11101   else
11102     {
11103       if (ALLOCATION_WINDOW (widget) == scroll_data->window)
11104         {
11105           allocation.x += scroll_data->dx;
11106           allocation.y += scroll_data->dy;
11107           gtk_widget_set_allocation (widget, &allocation);
11108
11109           if (GTK_IS_CONTAINER (widget))
11110             gtk_container_forall (GTK_CONTAINER (widget),
11111                                   adjust_allocation_recurse,
11112                                   data);
11113         }
11114     }
11115 }
11116
11117 static void
11118 adjust_allocation (GtkWidget *widget,
11119                    int        dx,
11120                    int        dy)
11121 {
11122   ScrollData scroll_data;
11123
11124   if (gtk_widget_get_realized (widget))
11125     scroll_data.window = ALLOCATION_WINDOW (widget);
11126   else
11127     scroll_data.window = NULL;
11128     
11129   scroll_data.dx = dx;
11130   scroll_data.dy = dy;
11131   
11132   adjust_allocation_recurse (widget, &scroll_data);
11133 }
11134
11135 /* Callbacks */
11136 static void
11137 gtk_tree_view_adjustment_changed (GtkAdjustment *adjustment,
11138                                   GtkTreeView   *tree_view)
11139 {
11140   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11141     {
11142       GtkStyleContext *context;
11143       gint dy;
11144         
11145       gdk_window_move (tree_view->priv->bin_window,
11146                        - gtk_adjustment_get_value (tree_view->priv->hadjustment),
11147                        gtk_tree_view_get_effective_header_height (tree_view));
11148       gdk_window_move (tree_view->priv->header_window,
11149                        - gtk_adjustment_get_value (tree_view->priv->hadjustment),
11150                        0);
11151       dy = tree_view->priv->dy - (int) gtk_adjustment_get_value (tree_view->priv->vadjustment);
11152       if (dy)
11153         {
11154           update_prelight (tree_view,
11155                            tree_view->priv->event_last_x,
11156                            tree_view->priv->event_last_y - dy);
11157
11158           if (tree_view->priv->edited_column)
11159             {
11160               GList *list;
11161               GtkTreeViewChild *child = NULL;
11162               GtkCellEditable *edit_widget;
11163               GtkCellArea *area;
11164
11165               area        = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (tree_view->priv->edited_column));
11166               edit_widget = gtk_cell_area_get_edit_widget (area);
11167               if (GTK_IS_WIDGET (edit_widget))
11168                 {
11169                   adjust_allocation (GTK_WIDGET (edit_widget), 0, dy);
11170
11171                   for (list = tree_view->priv->children; list; list = list->next)
11172                     {
11173                       child = (GtkTreeViewChild *)list->data;
11174                       if (child->widget == GTK_WIDGET (edit_widget))
11175                         {
11176                           child->y += dy;
11177                           break;
11178                         }
11179                     }
11180                 }
11181             }
11182         }
11183       gdk_window_scroll (tree_view->priv->bin_window, 0, dy);
11184
11185       context = gtk_widget_get_style_context (GTK_WIDGET (tree_view));
11186       gtk_style_context_scroll_animations (context, tree_view->priv->bin_window, 0, dy);
11187
11188       if (tree_view->priv->dy != (int) gtk_adjustment_get_value (tree_view->priv->vadjustment))
11189         {
11190           /* update our dy and top_row */
11191           tree_view->priv->dy = (int) gtk_adjustment_get_value (tree_view->priv->vadjustment);
11192
11193           if (!tree_view->priv->in_top_row_to_dy)
11194             gtk_tree_view_dy_to_top_row (tree_view);
11195         }
11196
11197       gdk_window_process_updates (tree_view->priv->header_window, TRUE);
11198       gtk_tree_view_bin_process_updates (tree_view);
11199     }
11200 }
11201
11202 \f
11203
11204 /* Public methods
11205  */
11206
11207 /**
11208  * gtk_tree_view_new:
11209  *
11210  * Creates a new #GtkTreeView widget.
11211  *
11212  * Return value: A newly created #GtkTreeView widget.
11213  **/
11214 GtkWidget *
11215 gtk_tree_view_new (void)
11216 {
11217   return g_object_new (GTK_TYPE_TREE_VIEW, NULL);
11218 }
11219
11220 /**
11221  * gtk_tree_view_new_with_model:
11222  * @model: the model.
11223  *
11224  * Creates a new #GtkTreeView widget with the model initialized to @model.
11225  *
11226  * Return value: A newly created #GtkTreeView widget.
11227  **/
11228 GtkWidget *
11229 gtk_tree_view_new_with_model (GtkTreeModel *model)
11230 {
11231   return g_object_new (GTK_TYPE_TREE_VIEW, "model", model, NULL);
11232 }
11233
11234 /* Public Accessors
11235  */
11236
11237 /**
11238  * gtk_tree_view_get_model:
11239  * @tree_view: a #GtkTreeView
11240  *
11241  * Returns the model the #GtkTreeView is based on.  Returns %NULL if the
11242  * model is unset.
11243  *
11244  * Return value: (transfer none): A #GtkTreeModel, or %NULL if none is currently being used.
11245  **/
11246 GtkTreeModel *
11247 gtk_tree_view_get_model (GtkTreeView *tree_view)
11248 {
11249   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11250
11251   return tree_view->priv->model;
11252 }
11253
11254 /**
11255  * gtk_tree_view_set_model:
11256  * @tree_view: A #GtkTreeNode.
11257  * @model: (allow-none): The model.
11258  *
11259  * Sets the model for a #GtkTreeView.  If the @tree_view already has a model
11260  * set, it will remove it before setting the new model.  If @model is %NULL,
11261  * then it will unset the old model.
11262  **/
11263 void
11264 gtk_tree_view_set_model (GtkTreeView  *tree_view,
11265                          GtkTreeModel *model)
11266 {
11267   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11268   g_return_if_fail (model == NULL || GTK_IS_TREE_MODEL (model));
11269
11270   if (model == tree_view->priv->model)
11271     return;
11272
11273   if (tree_view->priv->scroll_to_path)
11274     {
11275       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
11276       tree_view->priv->scroll_to_path = NULL;
11277     }
11278
11279   if (tree_view->priv->rubber_band_status)
11280     gtk_tree_view_stop_rubber_band (tree_view);
11281
11282   if (tree_view->priv->model)
11283     {
11284       GList *tmplist = tree_view->priv->columns;
11285       GtkStyleContext *context;
11286
11287       gtk_tree_view_unref_and_check_selection_tree (tree_view, tree_view->priv->tree);
11288       gtk_tree_view_stop_editing (tree_view, TRUE);
11289
11290       context = gtk_widget_get_style_context (GTK_WIDGET (tree_view));
11291       gtk_style_context_cancel_animations (context, NULL);
11292
11293       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
11294                                             gtk_tree_view_row_changed,
11295                                             tree_view);
11296       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
11297                                             gtk_tree_view_row_inserted,
11298                                             tree_view);
11299       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
11300                                             gtk_tree_view_row_has_child_toggled,
11301                                             tree_view);
11302       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
11303                                             gtk_tree_view_row_deleted,
11304                                             tree_view);
11305       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
11306                                             gtk_tree_view_rows_reordered,
11307                                             tree_view);
11308
11309       for (; tmplist; tmplist = tmplist->next)
11310         _gtk_tree_view_column_unset_model (tmplist->data,
11311                                            tree_view->priv->model);
11312
11313       if (tree_view->priv->tree)
11314         gtk_tree_view_free_rbtree (tree_view);
11315
11316       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
11317       tree_view->priv->drag_dest_row = NULL;
11318       tree_view->priv->cursor_tree = NULL;
11319       tree_view->priv->cursor_node = NULL;
11320       gtk_tree_row_reference_free (tree_view->priv->anchor);
11321       tree_view->priv->anchor = NULL;
11322       gtk_tree_row_reference_free (tree_view->priv->top_row);
11323       tree_view->priv->top_row = NULL;
11324       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
11325       tree_view->priv->scroll_to_path = NULL;
11326
11327       tree_view->priv->scroll_to_column = NULL;
11328
11329       g_object_unref (tree_view->priv->model);
11330
11331       tree_view->priv->search_column = -1;
11332       tree_view->priv->fixed_height_check = 0;
11333       tree_view->priv->fixed_height = -1;
11334       tree_view->priv->dy = tree_view->priv->top_row_dy = 0;
11335       tree_view->priv->last_button_x = -1;
11336       tree_view->priv->last_button_y = -1;
11337     }
11338
11339   tree_view->priv->model = model;
11340
11341   if (tree_view->priv->model)
11342     {
11343       gint i;
11344       GtkTreePath *path;
11345       GtkTreeIter iter;
11346       GtkTreeModelFlags flags;
11347
11348       if (tree_view->priv->search_column == -1)
11349         {
11350           for (i = 0; i < gtk_tree_model_get_n_columns (model); i++)
11351             {
11352               GType type = gtk_tree_model_get_column_type (model, i);
11353
11354               if (g_value_type_transformable (type, G_TYPE_STRING))
11355                 {
11356                   tree_view->priv->search_column = i;
11357                   break;
11358                 }
11359             }
11360         }
11361
11362       g_object_ref (tree_view->priv->model);
11363       g_signal_connect (tree_view->priv->model,
11364                         "row-changed",
11365                         G_CALLBACK (gtk_tree_view_row_changed),
11366                         tree_view);
11367       g_signal_connect (tree_view->priv->model,
11368                         "row-inserted",
11369                         G_CALLBACK (gtk_tree_view_row_inserted),
11370                         tree_view);
11371       g_signal_connect (tree_view->priv->model,
11372                         "row-has-child-toggled",
11373                         G_CALLBACK (gtk_tree_view_row_has_child_toggled),
11374                         tree_view);
11375       g_signal_connect (tree_view->priv->model,
11376                         "row-deleted",
11377                         G_CALLBACK (gtk_tree_view_row_deleted),
11378                         tree_view);
11379       g_signal_connect (tree_view->priv->model,
11380                         "rows-reordered",
11381                         G_CALLBACK (gtk_tree_view_rows_reordered),
11382                         tree_view);
11383
11384       flags = gtk_tree_model_get_flags (tree_view->priv->model);
11385       if ((flags & GTK_TREE_MODEL_LIST_ONLY) == GTK_TREE_MODEL_LIST_ONLY)
11386         tree_view->priv->is_list = TRUE;
11387       else
11388         tree_view->priv->is_list = FALSE;
11389
11390       path = gtk_tree_path_new_first ();
11391       if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, path))
11392         {
11393           tree_view->priv->tree = _gtk_rbtree_new ();
11394           gtk_tree_view_build_tree (tree_view, tree_view->priv->tree, &iter, 1, FALSE);
11395         }
11396       gtk_tree_path_free (path);
11397
11398       /*  FIXME: do I need to do this? gtk_tree_view_create_buttons (tree_view); */
11399       install_presize_handler (tree_view);
11400     }
11401
11402   g_object_notify (G_OBJECT (tree_view), "model");
11403
11404   if (tree_view->priv->selection)
11405   _gtk_tree_selection_emit_changed (tree_view->priv->selection);
11406
11407   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11408     gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11409 }
11410
11411 /**
11412  * gtk_tree_view_get_selection:
11413  * @tree_view: A #GtkTreeView.
11414  *
11415  * Gets the #GtkTreeSelection associated with @tree_view.
11416  *
11417  * Return value: (transfer none): A #GtkTreeSelection object.
11418  **/
11419 GtkTreeSelection *
11420 gtk_tree_view_get_selection (GtkTreeView *tree_view)
11421 {
11422   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11423
11424   return tree_view->priv->selection;
11425 }
11426
11427 /**
11428  * gtk_tree_view_get_hadjustment:
11429  * @tree_view: A #GtkTreeView
11430  *
11431  * Gets the #GtkAdjustment currently being used for the horizontal aspect.
11432  *
11433  * Return value: (transfer none): A #GtkAdjustment object, or %NULL
11434  *     if none is currently being used.
11435  *
11436  * Deprecated: 3.0: Use gtk_scrollable_get_hadjustment()
11437  **/
11438 GtkAdjustment *
11439 gtk_tree_view_get_hadjustment (GtkTreeView *tree_view)
11440 {
11441   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11442
11443   return gtk_tree_view_do_get_hadjustment (tree_view);
11444 }
11445
11446 static GtkAdjustment *
11447 gtk_tree_view_do_get_hadjustment (GtkTreeView *tree_view)
11448 {
11449   return tree_view->priv->hadjustment;
11450 }
11451
11452 /**
11453  * gtk_tree_view_set_hadjustment:
11454  * @tree_view: A #GtkTreeView
11455  * @adjustment: (allow-none): The #GtkAdjustment to set, or %NULL
11456  *
11457  * Sets the #GtkAdjustment for the current horizontal aspect.
11458  *
11459  * Deprecated: 3.0: Use gtk_scrollable_set_hadjustment()
11460  **/
11461 void
11462 gtk_tree_view_set_hadjustment (GtkTreeView   *tree_view,
11463                                GtkAdjustment *adjustment)
11464 {
11465   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11466   g_return_if_fail (adjustment == NULL || GTK_IS_ADJUSTMENT (adjustment));
11467
11468   gtk_tree_view_do_set_hadjustment (tree_view, adjustment);
11469 }
11470
11471 static void
11472 gtk_tree_view_do_set_hadjustment (GtkTreeView   *tree_view,
11473                                   GtkAdjustment *adjustment)
11474 {
11475   GtkTreeViewPrivate *priv = tree_view->priv;
11476
11477   if (adjustment && priv->hadjustment == adjustment)
11478     return;
11479
11480   if (priv->hadjustment != NULL)
11481     {
11482       g_signal_handlers_disconnect_by_func (priv->hadjustment,
11483                                             gtk_tree_view_adjustment_changed,
11484                                             tree_view);
11485       g_object_unref (priv->hadjustment);
11486     }
11487
11488   if (adjustment == NULL)
11489     adjustment = gtk_adjustment_new (0.0, 0.0, 0.0,
11490                                      0.0, 0.0, 0.0);
11491
11492   g_signal_connect (adjustment, "value-changed",
11493                     G_CALLBACK (gtk_tree_view_adjustment_changed), tree_view);
11494   priv->hadjustment = g_object_ref_sink (adjustment);
11495   /* FIXME: Adjustment should probably be populated here with fresh values, but
11496    * internal details are too complicated for me to decipher right now.
11497    */
11498   gtk_tree_view_adjustment_changed (NULL, tree_view);
11499
11500   g_object_notify (G_OBJECT (tree_view), "hadjustment");
11501 }
11502
11503 /**
11504  * gtk_tree_view_get_vadjustment:
11505  * @tree_view: A #GtkTreeView
11506  *
11507  * Gets the #GtkAdjustment currently being used for the vertical aspect.
11508  *
11509  * Return value: (transfer none): A #GtkAdjustment object, or %NULL
11510  *     if none is currently being used.
11511  *
11512  * Deprecated: 3.0: Use gtk_scrollable_get_vadjustment()
11513  **/
11514 GtkAdjustment *
11515 gtk_tree_view_get_vadjustment (GtkTreeView *tree_view)
11516 {
11517   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11518
11519   return gtk_tree_view_do_get_vadjustment (tree_view);
11520 }
11521
11522 static GtkAdjustment *
11523 gtk_tree_view_do_get_vadjustment (GtkTreeView *tree_view)
11524 {
11525   return tree_view->priv->vadjustment;
11526 }
11527
11528 /**
11529  * gtk_tree_view_set_vadjustment:
11530  * @tree_view: A #GtkTreeView
11531  * @adjustment: (allow-none): The #GtkAdjustment to set, or %NULL
11532  *
11533  * Sets the #GtkAdjustment for the current vertical aspect.
11534  *
11535  * Deprecated: 3.0: Use gtk_scrollable_set_vadjustment()
11536  **/
11537 void
11538 gtk_tree_view_set_vadjustment (GtkTreeView   *tree_view,
11539                                GtkAdjustment *adjustment)
11540 {
11541   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11542   g_return_if_fail (adjustment == NULL || GTK_IS_ADJUSTMENT (adjustment));
11543
11544   gtk_tree_view_do_set_vadjustment (tree_view, adjustment);
11545 }
11546
11547 static void
11548 gtk_tree_view_do_set_vadjustment (GtkTreeView   *tree_view,
11549                                   GtkAdjustment *adjustment)
11550 {
11551   GtkTreeViewPrivate *priv = tree_view->priv;
11552
11553   if (adjustment && priv->vadjustment == adjustment)
11554     return;
11555
11556   if (priv->vadjustment != NULL)
11557     {
11558       g_signal_handlers_disconnect_by_func (priv->vadjustment,
11559                                             gtk_tree_view_adjustment_changed,
11560                                             tree_view);
11561       g_object_unref (priv->vadjustment);
11562     }
11563
11564   if (adjustment == NULL)
11565     adjustment = gtk_adjustment_new (0.0, 0.0, 0.0,
11566                                      0.0, 0.0, 0.0);
11567
11568   g_signal_connect (adjustment, "value-changed",
11569                     G_CALLBACK (gtk_tree_view_adjustment_changed), tree_view);
11570   priv->vadjustment = g_object_ref_sink (adjustment);
11571   /* FIXME: Adjustment should probably be populated here with fresh values, but
11572    * internal details are too complicated for me to decipher right now.
11573    */
11574   gtk_tree_view_adjustment_changed (NULL, tree_view);
11575   g_object_notify (G_OBJECT (tree_view), "vadjustment");
11576 }
11577
11578 /* Column and header operations */
11579
11580 /**
11581  * gtk_tree_view_get_headers_visible:
11582  * @tree_view: A #GtkTreeView.
11583  *
11584  * Returns %TRUE if the headers on the @tree_view are visible.
11585  *
11586  * Return value: Whether the headers are visible or not.
11587  **/
11588 gboolean
11589 gtk_tree_view_get_headers_visible (GtkTreeView *tree_view)
11590 {
11591   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
11592
11593   return tree_view->priv->headers_visible;
11594 }
11595
11596 /**
11597  * gtk_tree_view_set_headers_visible:
11598  * @tree_view: A #GtkTreeView.
11599  * @headers_visible: %TRUE if the headers are visible
11600  *
11601  * Sets the visibility state of the headers.
11602  **/
11603 void
11604 gtk_tree_view_set_headers_visible (GtkTreeView *tree_view,
11605                                    gboolean     headers_visible)
11606 {
11607   gint x, y;
11608   GList *list;
11609   GtkTreeViewColumn *column;
11610   GtkAllocation allocation;
11611   GtkWidget *button;
11612
11613   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11614
11615   headers_visible = !! headers_visible;
11616
11617   if (tree_view->priv->headers_visible == headers_visible)
11618     return;
11619
11620   tree_view->priv->headers_visible = headers_visible == TRUE;
11621
11622   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11623     {
11624       gdk_window_get_position (tree_view->priv->bin_window, &x, &y);
11625       if (headers_visible)
11626         {
11627           gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
11628           gdk_window_move_resize (tree_view->priv->bin_window,
11629                                   x, y  + gtk_tree_view_get_effective_header_height (tree_view),
11630                                   tree_view->priv->width, allocation.height -  + gtk_tree_view_get_effective_header_height (tree_view));
11631
11632           if (gtk_widget_get_mapped (GTK_WIDGET (tree_view)))
11633             gtk_tree_view_map_buttons (tree_view);
11634         }
11635       else
11636         {
11637           gdk_window_move_resize (tree_view->priv->bin_window, x, y, tree_view->priv->width, tree_view->priv->height);
11638
11639           for (list = tree_view->priv->columns; list; list = list->next)
11640             {
11641               column = list->data;
11642               button = gtk_tree_view_column_get_button (column);
11643
11644               gtk_widget_hide (button);
11645               gtk_widget_unmap (button);
11646             }
11647           gdk_window_hide (tree_view->priv->header_window);
11648         }
11649     }
11650
11651   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
11652   gtk_adjustment_configure (tree_view->priv->vadjustment,
11653                             gtk_adjustment_get_value (tree_view->priv->vadjustment),
11654                             0,
11655                             tree_view->priv->height,
11656                             gtk_adjustment_get_step_increment (tree_view->priv->vadjustment),
11657                             (allocation.height - gtk_tree_view_get_effective_header_height (tree_view)) / 2,
11658                             allocation.height - gtk_tree_view_get_effective_header_height (tree_view));
11659
11660   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11661
11662   g_object_notify (G_OBJECT (tree_view), "headers-visible");
11663 }
11664
11665 /**
11666  * gtk_tree_view_columns_autosize:
11667  * @tree_view: A #GtkTreeView.
11668  *
11669  * Resizes all columns to their optimal width. Only works after the
11670  * treeview has been realized.
11671  **/
11672 void
11673 gtk_tree_view_columns_autosize (GtkTreeView *tree_view)
11674 {
11675   gboolean dirty = FALSE;
11676   GList *list;
11677   GtkTreeViewColumn *column;
11678
11679   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11680
11681   for (list = tree_view->priv->columns; list; list = list->next)
11682     {
11683       column = list->data;
11684       if (gtk_tree_view_column_get_sizing (column) == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
11685         continue;
11686       _gtk_tree_view_column_cell_set_dirty (column, TRUE);
11687       dirty = TRUE;
11688     }
11689
11690   if (dirty)
11691     gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11692 }
11693
11694 /**
11695  * gtk_tree_view_set_headers_clickable:
11696  * @tree_view: A #GtkTreeView.
11697  * @setting: %TRUE if the columns are clickable.
11698  *
11699  * Allow the column title buttons to be clicked.
11700  **/
11701 void
11702 gtk_tree_view_set_headers_clickable (GtkTreeView *tree_view,
11703                                      gboolean   setting)
11704 {
11705   GList *list;
11706
11707   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11708
11709   for (list = tree_view->priv->columns; list; list = list->next)
11710     gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (list->data), setting);
11711
11712   g_object_notify (G_OBJECT (tree_view), "headers-clickable");
11713 }
11714
11715
11716 /**
11717  * gtk_tree_view_get_headers_clickable:
11718  * @tree_view: A #GtkTreeView.
11719  *
11720  * Returns whether all header columns are clickable.
11721  *
11722  * Return value: %TRUE if all header columns are clickable, otherwise %FALSE
11723  *
11724  * Since: 2.10
11725  **/
11726 gboolean 
11727 gtk_tree_view_get_headers_clickable (GtkTreeView *tree_view)
11728 {
11729   GList *list;
11730   
11731   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
11732
11733   for (list = tree_view->priv->columns; list; list = list->next)
11734     if (!gtk_tree_view_column_get_clickable (GTK_TREE_VIEW_COLUMN (list->data)))
11735       return FALSE;
11736
11737   return TRUE;
11738 }
11739
11740 /**
11741  * gtk_tree_view_set_rules_hint
11742  * @tree_view: a #GtkTreeView
11743  * @setting: %TRUE if the tree requires reading across rows
11744  *
11745  * This function tells GTK+ that the user interface for your
11746  * application requires users to read across tree rows and associate
11747  * cells with one another. By default, GTK+ will then render the tree
11748  * with alternating row colors. Do <emphasis>not</emphasis> use it
11749  * just because you prefer the appearance of the ruled tree; that's a
11750  * question for the theme. Some themes will draw tree rows in
11751  * alternating colors even when rules are turned off, and users who
11752  * prefer that appearance all the time can choose those themes. You
11753  * should call this function only as a <emphasis>semantic</emphasis>
11754  * hint to the theme engine that your tree makes alternating colors
11755  * useful from a functional standpoint (since it has lots of columns,
11756  * generally).
11757  *
11758  **/
11759 void
11760 gtk_tree_view_set_rules_hint (GtkTreeView  *tree_view,
11761                               gboolean      setting)
11762 {
11763   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11764
11765   setting = setting != FALSE;
11766
11767   if (tree_view->priv->has_rules != setting)
11768     {
11769       tree_view->priv->has_rules = setting;
11770       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
11771     }
11772
11773   g_object_notify (G_OBJECT (tree_view), "rules-hint");
11774 }
11775
11776 /**
11777  * gtk_tree_view_get_rules_hint
11778  * @tree_view: a #GtkTreeView
11779  *
11780  * Gets the setting set by gtk_tree_view_set_rules_hint().
11781  *
11782  * Return value: %TRUE if rules are useful for the user of this tree
11783  **/
11784 gboolean
11785 gtk_tree_view_get_rules_hint (GtkTreeView  *tree_view)
11786 {
11787   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
11788
11789   return tree_view->priv->has_rules;
11790 }
11791
11792 /* Public Column functions
11793  */
11794
11795 /**
11796  * gtk_tree_view_append_column:
11797  * @tree_view: A #GtkTreeView.
11798  * @column: The #GtkTreeViewColumn to add.
11799  *
11800  * Appends @column to the list of columns. If @tree_view has "fixed_height"
11801  * mode enabled, then @column must have its "sizing" property set to be
11802  * GTK_TREE_VIEW_COLUMN_FIXED.
11803  *
11804  * Return value: The number of columns in @tree_view after appending.
11805  **/
11806 gint
11807 gtk_tree_view_append_column (GtkTreeView       *tree_view,
11808                              GtkTreeViewColumn *column)
11809 {
11810   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11811   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
11812   g_return_val_if_fail (gtk_tree_view_column_get_tree_view (column) == NULL, -1);
11813
11814   return gtk_tree_view_insert_column (tree_view, column, -1);
11815 }
11816
11817 void
11818 _gtk_tree_view_reset_header_styles (GtkTreeView *tree_view)
11819 {
11820   GList *columns;
11821
11822   for (columns = tree_view->priv->columns; columns; columns = columns->next)
11823     {
11824       GtkTreeViewColumn *column = columns->data;
11825       GtkWidget *header_widget;
11826
11827       if (gtk_tree_view_column_get_visible (column))
11828         continue;
11829
11830       header_widget = gtk_tree_view_column_get_widget (column);
11831
11832       if (!header_widget)
11833         header_widget = gtk_tree_view_column_get_button (column);
11834
11835       gtk_widget_reset_style (header_widget);
11836     }
11837 }
11838
11839
11840 /**
11841  * gtk_tree_view_remove_column:
11842  * @tree_view: A #GtkTreeView.
11843  * @column: The #GtkTreeViewColumn to remove.
11844  *
11845  * Removes @column from @tree_view.
11846  *
11847  * Return value: The number of columns in @tree_view after removing.
11848  **/
11849 gint
11850 gtk_tree_view_remove_column (GtkTreeView       *tree_view,
11851                              GtkTreeViewColumn *column)
11852 {
11853   guint position;
11854
11855   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11856   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
11857   g_return_val_if_fail (gtk_tree_view_column_get_tree_view (column) == GTK_WIDGET (tree_view), -1);
11858
11859   if (tree_view->priv->focus_column == column)
11860     tree_view->priv->focus_column = NULL;
11861
11862   if (tree_view->priv->edited_column == column)
11863     {
11864       gtk_tree_view_stop_editing (tree_view, TRUE);
11865
11866       /* no need to, but just to be sure ... */
11867       tree_view->priv->edited_column = NULL;
11868     }
11869
11870   if (tree_view->priv->expander_column == column)
11871     tree_view->priv->expander_column = NULL;
11872
11873   g_signal_handlers_disconnect_by_func (column,
11874                                         G_CALLBACK (column_sizing_notify),
11875                                         tree_view);
11876
11877   _gtk_tree_view_column_unset_tree_view (column);
11878
11879   position = g_list_index (tree_view->priv->columns, column);
11880
11881   tree_view->priv->columns = g_list_remove (tree_view->priv->columns, column);
11882   tree_view->priv->n_columns--;
11883
11884   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11885     {
11886       GList *list;
11887
11888       _gtk_tree_view_column_unrealize_button (column);
11889       for (list = tree_view->priv->columns; list; list = list->next)
11890         {
11891           GtkTreeViewColumn *tmp_column;
11892
11893           tmp_column = GTK_TREE_VIEW_COLUMN (list->data);
11894           if (gtk_tree_view_column_get_visible (tmp_column))
11895             _gtk_tree_view_column_cell_set_dirty (tmp_column, TRUE);
11896         }
11897
11898       if (tree_view->priv->n_columns == 0 &&
11899           gtk_tree_view_get_headers_visible (tree_view))
11900         gdk_window_hide (tree_view->priv->header_window);
11901
11902       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11903     }
11904
11905   _gtk_tree_view_reset_header_styles (tree_view);
11906
11907   _gtk_tree_view_accessible_remove_column (tree_view, column, position);
11908
11909   g_object_unref (column);
11910   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
11911
11912   return tree_view->priv->n_columns;
11913 }
11914
11915 /**
11916  * gtk_tree_view_insert_column:
11917  * @tree_view: A #GtkTreeView.
11918  * @column: The #GtkTreeViewColumn to be inserted.
11919  * @position: The position to insert @column in.
11920  *
11921  * This inserts the @column into the @tree_view at @position.  If @position is
11922  * -1, then the column is inserted at the end. If @tree_view has
11923  * "fixed_height" mode enabled, then @column must have its "sizing" property
11924  * set to be GTK_TREE_VIEW_COLUMN_FIXED.
11925  *
11926  * Return value: The number of columns in @tree_view after insertion.
11927  **/
11928 gint
11929 gtk_tree_view_insert_column (GtkTreeView       *tree_view,
11930                              GtkTreeViewColumn *column,
11931                              gint               position)
11932 {
11933   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11934   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
11935   g_return_val_if_fail (gtk_tree_view_column_get_tree_view (column) == NULL, -1);
11936
11937   if (tree_view->priv->fixed_height_mode)
11938     g_return_val_if_fail (gtk_tree_view_column_get_sizing (column)
11939                           == GTK_TREE_VIEW_COLUMN_FIXED, -1);
11940
11941   if (position < 0 || position > tree_view->priv->n_columns)
11942     position = tree_view->priv->n_columns;
11943
11944   g_object_ref_sink (column);
11945
11946   if (tree_view->priv->n_columns == 0 &&
11947       gtk_widget_get_realized (GTK_WIDGET (tree_view)) &&
11948       gtk_tree_view_get_headers_visible (tree_view))
11949     {
11950       gdk_window_show (tree_view->priv->header_window);
11951     }
11952
11953   g_signal_connect (column, "notify::sizing",
11954                     G_CALLBACK (column_sizing_notify), tree_view);
11955
11956   tree_view->priv->columns = g_list_insert (tree_view->priv->columns,
11957                                             column, position);
11958   tree_view->priv->n_columns++;
11959
11960   _gtk_tree_view_column_set_tree_view (column, tree_view);
11961
11962   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11963     {
11964       GList *list;
11965
11966       _gtk_tree_view_column_realize_button (column);
11967
11968       for (list = tree_view->priv->columns; list; list = list->next)
11969         {
11970           column = GTK_TREE_VIEW_COLUMN (list->data);
11971           if (gtk_tree_view_column_get_visible (column))
11972             _gtk_tree_view_column_cell_set_dirty (column, TRUE);
11973         }
11974       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11975     }
11976
11977   _gtk_tree_view_reset_header_styles (tree_view);
11978
11979   _gtk_tree_view_accessible_add_column (tree_view, column, position);
11980
11981   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
11982
11983   return tree_view->priv->n_columns;
11984 }
11985
11986 /**
11987  * gtk_tree_view_insert_column_with_attributes:
11988  * @tree_view: A #GtkTreeView
11989  * @position: The position to insert the new column in
11990  * @title: The title to set the header to
11991  * @cell: The #GtkCellRenderer
11992  * @...: A %NULL-terminated list of attributes
11993  *
11994  * Creates a new #GtkTreeViewColumn and inserts it into the @tree_view at
11995  * @position.  If @position is -1, then the newly created column is inserted at
11996  * the end.  The column is initialized with the attributes given. If @tree_view
11997  * has "fixed_height" mode enabled, then the new column will have its sizing
11998  * property set to be GTK_TREE_VIEW_COLUMN_FIXED.
11999  *
12000  * Return value: The number of columns in @tree_view after insertion.
12001  **/
12002 gint
12003 gtk_tree_view_insert_column_with_attributes (GtkTreeView     *tree_view,
12004                                              gint             position,
12005                                              const gchar     *title,
12006                                              GtkCellRenderer *cell,
12007                                              ...)
12008 {
12009   GtkTreeViewColumn *column;
12010   gchar *attribute;
12011   va_list args;
12012   gint column_id;
12013
12014   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
12015
12016   column = gtk_tree_view_column_new ();
12017   if (tree_view->priv->fixed_height_mode)
12018     gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
12019
12020   gtk_tree_view_column_set_title (column, title);
12021   gtk_tree_view_column_pack_start (column, cell, TRUE);
12022
12023   va_start (args, cell);
12024
12025   attribute = va_arg (args, gchar *);
12026
12027   while (attribute != NULL)
12028     {
12029       column_id = va_arg (args, gint);
12030       gtk_tree_view_column_add_attribute (column, cell, attribute, column_id);
12031       attribute = va_arg (args, gchar *);
12032     }
12033
12034   va_end (args);
12035
12036   return gtk_tree_view_insert_column (tree_view, column, position);
12037 }
12038
12039 /**
12040  * gtk_tree_view_insert_column_with_data_func:
12041  * @tree_view: a #GtkTreeView
12042  * @position: Position to insert, -1 for append
12043  * @title: column title
12044  * @cell: cell renderer for column
12045  * @func: function to set attributes of cell renderer
12046  * @data: data for @func
12047  * @dnotify: destroy notifier for @data
12048  *
12049  * Convenience function that inserts a new column into the #GtkTreeView
12050  * with the given cell renderer and a #GtkCellDataFunc to set cell renderer
12051  * attributes (normally using data from the model). See also
12052  * gtk_tree_view_column_set_cell_data_func(), gtk_tree_view_column_pack_start().
12053  * If @tree_view has "fixed_height" mode enabled, then the new column will have its
12054  * "sizing" property set to be GTK_TREE_VIEW_COLUMN_FIXED.
12055  *
12056  * Return value: number of columns in the tree view post-insert
12057  **/
12058 gint
12059 gtk_tree_view_insert_column_with_data_func  (GtkTreeView               *tree_view,
12060                                              gint                       position,
12061                                              const gchar               *title,
12062                                              GtkCellRenderer           *cell,
12063                                              GtkTreeCellDataFunc        func,
12064                                              gpointer                   data,
12065                                              GDestroyNotify             dnotify)
12066 {
12067   GtkTreeViewColumn *column;
12068
12069   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
12070
12071   column = gtk_tree_view_column_new ();
12072   if (tree_view->priv->fixed_height_mode)
12073     gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
12074
12075   gtk_tree_view_column_set_title (column, title);
12076   gtk_tree_view_column_pack_start (column, cell, TRUE);
12077   gtk_tree_view_column_set_cell_data_func (column, cell, func, data, dnotify);
12078
12079   return gtk_tree_view_insert_column (tree_view, column, position);
12080 }
12081
12082 /**
12083  * gtk_tree_view_get_n_columns:
12084  * @tree_view: a #GtkTreeView
12085  *
12086  * Queries the number of columns in the given @tree_view.
12087  *
12088  * Returns: The number of columns in the @tree_view
12089  *
12090  * Since: 3.4
12091  **/
12092 guint
12093 gtk_tree_view_get_n_columns (GtkTreeView *tree_view)
12094 {
12095   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
12096
12097   return tree_view->priv->n_columns;
12098 }
12099
12100 /**
12101  * gtk_tree_view_get_column:
12102  * @tree_view: A #GtkTreeView.
12103  * @n: The position of the column, counting from 0.
12104  *
12105  * Gets the #GtkTreeViewColumn at the given position in the #tree_view.
12106  *
12107  * Return value: (transfer none): The #GtkTreeViewColumn, or %NULL if the
12108  *     position is outside the range of columns.
12109  **/
12110 GtkTreeViewColumn *
12111 gtk_tree_view_get_column (GtkTreeView *tree_view,
12112                           gint         n)
12113 {
12114   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
12115
12116   if (n < 0 || n >= tree_view->priv->n_columns)
12117     return NULL;
12118
12119   if (tree_view->priv->columns == NULL)
12120     return NULL;
12121
12122   return GTK_TREE_VIEW_COLUMN (g_list_nth (tree_view->priv->columns, n)->data);
12123 }
12124
12125 /**
12126  * gtk_tree_view_get_columns:
12127  * @tree_view: A #GtkTreeView
12128  *
12129  * Returns a #GList of all the #GtkTreeViewColumn s currently in @tree_view.
12130  * The returned list must be freed with g_list_free ().
12131  *
12132  * Return value: (element-type GtkTreeViewColumn) (transfer container): A list of #GtkTreeViewColumn s
12133  **/
12134 GList *
12135 gtk_tree_view_get_columns (GtkTreeView *tree_view)
12136 {
12137   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
12138
12139   return g_list_copy (tree_view->priv->columns);
12140 }
12141
12142 /**
12143  * gtk_tree_view_move_column_after:
12144  * @tree_view: A #GtkTreeView
12145  * @column: The #GtkTreeViewColumn to be moved.
12146  * @base_column: (allow-none): The #GtkTreeViewColumn to be moved relative to, or %NULL.
12147  *
12148  * Moves @column to be after to @base_column.  If @base_column is %NULL, then
12149  * @column is placed in the first position.
12150  **/
12151 void
12152 gtk_tree_view_move_column_after (GtkTreeView       *tree_view,
12153                                  GtkTreeViewColumn *column,
12154                                  GtkTreeViewColumn *base_column)
12155 {
12156   GList *column_list_el, *base_el = NULL;
12157
12158   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12159
12160   column_list_el = g_list_find (tree_view->priv->columns, column);
12161   g_return_if_fail (column_list_el != NULL);
12162
12163   if (base_column)
12164     {
12165       base_el = g_list_find (tree_view->priv->columns, base_column);
12166       g_return_if_fail (base_el != NULL);
12167     }
12168
12169   if (column_list_el->prev == base_el)
12170     return;
12171
12172   tree_view->priv->columns = g_list_remove_link (tree_view->priv->columns, column_list_el);
12173   if (base_el == NULL)
12174     {
12175       column_list_el->prev = NULL;
12176       column_list_el->next = tree_view->priv->columns;
12177       if (column_list_el->next)
12178         column_list_el->next->prev = column_list_el;
12179       tree_view->priv->columns = column_list_el;
12180     }
12181   else
12182     {
12183       column_list_el->prev = base_el;
12184       column_list_el->next = base_el->next;
12185       if (column_list_el->next)
12186         column_list_el->next->prev = column_list_el;
12187       base_el->next = column_list_el;
12188     }
12189
12190   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
12191     {
12192       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
12193       gtk_tree_view_size_allocate_columns (GTK_WIDGET (tree_view), NULL);
12194     }
12195
12196   _gtk_tree_view_reset_header_styles (tree_view);
12197
12198   _gtk_tree_view_accessible_reorder_column (tree_view, column);
12199
12200   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
12201 }
12202
12203 /**
12204  * gtk_tree_view_set_expander_column:
12205  * @tree_view: A #GtkTreeView
12206  * @column: %NULL, or the column to draw the expander arrow at.
12207  *
12208  * Sets the column to draw the expander arrow at. It must be in @tree_view.  
12209  * If @column is %NULL, then the expander arrow is always at the first 
12210  * visible column.
12211  *
12212  * If you do not want expander arrow to appear in your tree, set the 
12213  * expander column to a hidden column.
12214  **/
12215 void
12216 gtk_tree_view_set_expander_column (GtkTreeView       *tree_view,
12217                                    GtkTreeViewColumn *column)
12218 {
12219   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12220   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
12221   g_return_if_fail (column == NULL || gtk_tree_view_column_get_tree_view (column) == GTK_WIDGET (tree_view));
12222
12223   if (tree_view->priv->expander_column != column)
12224     {
12225       tree_view->priv->expander_column = column;
12226       g_object_notify (G_OBJECT (tree_view), "expander-column");
12227     }
12228 }
12229
12230 /**
12231  * gtk_tree_view_get_expander_column:
12232  * @tree_view: A #GtkTreeView
12233  *
12234  * Returns the column that is the current expander column.
12235  * This column has the expander arrow drawn next to it.
12236  *
12237  * Return value: (transfer none): The expander column.
12238  **/
12239 GtkTreeViewColumn *
12240 gtk_tree_view_get_expander_column (GtkTreeView *tree_view)
12241 {
12242   GList *list;
12243
12244   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
12245
12246   for (list = tree_view->priv->columns; list; list = list->next)
12247     if (gtk_tree_view_is_expander_column (tree_view, GTK_TREE_VIEW_COLUMN (list->data)))
12248       return (GtkTreeViewColumn *) list->data;
12249   return NULL;
12250 }
12251
12252
12253 /**
12254  * gtk_tree_view_set_column_drag_function:
12255  * @tree_view: A #GtkTreeView.
12256  * @func: (allow-none): A function to determine which columns are reorderable, or %NULL.
12257  * @user_data: (allow-none): User data to be passed to @func, or %NULL
12258  * @destroy: (allow-none): Destroy notifier for @user_data, or %NULL
12259  *
12260  * Sets a user function for determining where a column may be dropped when
12261  * dragged.  This function is called on every column pair in turn at the
12262  * beginning of a column drag to determine where a drop can take place.  The
12263  * arguments passed to @func are: the @tree_view, the #GtkTreeViewColumn being
12264  * dragged, the two #GtkTreeViewColumn s determining the drop spot, and
12265  * @user_data.  If either of the #GtkTreeViewColumn arguments for the drop spot
12266  * are %NULL, then they indicate an edge.  If @func is set to be %NULL, then
12267  * @tree_view reverts to the default behavior of allowing all columns to be
12268  * dropped everywhere.
12269  **/
12270 void
12271 gtk_tree_view_set_column_drag_function (GtkTreeView               *tree_view,
12272                                         GtkTreeViewColumnDropFunc  func,
12273                                         gpointer                   user_data,
12274                                         GDestroyNotify             destroy)
12275 {
12276   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12277
12278   if (tree_view->priv->column_drop_func_data_destroy)
12279     tree_view->priv->column_drop_func_data_destroy (tree_view->priv->column_drop_func_data);
12280
12281   tree_view->priv->column_drop_func = func;
12282   tree_view->priv->column_drop_func_data = user_data;
12283   tree_view->priv->column_drop_func_data_destroy = destroy;
12284 }
12285
12286 /**
12287  * gtk_tree_view_scroll_to_point:
12288  * @tree_view: a #GtkTreeView
12289  * @tree_x: X coordinate of new top-left pixel of visible area, or -1
12290  * @tree_y: Y coordinate of new top-left pixel of visible area, or -1
12291  *
12292  * Scrolls the tree view such that the top-left corner of the visible
12293  * area is @tree_x, @tree_y, where @tree_x and @tree_y are specified
12294  * in tree coordinates.  The @tree_view must be realized before
12295  * this function is called.  If it isn't, you probably want to be
12296  * using gtk_tree_view_scroll_to_cell().
12297  *
12298  * If either @tree_x or @tree_y are -1, then that direction isn't scrolled.
12299  **/
12300 void
12301 gtk_tree_view_scroll_to_point (GtkTreeView *tree_view,
12302                                gint         tree_x,
12303                                gint         tree_y)
12304 {
12305   GtkAdjustment *hadj;
12306   GtkAdjustment *vadj;
12307
12308   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12309   g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (tree_view)));
12310
12311   hadj = tree_view->priv->hadjustment;
12312   vadj = tree_view->priv->vadjustment;
12313
12314   if (tree_x != -1)
12315     gtk_adjustment_set_value (hadj, tree_x);
12316   if (tree_y != -1)
12317     gtk_adjustment_set_value (vadj, tree_y);
12318 }
12319
12320 /**
12321  * gtk_tree_view_scroll_to_cell:
12322  * @tree_view: A #GtkTreeView.
12323  * @path: (allow-none): The path of the row to move to, or %NULL.
12324  * @column: (allow-none): The #GtkTreeViewColumn to move horizontally to, or %NULL.
12325  * @use_align: whether to use alignment arguments, or %FALSE.
12326  * @row_align: The vertical alignment of the row specified by @path.
12327  * @col_align: The horizontal alignment of the column specified by @column.
12328  *
12329  * Moves the alignments of @tree_view to the position specified by @column and
12330  * @path.  If @column is %NULL, then no horizontal scrolling occurs.  Likewise,
12331  * if @path is %NULL no vertical scrolling occurs.  At a minimum, one of @column
12332  * or @path need to be non-%NULL.  @row_align determines where the row is
12333  * placed, and @col_align determines where @column is placed.  Both are expected
12334  * to be between 0.0 and 1.0. 0.0 means left/top alignment, 1.0 means
12335  * right/bottom alignment, 0.5 means center.
12336  *
12337  * If @use_align is %FALSE, then the alignment arguments are ignored, and the
12338  * tree does the minimum amount of work to scroll the cell onto the screen.
12339  * This means that the cell will be scrolled to the edge closest to its current
12340  * position.  If the cell is currently visible on the screen, nothing is done.
12341  *
12342  * This function only works if the model is set, and @path is a valid row on the
12343  * model.  If the model changes before the @tree_view is realized, the centered
12344  * path will be modified to reflect this change.
12345  **/
12346 void
12347 gtk_tree_view_scroll_to_cell (GtkTreeView       *tree_view,
12348                               GtkTreePath       *path,
12349                               GtkTreeViewColumn *column,
12350                               gboolean           use_align,
12351                               gfloat             row_align,
12352                               gfloat             col_align)
12353 {
12354   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12355   g_return_if_fail (tree_view->priv->model != NULL);
12356   g_return_if_fail (tree_view->priv->tree != NULL);
12357   g_return_if_fail (row_align >= 0.0 && row_align <= 1.0);
12358   g_return_if_fail (col_align >= 0.0 && col_align <= 1.0);
12359   g_return_if_fail (path != NULL || column != NULL);
12360
12361 #if 0
12362   g_print ("gtk_tree_view_scroll_to_cell:\npath: %s\ncolumn: %s\nuse_align: %d\nrow_align: %f\ncol_align: %f\n",
12363            gtk_tree_path_to_string (path), column?"non-null":"null", use_align, row_align, col_align);
12364 #endif
12365   row_align = CLAMP (row_align, 0.0, 1.0);
12366   col_align = CLAMP (col_align, 0.0, 1.0);
12367
12368
12369   /* Note: Despite the benefits that come from having one code path for the
12370    * scrolling code, we short-circuit validate_visible_area's immplementation as
12371    * it is much slower than just going to the point.
12372    */
12373   if (!gtk_widget_get_visible (GTK_WIDGET (tree_view)) ||
12374       !gtk_widget_get_realized (GTK_WIDGET (tree_view)) ||
12375       _gtk_widget_get_alloc_needed (GTK_WIDGET (tree_view)) ||
12376       GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID))
12377     {
12378       if (tree_view->priv->scroll_to_path)
12379         gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
12380
12381       tree_view->priv->scroll_to_path = NULL;
12382       tree_view->priv->scroll_to_column = NULL;
12383
12384       if (path)
12385         tree_view->priv->scroll_to_path = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
12386       if (column)
12387         tree_view->priv->scroll_to_column = column;
12388       tree_view->priv->scroll_to_use_align = use_align;
12389       tree_view->priv->scroll_to_row_align = row_align;
12390       tree_view->priv->scroll_to_col_align = col_align;
12391
12392       install_presize_handler (tree_view);
12393     }
12394   else
12395     {
12396       GdkRectangle cell_rect;
12397       GdkRectangle vis_rect;
12398       gint dest_x, dest_y;
12399
12400       gtk_tree_view_get_background_area (tree_view, path, column, &cell_rect);
12401       gtk_tree_view_get_visible_rect (tree_view, &vis_rect);
12402
12403       cell_rect.y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, cell_rect.y);
12404
12405       dest_x = vis_rect.x;
12406       dest_y = vis_rect.y;
12407
12408       if (column)
12409         {
12410           if (use_align)
12411             {
12412               dest_x = cell_rect.x - ((vis_rect.width - cell_rect.width) * col_align);
12413             }
12414           else
12415             {
12416               if (cell_rect.x < vis_rect.x)
12417                 dest_x = cell_rect.x;
12418               if (cell_rect.x + cell_rect.width > vis_rect.x + vis_rect.width)
12419                 dest_x = cell_rect.x + cell_rect.width - vis_rect.width;
12420             }
12421         }
12422
12423       if (path)
12424         {
12425           if (use_align)
12426             {
12427               dest_y = cell_rect.y - ((vis_rect.height - cell_rect.height) * row_align);
12428               dest_y = MAX (dest_y, 0);
12429             }
12430           else
12431             {
12432               if (cell_rect.y < vis_rect.y)
12433                 dest_y = cell_rect.y;
12434               if (cell_rect.y + cell_rect.height > vis_rect.y + vis_rect.height)
12435                 dest_y = cell_rect.y + cell_rect.height - vis_rect.height;
12436             }
12437         }
12438
12439       gtk_tree_view_scroll_to_point (tree_view, dest_x, dest_y);
12440     }
12441 }
12442
12443 /**
12444  * gtk_tree_view_row_activated:
12445  * @tree_view: A #GtkTreeView
12446  * @path: The #GtkTreePath to be activated.
12447  * @column: The #GtkTreeViewColumn to be activated.
12448  *
12449  * Activates the cell determined by @path and @column.
12450  **/
12451 void
12452 gtk_tree_view_row_activated (GtkTreeView       *tree_view,
12453                              GtkTreePath       *path,
12454                              GtkTreeViewColumn *column)
12455 {
12456   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12457
12458   g_signal_emit (tree_view, tree_view_signals[ROW_ACTIVATED], 0, path, column);
12459 }
12460
12461
12462 static void
12463 gtk_tree_view_expand_all_emission_helper (GtkRBTree *tree,
12464                                           GtkRBNode *node,
12465                                           gpointer   data)
12466 {
12467   GtkTreeView *tree_view = data;
12468
12469   if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT &&
12470       node->children)
12471     {
12472       GtkTreePath *path;
12473       GtkTreeIter iter;
12474
12475       path = _gtk_tree_path_new_from_rbtree (tree, node);
12476       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
12477
12478       g_signal_emit (tree_view, tree_view_signals[ROW_EXPANDED], 0, &iter, path);
12479
12480       gtk_tree_path_free (path);
12481     }
12482
12483   if (node->children)
12484     _gtk_rbtree_traverse (node->children,
12485                           node->children->root,
12486                           G_PRE_ORDER,
12487                           gtk_tree_view_expand_all_emission_helper,
12488                           tree_view);
12489 }
12490
12491 /**
12492  * gtk_tree_view_expand_all:
12493  * @tree_view: A #GtkTreeView.
12494  *
12495  * Recursively expands all nodes in the @tree_view.
12496  **/
12497 void
12498 gtk_tree_view_expand_all (GtkTreeView *tree_view)
12499 {
12500   GtkTreePath *path;
12501   GtkRBTree *tree;
12502   GtkRBNode *node;
12503
12504   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12505
12506   if (tree_view->priv->tree == NULL)
12507     return;
12508
12509   path = gtk_tree_path_new_first ();
12510   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
12511
12512   while (node)
12513     {
12514       gtk_tree_view_real_expand_row (tree_view, path, tree, node, TRUE, FALSE);
12515       node = _gtk_rbtree_next (tree, node);
12516       gtk_tree_path_next (path);
12517   }
12518
12519   gtk_tree_path_free (path);
12520 }
12521
12522 /**
12523  * gtk_tree_view_collapse_all:
12524  * @tree_view: A #GtkTreeView.
12525  *
12526  * Recursively collapses all visible, expanded nodes in @tree_view.
12527  **/
12528 void
12529 gtk_tree_view_collapse_all (GtkTreeView *tree_view)
12530 {
12531   GtkRBTree *tree;
12532   GtkRBNode *node;
12533   GtkTreePath *path;
12534   gint *indices;
12535
12536   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12537
12538   if (tree_view->priv->tree == NULL)
12539     return;
12540
12541   path = gtk_tree_path_new ();
12542   gtk_tree_path_down (path);
12543   indices = gtk_tree_path_get_indices (path);
12544
12545   tree = tree_view->priv->tree;
12546   node = _gtk_rbtree_first (tree);
12547
12548   while (node)
12549     {
12550       if (node->children)
12551         gtk_tree_view_real_collapse_row (tree_view, path, tree, node, FALSE);
12552       indices[0]++;
12553       node = _gtk_rbtree_next (tree, node);
12554     }
12555
12556   gtk_tree_path_free (path);
12557 }
12558
12559 /**
12560  * gtk_tree_view_expand_to_path:
12561  * @tree_view: A #GtkTreeView.
12562  * @path: path to a row.
12563  *
12564  * Expands the row at @path. This will also expand all parent rows of
12565  * @path as necessary.
12566  *
12567  * Since: 2.2
12568  **/
12569 void
12570 gtk_tree_view_expand_to_path (GtkTreeView *tree_view,
12571                               GtkTreePath *path)
12572 {
12573   gint i, depth;
12574   gint *indices;
12575   GtkTreePath *tmp;
12576
12577   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12578   g_return_if_fail (path != NULL);
12579
12580   depth = gtk_tree_path_get_depth (path);
12581   indices = gtk_tree_path_get_indices (path);
12582
12583   tmp = gtk_tree_path_new ();
12584   g_return_if_fail (tmp != NULL);
12585
12586   for (i = 0; i < depth; i++)
12587     {
12588       gtk_tree_path_append_index (tmp, indices[i]);
12589       gtk_tree_view_expand_row (tree_view, tmp, FALSE);
12590     }
12591
12592   gtk_tree_path_free (tmp);
12593 }
12594
12595 /* FIXME the bool return values for expand_row and collapse_row are
12596  * not analagous; they should be TRUE if the row had children and
12597  * was not already in the requested state.
12598  */
12599
12600
12601 static gboolean
12602 gtk_tree_view_real_expand_row (GtkTreeView *tree_view,
12603                                GtkTreePath *path,
12604                                GtkRBTree   *tree,
12605                                GtkRBNode   *node,
12606                                gboolean     open_all,
12607                                gboolean     animate)
12608 {
12609   GtkTreeIter iter;
12610   GtkTreeIter temp;
12611   gboolean expand;
12612
12613   if (animate)
12614     g_object_get (gtk_widget_get_settings (GTK_WIDGET (tree_view)),
12615                   "gtk-enable-animations", &animate,
12616                   NULL);
12617
12618   remove_auto_expand_timeout (tree_view);
12619
12620   if (node->children && !open_all)
12621     return FALSE;
12622
12623   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
12624     return FALSE;
12625
12626   gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
12627   if (! gtk_tree_model_iter_has_child (tree_view->priv->model, &iter))
12628     return FALSE;
12629
12630
12631    if (node->children && open_all)
12632     {
12633       gboolean retval = FALSE;
12634       GtkTreePath *tmp_path = gtk_tree_path_copy (path);
12635
12636       gtk_tree_path_append_index (tmp_path, 0);
12637       tree = node->children;
12638       node = _gtk_rbtree_first (tree);
12639       /* try to expand the children */
12640       do
12641         {
12642          gboolean t;
12643          t = gtk_tree_view_real_expand_row (tree_view, tmp_path, tree, node,
12644                                             TRUE, animate);
12645          if (t)
12646            retval = TRUE;
12647
12648          gtk_tree_path_next (tmp_path);
12649          node = _gtk_rbtree_next (tree, node);
12650        }
12651       while (node != NULL);
12652
12653       gtk_tree_path_free (tmp_path);
12654
12655       return retval;
12656     }
12657
12658   g_signal_emit (tree_view, tree_view_signals[TEST_EXPAND_ROW], 0, &iter, path, &expand);
12659
12660   if (!gtk_tree_model_iter_has_child (tree_view->priv->model, &iter))
12661     return FALSE;
12662
12663   if (expand)
12664     return FALSE;
12665
12666   node->children = _gtk_rbtree_new ();
12667   node->children->parent_tree = tree;
12668   node->children->parent_node = node;
12669
12670   gtk_tree_model_iter_children (tree_view->priv->model, &temp, &iter);
12671
12672   gtk_tree_view_build_tree (tree_view,
12673                             node->children,
12674                             &temp,
12675                             gtk_tree_path_get_depth (path) + 1,
12676                             open_all);
12677
12678   if (animate)
12679     {
12680       GtkStyleContext *context;
12681
12682       context = gtk_widget_get_style_context (GTK_WIDGET (tree_view));
12683
12684       gtk_style_context_save (context);
12685       gtk_style_context_add_class (context, GTK_STYLE_CLASS_EXPANDER);
12686
12687       gtk_style_context_notify_state_change (context, tree_view->priv->bin_window,
12688                                              node, GTK_STATE_ACTIVE, TRUE);
12689
12690       _gtk_style_context_invalidate_animation_areas (context);
12691       gtk_style_context_restore (context);
12692     }
12693
12694   install_presize_handler (tree_view);
12695
12696   g_signal_emit (tree_view, tree_view_signals[ROW_EXPANDED], 0, &iter, path);
12697   if (open_all && node->children)
12698     {
12699       _gtk_rbtree_traverse (node->children,
12700                             node->children->root,
12701                             G_PRE_ORDER,
12702                             gtk_tree_view_expand_all_emission_helper,
12703                             tree_view);
12704     }
12705   return TRUE;
12706 }
12707
12708
12709 /**
12710  * gtk_tree_view_expand_row:
12711  * @tree_view: a #GtkTreeView
12712  * @path: path to a row
12713  * @open_all: whether to recursively expand, or just expand immediate children
12714  *
12715  * Opens the row so its children are visible.
12716  *
12717  * Return value: %TRUE if the row existed and had children
12718  **/
12719 gboolean
12720 gtk_tree_view_expand_row (GtkTreeView *tree_view,
12721                           GtkTreePath *path,
12722                           gboolean     open_all)
12723 {
12724   GtkRBTree *tree;
12725   GtkRBNode *node;
12726
12727   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12728   g_return_val_if_fail (tree_view->priv->model != NULL, FALSE);
12729   g_return_val_if_fail (path != NULL, FALSE);
12730
12731   if (_gtk_tree_view_find_node (tree_view,
12732                                 path,
12733                                 &tree,
12734                                 &node))
12735     return FALSE;
12736
12737   if (tree != NULL)
12738     return gtk_tree_view_real_expand_row (tree_view, path, tree, node, open_all, FALSE);
12739   else
12740     return FALSE;
12741 }
12742
12743 static gboolean
12744 gtk_tree_view_real_collapse_row (GtkTreeView *tree_view,
12745                                  GtkTreePath *path,
12746                                  GtkRBTree   *tree,
12747                                  GtkRBNode   *node,
12748                                  gboolean     animate)
12749 {
12750   GtkTreeIter iter;
12751   GtkTreeIter children;
12752   gboolean collapse;
12753   gint x, y;
12754   GList *list;
12755   GdkWindow *child;
12756   gboolean selection_changed, cursor_changed;
12757
12758   if (animate)
12759     g_object_get (gtk_widget_get_settings (GTK_WIDGET (tree_view)),
12760                   "gtk-enable-animations", &animate,
12761                   NULL);
12762
12763   remove_auto_expand_timeout (tree_view);
12764
12765   if (node->children == NULL)
12766     return FALSE;
12767   gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
12768
12769   g_signal_emit (tree_view, tree_view_signals[TEST_COLLAPSE_ROW], 0, &iter, path, &collapse);
12770
12771   if (collapse)
12772     return FALSE;
12773
12774   /* if the prelighted node is a child of us, we want to unprelight it.  We have
12775    * a chance to prelight the correct node below */
12776
12777   if (tree_view->priv->prelight_tree)
12778     {
12779       GtkRBTree *parent_tree;
12780       GtkRBNode *parent_node;
12781
12782       parent_tree = tree_view->priv->prelight_tree->parent_tree;
12783       parent_node = tree_view->priv->prelight_tree->parent_node;
12784       while (parent_tree)
12785         {
12786           if (parent_tree == tree && parent_node == node)
12787             {
12788               ensure_unprelighted (tree_view);
12789               break;
12790             }
12791           parent_node = parent_tree->parent_node;
12792           parent_tree = parent_tree->parent_tree;
12793         }
12794     }
12795
12796   TREE_VIEW_INTERNAL_ASSERT (gtk_tree_model_iter_children (tree_view->priv->model, &children, &iter), FALSE);
12797
12798   for (list = tree_view->priv->columns; list; list = list->next)
12799     {
12800       GtkTreeViewColumn *column = list->data;
12801
12802       if (gtk_tree_view_column_get_visible (column) == FALSE)
12803         continue;
12804       if (gtk_tree_view_column_get_sizing (column) == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
12805         _gtk_tree_view_column_cell_set_dirty (column, TRUE);
12806     }
12807
12808   if (tree_view->priv->destroy_count_func)
12809     {
12810       GtkTreePath *child_path;
12811       gint child_count = 0;
12812       child_path = gtk_tree_path_copy (path);
12813       gtk_tree_path_down (child_path);
12814       if (node->children)
12815         _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, &child_count);
12816       tree_view->priv->destroy_count_func (tree_view, child_path, child_count, tree_view->priv->destroy_count_data);
12817       gtk_tree_path_free (child_path);
12818     }
12819
12820   if (tree_view->priv->cursor_node)
12821     {
12822       cursor_changed = (node->children == tree_view->priv->cursor_tree)
12823                        || _gtk_rbtree_contains (node->children, tree_view->priv->cursor_tree);
12824     }
12825
12826   if (gtk_tree_row_reference_valid (tree_view->priv->anchor))
12827     {
12828       GtkTreePath *anchor_path = gtk_tree_row_reference_get_path (tree_view->priv->anchor);
12829       if (gtk_tree_path_is_ancestor (path, anchor_path))
12830         {
12831           gtk_tree_row_reference_free (tree_view->priv->anchor);
12832           tree_view->priv->anchor = NULL;
12833         }
12834       gtk_tree_path_free (anchor_path);
12835     }
12836
12837   selection_changed = gtk_tree_view_unref_and_check_selection_tree (tree_view, node->children);
12838   
12839   /* Stop a pending double click */
12840   tree_view->priv->last_button_x = -1;
12841   tree_view->priv->last_button_y = -1;
12842
12843   _gtk_tree_view_accessible_remove (tree_view, node->children, NULL);
12844
12845   _gtk_rbtree_remove (node->children);
12846
12847   /* if we change the cursor, we also change the selection,
12848    * so no need to emit selection-changed. */
12849   if (cursor_changed)
12850     gtk_tree_view_real_set_cursor (tree_view, path, TRUE, FALSE);
12851   else if (selection_changed)
12852     g_signal_emit_by_name (tree_view->priv->selection, "changed");
12853
12854   if (animate)
12855     {
12856       GtkStyleContext *context;
12857
12858       context = gtk_widget_get_style_context (GTK_WIDGET (tree_view));
12859
12860       gtk_style_context_save (context);
12861       gtk_style_context_add_class (context, GTK_STYLE_CLASS_EXPANDER);
12862
12863       gtk_style_context_notify_state_change (context, tree_view->priv->bin_window,
12864                                              node, GTK_STATE_ACTIVE, FALSE);
12865
12866       _gtk_style_context_invalidate_animation_areas (context);
12867       gtk_style_context_restore (context);
12868     }
12869
12870   if (gtk_widget_get_mapped (GTK_WIDGET (tree_view)))
12871     {
12872       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
12873     }
12874
12875   g_signal_emit (tree_view, tree_view_signals[ROW_COLLAPSED], 0, &iter, path);
12876   
12877   if (gtk_widget_get_mapped (GTK_WIDGET (tree_view)))
12878     {
12879       /* now that we've collapsed all rows, we want to try to set the prelight
12880        * again. To do this, we fake a motion event and send it to ourselves. */
12881
12882       child = gdk_window_get_device_position (gdk_window_get_parent (tree_view->priv->bin_window),
12883                                               gdk_device_manager_get_client_pointer (
12884                                                 gdk_display_get_device_manager (
12885                                                   gtk_widget_get_display (GTK_WIDGET (tree_view)))),
12886                                               &x, &y, NULL);
12887       if (child == tree_view->priv->bin_window)
12888         {
12889           GdkEventMotion event;
12890           gint child_x, child_y;
12891
12892           gdk_window_get_position (child, &child_x, &child_y);
12893
12894           event.window = tree_view->priv->bin_window;
12895           event.x = x - child_x;
12896           event.y = y - child_y;
12897
12898           /* despite the fact this isn't a real event, I'm almost positive it will
12899            * never trigger a drag event.  maybe_drag is the only function that uses
12900            * more than just event.x and event.y. */
12901           gtk_tree_view_motion_bin_window (GTK_WIDGET (tree_view), &event);
12902         }
12903     }
12904
12905   return TRUE;
12906 }
12907
12908 /**
12909  * gtk_tree_view_collapse_row:
12910  * @tree_view: a #GtkTreeView
12911  * @path: path to a row in the @tree_view
12912  *
12913  * Collapses a row (hides its child rows, if they exist).
12914  *
12915  * Return value: %TRUE if the row was collapsed.
12916  **/
12917 gboolean
12918 gtk_tree_view_collapse_row (GtkTreeView *tree_view,
12919                             GtkTreePath *path)
12920 {
12921   GtkRBTree *tree;
12922   GtkRBNode *node;
12923
12924   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12925   g_return_val_if_fail (tree_view->priv->tree != NULL, FALSE);
12926   g_return_val_if_fail (path != NULL, FALSE);
12927
12928   if (_gtk_tree_view_find_node (tree_view,
12929                                 path,
12930                                 &tree,
12931                                 &node))
12932     return FALSE;
12933
12934   if (tree == NULL || node->children == NULL)
12935     return FALSE;
12936
12937   return gtk_tree_view_real_collapse_row (tree_view, path, tree, node, FALSE);
12938 }
12939
12940 static void
12941 gtk_tree_view_map_expanded_rows_helper (GtkTreeView            *tree_view,
12942                                         GtkRBTree              *tree,
12943                                         GtkTreePath            *path,
12944                                         GtkTreeViewMappingFunc  func,
12945                                         gpointer                user_data)
12946 {
12947   GtkRBNode *node;
12948
12949   if (tree == NULL || tree->root == NULL)
12950     return;
12951
12952   node = _gtk_rbtree_first (tree);
12953
12954   while (node)
12955     {
12956       if (node->children)
12957         {
12958           (* func) (tree_view, path, user_data);
12959           gtk_tree_path_down (path);
12960           gtk_tree_view_map_expanded_rows_helper (tree_view, node->children, path, func, user_data);
12961           gtk_tree_path_up (path);
12962         }
12963       gtk_tree_path_next (path);
12964       node = _gtk_rbtree_next (tree, node);
12965     }
12966 }
12967
12968 /**
12969  * gtk_tree_view_map_expanded_rows:
12970  * @tree_view: A #GtkTreeView
12971  * @func: (scope call): A function to be called
12972  * @data: User data to be passed to the function.
12973  *
12974  * Calls @func on all expanded rows.
12975  **/
12976 void
12977 gtk_tree_view_map_expanded_rows (GtkTreeView            *tree_view,
12978                                  GtkTreeViewMappingFunc  func,
12979                                  gpointer                user_data)
12980 {
12981   GtkTreePath *path;
12982
12983   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12984   g_return_if_fail (func != NULL);
12985
12986   path = gtk_tree_path_new_first ();
12987
12988   gtk_tree_view_map_expanded_rows_helper (tree_view,
12989                                           tree_view->priv->tree,
12990                                           path, func, user_data);
12991
12992   gtk_tree_path_free (path);
12993 }
12994
12995 /**
12996  * gtk_tree_view_row_expanded:
12997  * @tree_view: A #GtkTreeView.
12998  * @path: A #GtkTreePath to test expansion state.
12999  *
13000  * Returns %TRUE if the node pointed to by @path is expanded in @tree_view.
13001  *
13002  * Return value: %TRUE if #path is expanded.
13003  **/
13004 gboolean
13005 gtk_tree_view_row_expanded (GtkTreeView *tree_view,
13006                             GtkTreePath *path)
13007 {
13008   GtkRBTree *tree;
13009   GtkRBNode *node;
13010
13011   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
13012   g_return_val_if_fail (path != NULL, FALSE);
13013
13014   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
13015
13016   if (node == NULL)
13017     return FALSE;
13018
13019   return (node->children != NULL);
13020 }
13021
13022 /**
13023  * gtk_tree_view_get_reorderable:
13024  * @tree_view: a #GtkTreeView
13025  *
13026  * Retrieves whether the user can reorder the tree via drag-and-drop. See
13027  * gtk_tree_view_set_reorderable().
13028  *
13029  * Return value: %TRUE if the tree can be reordered.
13030  **/
13031 gboolean
13032 gtk_tree_view_get_reorderable (GtkTreeView *tree_view)
13033 {
13034   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
13035
13036   return tree_view->priv->reorderable;
13037 }
13038
13039 /**
13040  * gtk_tree_view_set_reorderable:
13041  * @tree_view: A #GtkTreeView.
13042  * @reorderable: %TRUE, if the tree can be reordered.
13043  *
13044  * This function is a convenience function to allow you to reorder
13045  * models that support the #GtkTreeDragSourceIface and the
13046  * #GtkTreeDragDestIface.  Both #GtkTreeStore and #GtkListStore support
13047  * these.  If @reorderable is %TRUE, then the user can reorder the
13048  * model by dragging and dropping rows. The developer can listen to
13049  * these changes by connecting to the model's row_inserted and
13050  * row_deleted signals. The reordering is implemented by setting up
13051  * the tree view as a drag source and destination. Therefore, drag and
13052  * drop can not be used in a reorderable view for any other purpose.
13053  *
13054  * This function does not give you any degree of control over the order -- any
13055  * reordering is allowed.  If more control is needed, you should probably
13056  * handle drag and drop manually.
13057  **/
13058 void
13059 gtk_tree_view_set_reorderable (GtkTreeView *tree_view,
13060                                gboolean     reorderable)
13061 {
13062   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13063
13064   reorderable = reorderable != FALSE;
13065
13066   if (tree_view->priv->reorderable == reorderable)
13067     return;
13068
13069   if (reorderable)
13070     {
13071       const GtkTargetEntry row_targets[] = {
13072         { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, 0 }
13073       };
13074
13075       gtk_tree_view_enable_model_drag_source (tree_view,
13076                                               GDK_BUTTON1_MASK,
13077                                               row_targets,
13078                                               G_N_ELEMENTS (row_targets),
13079                                               GDK_ACTION_MOVE);
13080       gtk_tree_view_enable_model_drag_dest (tree_view,
13081                                             row_targets,
13082                                             G_N_ELEMENTS (row_targets),
13083                                             GDK_ACTION_MOVE);
13084     }
13085   else
13086     {
13087       gtk_tree_view_unset_rows_drag_source (tree_view);
13088       gtk_tree_view_unset_rows_drag_dest (tree_view);
13089     }
13090
13091   tree_view->priv->reorderable = reorderable;
13092
13093   g_object_notify (G_OBJECT (tree_view), "reorderable");
13094 }
13095
13096 static void
13097 gtk_tree_view_real_set_cursor (GtkTreeView     *tree_view,
13098                                GtkTreePath     *path,
13099                                gboolean         clear_and_select,
13100                                gboolean         clamp_node)
13101 {
13102   if (tree_view->priv->cursor_node)
13103     {
13104       _gtk_tree_view_queue_draw_node (tree_view,
13105                                       tree_view->priv->cursor_tree,
13106                                       tree_view->priv->cursor_node,
13107                                       NULL);
13108     }
13109
13110   /* One cannot set the cursor on a separator.   Also, if
13111    * _gtk_tree_view_find_node returns TRUE, it ran out of tree
13112    * before finding the tree and node belonging to path.  The
13113    * path maps to a non-existing path and we will silently bail out.
13114    * We unset tree and node to avoid further processing.
13115    */
13116   if (row_is_separator (tree_view, NULL, path)
13117       || _gtk_tree_view_find_node (tree_view,
13118                                    path,
13119                                    &tree_view->priv->cursor_tree,
13120                                    &tree_view->priv->cursor_node))
13121     {
13122       tree_view->priv->cursor_tree = NULL;
13123       tree_view->priv->cursor_node = NULL;
13124     }
13125
13126   if (tree_view->priv->cursor_node != NULL)
13127     {
13128       GtkRBTree *new_tree = NULL;
13129       GtkRBNode *new_node = NULL;
13130
13131       if (clear_and_select && !tree_view->priv->modify_selection_pressed)
13132         {
13133           GtkTreeSelectMode mode = 0;
13134
13135           if (tree_view->priv->extend_selection_pressed)
13136             mode |= GTK_TREE_SELECT_MODE_EXTEND;
13137
13138           _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
13139                                                     tree_view->priv->cursor_node,
13140                                                     tree_view->priv->cursor_tree,
13141                                                     path,
13142                                                     mode,
13143                                                     FALSE);
13144         }
13145
13146       /* We have to re-find tree and node here again, somebody might have
13147        * cleared the node or the whole tree in the GtkTreeSelection::changed
13148        * callback. If the nodes differ we bail out here.
13149        */
13150       _gtk_tree_view_find_node (tree_view, path, &new_tree, &new_node);
13151
13152       if (tree_view->priv->cursor_node != new_node)
13153         return;
13154
13155       if (clamp_node)
13156         {
13157           gtk_tree_view_clamp_node_visible (tree_view,
13158                                             tree_view->priv->cursor_tree,
13159                                             tree_view->priv->cursor_node);
13160           _gtk_tree_view_queue_draw_node (tree_view,
13161                                           tree_view->priv->cursor_tree,
13162                                           tree_view->priv->cursor_node,
13163                                           NULL);
13164         }
13165     }
13166
13167   g_signal_emit (tree_view, tree_view_signals[CURSOR_CHANGED], 0);
13168 }
13169
13170 /**
13171  * gtk_tree_view_get_cursor:
13172  * @tree_view: A #GtkTreeView
13173  * @path: (out) (transfer full) (allow-none): A pointer to be filled with the current cursor path, or %NULL
13174  * @focus_column: (out) (transfer none) (allow-none): A pointer to be filled with the current focus column, or %NULL
13175  *
13176  * Fills in @path and @focus_column with the current path and focus column.  If
13177  * the cursor isn't currently set, then *@path will be %NULL.  If no column
13178  * currently has focus, then *@focus_column will be %NULL.
13179  *
13180  * The returned #GtkTreePath must be freed with gtk_tree_path_free() when
13181  * you are done with it.
13182  **/
13183 void
13184 gtk_tree_view_get_cursor (GtkTreeView        *tree_view,
13185                           GtkTreePath       **path,
13186                           GtkTreeViewColumn **focus_column)
13187 {
13188   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13189
13190   if (path)
13191     {
13192       if (tree_view->priv->cursor_node)
13193         *path = _gtk_tree_path_new_from_rbtree (tree_view->priv->cursor_tree,
13194                                                 tree_view->priv->cursor_node);
13195       else
13196         *path = NULL;
13197     }
13198
13199   if (focus_column)
13200     {
13201       *focus_column = tree_view->priv->focus_column;
13202     }
13203 }
13204
13205 /**
13206  * gtk_tree_view_set_cursor:
13207  * @tree_view: A #GtkTreeView
13208  * @path: A #GtkTreePath
13209  * @focus_column: (allow-none): A #GtkTreeViewColumn, or %NULL
13210  * @start_editing: %TRUE if the specified cell should start being edited.
13211  *
13212  * Sets the current keyboard focus to be at @path, and selects it.  This is
13213  * useful when you want to focus the user's attention on a particular row.  If
13214  * @focus_column is not %NULL, then focus is given to the column specified by 
13215  * it. Additionally, if @focus_column is specified, and @start_editing is 
13216  * %TRUE, then editing should be started in the specified cell.  
13217  * This function is often followed by @gtk_widget_grab_focus (@tree_view) 
13218  * in order to give keyboard focus to the widget.  Please note that editing 
13219  * can only happen when the widget is realized.
13220  *
13221  * If @path is invalid for @model, the current cursor (if any) will be unset
13222  * and the function will return without failing.
13223  **/
13224 void
13225 gtk_tree_view_set_cursor (GtkTreeView       *tree_view,
13226                           GtkTreePath       *path,
13227                           GtkTreeViewColumn *focus_column,
13228                           gboolean           start_editing)
13229 {
13230   gtk_tree_view_set_cursor_on_cell (tree_view, path, focus_column,
13231                                     NULL, start_editing);
13232 }
13233
13234 /**
13235  * gtk_tree_view_set_cursor_on_cell:
13236  * @tree_view: A #GtkTreeView
13237  * @path: A #GtkTreePath
13238  * @focus_column: (allow-none): A #GtkTreeViewColumn, or %NULL
13239  * @focus_cell: (allow-none): A #GtkCellRenderer, or %NULL
13240  * @start_editing: %TRUE if the specified cell should start being edited.
13241  *
13242  * Sets the current keyboard focus to be at @path, and selects it.  This is
13243  * useful when you want to focus the user's attention on a particular row.  If
13244  * @focus_column is not %NULL, then focus is given to the column specified by
13245  * it. If @focus_column and @focus_cell are not %NULL, and @focus_column
13246  * contains 2 or more editable or activatable cells, then focus is given to
13247  * the cell specified by @focus_cell. Additionally, if @focus_column is
13248  * specified, and @start_editing is %TRUE, then editing should be started in
13249  * the specified cell.  This function is often followed by
13250  * @gtk_widget_grab_focus (@tree_view) in order to give keyboard focus to the
13251  * widget.  Please note that editing can only happen when the widget is
13252  * realized.
13253  *
13254  * If @path is invalid for @model, the current cursor (if any) will be unset
13255  * and the function will return without failing.
13256  *
13257  * Since: 2.2
13258  **/
13259 void
13260 gtk_tree_view_set_cursor_on_cell (GtkTreeView       *tree_view,
13261                                   GtkTreePath       *path,
13262                                   GtkTreeViewColumn *focus_column,
13263                                   GtkCellRenderer   *focus_cell,
13264                                   gboolean           start_editing)
13265 {
13266   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13267   g_return_if_fail (path != NULL);
13268   g_return_if_fail (focus_column == NULL || GTK_IS_TREE_VIEW_COLUMN (focus_column));
13269
13270   if (!tree_view->priv->model)
13271     return;
13272
13273   if (focus_cell)
13274     {
13275       g_return_if_fail (focus_column);
13276       g_return_if_fail (GTK_IS_CELL_RENDERER (focus_cell));
13277     }
13278
13279   /* cancel the current editing, if it exists */
13280   if (tree_view->priv->edited_column &&
13281       gtk_cell_area_get_edit_widget
13282       (gtk_cell_layout_get_area (GTK_CELL_LAYOUT (tree_view->priv->edited_column))))
13283     gtk_tree_view_stop_editing (tree_view, TRUE);
13284
13285   gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
13286
13287   if (focus_column &&
13288       gtk_tree_view_column_get_visible (focus_column))
13289     {
13290       GList *list;
13291       gboolean column_in_tree = FALSE;
13292
13293       for (list = tree_view->priv->columns; list; list = list->next)
13294         if (list->data == focus_column)
13295           {
13296             column_in_tree = TRUE;
13297             break;
13298           }
13299       g_return_if_fail (column_in_tree);
13300       tree_view->priv->focus_column = focus_column;
13301       if (focus_cell)
13302         gtk_tree_view_column_focus_cell (focus_column, focus_cell);
13303       if (start_editing)
13304         gtk_tree_view_start_editing (tree_view, path, TRUE);
13305     }
13306 }
13307
13308 /**
13309  * gtk_tree_view_get_bin_window:
13310  * @tree_view: A #GtkTreeView
13311  *
13312  * Returns the window that @tree_view renders to.
13313  * This is used primarily to compare to <literal>event->window</literal>
13314  * to confirm that the event on @tree_view is on the right window.
13315  *
13316  * Return value: (transfer none): A #GdkWindow, or %NULL when @tree_view
13317  *     hasn't been realized yet
13318  **/
13319 GdkWindow *
13320 gtk_tree_view_get_bin_window (GtkTreeView *tree_view)
13321 {
13322   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
13323
13324   return tree_view->priv->bin_window;
13325 }
13326
13327 /**
13328  * gtk_tree_view_get_path_at_pos:
13329  * @tree_view: A #GtkTreeView.
13330  * @x: The x position to be identified (relative to bin_window).
13331  * @y: The y position to be identified (relative to bin_window).
13332  * @path: (out) (allow-none): A pointer to a #GtkTreePath pointer to be filled in, or %NULL
13333  * @column: (out) (transfer none) (allow-none): A pointer to a #GtkTreeViewColumn pointer to be filled in, or %NULL
13334  * @cell_x: (out) (allow-none): A pointer where the X coordinate relative to the cell can be placed, or %NULL
13335  * @cell_y: (out) (allow-none): A pointer where the Y coordinate relative to the cell can be placed, or %NULL
13336  *
13337  * Finds the path at the point (@x, @y), relative to bin_window coordinates
13338  * (please see gtk_tree_view_get_bin_window()).
13339  * That is, @x and @y are relative to an events coordinates. @x and @y must
13340  * come from an event on the @tree_view only where <literal>event->window ==
13341  * gtk_tree_view_get_bin_window (<!-- -->)</literal>. It is primarily for
13342  * things like popup menus. If @path is non-%NULL, then it will be filled
13343  * with the #GtkTreePath at that point.  This path should be freed with
13344  * gtk_tree_path_free().  If @column is non-%NULL, then it will be filled
13345  * with the column at that point.  @cell_x and @cell_y return the coordinates
13346  * relative to the cell background (i.e. the @background_area passed to
13347  * gtk_cell_renderer_render()).  This function is only meaningful if
13348  * @tree_view is realized.  Therefore this function will always return %FALSE
13349  * if @tree_view is not realized or does not have a model.
13350  *
13351  * For converting widget coordinates (eg. the ones you get from
13352  * GtkWidget::query-tooltip), please see
13353  * gtk_tree_view_convert_widget_to_bin_window_coords().
13354  *
13355  * Return value: %TRUE if a row exists at that coordinate.
13356  **/
13357 gboolean
13358 gtk_tree_view_get_path_at_pos (GtkTreeView        *tree_view,
13359                                gint                x,
13360                                gint                y,
13361                                GtkTreePath       **path,
13362                                GtkTreeViewColumn **column,
13363                                gint               *cell_x,
13364                                gint               *cell_y)
13365 {
13366   GtkRBTree *tree;
13367   GtkRBNode *node;
13368   gint y_offset;
13369
13370   g_return_val_if_fail (tree_view != NULL, FALSE);
13371
13372   if (path)
13373     *path = NULL;
13374   if (column)
13375     *column = NULL;
13376
13377   if (tree_view->priv->bin_window == NULL)
13378     return FALSE;
13379
13380   if (tree_view->priv->tree == NULL)
13381     return FALSE;
13382
13383   if (x > gtk_adjustment_get_upper (tree_view->priv->hadjustment))
13384     return FALSE;
13385
13386   if (x < 0 || y < 0)
13387     return FALSE;
13388
13389   if (column || cell_x)
13390     {
13391       GtkTreeViewColumn *tmp_column;
13392       GtkTreeViewColumn *last_column = NULL;
13393       GList *list;
13394       gint remaining_x = x;
13395       gboolean found = FALSE;
13396       gboolean rtl;
13397       gint width;
13398
13399       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
13400       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
13401            list;
13402            list = (rtl ? list->prev : list->next))
13403         {
13404           tmp_column = list->data;
13405
13406           if (gtk_tree_view_column_get_visible (tmp_column) == FALSE)
13407             continue;
13408
13409           last_column = tmp_column;
13410           width = gtk_tree_view_column_get_width (tmp_column);
13411           if (remaining_x <= width)
13412             {
13413               found = TRUE;
13414
13415               if (column)
13416                 *column = tmp_column;
13417
13418               if (cell_x)
13419                 *cell_x = remaining_x;
13420
13421               break;
13422             }
13423           remaining_x -= width;
13424         }
13425
13426       /* If found is FALSE and there is a last_column, then it the remainder
13427        * space is in that area
13428        */
13429       if (!found)
13430         {
13431           if (last_column)
13432             {
13433               if (column)
13434                 *column = last_column;
13435               
13436               if (cell_x)
13437                 *cell_x = gtk_tree_view_column_get_width (last_column) + remaining_x;
13438             }
13439           else
13440             {
13441               return FALSE;
13442             }
13443         }
13444     }
13445
13446   y_offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
13447                                       TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, y),
13448                                       &tree, &node);
13449
13450   if (tree == NULL)
13451     return FALSE;
13452
13453   if (cell_y)
13454     *cell_y = y_offset;
13455
13456   if (path)
13457     *path = _gtk_tree_path_new_from_rbtree (tree, node);
13458
13459   return TRUE;
13460 }
13461
13462
13463 static inline gint
13464 gtk_tree_view_get_cell_area_height (GtkTreeView *tree_view,
13465                                     GtkRBNode   *node,
13466                                     gint         vertical_separator)
13467 {
13468   int height;
13469
13470   /* The "cell" areas are the cell_area passed in to gtk_cell_renderer_render(),
13471    * i.e. just the cells, no spacing.
13472    *
13473    * The cell area height is at least expander_size - vertical_separator.
13474    * For regular nodes, the height is then at least expander_size. We should
13475    * be able to enforce the expander_size minimum here, because this
13476    * function will not be called for irregular (e.g. separator) rows.
13477    */
13478   height = gtk_tree_view_get_row_height (tree_view, node);
13479   if (height < tree_view->priv->expander_size)
13480     height = tree_view->priv->expander_size;
13481
13482   return height - vertical_separator;
13483 }
13484
13485 static inline gint
13486 gtk_tree_view_get_cell_area_y_offset (GtkTreeView *tree_view,
13487                                       GtkRBTree   *tree,
13488                                       GtkRBNode   *node,
13489                                       gint         vertical_separator)
13490 {
13491   int offset;
13492
13493   offset = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
13494   offset += vertical_separator / 2;
13495
13496   return offset;
13497 }
13498
13499 /**
13500  * gtk_tree_view_get_cell_area:
13501  * @tree_view: a #GtkTreeView
13502  * @path: (allow-none): a #GtkTreePath for the row, or %NULL to get only horizontal coordinates
13503  * @column: (allow-none): a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordinates
13504  * @rect: (out): rectangle to fill with cell rect
13505  *
13506  * Fills the bounding rectangle in bin_window coordinates for the cell at the
13507  * row specified by @path and the column specified by @column.  If @path is
13508  * %NULL, or points to a path not currently displayed, the @y and @height fields
13509  * of the rectangle will be filled with 0. If @column is %NULL, the @x and @width
13510  * fields will be filled with 0.  The sum of all cell rects does not cover the
13511  * entire tree; there are extra pixels in between rows, for example. The
13512  * returned rectangle is equivalent to the @cell_area passed to
13513  * gtk_cell_renderer_render().  This function is only valid if @tree_view is
13514  * realized.
13515  **/
13516 void
13517 gtk_tree_view_get_cell_area (GtkTreeView        *tree_view,
13518                              GtkTreePath        *path,
13519                              GtkTreeViewColumn  *column,
13520                              GdkRectangle       *rect)
13521 {
13522   GtkRBTree *tree = NULL;
13523   GtkRBNode *node = NULL;
13524   gint vertical_separator;
13525   gint horizontal_separator;
13526
13527   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13528   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
13529   g_return_if_fail (rect != NULL);
13530   g_return_if_fail (!column || gtk_tree_view_column_get_tree_view (column) == (GtkWidget *) tree_view);
13531   g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (tree_view)));
13532
13533   gtk_widget_style_get (GTK_WIDGET (tree_view),
13534                         "vertical-separator", &vertical_separator,
13535                         "horizontal-separator", &horizontal_separator,
13536                         NULL);
13537
13538   rect->x = 0;
13539   rect->y = 0;
13540   rect->width = 0;
13541   rect->height = 0;
13542
13543   if (column)
13544     {
13545       rect->x = gtk_tree_view_column_get_x_offset (column) + horizontal_separator/2;
13546       rect->width = gtk_tree_view_column_get_width (column) - horizontal_separator;
13547     }
13548
13549   if (path)
13550     {
13551       gboolean ret = _gtk_tree_view_find_node (tree_view, path, &tree, &node);
13552
13553       /* Get vertical coords */
13554       if ((!ret && tree == NULL) || ret)
13555         return;
13556
13557       if (row_is_separator (tree_view, NULL, path))
13558         {
13559           /* There isn't really a "cell area" for separator, so we
13560            * return the y, height values for background area instead.
13561            */
13562           rect->y = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
13563           rect->height = gtk_tree_view_get_row_height (tree_view, node);
13564         }
13565       else
13566         {
13567           rect->y = gtk_tree_view_get_cell_area_y_offset (tree_view, tree, node,
13568                                                           vertical_separator);
13569           rect->height = gtk_tree_view_get_cell_area_height (tree_view, node,
13570                                                              vertical_separator);
13571         }
13572
13573       if (column &&
13574           gtk_tree_view_is_expander_column (tree_view, column))
13575         {
13576           gint depth = gtk_tree_path_get_depth (path);
13577           gboolean rtl;
13578
13579           rtl = gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL;
13580
13581           if (!rtl)
13582             rect->x += (depth - 1) * tree_view->priv->level_indentation;
13583           rect->width -= (depth - 1) * tree_view->priv->level_indentation;
13584
13585           if (gtk_tree_view_draw_expanders (tree_view))
13586             {
13587               if (!rtl)
13588                 rect->x += depth * tree_view->priv->expander_size;
13589               rect->width -= depth * tree_view->priv->expander_size;
13590             }
13591
13592           rect->width = MAX (rect->width, 0);
13593         }
13594     }
13595 }
13596
13597 static inline gint
13598 gtk_tree_view_get_row_height (GtkTreeView *tree_view,
13599                               GtkRBNode   *node)
13600 {
13601   int height;
13602
13603   /* The "background" areas of all rows/cells add up to cover the entire tree.
13604    * The background includes all inter-row and inter-cell spacing.
13605    *
13606    * If the row pointed at by node does not have a height set, we default
13607    * to expander_size, which is the minimum height for regular nodes.
13608    * Non-regular nodes (e.g. separators) can have a height set smaller
13609    * than expander_size and should not be overruled here.
13610    */
13611   height = GTK_RBNODE_GET_HEIGHT (node);
13612   if (height <= 0)
13613     height = tree_view->priv->expander_size;
13614
13615   return height;
13616 }
13617
13618 static inline gint
13619 gtk_tree_view_get_row_y_offset (GtkTreeView *tree_view,
13620                                 GtkRBTree   *tree,
13621                                 GtkRBNode   *node)
13622 {
13623   int offset;
13624
13625   offset = _gtk_rbtree_node_find_offset (tree, node);
13626
13627   return RBTREE_Y_TO_TREE_WINDOW_Y (tree_view, offset);
13628 }
13629
13630 /**
13631  * gtk_tree_view_get_background_area:
13632  * @tree_view: a #GtkTreeView
13633  * @path: (allow-none): a #GtkTreePath for the row, or %NULL to get only horizontal coordinates
13634  * @column: (allow-none): a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordiantes
13635  * @rect: (out): rectangle to fill with cell background rect
13636  *
13637  * Fills the bounding rectangle in bin_window coordinates for the cell at the
13638  * row specified by @path and the column specified by @column.  If @path is
13639  * %NULL, or points to a node not found in the tree, the @y and @height fields of
13640  * the rectangle will be filled with 0. If @column is %NULL, the @x and @width
13641  * fields will be filled with 0.  The returned rectangle is equivalent to the
13642  * @background_area passed to gtk_cell_renderer_render().  These background
13643  * areas tile to cover the entire bin window.  Contrast with the @cell_area,
13644  * returned by gtk_tree_view_get_cell_area(), which returns only the cell
13645  * itself, excluding surrounding borders and the tree expander area.
13646  *
13647  **/
13648 void
13649 gtk_tree_view_get_background_area (GtkTreeView        *tree_view,
13650                                    GtkTreePath        *path,
13651                                    GtkTreeViewColumn  *column,
13652                                    GdkRectangle       *rect)
13653 {
13654   GtkRBTree *tree = NULL;
13655   GtkRBNode *node = NULL;
13656
13657   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13658   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
13659   g_return_if_fail (rect != NULL);
13660
13661   rect->x = 0;
13662   rect->y = 0;
13663   rect->width = 0;
13664   rect->height = 0;
13665
13666   if (path)
13667     {
13668       /* Get vertical coords */
13669
13670       if (!_gtk_tree_view_find_node (tree_view, path, &tree, &node) &&
13671           tree == NULL)
13672         return;
13673
13674       rect->y = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
13675       rect->height = gtk_tree_view_get_row_height (tree_view, node);
13676     }
13677
13678   if (column)
13679     {
13680       gint x2 = 0;
13681
13682       gtk_tree_view_get_background_xrange (tree_view, tree, column, &rect->x, &x2);
13683       rect->width = x2 - rect->x;
13684     }
13685 }
13686
13687 /**
13688  * gtk_tree_view_get_visible_rect:
13689  * @tree_view: a #GtkTreeView
13690  * @visible_rect: (out): rectangle to fill
13691  *
13692  * Fills @visible_rect with the currently-visible region of the
13693  * buffer, in tree coordinates. Convert to bin_window coordinates with
13694  * gtk_tree_view_convert_tree_to_bin_window_coords().
13695  * Tree coordinates start at 0,0 for row 0 of the tree, and cover the entire
13696  * scrollable area of the tree.
13697  **/
13698 void
13699 gtk_tree_view_get_visible_rect (GtkTreeView  *tree_view,
13700                                 GdkRectangle *visible_rect)
13701 {
13702   GtkAllocation allocation;
13703   GtkWidget *widget;
13704
13705   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13706
13707   widget = GTK_WIDGET (tree_view);
13708
13709   if (visible_rect)
13710     {
13711       gtk_widget_get_allocation (widget, &allocation);
13712       visible_rect->x = gtk_adjustment_get_value (tree_view->priv->hadjustment);
13713       visible_rect->y = gtk_adjustment_get_value (tree_view->priv->vadjustment);
13714       visible_rect->width = allocation.width;
13715       visible_rect->height = allocation.height - gtk_tree_view_get_effective_header_height (tree_view);
13716     }
13717 }
13718
13719 /**
13720  * gtk_tree_view_convert_widget_to_tree_coords:
13721  * @tree_view: a #GtkTreeView
13722  * @wx: X coordinate relative to the widget
13723  * @wy: Y coordinate relative to the widget
13724  * @tx: (out): return location for tree X coordinate
13725  * @ty: (out): return location for tree Y coordinate
13726  *
13727  * Converts widget coordinates to coordinates for the
13728  * tree (the full scrollable area of the tree).
13729  *
13730  * Since: 2.12
13731  **/
13732 void
13733 gtk_tree_view_convert_widget_to_tree_coords (GtkTreeView *tree_view,
13734                                              gint         wx,
13735                                              gint         wy,
13736                                              gint        *tx,
13737                                              gint        *ty)
13738 {
13739   gint x, y;
13740
13741   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13742
13743   gtk_tree_view_convert_widget_to_bin_window_coords (tree_view,
13744                                                      wx, wy,
13745                                                      &x, &y);
13746   gtk_tree_view_convert_bin_window_to_tree_coords (tree_view,
13747                                                    x, y,
13748                                                    tx, ty);
13749 }
13750
13751 /**
13752  * gtk_tree_view_convert_tree_to_widget_coords:
13753  * @tree_view: a #GtkTreeView
13754  * @tx: X coordinate relative to the tree
13755  * @ty: Y coordinate relative to the tree
13756  * @wx: (out): return location for widget X coordinate
13757  * @wy: (out): return location for widget Y coordinate
13758  *
13759  * Converts tree coordinates (coordinates in full scrollable area of the tree)
13760  * to widget coordinates.
13761  *
13762  * Since: 2.12
13763  **/
13764 void
13765 gtk_tree_view_convert_tree_to_widget_coords (GtkTreeView *tree_view,
13766                                              gint         tx,
13767                                              gint         ty,
13768                                              gint        *wx,
13769                                              gint        *wy)
13770 {
13771   gint x, y;
13772
13773   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13774
13775   gtk_tree_view_convert_tree_to_bin_window_coords (tree_view,
13776                                                    tx, ty,
13777                                                    &x, &y);
13778   gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
13779                                                      x, y,
13780                                                      wx, wy);
13781 }
13782
13783 /**
13784  * gtk_tree_view_convert_widget_to_bin_window_coords:
13785  * @tree_view: a #GtkTreeView
13786  * @wx: X coordinate relative to the widget
13787  * @wy: Y coordinate relative to the widget
13788  * @bx: (out): return location for bin_window X coordinate
13789  * @by: (out): return location for bin_window Y coordinate
13790  *
13791  * Converts widget coordinates to coordinates for the bin_window
13792  * (see gtk_tree_view_get_bin_window()).
13793  *
13794  * Since: 2.12
13795  **/
13796 void
13797 gtk_tree_view_convert_widget_to_bin_window_coords (GtkTreeView *tree_view,
13798                                                    gint         wx,
13799                                                    gint         wy,
13800                                                    gint        *bx,
13801                                                    gint        *by)
13802 {
13803   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13804
13805   if (bx)
13806     *bx = wx + gtk_adjustment_get_value (tree_view->priv->hadjustment);
13807   if (by)
13808     *by = wy - gtk_tree_view_get_effective_header_height (tree_view);
13809 }
13810
13811 /**
13812  * gtk_tree_view_convert_bin_window_to_widget_coords:
13813  * @tree_view: a #GtkTreeView
13814  * @bx: bin_window X coordinate
13815  * @by: bin_window Y coordinate
13816  * @wx: (out): return location for widget X coordinate
13817  * @wy: (out): return location for widget Y coordinate
13818  *
13819  * Converts bin_window coordinates (see gtk_tree_view_get_bin_window())
13820  * to widget relative coordinates.
13821  *
13822  * Since: 2.12
13823  **/
13824 void
13825 gtk_tree_view_convert_bin_window_to_widget_coords (GtkTreeView *tree_view,
13826                                                    gint         bx,
13827                                                    gint         by,
13828                                                    gint        *wx,
13829                                                    gint        *wy)
13830 {
13831   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13832
13833   if (wx)
13834     *wx = bx - gtk_adjustment_get_value (tree_view->priv->hadjustment);
13835   if (wy)
13836     *wy = by + gtk_tree_view_get_effective_header_height (tree_view);
13837 }
13838
13839 /**
13840  * gtk_tree_view_convert_tree_to_bin_window_coords:
13841  * @tree_view: a #GtkTreeView
13842  * @tx: tree X coordinate
13843  * @ty: tree Y coordinate
13844  * @bx: (out): return location for X coordinate relative to bin_window
13845  * @by: (out): return location for Y coordinate relative to bin_window
13846  *
13847  * Converts tree coordinates (coordinates in full scrollable area of the tree)
13848  * to bin_window coordinates.
13849  *
13850  * Since: 2.12
13851  **/
13852 void
13853 gtk_tree_view_convert_tree_to_bin_window_coords (GtkTreeView *tree_view,
13854                                                  gint         tx,
13855                                                  gint         ty,
13856                                                  gint        *bx,
13857                                                  gint        *by)
13858 {
13859   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13860
13861   if (bx)
13862     *bx = tx;
13863   if (by)
13864     *by = ty - tree_view->priv->dy;
13865 }
13866
13867 /**
13868  * gtk_tree_view_convert_bin_window_to_tree_coords:
13869  * @tree_view: a #GtkTreeView
13870  * @bx: X coordinate relative to bin_window
13871  * @by: Y coordinate relative to bin_window
13872  * @tx: (out): return location for tree X coordinate
13873  * @ty: (out): return location for tree Y coordinate
13874  *
13875  * Converts bin_window coordinates to coordinates for the
13876  * tree (the full scrollable area of the tree).
13877  *
13878  * Since: 2.12
13879  **/
13880 void
13881 gtk_tree_view_convert_bin_window_to_tree_coords (GtkTreeView *tree_view,
13882                                                  gint         bx,
13883                                                  gint         by,
13884                                                  gint        *tx,
13885                                                  gint        *ty)
13886 {
13887   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13888
13889   if (tx)
13890     *tx = bx;
13891   if (ty)
13892     *ty = by + tree_view->priv->dy;
13893 }
13894
13895
13896
13897 /**
13898  * gtk_tree_view_get_visible_range:
13899  * @tree_view: A #GtkTreeView
13900  * @start_path: (out) (allow-none): Return location for start of region,
13901  *              or %NULL.
13902  * @end_path: (out) (allow-none): Return location for end of region, or %NULL.
13903  *
13904  * Sets @start_path and @end_path to be the first and last visible path.
13905  * Note that there may be invisible paths in between.
13906  *
13907  * The paths should be freed with gtk_tree_path_free() after use.
13908  *
13909  * Returns: %TRUE, if valid paths were placed in @start_path and @end_path.
13910  *
13911  * Since: 2.8
13912  **/
13913 gboolean
13914 gtk_tree_view_get_visible_range (GtkTreeView  *tree_view,
13915                                  GtkTreePath **start_path,
13916                                  GtkTreePath **end_path)
13917 {
13918   GtkRBTree *tree;
13919   GtkRBNode *node;
13920   gboolean retval;
13921   
13922   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
13923
13924   if (!tree_view->priv->tree)
13925     return FALSE;
13926
13927   retval = TRUE;
13928
13929   if (start_path)
13930     {
13931       _gtk_rbtree_find_offset (tree_view->priv->tree,
13932                                TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, 0),
13933                                &tree, &node);
13934       if (node)
13935         *start_path = _gtk_tree_path_new_from_rbtree (tree, node);
13936       else
13937         retval = FALSE;
13938     }
13939
13940   if (end_path)
13941     {
13942       gint y;
13943
13944       if (tree_view->priv->height < gtk_adjustment_get_page_size (tree_view->priv->vadjustment))
13945         y = tree_view->priv->height - 1;
13946       else
13947         y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, gtk_adjustment_get_page_size (tree_view->priv->vadjustment)) - 1;
13948
13949       _gtk_rbtree_find_offset (tree_view->priv->tree, y, &tree, &node);
13950       if (node)
13951         *end_path = _gtk_tree_path_new_from_rbtree (tree, node);
13952       else
13953         retval = FALSE;
13954     }
13955
13956   return retval;
13957 }
13958
13959 /**
13960  * gtk_tree_view_is_blank_at_pos:
13961  * @tree_view: A #GtkTreeView
13962  * @x: The x position to be identified (relative to bin_window)
13963  * @y: The y position to be identified (relative to bin_window)
13964  * @path: (out) (allow-none): A pointer to a #GtkTreePath pointer to be filled in, or %NULL
13965  * @column: (out) (allow-none): A pointer to a #GtkTreeViewColumn pointer to be filled in, or %NULL
13966  * @cell_x: (out) (allow-none): A pointer where the X coordinate relative to the cell can be placed, or %NULL
13967  * @cell_y: (out) (allow-none): A pointer where the Y coordinate relative to the cell can be placed, or %NULL
13968  *
13969  * Determine whether the point (@x, @y) in @tree_view is blank, that is no
13970  * cell content nor an expander arrow is drawn at the location. If so, the
13971  * location can be considered as the background. You might wish to take
13972  * special action on clicks on the background, such as clearing a current
13973  * selection, having a custom context menu or starting rubber banding.
13974  *
13975  * The @x and @y coordinate that are provided must be relative to bin_window
13976  * coordinates.  That is, @x and @y must come from an event on @tree_view
13977  * where <literal>event->window == gtk_tree_view_get_bin_window (<!-- -->)</literal>.
13978  *
13979  * For converting widget coordinates (eg. the ones you get from
13980  * GtkWidget::query-tooltip), please see
13981  * gtk_tree_view_convert_widget_to_bin_window_coords().
13982  *
13983  * The @path, @column, @cell_x and @cell_y arguments will be filled in
13984  * likewise as for gtk_tree_view_get_path_at_pos().  Please see
13985  * gtk_tree_view_get_path_at_pos() for more information.
13986  *
13987  * Return value: %TRUE if the area at the given coordinates is blank,
13988  * %FALSE otherwise.
13989  *
13990  * Since: 3.0
13991  */
13992 gboolean
13993 gtk_tree_view_is_blank_at_pos (GtkTreeView       *tree_view,
13994                                gint                x,
13995                                gint                y,
13996                                GtkTreePath       **path,
13997                                GtkTreeViewColumn **column,
13998                                gint               *cell_x,
13999                                gint               *cell_y)
14000 {
14001   GtkRBTree *tree;
14002   GtkRBNode *node;
14003   GtkTreeIter iter;
14004   GtkTreePath *real_path;
14005   GtkTreeViewColumn *real_column;
14006   GdkRectangle cell_area, background_area;
14007
14008   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
14009
14010   if (!gtk_tree_view_get_path_at_pos (tree_view, x, y,
14011                                       &real_path, &real_column,
14012                                       cell_x, cell_y))
14013     /* If there's no path here, it is blank */
14014     return TRUE;
14015
14016   if (path)
14017     *path = real_path;
14018
14019   if (column)
14020     *column = real_column;
14021
14022   gtk_tree_model_get_iter (tree_view->priv->model, &iter, real_path);
14023   _gtk_tree_view_find_node (tree_view, real_path, &tree, &node);
14024
14025   /* Check if there's an expander arrow at (x, y) */
14026   if (real_column == tree_view->priv->expander_column
14027       && gtk_tree_view_draw_expanders (tree_view))
14028     {
14029       gboolean over_arrow;
14030
14031       over_arrow = coords_are_over_arrow (tree_view, tree, node, x, y);
14032
14033       if (over_arrow)
14034         {
14035           if (!path)
14036             gtk_tree_path_free (real_path);
14037           return FALSE;
14038         }
14039     }
14040
14041   /* Otherwise, have the column see if there's a cell at (x, y) */
14042   gtk_tree_view_column_cell_set_cell_data (real_column,
14043                                            tree_view->priv->model,
14044                                            &iter,
14045                                            GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
14046                                            node->children ? TRUE : FALSE);
14047
14048   gtk_tree_view_get_background_area (tree_view, real_path, real_column,
14049                                      &background_area);
14050   gtk_tree_view_get_cell_area (tree_view, real_path, real_column,
14051                                &cell_area);
14052
14053   if (!path)
14054     gtk_tree_path_free (real_path);
14055
14056   return _gtk_tree_view_column_is_blank_at_pos (real_column,
14057                                                 &cell_area,
14058                                                 &background_area,
14059                                                 x, y);
14060 }
14061
14062 static void
14063 unset_reorderable (GtkTreeView *tree_view)
14064 {
14065   if (tree_view->priv->reorderable)
14066     {
14067       tree_view->priv->reorderable = FALSE;
14068       g_object_notify (G_OBJECT (tree_view), "reorderable");
14069     }
14070 }
14071
14072 /**
14073  * gtk_tree_view_enable_model_drag_source:
14074  * @tree_view: a #GtkTreeView
14075  * @start_button_mask: Mask of allowed buttons to start drag
14076  * @targets: (array length=n_targets): the table of targets that the drag will support
14077  * @n_targets: the number of items in @targets
14078  * @actions: the bitmask of possible actions for a drag from this
14079  *    widget
14080  *
14081  * Turns @tree_view into a drag source for automatic DND. Calling this
14082  * method sets #GtkTreeView:reorderable to %FALSE.
14083  **/
14084 void
14085 gtk_tree_view_enable_model_drag_source (GtkTreeView              *tree_view,
14086                                         GdkModifierType           start_button_mask,
14087                                         const GtkTargetEntry     *targets,
14088                                         gint                      n_targets,
14089                                         GdkDragAction             actions)
14090 {
14091   TreeViewDragInfo *di;
14092
14093   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14094
14095   gtk_drag_source_set (GTK_WIDGET (tree_view),
14096                        0,
14097                        targets,
14098                        n_targets,
14099                        actions);
14100
14101   di = ensure_info (tree_view);
14102
14103   di->start_button_mask = start_button_mask;
14104   di->source_actions = actions;
14105   di->source_set = TRUE;
14106
14107   unset_reorderable (tree_view);
14108 }
14109
14110 /**
14111  * gtk_tree_view_enable_model_drag_dest:
14112  * @tree_view: a #GtkTreeView
14113  * @targets: (array length=n_targets): the table of targets that
14114  *           the drag will support
14115  * @n_targets: the number of items in @targets
14116  * @actions: the bitmask of possible actions for a drag from this
14117  *    widget
14118  * 
14119  * Turns @tree_view into a drop destination for automatic DND. Calling
14120  * this method sets #GtkTreeView:reorderable to %FALSE.
14121  **/
14122 void
14123 gtk_tree_view_enable_model_drag_dest (GtkTreeView              *tree_view,
14124                                       const GtkTargetEntry     *targets,
14125                                       gint                      n_targets,
14126                                       GdkDragAction             actions)
14127 {
14128   TreeViewDragInfo *di;
14129
14130   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14131
14132   gtk_drag_dest_set (GTK_WIDGET (tree_view),
14133                      0,
14134                      targets,
14135                      n_targets,
14136                      actions);
14137
14138   di = ensure_info (tree_view);
14139   di->dest_set = TRUE;
14140
14141   unset_reorderable (tree_view);
14142 }
14143
14144 /**
14145  * gtk_tree_view_unset_rows_drag_source:
14146  * @tree_view: a #GtkTreeView
14147  *
14148  * Undoes the effect of
14149  * gtk_tree_view_enable_model_drag_source(). Calling this method sets
14150  * #GtkTreeView:reorderable to %FALSE.
14151  **/
14152 void
14153 gtk_tree_view_unset_rows_drag_source (GtkTreeView *tree_view)
14154 {
14155   TreeViewDragInfo *di;
14156
14157   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14158
14159   di = get_info (tree_view);
14160
14161   if (di)
14162     {
14163       if (di->source_set)
14164         {
14165           gtk_drag_source_unset (GTK_WIDGET (tree_view));
14166           di->source_set = FALSE;
14167         }
14168
14169       if (!di->dest_set && !di->source_set)
14170         remove_info (tree_view);
14171     }
14172   
14173   unset_reorderable (tree_view);
14174 }
14175
14176 /**
14177  * gtk_tree_view_unset_rows_drag_dest:
14178  * @tree_view: a #GtkTreeView
14179  *
14180  * Undoes the effect of
14181  * gtk_tree_view_enable_model_drag_dest(). Calling this method sets
14182  * #GtkTreeView:reorderable to %FALSE.
14183  **/
14184 void
14185 gtk_tree_view_unset_rows_drag_dest (GtkTreeView *tree_view)
14186 {
14187   TreeViewDragInfo *di;
14188
14189   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14190
14191   di = get_info (tree_view);
14192
14193   if (di)
14194     {
14195       if (di->dest_set)
14196         {
14197           gtk_drag_dest_unset (GTK_WIDGET (tree_view));
14198           di->dest_set = FALSE;
14199         }
14200
14201       if (!di->dest_set && !di->source_set)
14202         remove_info (tree_view);
14203     }
14204
14205   unset_reorderable (tree_view);
14206 }
14207
14208 /**
14209  * gtk_tree_view_set_drag_dest_row:
14210  * @tree_view: a #GtkTreeView
14211  * @path: (allow-none): The path of the row to highlight, or %NULL
14212  * @pos: Specifies whether to drop before, after or into the row
14213  *
14214  * Sets the row that is highlighted for feedback.
14215  * If @path is %NULL, an existing highlight is removed.
14216  */
14217 void
14218 gtk_tree_view_set_drag_dest_row (GtkTreeView            *tree_view,
14219                                  GtkTreePath            *path,
14220                                  GtkTreeViewDropPosition pos)
14221 {
14222   GtkTreePath *current_dest;
14223
14224   /* Note; this function is exported to allow a custom DND
14225    * implementation, so it can't touch TreeViewDragInfo
14226    */
14227
14228   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14229
14230   current_dest = NULL;
14231
14232   if (tree_view->priv->drag_dest_row)
14233     {
14234       current_dest = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
14235       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
14236     }
14237
14238   /* special case a drop on an empty model */
14239   tree_view->priv->empty_view_drop = 0;
14240
14241   if (pos == GTK_TREE_VIEW_DROP_BEFORE && path
14242       && gtk_tree_path_get_depth (path) == 1
14243       && gtk_tree_path_get_indices (path)[0] == 0)
14244     {
14245       gint n_children;
14246
14247       n_children = gtk_tree_model_iter_n_children (tree_view->priv->model,
14248                                                    NULL);
14249
14250       if (!n_children)
14251         tree_view->priv->empty_view_drop = 1;
14252     }
14253
14254   tree_view->priv->drag_dest_pos = pos;
14255
14256   if (path)
14257     {
14258       tree_view->priv->drag_dest_row =
14259         gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
14260       gtk_tree_view_queue_draw_path (tree_view, path, NULL);
14261     }
14262   else
14263     tree_view->priv->drag_dest_row = NULL;
14264
14265   if (current_dest)
14266     {
14267       GtkRBTree *tree, *new_tree;
14268       GtkRBNode *node, *new_node;
14269
14270       _gtk_tree_view_find_node (tree_view, current_dest, &tree, &node);
14271       _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
14272
14273       if (tree && node)
14274         {
14275           _gtk_rbtree_next_full (tree, node, &new_tree, &new_node);
14276           if (new_tree && new_node)
14277             _gtk_tree_view_queue_draw_node (tree_view, new_tree, new_node, NULL);
14278
14279           _gtk_rbtree_prev_full (tree, node, &new_tree, &new_node);
14280           if (new_tree && new_node)
14281             _gtk_tree_view_queue_draw_node (tree_view, new_tree, new_node, NULL);
14282         }
14283       gtk_tree_path_free (current_dest);
14284     }
14285 }
14286
14287 /**
14288  * gtk_tree_view_get_drag_dest_row:
14289  * @tree_view: a #GtkTreeView
14290  * @path: (out) (allow-none): Return location for the path of the highlighted row, or %NULL.
14291  * @pos: (out) (allow-none): Return location for the drop position, or %NULL
14292  * 
14293  * Gets information about the row that is highlighted for feedback.
14294  **/
14295 void
14296 gtk_tree_view_get_drag_dest_row (GtkTreeView              *tree_view,
14297                                  GtkTreePath             **path,
14298                                  GtkTreeViewDropPosition  *pos)
14299 {
14300   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14301
14302   if (path)
14303     {
14304       if (tree_view->priv->drag_dest_row)
14305         *path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
14306       else
14307         {
14308           if (tree_view->priv->empty_view_drop)
14309             *path = gtk_tree_path_new_from_indices (0, -1);
14310           else
14311             *path = NULL;
14312         }
14313     }
14314
14315   if (pos)
14316     *pos = tree_view->priv->drag_dest_pos;
14317 }
14318
14319 /**
14320  * gtk_tree_view_get_dest_row_at_pos:
14321  * @tree_view: a #GtkTreeView
14322  * @drag_x: the position to determine the destination row for
14323  * @drag_y: the position to determine the destination row for
14324  * @path: (out) (allow-none): Return location for the path of the highlighted row, or %NULL.
14325  * @pos: (out) (allow-none): Return location for the drop position, or %NULL
14326  * 
14327  * Determines the destination row for a given position.  @drag_x and
14328  * @drag_y are expected to be in widget coordinates.  This function is only
14329  * meaningful if @tree_view is realized.  Therefore this function will always
14330  * return %FALSE if @tree_view is not realized or does not have a model.
14331  * 
14332  * Return value: whether there is a row at the given position, %TRUE if this
14333  * is indeed the case.
14334  **/
14335 gboolean
14336 gtk_tree_view_get_dest_row_at_pos (GtkTreeView             *tree_view,
14337                                    gint                     drag_x,
14338                                    gint                     drag_y,
14339                                    GtkTreePath            **path,
14340                                    GtkTreeViewDropPosition *pos)
14341 {
14342   gint cell_y;
14343   gint bin_x, bin_y;
14344   gdouble offset_into_row;
14345   gdouble third;
14346   GdkRectangle cell;
14347   GtkTreeViewColumn *column = NULL;
14348   GtkTreePath *tmp_path = NULL;
14349
14350   /* Note; this function is exported to allow a custom DND
14351    * implementation, so it can't touch TreeViewDragInfo
14352    */
14353
14354   g_return_val_if_fail (tree_view != NULL, FALSE);
14355   g_return_val_if_fail (drag_x >= 0, FALSE);
14356   g_return_val_if_fail (drag_y >= 0, FALSE);
14357
14358   if (path)
14359     *path = NULL;
14360
14361   if (tree_view->priv->bin_window == NULL)
14362     return FALSE;
14363
14364   if (tree_view->priv->tree == NULL)
14365     return FALSE;
14366
14367   /* If in the top third of a row, we drop before that row; if
14368    * in the bottom third, drop after that row; if in the middle,
14369    * and the row has children, drop into the row.
14370    */
14371   gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, drag_x, drag_y,
14372                                                      &bin_x, &bin_y);
14373
14374   if (!gtk_tree_view_get_path_at_pos (tree_view,
14375                                       bin_x,
14376                                       bin_y,
14377                                       &tmp_path,
14378                                       &column,
14379                                       NULL,
14380                                       &cell_y))
14381     return FALSE;
14382
14383   gtk_tree_view_get_background_area (tree_view, tmp_path, column,
14384                                      &cell);
14385
14386   offset_into_row = cell_y;
14387
14388   if (path)
14389     *path = tmp_path;
14390   else
14391     gtk_tree_path_free (tmp_path);
14392
14393   tmp_path = NULL;
14394
14395   third = cell.height / 3.0;
14396
14397   if (pos)
14398     {
14399       if (offset_into_row < third)
14400         {
14401           *pos = GTK_TREE_VIEW_DROP_BEFORE;
14402         }
14403       else if (offset_into_row < (cell.height / 2.0))
14404         {
14405           *pos = GTK_TREE_VIEW_DROP_INTO_OR_BEFORE;
14406         }
14407       else if (offset_into_row < third * 2.0)
14408         {
14409           *pos = GTK_TREE_VIEW_DROP_INTO_OR_AFTER;
14410         }
14411       else
14412         {
14413           *pos = GTK_TREE_VIEW_DROP_AFTER;
14414         }
14415     }
14416
14417   return TRUE;
14418 }
14419
14420
14421
14422 /* KEEP IN SYNC WITH GTK_TREE_VIEW_BIN_EXPOSE */
14423 /**
14424  * gtk_tree_view_create_row_drag_icon:
14425  * @tree_view: a #GtkTreeView
14426  * @path: a #GtkTreePath in @tree_view
14427  *
14428  * Creates a #cairo_surface_t representation of the row at @path.  
14429  * This image is used for a drag icon.
14430  *
14431  * Return value: (transfer full): a newly-allocated surface of the drag icon.
14432  **/
14433 cairo_surface_t *
14434 gtk_tree_view_create_row_drag_icon (GtkTreeView  *tree_view,
14435                                     GtkTreePath  *path)
14436 {
14437   GtkTreeIter   iter;
14438   GtkRBTree    *tree;
14439   GtkRBNode    *node;
14440   GtkStyleContext *context;
14441   GtkStateFlags state;
14442   gint cell_offset;
14443   GList *list;
14444   GdkRectangle background_area;
14445   GtkWidget *widget;
14446   gint depth;
14447   /* start drawing inside the black outline */
14448   gint x = 1, y = 1;
14449   cairo_surface_t *surface;
14450   gint bin_window_width;
14451   gboolean is_separator = FALSE;
14452   gboolean rtl, allow_rules;
14453   cairo_t *cr;
14454
14455   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14456   g_return_val_if_fail (path != NULL, NULL);
14457
14458   widget = GTK_WIDGET (tree_view);
14459
14460   if (!gtk_widget_get_realized (widget))
14461     return NULL;
14462
14463   depth = gtk_tree_path_get_depth (path);
14464
14465   _gtk_tree_view_find_node (tree_view,
14466                             path,
14467                             &tree,
14468                             &node);
14469
14470   if (tree == NULL)
14471     return NULL;
14472
14473   if (!gtk_tree_model_get_iter (tree_view->priv->model,
14474                                 &iter,
14475                                 path))
14476     return NULL;
14477
14478   context = gtk_widget_get_style_context (widget);
14479
14480   gtk_style_context_save (context);
14481
14482   state = gtk_widget_get_state_flags (widget);
14483   gtk_style_context_set_state (context, state);
14484
14485   gtk_style_context_add_class (context, GTK_STYLE_CLASS_VIEW);
14486   gtk_style_context_add_region (context, GTK_STYLE_REGION_COLUMN, 0);
14487
14488   gtk_widget_style_get (widget,
14489                         "allow-rules", &allow_rules,
14490                         NULL);
14491
14492   if (allow_rules && tree_view->priv->has_rules)
14493     {
14494       GtkRegionFlags row_flags;
14495
14496       if ((_gtk_rbtree_node_get_index (tree, node) % 2))
14497         row_flags = GTK_REGION_ODD;
14498       else
14499         row_flags = GTK_REGION_EVEN;
14500
14501       gtk_style_context_add_region (context, GTK_STYLE_REGION_ROW, row_flags);
14502     }
14503
14504   is_separator = row_is_separator (tree_view, &iter, NULL);
14505
14506   cell_offset = x;
14507
14508   background_area.y = y;
14509   background_area.height = gtk_tree_view_get_row_height (tree_view, node);
14510
14511   bin_window_width = gdk_window_get_width (tree_view->priv->bin_window);
14512
14513   surface = gdk_window_create_similar_surface (tree_view->priv->bin_window,
14514                                                CAIRO_CONTENT_COLOR,
14515                                                bin_window_width + 2,
14516                                                background_area.height + 2);
14517
14518   cr = cairo_create (surface);
14519
14520   gtk_render_background (context, cr, 0, 0,
14521                          bin_window_width + 2,
14522                          background_area.height + 2);
14523
14524   rtl = gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL;
14525
14526   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
14527       list;
14528       list = (rtl ? list->prev : list->next))
14529     {
14530       GtkTreeViewColumn *column = list->data;
14531       GdkRectangle cell_area;
14532       gint vertical_separator;
14533
14534       if (!gtk_tree_view_column_get_visible (column))
14535         continue;
14536
14537       gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, &iter,
14538                                                GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
14539                                                node->children?TRUE:FALSE);
14540
14541       background_area.x = cell_offset;
14542       background_area.width = gtk_tree_view_column_get_width (column);
14543
14544       gtk_widget_style_get (widget,
14545                             "vertical-separator", &vertical_separator,
14546                             NULL);
14547
14548       cell_area = background_area;
14549
14550       cell_area.y += vertical_separator / 2;
14551       cell_area.height -= vertical_separator;
14552
14553       if (gtk_tree_view_is_expander_column (tree_view, column))
14554         {
14555           if (!rtl)
14556             cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
14557           cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
14558
14559           if (gtk_tree_view_draw_expanders (tree_view))
14560             {
14561               if (!rtl)
14562                 cell_area.x += depth * tree_view->priv->expander_size;
14563               cell_area.width -= depth * tree_view->priv->expander_size;
14564             }
14565         }
14566
14567       if (gtk_tree_view_column_cell_is_visible (column))
14568         {
14569           if (is_separator)
14570             {
14571               gtk_style_context_save (context);
14572               gtk_style_context_add_class (context, GTK_STYLE_CLASS_SEPARATOR);
14573
14574               gtk_render_line (context, cr,
14575                                cell_area.x,
14576                                cell_area.y + cell_area.height / 2,
14577                                cell_area.x + cell_area.width,
14578                                cell_area.y + cell_area.height / 2);
14579
14580               gtk_style_context_restore (context);
14581             }
14582           else
14583             {
14584               _gtk_tree_view_column_cell_render (column,
14585                                                  cr,
14586                                                  &background_area,
14587                                                  &cell_area,
14588                                                  0, FALSE);
14589             }
14590         }
14591       cell_offset += gtk_tree_view_column_get_width (column);
14592     }
14593
14594   cairo_set_source_rgb (cr, 0, 0, 0);
14595   cairo_rectangle (cr, 
14596                    0.5, 0.5, 
14597                    bin_window_width + 1,
14598                    background_area.height + 1);
14599   cairo_set_line_width (cr, 1.0);
14600   cairo_stroke (cr);
14601
14602   cairo_destroy (cr);
14603
14604   cairo_surface_set_device_offset (surface, 2, 2);
14605
14606   gtk_style_context_restore (context);
14607
14608   return surface;
14609 }
14610
14611
14612 /**
14613  * gtk_tree_view_set_destroy_count_func:
14614  * @tree_view: A #GtkTreeView
14615  * @func: (allow-none): Function to be called when a view row is destroyed, or %NULL
14616  * @data: (allow-none): User data to be passed to @func, or %NULL
14617  * @destroy: (allow-none): Destroy notifier for @data, or %NULL
14618  *
14619  * This function should almost never be used.  It is meant for private use by
14620  * ATK for determining the number of visible children that are removed when the
14621  * user collapses a row, or a row is deleted.
14622  **/
14623 void
14624 gtk_tree_view_set_destroy_count_func (GtkTreeView             *tree_view,
14625                                       GtkTreeDestroyCountFunc  func,
14626                                       gpointer                 data,
14627                                       GDestroyNotify           destroy)
14628 {
14629   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14630
14631   if (tree_view->priv->destroy_count_destroy)
14632     tree_view->priv->destroy_count_destroy (tree_view->priv->destroy_count_data);
14633
14634   tree_view->priv->destroy_count_func = func;
14635   tree_view->priv->destroy_count_data = data;
14636   tree_view->priv->destroy_count_destroy = destroy;
14637 }
14638
14639
14640 /*
14641  * Interactive search
14642  */
14643
14644 /**
14645  * gtk_tree_view_set_enable_search:
14646  * @tree_view: A #GtkTreeView
14647  * @enable_search: %TRUE, if the user can search interactively
14648  *
14649  * If @enable_search is set, then the user can type in text to search through
14650  * the tree interactively (this is sometimes called "typeahead find").
14651  * 
14652  * Note that even if this is %FALSE, the user can still initiate a search 
14653  * using the "start-interactive-search" key binding.
14654  */
14655 void
14656 gtk_tree_view_set_enable_search (GtkTreeView *tree_view,
14657                                  gboolean     enable_search)
14658 {
14659   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14660
14661   enable_search = !!enable_search;
14662   
14663   if (tree_view->priv->enable_search != enable_search)
14664     {
14665        tree_view->priv->enable_search = enable_search;
14666        g_object_notify (G_OBJECT (tree_view), "enable-search");
14667     }
14668 }
14669
14670 /**
14671  * gtk_tree_view_get_enable_search:
14672  * @tree_view: A #GtkTreeView
14673  *
14674  * Returns whether or not the tree allows to start interactive searching 
14675  * by typing in text.
14676  *
14677  * Return value: whether or not to let the user search interactively
14678  */
14679 gboolean
14680 gtk_tree_view_get_enable_search (GtkTreeView *tree_view)
14681 {
14682   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
14683
14684   return tree_view->priv->enable_search;
14685 }
14686
14687
14688 /**
14689  * gtk_tree_view_get_search_column:
14690  * @tree_view: A #GtkTreeView
14691  *
14692  * Gets the column searched on by the interactive search code.
14693  *
14694  * Return value: the column the interactive search code searches in.
14695  */
14696 gint
14697 gtk_tree_view_get_search_column (GtkTreeView *tree_view)
14698 {
14699   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
14700
14701   return (tree_view->priv->search_column);
14702 }
14703
14704 /**
14705  * gtk_tree_view_set_search_column:
14706  * @tree_view: A #GtkTreeView
14707  * @column: the column of the model to search in, or -1 to disable searching
14708  *
14709  * Sets @column as the column where the interactive search code should
14710  * search in for the current model. 
14711  * 
14712  * If the search column is set, users can use the "start-interactive-search"
14713  * key binding to bring up search popup. The enable-search property controls
14714  * whether simply typing text will also start an interactive search.
14715  *
14716  * Note that @column refers to a column of the current model. The search 
14717  * column is reset to -1 when the model is changed.
14718  */
14719 void
14720 gtk_tree_view_set_search_column (GtkTreeView *tree_view,
14721                                  gint         column)
14722 {
14723   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14724   g_return_if_fail (column >= -1);
14725
14726   if (tree_view->priv->search_column == column)
14727     return;
14728
14729   tree_view->priv->search_column = column;
14730   g_object_notify (G_OBJECT (tree_view), "search-column");
14731 }
14732
14733 /**
14734  * gtk_tree_view_get_search_equal_func: (skip)
14735  * @tree_view: A #GtkTreeView
14736  *
14737  * Returns the compare function currently in use.
14738  *
14739  * Return value: the currently used compare function for the search code.
14740  */
14741
14742 GtkTreeViewSearchEqualFunc
14743 gtk_tree_view_get_search_equal_func (GtkTreeView *tree_view)
14744 {
14745   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14746
14747   return tree_view->priv->search_equal_func;
14748 }
14749
14750 /**
14751  * gtk_tree_view_set_search_equal_func:
14752  * @tree_view: A #GtkTreeView
14753  * @search_equal_func: the compare function to use during the search
14754  * @search_user_data: (allow-none): user data to pass to @search_equal_func, or %NULL
14755  * @search_destroy: (allow-none): Destroy notifier for @search_user_data, or %NULL
14756  *
14757  * Sets the compare function for the interactive search capabilities; note
14758  * that somewhat like strcmp() returning 0 for equality
14759  * #GtkTreeViewSearchEqualFunc returns %FALSE on matches.
14760  **/
14761 void
14762 gtk_tree_view_set_search_equal_func (GtkTreeView                *tree_view,
14763                                      GtkTreeViewSearchEqualFunc  search_equal_func,
14764                                      gpointer                    search_user_data,
14765                                      GDestroyNotify              search_destroy)
14766 {
14767   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14768   g_return_if_fail (search_equal_func != NULL);
14769
14770   if (tree_view->priv->search_destroy)
14771     tree_view->priv->search_destroy (tree_view->priv->search_user_data);
14772
14773   tree_view->priv->search_equal_func = search_equal_func;
14774   tree_view->priv->search_user_data = search_user_data;
14775   tree_view->priv->search_destroy = search_destroy;
14776   if (tree_view->priv->search_equal_func == NULL)
14777     tree_view->priv->search_equal_func = gtk_tree_view_search_equal_func;
14778 }
14779
14780 /**
14781  * gtk_tree_view_get_search_entry:
14782  * @tree_view: A #GtkTreeView
14783  *
14784  * Returns the #GtkEntry which is currently in use as interactive search
14785  * entry for @tree_view.  In case the built-in entry is being used, %NULL
14786  * will be returned.
14787  *
14788  * Return value: (transfer none): the entry currently in use as search entry.
14789  *
14790  * Since: 2.10
14791  */
14792 GtkEntry *
14793 gtk_tree_view_get_search_entry (GtkTreeView *tree_view)
14794 {
14795   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14796
14797   if (tree_view->priv->search_custom_entry_set)
14798     return GTK_ENTRY (tree_view->priv->search_entry);
14799
14800   return NULL;
14801 }
14802
14803 /**
14804  * gtk_tree_view_set_search_entry:
14805  * @tree_view: A #GtkTreeView
14806  * @entry: (allow-none): the entry the interactive search code of @tree_view should use or %NULL
14807  *
14808  * Sets the entry which the interactive search code will use for this
14809  * @tree_view.  This is useful when you want to provide a search entry
14810  * in our interface at all time at a fixed position.  Passing %NULL for
14811  * @entry will make the interactive search code use the built-in popup
14812  * entry again.
14813  *
14814  * Since: 2.10
14815  */
14816 void
14817 gtk_tree_view_set_search_entry (GtkTreeView *tree_view,
14818                                 GtkEntry    *entry)
14819 {
14820   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14821   g_return_if_fail (entry == NULL || GTK_IS_ENTRY (entry));
14822
14823   if (tree_view->priv->search_custom_entry_set)
14824     {
14825       if (tree_view->priv->search_entry_changed_id)
14826         {
14827           g_signal_handler_disconnect (tree_view->priv->search_entry,
14828                                        tree_view->priv->search_entry_changed_id);
14829           tree_view->priv->search_entry_changed_id = 0;
14830         }
14831       g_signal_handlers_disconnect_by_func (tree_view->priv->search_entry,
14832                                             G_CALLBACK (gtk_tree_view_search_key_press_event),
14833                                             tree_view);
14834
14835       g_object_unref (tree_view->priv->search_entry);
14836     }
14837   else if (tree_view->priv->search_window)
14838     {
14839       gtk_widget_destroy (tree_view->priv->search_window);
14840
14841       tree_view->priv->search_window = NULL;
14842     }
14843
14844   if (entry)
14845     {
14846       tree_view->priv->search_entry = g_object_ref (entry);
14847       tree_view->priv->search_custom_entry_set = TRUE;
14848
14849       if (tree_view->priv->search_entry_changed_id == 0)
14850         {
14851           tree_view->priv->search_entry_changed_id =
14852             g_signal_connect (tree_view->priv->search_entry, "changed",
14853                               G_CALLBACK (gtk_tree_view_search_init),
14854                               tree_view);
14855         }
14856       
14857         g_signal_connect (tree_view->priv->search_entry, "key-press-event",
14858                           G_CALLBACK (gtk_tree_view_search_key_press_event),
14859                           tree_view);
14860
14861         gtk_tree_view_search_init (tree_view->priv->search_entry, tree_view);
14862     }
14863   else
14864     {
14865       tree_view->priv->search_entry = NULL;
14866       tree_view->priv->search_custom_entry_set = FALSE;
14867     }
14868 }
14869
14870 /**
14871  * gtk_tree_view_set_search_position_func:
14872  * @tree_view: A #GtkTreeView
14873  * @func: (allow-none): the function to use to position the search dialog, or %NULL
14874  *    to use the default search position function
14875  * @data: (allow-none): user data to pass to @func, or %NULL
14876  * @destroy: (allow-none): Destroy notifier for @data, or %NULL
14877  *
14878  * Sets the function to use when positioning the search dialog.
14879  *
14880  * Since: 2.10
14881  **/
14882 void
14883 gtk_tree_view_set_search_position_func (GtkTreeView                   *tree_view,
14884                                         GtkTreeViewSearchPositionFunc  func,
14885                                         gpointer                       user_data,
14886                                         GDestroyNotify                 destroy)
14887 {
14888   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14889
14890   if (tree_view->priv->search_position_destroy)
14891     tree_view->priv->search_position_destroy (tree_view->priv->search_position_user_data);
14892
14893   tree_view->priv->search_position_func = func;
14894   tree_view->priv->search_position_user_data = user_data;
14895   tree_view->priv->search_position_destroy = destroy;
14896   if (tree_view->priv->search_position_func == NULL)
14897     tree_view->priv->search_position_func = gtk_tree_view_search_position_func;
14898 }
14899
14900 /**
14901  * gtk_tree_view_get_search_position_func: (skip)
14902  * @tree_view: A #GtkTreeView
14903  *
14904  * Returns the positioning function currently in use.
14905  *
14906  * Return value: the currently used function for positioning the search dialog.
14907  *
14908  * Since: 2.10
14909  */
14910 GtkTreeViewSearchPositionFunc
14911 gtk_tree_view_get_search_position_func (GtkTreeView *tree_view)
14912 {
14913   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14914
14915   return tree_view->priv->search_position_func;
14916 }
14917
14918
14919 static void
14920 gtk_tree_view_search_dialog_hide (GtkWidget   *search_dialog,
14921                                   GtkTreeView *tree_view,
14922                                   GdkDevice   *device)
14923 {
14924   if (tree_view->priv->disable_popdown)
14925     return;
14926
14927   if (tree_view->priv->search_entry_changed_id)
14928     {
14929       g_signal_handler_disconnect (tree_view->priv->search_entry,
14930                                    tree_view->priv->search_entry_changed_id);
14931       tree_view->priv->search_entry_changed_id = 0;
14932     }
14933   if (tree_view->priv->typeselect_flush_timeout)
14934     {
14935       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14936       tree_view->priv->typeselect_flush_timeout = 0;
14937     }
14938         
14939   if (gtk_widget_get_visible (search_dialog))
14940     {
14941       /* send focus-in event */
14942       send_focus_change (GTK_WIDGET (tree_view->priv->search_entry), device, FALSE);
14943       gtk_widget_hide (search_dialog);
14944       gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
14945       send_focus_change (GTK_WIDGET (tree_view), device, TRUE);
14946     }
14947 }
14948
14949 static void
14950 gtk_tree_view_search_position_func (GtkTreeView *tree_view,
14951                                     GtkWidget   *search_dialog,
14952                                     gpointer     user_data)
14953 {
14954   gint x, y;
14955   gint tree_x, tree_y;
14956   gint tree_width, tree_height;
14957   GdkWindow *tree_window = gtk_widget_get_window (GTK_WIDGET (tree_view));
14958   GdkScreen *screen = gdk_window_get_screen (tree_window);
14959   GtkRequisition requisition;
14960   gint monitor_num;
14961   GdkRectangle monitor;
14962
14963   monitor_num = gdk_screen_get_monitor_at_window (screen, tree_window);
14964   gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
14965
14966   gtk_widget_realize (search_dialog);
14967
14968   gdk_window_get_origin (tree_window, &tree_x, &tree_y);
14969   tree_width = gdk_window_get_width (tree_window);
14970   tree_height = gdk_window_get_height (tree_window);
14971   gtk_widget_get_preferred_size (search_dialog, &requisition, NULL);
14972
14973   if (tree_x + tree_width > gdk_screen_get_width (screen))
14974     x = gdk_screen_get_width (screen) - requisition.width;
14975   else if (tree_x + tree_width - requisition.width < 0)
14976     x = 0;
14977   else
14978     x = tree_x + tree_width - requisition.width;
14979
14980   if (tree_y + tree_height + requisition.height > gdk_screen_get_height (screen))
14981     y = gdk_screen_get_height (screen) - requisition.height;
14982   else if (tree_y + tree_height < 0) /* isn't really possible ... */
14983     y = 0;
14984   else
14985     y = tree_y + tree_height;
14986
14987   gtk_window_move (GTK_WINDOW (search_dialog), x, y);
14988 }
14989
14990 static void
14991 gtk_tree_view_search_disable_popdown (GtkEntry *entry,
14992                                       GtkMenu  *menu,
14993                                       gpointer  data)
14994 {
14995   GtkTreeView *tree_view = (GtkTreeView *)data;
14996
14997   tree_view->priv->disable_popdown = 1;
14998   g_signal_connect (menu, "hide",
14999                     G_CALLBACK (gtk_tree_view_search_enable_popdown), data);
15000 }
15001
15002 /* Because we're visible but offscreen, we just set a flag in the preedit
15003  * callback.
15004  */
15005 static void
15006 gtk_tree_view_search_preedit_changed (GtkIMContext *im_context,
15007                                       GtkTreeView  *tree_view)
15008 {
15009   tree_view->priv->imcontext_changed = 1;
15010   if (tree_view->priv->typeselect_flush_timeout)
15011     {
15012       g_source_remove (tree_view->priv->typeselect_flush_timeout);
15013       tree_view->priv->typeselect_flush_timeout =
15014         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
15015                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
15016                        tree_view);
15017     }
15018
15019 }
15020
15021 static void
15022 gtk_tree_view_search_activate (GtkEntry    *entry,
15023                                GtkTreeView *tree_view)
15024 {
15025   GtkTreePath *path;
15026
15027   gtk_tree_view_search_dialog_hide (tree_view->priv->search_window,
15028                                     tree_view,
15029                                     gtk_get_current_event_device ());
15030
15031   /* If we have a row selected and it's the cursor row, we activate
15032    * the row XXX */
15033   if (tree_view->priv->cursor_node &&
15034       GTK_RBNODE_FLAG_SET (tree_view->priv->cursor_node, GTK_RBNODE_IS_SELECTED))
15035     {
15036       path = _gtk_tree_path_new_from_rbtree (tree_view->priv->cursor_tree,
15037                                              tree_view->priv->cursor_node);
15038       
15039       gtk_tree_view_row_activated (tree_view, path, tree_view->priv->focus_column);
15040       
15041       gtk_tree_path_free (path);
15042     }
15043 }
15044
15045 static gboolean
15046 gtk_tree_view_real_search_enable_popdown (gpointer data)
15047 {
15048   GtkTreeView *tree_view = (GtkTreeView *)data;
15049
15050   tree_view->priv->disable_popdown = 0;
15051
15052   return FALSE;
15053 }
15054
15055 static void
15056 gtk_tree_view_search_enable_popdown (GtkWidget *widget,
15057                                      gpointer   data)
15058 {
15059   gdk_threads_add_timeout_full (G_PRIORITY_HIGH, 200, gtk_tree_view_real_search_enable_popdown, g_object_ref (data), g_object_unref);
15060 }
15061
15062 static gboolean
15063 gtk_tree_view_search_delete_event (GtkWidget *widget,
15064                                    GdkEventAny *event,
15065                                    GtkTreeView *tree_view)
15066 {
15067   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
15068
15069   gtk_tree_view_search_dialog_hide (widget, tree_view, NULL);
15070
15071   return TRUE;
15072 }
15073
15074 static gboolean
15075 gtk_tree_view_search_button_press_event (GtkWidget *widget,
15076                                          GdkEventButton *event,
15077                                          GtkTreeView *tree_view)
15078 {
15079   GdkDevice *keyb_device;
15080
15081   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
15082
15083   keyb_device = gdk_device_get_associated_device (event->device);
15084   gtk_tree_view_search_dialog_hide (widget, tree_view, keyb_device);
15085
15086   if (event->window == tree_view->priv->bin_window)
15087     gtk_tree_view_button_press (GTK_WIDGET (tree_view), event);
15088
15089   return TRUE;
15090 }
15091
15092 static gboolean
15093 gtk_tree_view_search_scroll_event (GtkWidget *widget,
15094                                    GdkEventScroll *event,
15095                                    GtkTreeView *tree_view)
15096 {
15097   gboolean retval = FALSE;
15098
15099   if (event->direction == GDK_SCROLL_UP)
15100     {
15101       gtk_tree_view_search_move (widget, tree_view, TRUE);
15102       retval = TRUE;
15103     }
15104   else if (event->direction == GDK_SCROLL_DOWN)
15105     {
15106       gtk_tree_view_search_move (widget, tree_view, FALSE);
15107       retval = TRUE;
15108     }
15109
15110   /* renew the flush timeout */
15111   if (retval && tree_view->priv->typeselect_flush_timeout
15112       && !tree_view->priv->search_custom_entry_set)
15113     {
15114       g_source_remove (tree_view->priv->typeselect_flush_timeout);
15115       tree_view->priv->typeselect_flush_timeout =
15116         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
15117                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
15118                        tree_view);
15119     }
15120
15121   return retval;
15122 }
15123
15124 static gboolean
15125 gtk_tree_view_search_key_press_event (GtkWidget *widget,
15126                                       GdkEventKey *event,
15127                                       GtkTreeView *tree_view)
15128 {
15129   GdkModifierType default_accel;
15130   gboolean        retval = FALSE;
15131
15132   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
15133   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15134
15135   /* close window and cancel the search */
15136   if (!tree_view->priv->search_custom_entry_set
15137       && (event->keyval == GDK_KEY_Escape ||
15138           event->keyval == GDK_KEY_Tab ||
15139             event->keyval == GDK_KEY_KP_Tab ||
15140             event->keyval == GDK_KEY_ISO_Left_Tab))
15141     {
15142       gtk_tree_view_search_dialog_hide (widget, tree_view,
15143                                         gdk_event_get_device ((GdkEvent *) event));
15144       return TRUE;
15145     }
15146
15147   default_accel = gtk_widget_get_modifier_mask (widget,
15148                                                 GDK_MODIFIER_INTENT_PRIMARY_ACCELERATOR);
15149
15150   /* select previous matching iter */
15151   if (event->keyval == GDK_KEY_Up || event->keyval == GDK_KEY_KP_Up)
15152     {
15153       if (!gtk_tree_view_search_move (widget, tree_view, TRUE))
15154         gtk_widget_error_bell (widget);
15155
15156       retval = TRUE;
15157     }
15158
15159   if (((event->state & (default_accel | GDK_SHIFT_MASK)) == (default_accel | GDK_SHIFT_MASK))
15160       && (event->keyval == GDK_KEY_g || event->keyval == GDK_KEY_G))
15161     {
15162       if (!gtk_tree_view_search_move (widget, tree_view, TRUE))
15163         gtk_widget_error_bell (widget);
15164
15165       retval = TRUE;
15166     }
15167
15168   /* select next matching iter */
15169   if (event->keyval == GDK_KEY_Down || event->keyval == GDK_KEY_KP_Down)
15170     {
15171       if (!gtk_tree_view_search_move (widget, tree_view, FALSE))
15172         gtk_widget_error_bell (widget);
15173
15174       retval = TRUE;
15175     }
15176
15177   if (((event->state & (default_accel | GDK_SHIFT_MASK)) == default_accel)
15178       && (event->keyval == GDK_KEY_g || event->keyval == GDK_KEY_G))
15179     {
15180       if (!gtk_tree_view_search_move (widget, tree_view, FALSE))
15181         gtk_widget_error_bell (widget);
15182
15183       retval = TRUE;
15184     }
15185
15186   /* renew the flush timeout */
15187   if (retval && tree_view->priv->typeselect_flush_timeout
15188       && !tree_view->priv->search_custom_entry_set)
15189     {
15190       g_source_remove (tree_view->priv->typeselect_flush_timeout);
15191       tree_view->priv->typeselect_flush_timeout =
15192         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
15193                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
15194                        tree_view);
15195     }
15196
15197   return retval;
15198 }
15199
15200 /*  this function returns FALSE if there is a search string but
15201  *  nothing was found, and TRUE otherwise.
15202  */
15203 static gboolean
15204 gtk_tree_view_search_move (GtkWidget   *window,
15205                            GtkTreeView *tree_view,
15206                            gboolean     up)
15207 {
15208   gboolean ret;
15209   gint len;
15210   gint count = 0;
15211   const gchar *text;
15212   GtkTreeIter iter;
15213   GtkTreeModel *model;
15214   GtkTreeSelection *selection;
15215
15216   text = gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry));
15217
15218   g_return_val_if_fail (text != NULL, FALSE);
15219
15220   len = strlen (text);
15221
15222   if (up && tree_view->priv->selected_iter == 1)
15223     return strlen (text) < 1;
15224
15225   len = strlen (text);
15226
15227   if (len < 1)
15228     return TRUE;
15229
15230   model = gtk_tree_view_get_model (tree_view);
15231   selection = gtk_tree_view_get_selection (tree_view);
15232
15233   /* search */
15234   gtk_tree_selection_unselect_all (selection);
15235   if (!gtk_tree_model_get_iter_first (model, &iter))
15236     return TRUE;
15237
15238   ret = gtk_tree_view_search_iter (model, selection, &iter, text,
15239                                    &count, up?((tree_view->priv->selected_iter) - 1):((tree_view->priv->selected_iter + 1)));
15240
15241   if (ret)
15242     {
15243       /* found */
15244       tree_view->priv->selected_iter += up?(-1):(1);
15245       return TRUE;
15246     }
15247   else
15248     {
15249       /* return to old iter */
15250       count = 0;
15251       gtk_tree_model_get_iter_first (model, &iter);
15252       gtk_tree_view_search_iter (model, selection,
15253                                  &iter, text,
15254                                  &count, tree_view->priv->selected_iter);
15255       return FALSE;
15256     }
15257 }
15258
15259 static gboolean
15260 gtk_tree_view_search_equal_func (GtkTreeModel *model,
15261                                  gint          column,
15262                                  const gchar  *key,
15263                                  GtkTreeIter  *iter,
15264                                  gpointer      search_data)
15265 {
15266   gboolean retval = TRUE;
15267   const gchar *str;
15268   gchar *normalized_string;
15269   gchar *normalized_key;
15270   gchar *case_normalized_string = NULL;
15271   gchar *case_normalized_key = NULL;
15272   GValue value = G_VALUE_INIT;
15273   GValue transformed = G_VALUE_INIT;
15274
15275   gtk_tree_model_get_value (model, iter, column, &value);
15276
15277   g_value_init (&transformed, G_TYPE_STRING);
15278
15279   if (!g_value_transform (&value, &transformed))
15280     {
15281       g_value_unset (&value);
15282       return TRUE;
15283     }
15284
15285   g_value_unset (&value);
15286
15287   str = g_value_get_string (&transformed);
15288   if (!str)
15289     {
15290       g_value_unset (&transformed);
15291       return TRUE;
15292     }
15293
15294   normalized_string = g_utf8_normalize (str, -1, G_NORMALIZE_ALL);
15295   normalized_key = g_utf8_normalize (key, -1, G_NORMALIZE_ALL);
15296
15297   if (normalized_string && normalized_key)
15298     {
15299       case_normalized_string = g_utf8_casefold (normalized_string, -1);
15300       case_normalized_key = g_utf8_casefold (normalized_key, -1);
15301
15302       if (strncmp (case_normalized_key, case_normalized_string, strlen (case_normalized_key)) == 0)
15303         retval = FALSE;
15304     }
15305
15306   g_value_unset (&transformed);
15307   g_free (normalized_key);
15308   g_free (normalized_string);
15309   g_free (case_normalized_key);
15310   g_free (case_normalized_string);
15311
15312   return retval;
15313 }
15314
15315 static gboolean
15316 gtk_tree_view_search_iter (GtkTreeModel     *model,
15317                            GtkTreeSelection *selection,
15318                            GtkTreeIter      *iter,
15319                            const gchar      *text,
15320                            gint             *count,
15321                            gint              n)
15322 {
15323   GtkRBTree *tree = NULL;
15324   GtkRBNode *node = NULL;
15325   GtkTreePath *path;
15326
15327   GtkTreeView *tree_view = gtk_tree_selection_get_tree_view (selection);
15328
15329   path = gtk_tree_model_get_path (model, iter);
15330   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
15331
15332   do
15333     {
15334       if (! tree_view->priv->search_equal_func (model, tree_view->priv->search_column, text, iter, tree_view->priv->search_user_data))
15335         {
15336           (*count)++;
15337           if (*count == n)
15338             {
15339               gtk_tree_view_scroll_to_cell (tree_view, path, NULL,
15340                                             TRUE, 0.5, 0.0);
15341               gtk_tree_selection_select_iter (selection, iter);
15342               gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
15343
15344               if (path)
15345                 gtk_tree_path_free (path);
15346
15347               return TRUE;
15348             }
15349         }
15350
15351       if (node->children)
15352         {
15353           gboolean has_child;
15354           GtkTreeIter tmp;
15355
15356           tree = node->children;
15357           node = _gtk_rbtree_first (tree);
15358
15359           tmp = *iter;
15360           has_child = gtk_tree_model_iter_children (model, iter, &tmp);
15361           gtk_tree_path_down (path);
15362
15363           /* sanity check */
15364           TREE_VIEW_INTERNAL_ASSERT (has_child, FALSE);
15365         }
15366       else
15367         {
15368           gboolean done = FALSE;
15369
15370           do
15371             {
15372               node = _gtk_rbtree_next (tree, node);
15373
15374               if (node)
15375                 {
15376                   gboolean has_next;
15377
15378                   has_next = gtk_tree_model_iter_next (model, iter);
15379
15380                   done = TRUE;
15381                   gtk_tree_path_next (path);
15382
15383                   /* sanity check */
15384                   TREE_VIEW_INTERNAL_ASSERT (has_next, FALSE);
15385                 }
15386               else
15387                 {
15388                   gboolean has_parent;
15389                   GtkTreeIter tmp_iter = *iter;
15390
15391                   node = tree->parent_node;
15392                   tree = tree->parent_tree;
15393
15394                   if (!tree)
15395                     {
15396                       if (path)
15397                         gtk_tree_path_free (path);
15398
15399                       /* we've run out of tree, done with this func */
15400                       return FALSE;
15401                     }
15402
15403                   has_parent = gtk_tree_model_iter_parent (model,
15404                                                            iter,
15405                                                            &tmp_iter);
15406                   gtk_tree_path_up (path);
15407
15408                   /* sanity check */
15409                   TREE_VIEW_INTERNAL_ASSERT (has_parent, FALSE);
15410                 }
15411             }
15412           while (!done);
15413         }
15414     }
15415   while (1);
15416
15417   return FALSE;
15418 }
15419
15420 static void
15421 gtk_tree_view_search_init (GtkWidget   *entry,
15422                            GtkTreeView *tree_view)
15423 {
15424   gint ret;
15425   gint count = 0;
15426   const gchar *text;
15427   GtkTreeIter iter;
15428   GtkTreeModel *model;
15429   GtkTreeSelection *selection;
15430
15431   g_return_if_fail (GTK_IS_ENTRY (entry));
15432   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15433
15434   text = gtk_entry_get_text (GTK_ENTRY (entry));
15435
15436   model = gtk_tree_view_get_model (tree_view);
15437   selection = gtk_tree_view_get_selection (tree_view);
15438
15439   /* search */
15440   gtk_tree_selection_unselect_all (selection);
15441   if (tree_view->priv->typeselect_flush_timeout
15442       && !tree_view->priv->search_custom_entry_set)
15443     {
15444       g_source_remove (tree_view->priv->typeselect_flush_timeout);
15445       tree_view->priv->typeselect_flush_timeout =
15446         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
15447                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
15448                        tree_view);
15449     }
15450
15451   if (*text == '\0')
15452     return;
15453
15454   if (!gtk_tree_model_get_iter_first (model, &iter))
15455     return;
15456
15457   ret = gtk_tree_view_search_iter (model, selection,
15458                                    &iter, text,
15459                                    &count, 1);
15460
15461   if (ret)
15462     tree_view->priv->selected_iter = 1;
15463 }
15464
15465 void
15466 _gtk_tree_view_remove_editable (GtkTreeView       *tree_view,
15467                                 GtkTreeViewColumn *column,
15468                                 GtkCellEditable   *cell_editable)
15469 {
15470   if (tree_view->priv->edited_column == NULL)
15471     return;
15472
15473   g_return_if_fail (column == tree_view->priv->edited_column);
15474
15475   tree_view->priv->edited_column = NULL;
15476
15477   if (gtk_widget_has_focus (GTK_WIDGET (cell_editable)))
15478     gtk_widget_grab_focus (GTK_WIDGET (tree_view));
15479
15480   gtk_container_remove (GTK_CONTAINER (tree_view),
15481                         GTK_WIDGET (cell_editable));
15482
15483   /* FIXME should only redraw a single node */
15484   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15485 }
15486
15487 static gboolean
15488 gtk_tree_view_start_editing (GtkTreeView *tree_view,
15489                              GtkTreePath *cursor_path,
15490                              gboolean     edit_only)
15491 {
15492   GtkTreeIter iter;
15493   GdkRectangle cell_area;
15494   GtkTreeViewColumn *focus_column;
15495   guint flags = 0; /* can be 0, as the flags are primarily for rendering */
15496   gint retval = FALSE;
15497   GtkRBTree *cursor_tree;
15498   GtkRBNode *cursor_node;
15499
15500   g_assert (tree_view->priv->focus_column);
15501   focus_column = tree_view->priv->focus_column;
15502
15503   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
15504     return FALSE;
15505
15506   if (_gtk_tree_view_find_node (tree_view, cursor_path, &cursor_tree, &cursor_node) ||
15507       cursor_node == NULL)
15508     return FALSE;
15509
15510   gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path);
15511
15512   validate_row (tree_view, cursor_tree, cursor_node, &iter, cursor_path);
15513
15514   gtk_tree_view_column_cell_set_cell_data (focus_column,
15515                                            tree_view->priv->model,
15516                                            &iter,
15517                                            GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_PARENT),
15518                                            cursor_node->children ? TRUE : FALSE);
15519   gtk_tree_view_get_cell_area (tree_view,
15520                                cursor_path,
15521                                focus_column,
15522                                &cell_area);
15523
15524   if (gtk_cell_area_activate (gtk_cell_layout_get_area (GTK_CELL_LAYOUT (focus_column)),
15525                               _gtk_tree_view_column_get_context (focus_column),
15526                               GTK_WIDGET (tree_view),
15527                               &cell_area,
15528                               flags, edit_only))
15529     retval = TRUE;
15530
15531   return retval;
15532 }
15533
15534 void
15535 _gtk_tree_view_add_editable (GtkTreeView       *tree_view,
15536                              GtkTreeViewColumn *column,
15537                              GtkTreePath       *path,
15538                              GtkCellEditable   *cell_editable,
15539                              GdkRectangle      *cell_area)
15540 {
15541   gint pre_val = gtk_adjustment_get_value (tree_view->priv->vadjustment);
15542   GtkRequisition requisition;
15543
15544   tree_view->priv->edited_column = column;
15545
15546   gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
15547   cell_area->y += pre_val - (int)gtk_adjustment_get_value (tree_view->priv->vadjustment);
15548
15549   gtk_widget_get_preferred_size (GTK_WIDGET (cell_editable),
15550                                  &requisition, NULL);
15551
15552   tree_view->priv->draw_keyfocus = TRUE;
15553
15554   if (requisition.height < cell_area->height)
15555     {
15556       gint diff = cell_area->height - requisition.height;
15557       gtk_tree_view_put (tree_view,
15558                          GTK_WIDGET (cell_editable),
15559                          cell_area->x, cell_area->y + diff/2,
15560                          cell_area->width, requisition.height);
15561     }
15562   else
15563     {
15564       gtk_tree_view_put (tree_view,
15565                          GTK_WIDGET (cell_editable),
15566                          cell_area->x, cell_area->y,
15567                          cell_area->width, cell_area->height);
15568     }
15569 }
15570
15571 static void
15572 gtk_tree_view_stop_editing (GtkTreeView *tree_view,
15573                             gboolean     cancel_editing)
15574 {
15575   GtkTreeViewColumn *column;
15576
15577   if (tree_view->priv->edited_column == NULL)
15578     return;
15579
15580   /*
15581    * This is very evil. We need to do this, because
15582    * gtk_cell_editable_editing_done may trigger gtk_tree_view_row_changed
15583    * later on. If gtk_tree_view_row_changed notices
15584    * tree_view->priv->edited_column != NULL, it'll call
15585    * gtk_tree_view_stop_editing again. Bad things will happen then.
15586    *
15587    * Please read that again if you intend to modify anything here.
15588    */
15589
15590   column = tree_view->priv->edited_column;
15591   gtk_cell_area_stop_editing (gtk_cell_layout_get_area (GTK_CELL_LAYOUT (column)), cancel_editing);
15592   tree_view->priv->edited_column = NULL;
15593 }
15594
15595
15596 /**
15597  * gtk_tree_view_set_hover_selection:
15598  * @tree_view: a #GtkTreeView
15599  * @hover: %TRUE to enable hover selection mode
15600  *
15601  * Enables or disables the hover selection mode of @tree_view.
15602  * Hover selection makes the selected row follow the pointer.
15603  * Currently, this works only for the selection modes 
15604  * %GTK_SELECTION_SINGLE and %GTK_SELECTION_BROWSE.
15605  * 
15606  * Since: 2.6
15607  **/
15608 void     
15609 gtk_tree_view_set_hover_selection (GtkTreeView *tree_view,
15610                                    gboolean     hover)
15611 {
15612   hover = hover != FALSE;
15613
15614   if (hover != tree_view->priv->hover_selection)
15615     {
15616       tree_view->priv->hover_selection = hover;
15617
15618       g_object_notify (G_OBJECT (tree_view), "hover-selection");
15619     }
15620 }
15621
15622 /**
15623  * gtk_tree_view_get_hover_selection:
15624  * @tree_view: a #GtkTreeView
15625  * 
15626  * Returns whether hover selection mode is turned on for @tree_view.
15627  * 
15628  * Return value: %TRUE if @tree_view is in hover selection mode
15629  *
15630  * Since: 2.6 
15631  **/
15632 gboolean 
15633 gtk_tree_view_get_hover_selection (GtkTreeView *tree_view)
15634 {
15635   return tree_view->priv->hover_selection;
15636 }
15637
15638 /**
15639  * gtk_tree_view_set_hover_expand:
15640  * @tree_view: a #GtkTreeView
15641  * @expand: %TRUE to enable hover selection mode
15642  *
15643  * Enables of disables the hover expansion mode of @tree_view.
15644  * Hover expansion makes rows expand or collapse if the pointer 
15645  * moves over them.
15646  * 
15647  * Since: 2.6
15648  **/
15649 void     
15650 gtk_tree_view_set_hover_expand (GtkTreeView *tree_view,
15651                                 gboolean     expand)
15652 {
15653   expand = expand != FALSE;
15654
15655   if (expand != tree_view->priv->hover_expand)
15656     {
15657       tree_view->priv->hover_expand = expand;
15658
15659       g_object_notify (G_OBJECT (tree_view), "hover-expand");
15660     }
15661 }
15662
15663 /**
15664  * gtk_tree_view_get_hover_expand:
15665  * @tree_view: a #GtkTreeView
15666  * 
15667  * Returns whether hover expansion mode is turned on for @tree_view.
15668  * 
15669  * Return value: %TRUE if @tree_view is in hover expansion mode
15670  *
15671  * Since: 2.6 
15672  **/
15673 gboolean 
15674 gtk_tree_view_get_hover_expand (GtkTreeView *tree_view)
15675 {
15676   return tree_view->priv->hover_expand;
15677 }
15678
15679 /**
15680  * gtk_tree_view_set_rubber_banding:
15681  * @tree_view: a #GtkTreeView
15682  * @enable: %TRUE to enable rubber banding
15683  *
15684  * Enables or disables rubber banding in @tree_view.  If the selection mode
15685  * is #GTK_SELECTION_MULTIPLE, rubber banding will allow the user to select
15686  * multiple rows by dragging the mouse.
15687  * 
15688  * Since: 2.10
15689  **/
15690 void
15691 gtk_tree_view_set_rubber_banding (GtkTreeView *tree_view,
15692                                   gboolean     enable)
15693 {
15694   enable = enable != FALSE;
15695
15696   if (enable != tree_view->priv->rubber_banding_enable)
15697     {
15698       tree_view->priv->rubber_banding_enable = enable;
15699
15700       g_object_notify (G_OBJECT (tree_view), "rubber-banding");
15701     }
15702 }
15703
15704 /**
15705  * gtk_tree_view_get_rubber_banding:
15706  * @tree_view: a #GtkTreeView
15707  * 
15708  * Returns whether rubber banding is turned on for @tree_view.  If the
15709  * selection mode is #GTK_SELECTION_MULTIPLE, rubber banding will allow the
15710  * user to select multiple rows by dragging the mouse.
15711  * 
15712  * Return value: %TRUE if rubber banding in @tree_view is enabled.
15713  *
15714  * Since: 2.10
15715  **/
15716 gboolean
15717 gtk_tree_view_get_rubber_banding (GtkTreeView *tree_view)
15718 {
15719   return tree_view->priv->rubber_banding_enable;
15720 }
15721
15722 /**
15723  * gtk_tree_view_is_rubber_banding_active:
15724  * @tree_view: a #GtkTreeView
15725  * 
15726  * Returns whether a rubber banding operation is currently being done
15727  * in @tree_view.
15728  *
15729  * Return value: %TRUE if a rubber banding operation is currently being
15730  * done in @tree_view.
15731  *
15732  * Since: 2.12
15733  **/
15734 gboolean
15735 gtk_tree_view_is_rubber_banding_active (GtkTreeView *tree_view)
15736 {
15737   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15738
15739   if (tree_view->priv->rubber_banding_enable
15740       && tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
15741     return TRUE;
15742
15743   return FALSE;
15744 }
15745
15746 /**
15747  * gtk_tree_view_get_row_separator_func: (skip)
15748  * @tree_view: a #GtkTreeView
15749  * 
15750  * Returns the current row separator function.
15751  * 
15752  * Return value: the current row separator function.
15753  *
15754  * Since: 2.6
15755  **/
15756 GtkTreeViewRowSeparatorFunc 
15757 gtk_tree_view_get_row_separator_func (GtkTreeView *tree_view)
15758 {
15759   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
15760
15761   return tree_view->priv->row_separator_func;
15762 }
15763
15764 /**
15765  * gtk_tree_view_set_row_separator_func:
15766  * @tree_view: a #GtkTreeView
15767  * @func: (allow-none): a #GtkTreeViewRowSeparatorFunc
15768  * @data: (allow-none): user data to pass to @func, or %NULL
15769  * @destroy: (allow-none): destroy notifier for @data, or %NULL
15770  * 
15771  * Sets the row separator function, which is used to determine
15772  * whether a row should be drawn as a separator. If the row separator
15773  * function is %NULL, no separators are drawn. This is the default value.
15774  *
15775  * Since: 2.6
15776  **/
15777 void
15778 gtk_tree_view_set_row_separator_func (GtkTreeView                 *tree_view,
15779                                       GtkTreeViewRowSeparatorFunc  func,
15780                                       gpointer                     data,
15781                                       GDestroyNotify               destroy)
15782 {
15783   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15784
15785   if (tree_view->priv->row_separator_destroy)
15786     tree_view->priv->row_separator_destroy (tree_view->priv->row_separator_data);
15787
15788   tree_view->priv->row_separator_func = func;
15789   tree_view->priv->row_separator_data = data;
15790   tree_view->priv->row_separator_destroy = destroy;
15791
15792   /* Have the tree recalculate heights */
15793   _gtk_rbtree_mark_invalid (tree_view->priv->tree);
15794   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
15795 }
15796
15797   
15798 static void
15799 gtk_tree_view_grab_notify (GtkWidget *widget,
15800                            gboolean   was_grabbed)
15801 {
15802   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
15803
15804   tree_view->priv->in_grab = !was_grabbed;
15805
15806   if (!was_grabbed)
15807     {
15808       tree_view->priv->pressed_button = -1;
15809
15810       if (tree_view->priv->rubber_band_status)
15811         gtk_tree_view_stop_rubber_band (tree_view);
15812     }
15813 }
15814
15815 static void
15816 gtk_tree_view_state_flags_changed (GtkWidget     *widget,
15817                                    GtkStateFlags  previous_state)
15818 {
15819   if (gtk_widget_get_realized (widget))
15820     gtk_tree_view_ensure_background (GTK_TREE_VIEW (widget));
15821
15822   gtk_widget_queue_draw (widget);
15823 }
15824
15825 /**
15826  * gtk_tree_view_get_grid_lines:
15827  * @tree_view: a #GtkTreeView
15828  *
15829  * Returns which grid lines are enabled in @tree_view.
15830  *
15831  * Return value: a #GtkTreeViewGridLines value indicating which grid lines
15832  * are enabled.
15833  *
15834  * Since: 2.10
15835  */
15836 GtkTreeViewGridLines
15837 gtk_tree_view_get_grid_lines (GtkTreeView *tree_view)
15838 {
15839   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
15840
15841   return tree_view->priv->grid_lines;
15842 }
15843
15844 /**
15845  * gtk_tree_view_set_grid_lines:
15846  * @tree_view: a #GtkTreeView
15847  * @grid_lines: a #GtkTreeViewGridLines value indicating which grid lines to
15848  * enable.
15849  *
15850  * Sets which grid lines to draw in @tree_view.
15851  *
15852  * Since: 2.10
15853  */
15854 void
15855 gtk_tree_view_set_grid_lines (GtkTreeView           *tree_view,
15856                               GtkTreeViewGridLines   grid_lines)
15857 {
15858   GtkTreeViewPrivate *priv;
15859   GtkWidget *widget;
15860   GtkTreeViewGridLines old_grid_lines;
15861
15862   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15863
15864   priv = tree_view->priv;
15865   widget = GTK_WIDGET (tree_view);
15866
15867   old_grid_lines = priv->grid_lines;
15868   priv->grid_lines = grid_lines;
15869   
15870   if (gtk_widget_get_realized (widget))
15871     {
15872       if (grid_lines == GTK_TREE_VIEW_GRID_LINES_NONE &&
15873           priv->grid_line_width)
15874         {
15875           priv->grid_line_width = 0;
15876         }
15877       
15878       if (grid_lines != GTK_TREE_VIEW_GRID_LINES_NONE && 
15879           !priv->grid_line_width)
15880         {
15881           gint8 *dash_list;
15882
15883           gtk_widget_style_get (widget,
15884                                 "grid-line-width", &priv->grid_line_width,
15885                                 "grid-line-pattern", (gchar *)&dash_list,
15886                                 NULL);
15887       
15888           if (dash_list)
15889             {
15890               priv->grid_line_dashes[0] = dash_list[0];
15891               if (dash_list[0])
15892                 priv->grid_line_dashes[1] = dash_list[1];
15893               
15894               g_free (dash_list);
15895             }
15896           else
15897             {
15898               priv->grid_line_dashes[0] = 1;
15899               priv->grid_line_dashes[1] = 1;
15900             }
15901         }      
15902     }
15903
15904   if (old_grid_lines != grid_lines)
15905     {
15906       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15907       
15908       g_object_notify (G_OBJECT (tree_view), "enable-grid-lines");
15909     }
15910 }
15911
15912 /**
15913  * gtk_tree_view_get_enable_tree_lines:
15914  * @tree_view: a #GtkTreeView.
15915  *
15916  * Returns whether or not tree lines are drawn in @tree_view.
15917  *
15918  * Return value: %TRUE if tree lines are drawn in @tree_view, %FALSE
15919  * otherwise.
15920  *
15921  * Since: 2.10
15922  */
15923 gboolean
15924 gtk_tree_view_get_enable_tree_lines (GtkTreeView *tree_view)
15925 {
15926   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15927
15928   return tree_view->priv->tree_lines_enabled;
15929 }
15930
15931 /**
15932  * gtk_tree_view_set_enable_tree_lines:
15933  * @tree_view: a #GtkTreeView
15934  * @enabled: %TRUE to enable tree line drawing, %FALSE otherwise.
15935  *
15936  * Sets whether to draw lines interconnecting the expanders in @tree_view.
15937  * This does not have any visible effects for lists.
15938  *
15939  * Since: 2.10
15940  */
15941 void
15942 gtk_tree_view_set_enable_tree_lines (GtkTreeView *tree_view,
15943                                      gboolean     enabled)
15944 {
15945   GtkTreeViewPrivate *priv;
15946   GtkWidget *widget;
15947   gboolean was_enabled;
15948
15949   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15950
15951   enabled = enabled != FALSE;
15952
15953   priv = tree_view->priv;
15954   widget = GTK_WIDGET (tree_view);
15955
15956   was_enabled = priv->tree_lines_enabled;
15957
15958   priv->tree_lines_enabled = enabled;
15959
15960   if (gtk_widget_get_realized (widget))
15961     {
15962       if (!enabled && priv->tree_line_width)
15963         {
15964           priv->tree_line_width = 0;
15965         }
15966       
15967       if (enabled && !priv->tree_line_width)
15968         {
15969           gint8 *dash_list;
15970           gtk_widget_style_get (widget,
15971                                 "tree-line-width", &priv->tree_line_width,
15972                                 "tree-line-pattern", (gchar *)&dash_list,
15973                                 NULL);
15974           
15975           if (dash_list)
15976             {
15977               priv->tree_line_dashes[0] = dash_list[0];
15978               if (dash_list[0])
15979                 priv->tree_line_dashes[1] = dash_list[1];
15980               
15981               g_free (dash_list);
15982             }
15983           else
15984             {
15985               priv->tree_line_dashes[0] = 1;
15986               priv->tree_line_dashes[1] = 1;
15987             }
15988         }
15989     }
15990
15991   if (was_enabled != enabled)
15992     {
15993       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15994
15995       g_object_notify (G_OBJECT (tree_view), "enable-tree-lines");
15996     }
15997 }
15998
15999
16000 /**
16001  * gtk_tree_view_set_show_expanders:
16002  * @tree_view: a #GtkTreeView
16003  * @enabled: %TRUE to enable expander drawing, %FALSE otherwise.
16004  *
16005  * Sets whether to draw and enable expanders and indent child rows in
16006  * @tree_view.  When disabled there will be no expanders visible in trees
16007  * and there will be no way to expand and collapse rows by default.  Also
16008  * note that hiding the expanders will disable the default indentation.  You
16009  * can set a custom indentation in this case using
16010  * gtk_tree_view_set_level_indentation().
16011  * This does not have any visible effects for lists.
16012  *
16013  * Since: 2.12
16014  */
16015 void
16016 gtk_tree_view_set_show_expanders (GtkTreeView *tree_view,
16017                                   gboolean     enabled)
16018 {
16019   gboolean was_enabled;
16020
16021   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
16022
16023   enabled = enabled != FALSE;
16024   was_enabled = tree_view->priv->show_expanders;
16025
16026   tree_view->priv->show_expanders = enabled == TRUE;
16027
16028   if (enabled != was_enabled)
16029     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
16030 }
16031
16032 /**
16033  * gtk_tree_view_get_show_expanders:
16034  * @tree_view: a #GtkTreeView.
16035  *
16036  * Returns whether or not expanders are drawn in @tree_view.
16037  *
16038  * Return value: %TRUE if expanders are drawn in @tree_view, %FALSE
16039  * otherwise.
16040  *
16041  * Since: 2.12
16042  */
16043 gboolean
16044 gtk_tree_view_get_show_expanders (GtkTreeView *tree_view)
16045 {
16046   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
16047
16048   return tree_view->priv->show_expanders;
16049 }
16050
16051 /**
16052  * gtk_tree_view_set_level_indentation:
16053  * @tree_view: a #GtkTreeView
16054  * @indentation: the amount, in pixels, of extra indentation in @tree_view.
16055  *
16056  * Sets the amount of extra indentation for child levels to use in @tree_view
16057  * in addition to the default indentation.  The value should be specified in
16058  * pixels, a value of 0 disables this feature and in this case only the default
16059  * indentation will be used.
16060  * This does not have any visible effects for lists.
16061  *
16062  * Since: 2.12
16063  */
16064 void
16065 gtk_tree_view_set_level_indentation (GtkTreeView *tree_view,
16066                                      gint         indentation)
16067 {
16068   tree_view->priv->level_indentation = indentation;
16069
16070   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
16071 }
16072
16073 /**
16074  * gtk_tree_view_get_level_indentation:
16075  * @tree_view: a #GtkTreeView.
16076  *
16077  * Returns the amount, in pixels, of extra indentation for child levels
16078  * in @tree_view.
16079  *
16080  * Return value: the amount of extra indentation for child levels in
16081  * @tree_view.  A return value of 0 means that this feature is disabled.
16082  *
16083  * Since: 2.12
16084  */
16085 gint
16086 gtk_tree_view_get_level_indentation (GtkTreeView *tree_view)
16087 {
16088   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
16089
16090   return tree_view->priv->level_indentation;
16091 }
16092
16093 /**
16094  * gtk_tree_view_set_tooltip_row:
16095  * @tree_view: a #GtkTreeView
16096  * @tooltip: a #GtkTooltip
16097  * @path: a #GtkTreePath
16098  *
16099  * Sets the tip area of @tooltip to be the area covered by the row at @path.
16100  * See also gtk_tree_view_set_tooltip_column() for a simpler alternative.
16101  * See also gtk_tooltip_set_tip_area().
16102  *
16103  * Since: 2.12
16104  */
16105 void
16106 gtk_tree_view_set_tooltip_row (GtkTreeView *tree_view,
16107                                GtkTooltip  *tooltip,
16108                                GtkTreePath *path)
16109 {
16110   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
16111   g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
16112
16113   gtk_tree_view_set_tooltip_cell (tree_view, tooltip, path, NULL, NULL);
16114 }
16115
16116 /**
16117  * gtk_tree_view_set_tooltip_cell:
16118  * @tree_view: a #GtkTreeView
16119  * @tooltip: a #GtkTooltip
16120  * @path: (allow-none): a #GtkTreePath or %NULL
16121  * @column: (allow-none): a #GtkTreeViewColumn or %NULL
16122  * @cell: (allow-none): a #GtkCellRenderer or %NULL
16123  *
16124  * Sets the tip area of @tooltip to the area @path, @column and @cell have
16125  * in common.  For example if @path is %NULL and @column is set, the tip
16126  * area will be set to the full area covered by @column.  See also
16127  * gtk_tooltip_set_tip_area().
16128  *
16129  * Note that if @path is not specified and @cell is set and part of a column
16130  * containing the expander, the tooltip might not show and hide at the correct
16131  * position.  In such cases @path must be set to the current node under the
16132  * mouse cursor for this function to operate correctly.
16133  *
16134  * See also gtk_tree_view_set_tooltip_column() for a simpler alternative.
16135  *
16136  * Since: 2.12
16137  */
16138 void
16139 gtk_tree_view_set_tooltip_cell (GtkTreeView       *tree_view,
16140                                 GtkTooltip        *tooltip,
16141                                 GtkTreePath       *path,
16142                                 GtkTreeViewColumn *column,
16143                                 GtkCellRenderer   *cell)
16144 {
16145   GtkAllocation allocation;
16146   GdkRectangle rect;
16147
16148   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
16149   g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
16150   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
16151   g_return_if_fail (cell == NULL || GTK_IS_CELL_RENDERER (cell));
16152
16153   /* Determine x values. */
16154   if (column && cell)
16155     {
16156       GdkRectangle tmp;
16157       gint start, width;
16158
16159       /* We always pass in path here, whether it is NULL or not.
16160        * For cells in expander columns path must be specified so that
16161        * we can correctly account for the indentation.  This also means
16162        * that the tooltip is constrained vertically by the "Determine y
16163        * values" code below; this is not a real problem since cells actually
16164        * don't stretch vertically in constrast to columns.
16165        */
16166       gtk_tree_view_get_cell_area (tree_view, path, column, &tmp);
16167       gtk_tree_view_column_cell_get_position (column, cell, &start, &width);
16168
16169       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
16170                                                          tmp.x + start, 0,
16171                                                          &rect.x, NULL);
16172       rect.width = width;
16173     }
16174   else if (column)
16175     {
16176       GdkRectangle tmp;
16177
16178       gtk_tree_view_get_background_area (tree_view, NULL, column, &tmp);
16179       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
16180                                                          tmp.x, 0,
16181                                                          &rect.x, NULL);
16182       rect.width = tmp.width;
16183     }
16184   else
16185     {
16186       gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
16187       rect.x = 0;
16188       rect.width = allocation.width;
16189     }
16190
16191   /* Determine y values. */
16192   if (path)
16193     {
16194       GdkRectangle tmp;
16195
16196       gtk_tree_view_get_background_area (tree_view, path, NULL, &tmp);
16197       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
16198                                                          0, tmp.y,
16199                                                          NULL, &rect.y);
16200       rect.height = tmp.height;
16201     }
16202   else
16203     {
16204       rect.y = 0;
16205       rect.height = gtk_adjustment_get_page_size (tree_view->priv->vadjustment);
16206     }
16207
16208   gtk_tooltip_set_tip_area (tooltip, &rect);
16209 }
16210
16211 /**
16212  * gtk_tree_view_get_tooltip_context:
16213  * @tree_view: a #GtkTreeView
16214  * @x: (inout): the x coordinate (relative to widget coordinates)
16215  * @y: (inout): the y coordinate (relative to widget coordinates)
16216  * @keyboard_tip: whether this is a keyboard tooltip or not
16217  * @model: (out) (allow-none) (transfer none): a pointer to receive a
16218  *         #GtkTreeModel or %NULL
16219  * @path: (out) (allow-none): a pointer to receive a #GtkTreePath or %NULL
16220  * @iter: (out) (allow-none): a pointer to receive a #GtkTreeIter or %NULL
16221  *
16222  * This function is supposed to be used in a #GtkWidget::query-tooltip
16223  * signal handler for #GtkTreeView.  The @x, @y and @keyboard_tip values
16224  * which are received in the signal handler, should be passed to this
16225  * function without modification.
16226  *
16227  * The return value indicates whether there is a tree view row at the given
16228  * coordinates (%TRUE) or not (%FALSE) for mouse tooltips.  For keyboard
16229  * tooltips the row returned will be the cursor row.  When %TRUE, then any of
16230  * @model, @path and @iter which have been provided will be set to point to
16231  * that row and the corresponding model.  @x and @y will always be converted
16232  * to be relative to @tree_view's bin_window if @keyboard_tooltip is %FALSE.
16233  *
16234  * Return value: whether or not the given tooltip context points to a row.
16235  *
16236  * Since: 2.12
16237  */
16238 gboolean
16239 gtk_tree_view_get_tooltip_context (GtkTreeView   *tree_view,
16240                                    gint          *x,
16241                                    gint          *y,
16242                                    gboolean       keyboard_tip,
16243                                    GtkTreeModel **model,
16244                                    GtkTreePath  **path,
16245                                    GtkTreeIter   *iter)
16246 {
16247   GtkTreePath *tmppath = NULL;
16248
16249   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
16250   g_return_val_if_fail (x != NULL, FALSE);
16251   g_return_val_if_fail (y != NULL, FALSE);
16252
16253   if (keyboard_tip)
16254     {
16255       gtk_tree_view_get_cursor (tree_view, &tmppath, NULL);
16256
16257       if (!tmppath)
16258         return FALSE;
16259     }
16260   else
16261     {
16262       gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, *x, *y,
16263                                                          x, y);
16264
16265       if (!gtk_tree_view_get_path_at_pos (tree_view, *x, *y,
16266                                           &tmppath, NULL, NULL, NULL))
16267         return FALSE;
16268     }
16269
16270   if (model)
16271     *model = gtk_tree_view_get_model (tree_view);
16272
16273   if (iter)
16274     gtk_tree_model_get_iter (gtk_tree_view_get_model (tree_view),
16275                              iter, tmppath);
16276
16277   if (path)
16278     *path = tmppath;
16279   else
16280     gtk_tree_path_free (tmppath);
16281
16282   return TRUE;
16283 }
16284
16285 static gboolean
16286 gtk_tree_view_set_tooltip_query_cb (GtkWidget  *widget,
16287                                     gint        x,
16288                                     gint        y,
16289                                     gboolean    keyboard_tip,
16290                                     GtkTooltip *tooltip,
16291                                     gpointer    data)
16292 {
16293   GValue value = G_VALUE_INIT;
16294   GValue transformed = G_VALUE_INIT;
16295   GtkTreeIter iter;
16296   GtkTreePath *path;
16297   GtkTreeModel *model;
16298   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
16299
16300   if (!gtk_tree_view_get_tooltip_context (GTK_TREE_VIEW (widget),
16301                                           &x, &y,
16302                                           keyboard_tip,
16303                                           &model, &path, &iter))
16304     return FALSE;
16305
16306   gtk_tree_model_get_value (model, &iter,
16307                             tree_view->priv->tooltip_column, &value);
16308
16309   g_value_init (&transformed, G_TYPE_STRING);
16310
16311   if (!g_value_transform (&value, &transformed))
16312     {
16313       g_value_unset (&value);
16314       gtk_tree_path_free (path);
16315
16316       return FALSE;
16317     }
16318
16319   g_value_unset (&value);
16320
16321   if (!g_value_get_string (&transformed))
16322     {
16323       g_value_unset (&transformed);
16324       gtk_tree_path_free (path);
16325
16326       return FALSE;
16327     }
16328
16329   gtk_tooltip_set_markup (tooltip, g_value_get_string (&transformed));
16330   gtk_tree_view_set_tooltip_row (tree_view, tooltip, path);
16331
16332   gtk_tree_path_free (path);
16333   g_value_unset (&transformed);
16334
16335   return TRUE;
16336 }
16337
16338 /**
16339  * gtk_tree_view_set_tooltip_column:
16340  * @tree_view: a #GtkTreeView
16341  * @column: an integer, which is a valid column number for @tree_view's model
16342  *
16343  * If you only plan to have simple (text-only) tooltips on full rows, you
16344  * can use this function to have #GtkTreeView handle these automatically
16345  * for you. @column should be set to the column in @tree_view's model
16346  * containing the tooltip texts, or -1 to disable this feature.
16347  *
16348  * When enabled, #GtkWidget::has-tooltip will be set to %TRUE and
16349  * @tree_view will connect a #GtkWidget::query-tooltip signal handler.
16350  *
16351  * Note that the signal handler sets the text with gtk_tooltip_set_markup(),
16352  * so &amp;, &lt;, etc have to be escaped in the text.
16353  *
16354  * Since: 2.12
16355  */
16356 void
16357 gtk_tree_view_set_tooltip_column (GtkTreeView *tree_view,
16358                                   gint         column)
16359 {
16360   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
16361
16362   if (column == tree_view->priv->tooltip_column)
16363     return;
16364
16365   if (column == -1)
16366     {
16367       g_signal_handlers_disconnect_by_func (tree_view,
16368                                             gtk_tree_view_set_tooltip_query_cb,
16369                                             NULL);
16370       gtk_widget_set_has_tooltip (GTK_WIDGET (tree_view), FALSE);
16371     }
16372   else
16373     {
16374       if (tree_view->priv->tooltip_column == -1)
16375         {
16376           g_signal_connect (tree_view, "query-tooltip",
16377                             G_CALLBACK (gtk_tree_view_set_tooltip_query_cb), NULL);
16378           gtk_widget_set_has_tooltip (GTK_WIDGET (tree_view), TRUE);
16379         }
16380     }
16381
16382   tree_view->priv->tooltip_column = column;
16383   g_object_notify (G_OBJECT (tree_view), "tooltip-column");
16384 }
16385
16386 /**
16387  * gtk_tree_view_get_tooltip_column:
16388  * @tree_view: a #GtkTreeView
16389  *
16390  * Returns the column of @tree_view's model which is being used for
16391  * displaying tooltips on @tree_view's rows.
16392  *
16393  * Return value: the index of the tooltip column that is currently being
16394  * used, or -1 if this is disabled.
16395  *
16396  * Since: 2.12
16397  */
16398 gint
16399 gtk_tree_view_get_tooltip_column (GtkTreeView *tree_view)
16400 {
16401   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
16402
16403   return tree_view->priv->tooltip_column;
16404 }