]> Pileus Git - ~andy/gtk/blob - gtk/gtktreeview.c
7c3c0b0e0d25c115f837094eadf235792e84b6b0
[~andy/gtk] / gtk / gtktreeview.c
1 /* gtktreeview.c
2  * Copyright (C) 2000  Red Hat, Inc.,  Jonathan Blandford <jrb@redhat.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20
21 #include "config.h"
22
23 #include <math.h>
24 #include <string.h>
25
26 #include "gtktreeview.h"
27 #include "gtkrbtree.h"
28 #include "gtktreednd.h"
29 #include "gtktreeprivate.h"
30 #include "gtkcellrenderer.h"
31 #include "gtkmainprivate.h"
32 #include "gtkmarshalers.h"
33 #include "gtkbuildable.h"
34 #include "gtkbutton.h"
35 #include "gtklabel.h"
36 #include "gtkbox.h"
37 #include "gtkarrow.h"
38 #include "gtkintl.h"
39 #include "gtkbindings.h"
40 #include "gtkcontainer.h"
41 #include "gtkentry.h"
42 #include "gtkframe.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 "a11y/gtktreeviewaccessible.h"
53
54
55 /**
56  * SECTION:gtktreeview
57  * @Short_description: A widget for displaying both trees and lists
58  * @Title: GtkTreeView
59  * @See_also: #GtkTreeViewColumn, #GtkTreeSelection, #GtkTreeDnd, #GtkTreeMode,
60  *   #GtkTreeSortable, #GtkTreeModelSort, #GtkListStore, #GtkTreeStore,
61  *   #GtkCellRenderer, #GtkCellEditable, #GtkCellRendererPixbuf,
62  *   #GtkCellRendererText, #GtkCellRendererToggle
63  *
64  * Widget that displays any object that implements the #GtkTreeModel interface.
65  *
66  * Please refer to the <link linkend="TreeWidget">tree widget conceptual
67  * overview</link> for an overview of all the objects and data types related
68  * to the tree widget and how they work together.
69  *
70  * Several different coordinate systems are exposed in the GtkTreeView API.
71  * These are:
72  *
73  * <inlinegraphic fileref="tree-view-coordinates.png" format="PNG"></inlinegraphic>
74  * <variablelist><title>Coordinate systems in GtkTreeView API</title>
75  * <varlistentry><term>Widget coordinates</term>
76  * <listitem>
77  * <para>
78  * Coordinates relative to the widget (usually <literal>widget->window</literal>).
79  * </para>
80  * </listitem>
81  * </varlistentry>
82  * <varlistentry><term>Bin window coordinates</term>
83  * <listitem>
84  * <para>
85  * Coordinates relative to the window that GtkTreeView renders to.
86  * </para>
87  * </listitem>
88  * </varlistentry>
89  * <varlistentry><term>Tree coordinates</term>
90  * <listitem>
91  * <para>
92  * Coordinates relative to the entire scrollable area of GtkTreeView. These
93  * coordinates start at (0, 0) for row 0 of the tree.
94  * </para>
95  * </listitem>
96  * </varlistentry>
97  * </variablelist>
98  *
99  * Several functions are available for converting between the different
100  * coordinate systems.  The most common translations are between widget and bin
101  * window coordinates and between bin window and tree coordinates. For the
102  * former you can use gtk_tree_view_convert_widget_to_bin_window_coords()
103  * (and vice versa), for the latter gtk_tree_view_convert_bin_window_to_tree_coords()
104  * (and vice versa).
105  *
106  * <refsect2 id="GtkTreeView-BUILDER-UI">
107  * <title>GtkTreeView as GtkBuildable</title>
108  * The GtkTreeView implementation of the GtkBuildable interface accepts
109  * #GtkTreeViewColumn objects as &lt;child&gt; elements and exposes the
110  * internal #GtkTreeSelection in UI definitions.
111  * <example>
112  * <title>A UI definition fragment with GtkTreeView</title>
113  * <programlisting><![CDATA[
114  * <object class="GtkTreeView" id="treeview">
115  *   <property name="model">liststore1</property>
116  *   <child>
117  *     <object class="GtkTreeViewColumn" id="test-column">
118  *       <property name="title">Test</property>
119  *       <child>
120  *         <object class="GtkCellRendererText" id="test-renderer"/>
121  *         <attributes>
122  *           <attribute name="text">1</attribute>
123  *         </attributes>
124  *       </child>
125  *     </object>
126  *   </child>
127  *   <child internal-child="selection">
128  *     <object class="GtkTreeSelection" id="selection">
129  *       <signal name="changed" handler="on_treeview_selection_changed"/>
130  *     </object>
131  *   </child>
132  * </object>
133  * ]]></programlisting>
134  * </example>
135  * </refsect2>
136  */
137
138 enum
139 {
140   DRAG_COLUMN_WINDOW_STATE_UNSET = 0,
141   DRAG_COLUMN_WINDOW_STATE_ORIGINAL = 1,
142   DRAG_COLUMN_WINDOW_STATE_ARROW = 2,
143   DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT = 3,
144   DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT = 4
145 };
146
147 enum
148 {
149   RUBBER_BAND_OFF = 0,
150   RUBBER_BAND_MAYBE_START = 1,
151   RUBBER_BAND_ACTIVE = 2
152 };
153
154  /* This lovely little value is used to determine how far away from the title bar
155   * you can move the mouse and still have a column drag work.
156   */
157 #define TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER(tree_view) (10*gtk_tree_view_get_effective_header_height(tree_view))
158
159 #ifdef __GNUC__
160
161 #define TREE_VIEW_INTERNAL_ASSERT(expr, ret)     G_STMT_START{          \
162      if (!(expr))                                                       \
163        {                                                                \
164          g_log (G_LOG_DOMAIN,                                           \
165                 G_LOG_LEVEL_CRITICAL,                                   \
166                 "%s (%s): assertion `%s' failed.\n"                     \
167                 "There is a disparity between the internal view of the GtkTreeView,\n"    \
168                 "and the GtkTreeModel.  This generally means that the model has changed\n"\
169                 "without letting the view know.  Any display from now on is likely to\n"  \
170                 "be incorrect.\n",                                                        \
171                 G_STRLOC,                                               \
172                 G_STRFUNC,                                              \
173                 #expr);                                                 \
174          return ret;                                                    \
175        };                               }G_STMT_END
176
177 #define TREE_VIEW_INTERNAL_ASSERT_VOID(expr)     G_STMT_START{          \
178      if (!(expr))                                                       \
179        {                                                                \
180          g_log (G_LOG_DOMAIN,                                           \
181                 G_LOG_LEVEL_CRITICAL,                                   \
182                 "%s (%s): assertion `%s' failed.\n"                     \
183                 "There is a disparity between the internal view of the GtkTreeView,\n"    \
184                 "and the GtkTreeModel.  This generally means that the model has changed\n"\
185                 "without letting the view know.  Any display from now on is likely to\n"  \
186                 "be incorrect.\n",                                                        \
187                 G_STRLOC,                                               \
188                 G_STRFUNC,                                              \
189                 #expr);                                                 \
190          return;                                                        \
191        };                               }G_STMT_END
192
193 #else
194
195 #define TREE_VIEW_INTERNAL_ASSERT(expr, ret)     G_STMT_START{          \
196      if (!(expr))                                                       \
197        {                                                                \
198          g_log (G_LOG_DOMAIN,                                           \
199                 G_LOG_LEVEL_CRITICAL,                                   \
200                 "file %s: line %d: assertion `%s' failed.\n"       \
201                 "There is a disparity between the internal view of the GtkTreeView,\n"    \
202                 "and the GtkTreeModel.  This generally means that the model has changed\n"\
203                 "without letting the view know.  Any display from now on is likely to\n"  \
204                 "be incorrect.\n",                                                        \
205                 __FILE__,                                               \
206                 __LINE__,                                               \
207                 #expr);                                                 \
208          return ret;                                                    \
209        };                               }G_STMT_END
210
211 #define TREE_VIEW_INTERNAL_ASSERT_VOID(expr)     G_STMT_START{          \
212      if (!(expr))                                                       \
213        {                                                                \
214          g_log (G_LOG_DOMAIN,                                           \
215                 G_LOG_LEVEL_CRITICAL,                                   \
216                 "file %s: line %d: assertion '%s' failed.\n"            \
217                 "There is a disparity between the internal view of the GtkTreeView,\n"    \
218                 "and the GtkTreeModel.  This generally means that the model has changed\n"\
219                 "without letting the view know.  Any display from now on is likely to\n"  \
220                 "be incorrect.\n",                                                        \
221                 __FILE__,                                               \
222                 __LINE__,                                               \
223                 #expr);                                                 \
224          return;                                                        \
225        };                               }G_STMT_END
226 #endif
227
228 #define GTK_TREE_VIEW_PRIORITY_VALIDATE (GDK_PRIORITY_REDRAW + 5)
229 #define GTK_TREE_VIEW_PRIORITY_SCROLL_SYNC (GTK_TREE_VIEW_PRIORITY_VALIDATE + 2)
230 #define GTK_TREE_VIEW_TIME_MS_PER_IDLE 30
231 #define SCROLL_EDGE_SIZE 15
232 #define EXPANDER_EXTRA_PADDING 4
233 #define GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT 5000
234 #define AUTO_EXPAND_TIMEOUT 500
235
236 /* Translate from bin_window coordinates to rbtree (tree coordinates) and
237  * vice versa.
238  */
239 #define TREE_WINDOW_Y_TO_RBTREE_Y(tree_view,y) ((y) + tree_view->priv->dy)
240 #define RBTREE_Y_TO_TREE_WINDOW_Y(tree_view,y) ((y) - tree_view->priv->dy)
241
242 typedef struct _GtkTreeViewColumnReorder GtkTreeViewColumnReorder;
243 struct _GtkTreeViewColumnReorder
244 {
245   gint left_align;
246   gint right_align;
247   GtkTreeViewColumn *left_column;
248   GtkTreeViewColumn *right_column;
249 };
250
251 typedef struct _GtkTreeViewChild GtkTreeViewChild;
252 struct _GtkTreeViewChild
253 {
254   GtkWidget *widget;
255   gint x;
256   gint y;
257   gint width;
258   gint height;
259 };
260
261
262 typedef struct _TreeViewDragInfo TreeViewDragInfo;
263 struct _TreeViewDragInfo
264 {
265   GdkModifierType start_button_mask;
266   GtkTargetList *_unused_source_target_list;
267   GdkDragAction source_actions;
268
269   GtkTargetList *_unused_dest_target_list;
270
271   guint source_set : 1;
272   guint dest_set : 1;
273 };
274
275
276 struct _GtkTreeViewPrivate
277 {
278   GtkTreeModel *model;
279
280   /* tree information */
281   GtkRBTree *tree;
282
283   /* Container info */
284   GList *children;
285   gint width;
286   gint height;
287
288   /* Adjustments */
289   GtkAdjustment *hadjustment;
290   GtkAdjustment *vadjustment;
291   gint           min_display_width;
292   gint           min_display_height;
293
294   /* Sub windows */
295   GdkWindow *bin_window;
296   GdkWindow *header_window;
297
298   /* Scroll position state keeping */
299   GtkTreeRowReference *top_row;
300   gint top_row_dy;
301   /* dy == y pos of top_row + top_row_dy */
302   /* we cache it for simplicity of the code */
303   gint dy;
304
305   guint presize_handler_timer;
306   guint validate_rows_timer;
307   guint scroll_sync_timer;
308
309   /* Indentation and expander layout */
310   gint expander_size;
311   GtkTreeViewColumn *expander_column;
312
313   gint level_indentation;
314
315   /* Key navigation (focus), selection */
316   gint cursor_offset;
317
318   GtkTreeRowReference *anchor;
319   GtkTreeRowReference *cursor;
320
321   GtkTreeViewColumn *focus_column;
322
323   /* Current pressed node, previously pressed, prelight */
324   GtkRBNode *button_pressed_node;
325   GtkRBTree *button_pressed_tree;
326
327   gint pressed_button;
328   gint press_start_x;
329   gint press_start_y;
330
331   gint event_last_x;
332   gint event_last_y;
333
334   guint last_button_time;
335   gint last_button_x;
336   gint last_button_y;
337
338   GtkRBNode *prelight_node;
339   GtkRBTree *prelight_tree;
340
341   /* Cell Editing */
342   GtkTreeViewColumn *edited_column;
343
344   /* The node that's currently being collapsed or expanded */
345   GtkRBNode *expanded_collapsed_node;
346   GtkRBTree *expanded_collapsed_tree;
347   guint expand_collapse_timeout;
348
349   /* Auto expand/collapse timeout in hover mode */
350   guint auto_expand_timeout;
351
352   /* Selection information */
353   GtkTreeSelection *selection;
354
355   /* Header information */
356   gint n_columns;
357   GList *columns;
358   gint header_height;
359
360   GtkTreeViewColumnDropFunc column_drop_func;
361   gpointer column_drop_func_data;
362   GDestroyNotify column_drop_func_data_destroy;
363   GList *column_drag_info;
364   GtkTreeViewColumnReorder *cur_reorder;
365
366   gint prev_width_before_expander;
367
368   /* Interactive Header reordering */
369   GdkWindow *drag_window;
370   GdkWindow *drag_highlight_window;
371   GtkTreeViewColumn *drag_column;
372   gint drag_column_x;
373
374   /* Interactive Header Resizing */
375   gint drag_pos;
376   gint x_drag;
377
378   /* Non-interactive Header Resizing, expand flag support */
379   gint prev_width;
380
381   gint last_extra_space;
382   gint last_extra_space_per_column;
383   gint last_number_of_expand_columns;
384
385   /* ATK Hack */
386   GtkTreeDestroyCountFunc destroy_count_func;
387   gpointer destroy_count_data;
388   GDestroyNotify destroy_count_destroy;
389
390   /* Scroll timeout (e.g. during dnd, rubber banding) */
391   guint scroll_timeout;
392
393   /* Row drag-and-drop */
394   GtkTreeRowReference *drag_dest_row;
395   GtkTreeViewDropPosition drag_dest_pos;
396   guint open_dest_timeout;
397
398   /* Rubber banding */
399   gint rubber_band_status;
400   gint rubber_band_x;
401   gint rubber_band_y;
402   gint rubber_band_extend;
403   gint rubber_band_modify;
404
405   GtkRBNode *rubber_band_start_node;
406   GtkRBTree *rubber_band_start_tree;
407
408   GtkRBNode *rubber_band_end_node;
409   GtkRBTree *rubber_band_end_tree;
410
411   /* fixed height */
412   gint fixed_height;
413
414   /* Scroll-to functionality when unrealized */
415   GtkTreeRowReference *scroll_to_path;
416   GtkTreeViewColumn *scroll_to_column;
417   gfloat scroll_to_row_align;
418   gfloat scroll_to_col_align;
419
420   /* Interactive search */
421   gint selected_iter;
422   gint search_column;
423   GtkTreeViewSearchPositionFunc search_position_func;
424   GtkTreeViewSearchEqualFunc search_equal_func;
425   gpointer search_user_data;
426   GDestroyNotify search_destroy;
427   gpointer search_position_user_data;
428   GDestroyNotify search_position_destroy;
429   GtkWidget *search_window;
430   GtkWidget *search_entry;
431   gulong search_entry_changed_id;
432   guint typeselect_flush_timeout;
433
434   /* Grid and tree lines */
435   GtkTreeViewGridLines grid_lines;
436   double grid_line_dashes[2];
437   int grid_line_width;
438
439   gboolean tree_lines_enabled;
440   double tree_line_dashes[2];
441   int tree_line_width;
442
443   /* Row separators */
444   GtkTreeViewRowSeparatorFunc row_separator_func;
445   gpointer row_separator_data;
446   GDestroyNotify row_separator_destroy;
447
448   /* Tooltip support */
449   gint tooltip_column;
450
451   /* Here comes the bitfield */
452   guint scroll_to_use_align : 1;
453
454   guint fixed_height_mode : 1;
455   guint fixed_height_check : 1;
456
457   guint reorderable : 1;
458   guint header_has_focus : 1;
459   guint drag_column_window_state : 3;
460   /* hint to display rows in alternating colors */
461   guint has_rules : 1;
462   guint mark_rows_col_dirty : 1;
463
464   /* for DnD */
465   guint empty_view_drop : 1;
466
467   guint modify_selection_pressed : 1;
468   guint extend_selection_pressed : 1;
469
470   guint init_hadjust_value : 1;
471
472   guint in_top_row_to_dy : 1;
473
474   /* interactive search */
475   guint enable_search : 1;
476   guint disable_popdown : 1;
477   guint search_custom_entry_set : 1;
478   
479   guint hover_selection : 1;
480   guint hover_expand : 1;
481   guint imcontext_changed : 1;
482
483   guint rubber_banding_enable : 1;
484
485   guint in_grab : 1;
486
487   guint post_validation_flag : 1;
488
489   /* Whether our key press handler is to avoid sending an unhandled binding to the search entry */
490   guint search_entry_avoid_unhandled_binding : 1;
491
492   /* GtkScrollablePolicy needs to be checked when
493    * driving the scrollable adjustment values */
494   guint hscroll_policy : 1;
495   guint vscroll_policy : 1;
496
497   /* GtkTreeView flags */
498   guint is_list : 1;
499   guint show_expanders : 1;
500   guint in_column_resize : 1;
501   guint arrow_prelit : 1;
502   guint headers_visible : 1;
503   guint draw_keyfocus : 1;
504   guint model_setup : 1;
505   guint in_column_drag : 1;
506 };
507
508
509 /* Signals */
510 enum
511 {
512   ROW_ACTIVATED,
513   TEST_EXPAND_ROW,
514   TEST_COLLAPSE_ROW,
515   ROW_EXPANDED,
516   ROW_COLLAPSED,
517   COLUMNS_CHANGED,
518   CURSOR_CHANGED,
519   MOVE_CURSOR,
520   SELECT_ALL,
521   UNSELECT_ALL,
522   SELECT_CURSOR_ROW,
523   TOGGLE_CURSOR_ROW,
524   EXPAND_COLLAPSE_CURSOR_ROW,
525   SELECT_CURSOR_PARENT,
526   START_INTERACTIVE_SEARCH,
527   LAST_SIGNAL
528 };
529
530 /* Properties */
531 enum {
532   PROP_0,
533   PROP_MODEL,
534   PROP_HADJUSTMENT,
535   PROP_VADJUSTMENT,
536   PROP_HSCROLL_POLICY,
537   PROP_VSCROLL_POLICY,
538   PROP_HEADERS_VISIBLE,
539   PROP_HEADERS_CLICKABLE,
540   PROP_EXPANDER_COLUMN,
541   PROP_REORDERABLE,
542   PROP_RULES_HINT,
543   PROP_ENABLE_SEARCH,
544   PROP_SEARCH_COLUMN,
545   PROP_FIXED_HEIGHT_MODE,
546   PROP_HOVER_SELECTION,
547   PROP_HOVER_EXPAND,
548   PROP_SHOW_EXPANDERS,
549   PROP_LEVEL_INDENTATION,
550   PROP_RUBBER_BANDING,
551   PROP_ENABLE_GRID_LINES,
552   PROP_ENABLE_TREE_LINES,
553   PROP_TOOLTIP_COLUMN
554 };
555
556 /* object signals */
557 static void     gtk_tree_view_finalize             (GObject          *object);
558 static void     gtk_tree_view_set_property         (GObject         *object,
559                                                     guint            prop_id,
560                                                     const GValue    *value,
561                                                     GParamSpec      *pspec);
562 static void     gtk_tree_view_get_property         (GObject         *object,
563                                                     guint            prop_id,
564                                                     GValue          *value,
565                                                     GParamSpec      *pspec);
566
567 /* gtkwidget signals */
568 static void     gtk_tree_view_destroy              (GtkWidget        *widget);
569 static void     gtk_tree_view_realize              (GtkWidget        *widget);
570 static void     gtk_tree_view_unrealize            (GtkWidget        *widget);
571 static void     gtk_tree_view_map                  (GtkWidget        *widget);
572 static void     gtk_tree_view_get_preferred_width  (GtkWidget        *widget,
573                                                     gint             *minimum,
574                                                     gint             *natural);
575 static void     gtk_tree_view_get_preferred_height (GtkWidget        *widget,
576                                                     gint             *minimum,
577                                                     gint             *natural);
578 static void     gtk_tree_view_size_request         (GtkWidget        *widget,
579                                                     GtkRequisition   *requisition,
580                                                     gboolean          may_validate);
581 static void     gtk_tree_view_size_allocate        (GtkWidget        *widget,
582                                                     GtkAllocation    *allocation);
583 static gboolean gtk_tree_view_draw                 (GtkWidget        *widget,
584                                                     cairo_t          *cr);
585 static gboolean gtk_tree_view_key_press            (GtkWidget        *widget,
586                                                     GdkEventKey      *event);
587 static gboolean gtk_tree_view_key_release          (GtkWidget        *widget,
588                                                     GdkEventKey      *event);
589 static gboolean gtk_tree_view_motion               (GtkWidget        *widget,
590                                                     GdkEventMotion   *event);
591 static gboolean gtk_tree_view_enter_notify         (GtkWidget        *widget,
592                                                     GdkEventCrossing *event);
593 static gboolean gtk_tree_view_leave_notify         (GtkWidget        *widget,
594                                                     GdkEventCrossing *event);
595 static gboolean gtk_tree_view_button_press         (GtkWidget        *widget,
596                                                     GdkEventButton   *event);
597 static gboolean gtk_tree_view_button_release       (GtkWidget        *widget,
598                                                     GdkEventButton   *event);
599 static gboolean gtk_tree_view_grab_broken          (GtkWidget          *widget,
600                                                     GdkEventGrabBroken *event);
601 #if 0
602 static gboolean gtk_tree_view_configure            (GtkWidget         *widget,
603                                                     GdkEventConfigure *event);
604 #endif
605
606 static GtkWidgetPath * gtk_tree_view_get_path_for_child (GtkContainer *container,
607                                                          GtkWidget    *child);
608
609 static void     gtk_tree_view_set_focus_child      (GtkContainer     *container,
610                                                     GtkWidget        *child);
611 static gint     gtk_tree_view_focus_out            (GtkWidget        *widget,
612                                                     GdkEventFocus    *event);
613 static gint     gtk_tree_view_focus                (GtkWidget        *widget,
614                                                     GtkDirectionType  direction);
615 static void     gtk_tree_view_grab_focus           (GtkWidget        *widget);
616 static void     gtk_tree_view_style_updated        (GtkWidget        *widget);
617 static void     gtk_tree_view_grab_notify          (GtkWidget        *widget,
618                                                     gboolean          was_grabbed);
619 static void     gtk_tree_view_state_flags_changed  (GtkWidget        *widget,
620                                                     GtkStateFlags     previous_state);
621
622 /* container signals */
623 static void     gtk_tree_view_remove               (GtkContainer     *container,
624                                                     GtkWidget        *widget);
625 static void     gtk_tree_view_forall               (GtkContainer     *container,
626                                                     gboolean          include_internals,
627                                                     GtkCallback       callback,
628                                                     gpointer          callback_data);
629
630 /* Source side drag signals */
631 static void gtk_tree_view_drag_begin       (GtkWidget        *widget,
632                                             GdkDragContext   *context);
633 static void gtk_tree_view_drag_end         (GtkWidget        *widget,
634                                             GdkDragContext   *context);
635 static void gtk_tree_view_drag_data_get    (GtkWidget        *widget,
636                                             GdkDragContext   *context,
637                                             GtkSelectionData *selection_data,
638                                             guint             info,
639                                             guint             time);
640 static void gtk_tree_view_drag_data_delete (GtkWidget        *widget,
641                                             GdkDragContext   *context);
642
643 /* Target side drag signals */
644 static void     gtk_tree_view_drag_leave         (GtkWidget        *widget,
645                                                   GdkDragContext   *context,
646                                                   guint             time);
647 static gboolean gtk_tree_view_drag_motion        (GtkWidget        *widget,
648                                                   GdkDragContext   *context,
649                                                   gint              x,
650                                                   gint              y,
651                                                   guint             time);
652 static gboolean gtk_tree_view_drag_drop          (GtkWidget        *widget,
653                                                   GdkDragContext   *context,
654                                                   gint              x,
655                                                   gint              y,
656                                                   guint             time);
657 static void     gtk_tree_view_drag_data_received (GtkWidget        *widget,
658                                                   GdkDragContext   *context,
659                                                   gint              x,
660                                                   gint              y,
661                                                   GtkSelectionData *selection_data,
662                                                   guint             info,
663                                                   guint             time);
664
665 /* tree_model signals */
666 static void     gtk_tree_view_set_hadjustment             (GtkTreeView     *tree_view,
667                                                            GtkAdjustment   *adjustment);
668 static void     gtk_tree_view_set_vadjustment             (GtkTreeView     *tree_view,
669                                                            GtkAdjustment   *adjustment);
670 static gboolean gtk_tree_view_real_move_cursor            (GtkTreeView     *tree_view,
671                                                            GtkMovementStep  step,
672                                                            gint             count);
673 static gboolean gtk_tree_view_real_select_all             (GtkTreeView     *tree_view);
674 static gboolean gtk_tree_view_real_unselect_all           (GtkTreeView     *tree_view);
675 static gboolean gtk_tree_view_real_select_cursor_row      (GtkTreeView     *tree_view,
676                                                            gboolean         start_editing);
677 static gboolean gtk_tree_view_real_toggle_cursor_row      (GtkTreeView     *tree_view);
678 static gboolean gtk_tree_view_real_expand_collapse_cursor_row (GtkTreeView     *tree_view,
679                                                                gboolean         logical,
680                                                                gboolean         expand,
681                                                                gboolean         open_all);
682 static gboolean gtk_tree_view_real_select_cursor_parent   (GtkTreeView     *tree_view);
683 static void gtk_tree_view_row_changed                     (GtkTreeModel    *model,
684                                                            GtkTreePath     *path,
685                                                            GtkTreeIter     *iter,
686                                                            gpointer         data);
687 static void gtk_tree_view_row_inserted                    (GtkTreeModel    *model,
688                                                            GtkTreePath     *path,
689                                                            GtkTreeIter     *iter,
690                                                            gpointer         data);
691 static void gtk_tree_view_row_has_child_toggled           (GtkTreeModel    *model,
692                                                            GtkTreePath     *path,
693                                                            GtkTreeIter     *iter,
694                                                            gpointer         data);
695 static void gtk_tree_view_row_deleted                     (GtkTreeModel    *model,
696                                                            GtkTreePath     *path,
697                                                            gpointer         data);
698 static void gtk_tree_view_rows_reordered                  (GtkTreeModel    *model,
699                                                            GtkTreePath     *parent,
700                                                            GtkTreeIter     *iter,
701                                                            gint            *new_order,
702                                                            gpointer         data);
703
704 /* Incremental reflow */
705 static gboolean validate_row             (GtkTreeView *tree_view,
706                                           GtkRBTree   *tree,
707                                           GtkRBNode   *node,
708                                           GtkTreeIter *iter,
709                                           GtkTreePath *path);
710 static void     validate_visible_area    (GtkTreeView *tree_view);
711 static gboolean validate_rows_handler    (GtkTreeView *tree_view);
712 static gboolean do_validate_rows         (GtkTreeView *tree_view,
713                                           gboolean     size_request);
714 static gboolean validate_rows            (GtkTreeView *tree_view);
715 static gboolean presize_handler_callback (gpointer     data);
716 static void     install_presize_handler  (GtkTreeView *tree_view);
717 static void     install_scroll_sync_handler (GtkTreeView *tree_view);
718 static void     gtk_tree_view_set_top_row   (GtkTreeView *tree_view,
719                                              GtkTreePath *path,
720                                              gint         offset);
721 static void     gtk_tree_view_dy_to_top_row (GtkTreeView *tree_view);
722 static void     gtk_tree_view_top_row_to_dy (GtkTreeView *tree_view);
723 static void     invalidate_empty_focus      (GtkTreeView *tree_view);
724
725 /* Internal functions */
726 static gboolean gtk_tree_view_is_expander_column             (GtkTreeView        *tree_view,
727                                                               GtkTreeViewColumn  *column);
728 static inline gboolean gtk_tree_view_draw_expanders          (GtkTreeView        *tree_view);
729 static void     gtk_tree_view_add_move_binding               (GtkBindingSet      *binding_set,
730                                                               guint               keyval,
731                                                               guint               modmask,
732                                                               gboolean            add_shifted_binding,
733                                                               GtkMovementStep     step,
734                                                               gint                count);
735 static gint     gtk_tree_view_unref_and_check_selection_tree (GtkTreeView        *tree_view,
736                                                               GtkRBTree          *tree);
737 static void     gtk_tree_view_queue_draw_path                (GtkTreeView        *tree_view,
738                                                               GtkTreePath        *path,
739                                                               const GdkRectangle *clip_rect);
740 static void     gtk_tree_view_queue_draw_arrow               (GtkTreeView        *tree_view,
741                                                               GtkRBTree          *tree,
742                                                               GtkRBNode          *node);
743 static void     gtk_tree_view_draw_arrow                     (GtkTreeView        *tree_view,
744                                                               cairo_t            *cr,
745                                                               GtkRBTree          *tree,
746                                                               GtkRBNode          *node,
747                                                               gint                x,
748                                                               gint                y);
749 static void     gtk_tree_view_get_arrow_xrange               (GtkTreeView        *tree_view,
750                                                               GtkRBTree          *tree,
751                                                               gint               *x1,
752                                                               gint               *x2);
753 static gint     gtk_tree_view_new_column_width               (GtkTreeView        *tree_view,
754                                                               gint                i,
755                                                               gint               *x);
756 static void     gtk_tree_view_adjustment_changed             (GtkAdjustment      *adjustment,
757                                                               GtkTreeView        *tree_view);
758 static void     gtk_tree_view_build_tree                     (GtkTreeView        *tree_view,
759                                                               GtkRBTree          *tree,
760                                                               GtkTreeIter        *iter,
761                                                               gint                depth,
762                                                               gboolean            recurse);
763 static void     gtk_tree_view_clamp_node_visible             (GtkTreeView        *tree_view,
764                                                               GtkRBTree          *tree,
765                                                               GtkRBNode          *node);
766 static void     gtk_tree_view_clamp_column_visible           (GtkTreeView        *tree_view,
767                                                               GtkTreeViewColumn  *column,
768                                                               gboolean            focus_to_cell);
769 static gboolean gtk_tree_view_maybe_begin_dragging_row       (GtkTreeView        *tree_view,
770                                                               GdkEventMotion     *event);
771 static void     gtk_tree_view_focus_to_cursor                (GtkTreeView        *tree_view);
772 static void     gtk_tree_view_move_cursor_up_down            (GtkTreeView        *tree_view,
773                                                               gint                count);
774 static void     gtk_tree_view_move_cursor_page_up_down       (GtkTreeView        *tree_view,
775                                                               gint                count);
776 static void     gtk_tree_view_move_cursor_left_right         (GtkTreeView        *tree_view,
777                                                               gint                count);
778 static void     gtk_tree_view_move_cursor_start_end          (GtkTreeView        *tree_view,
779                                                               gint                count);
780 static gboolean gtk_tree_view_real_collapse_row              (GtkTreeView        *tree_view,
781                                                               GtkTreePath        *path,
782                                                               GtkRBTree          *tree,
783                                                               GtkRBNode          *node,
784                                                               gboolean            animate);
785 static gboolean gtk_tree_view_real_expand_row                (GtkTreeView        *tree_view,
786                                                               GtkTreePath        *path,
787                                                               GtkRBTree          *tree,
788                                                               GtkRBNode          *node,
789                                                               gboolean            open_all,
790                                                               gboolean            animate);
791 static void     gtk_tree_view_real_set_cursor                (GtkTreeView        *tree_view,
792                                                               GtkTreePath        *path,
793                                                               gboolean            clear_and_select,
794                                                               gboolean            clamp_node);
795 static gboolean gtk_tree_view_has_can_focus_cell             (GtkTreeView        *tree_view);
796 static void     column_sizing_notify                         (GObject            *object,
797                                                               GParamSpec         *pspec,
798                                                               gpointer            data);
799 static void     gtk_tree_view_stop_rubber_band               (GtkTreeView        *tree_view);
800 static void     update_prelight                              (GtkTreeView        *tree_view,
801                                                               int                 x,
802                                                               int                 y);
803
804 static inline gint gtk_tree_view_get_effective_header_height (GtkTreeView *tree_view);
805
806 static inline gint gtk_tree_view_get_cell_area_y_offset      (GtkTreeView *tree_view,
807                                                               GtkRBTree   *tree,
808                                                               GtkRBNode   *node,
809                                                               gint         vertical_separator);
810 static inline gint gtk_tree_view_get_cell_area_height        (GtkTreeView *tree_view,
811                                                               GtkRBNode   *node,
812                                                               gint         vertical_separator);
813
814 static inline gint gtk_tree_view_get_row_y_offset            (GtkTreeView *tree_view,
815                                                               GtkRBTree   *tree,
816                                                               GtkRBNode   *node);
817 static inline gint gtk_tree_view_get_row_height              (GtkTreeView *tree_view,
818                                                               GtkRBNode   *node);
819
820 /* interactive search */
821 static void     gtk_tree_view_ensure_interactive_directory (GtkTreeView *tree_view);
822 static void     gtk_tree_view_search_dialog_hide        (GtkWidget        *search_dialog,
823                                                          GtkTreeView      *tree_view,
824                                                          GdkDevice        *device);
825 static void     gtk_tree_view_search_position_func      (GtkTreeView      *tree_view,
826                                                          GtkWidget        *search_dialog,
827                                                          gpointer          user_data);
828 static void     gtk_tree_view_search_disable_popdown    (GtkEntry         *entry,
829                                                          GtkMenu          *menu,
830                                                          gpointer          data);
831 static void     gtk_tree_view_search_preedit_changed    (GtkIMContext     *im_context,
832                                                          GtkTreeView      *tree_view);
833 static void     gtk_tree_view_search_activate           (GtkEntry         *entry,
834                                                          GtkTreeView      *tree_view);
835 static gboolean gtk_tree_view_real_search_enable_popdown(gpointer          data);
836 static void     gtk_tree_view_search_enable_popdown     (GtkWidget        *widget,
837                                                          gpointer          data);
838 static gboolean gtk_tree_view_search_delete_event       (GtkWidget        *widget,
839                                                          GdkEventAny      *event,
840                                                          GtkTreeView      *tree_view);
841 static gboolean gtk_tree_view_search_button_press_event (GtkWidget        *widget,
842                                                          GdkEventButton   *event,
843                                                          GtkTreeView      *tree_view);
844 static gboolean gtk_tree_view_search_scroll_event       (GtkWidget        *entry,
845                                                          GdkEventScroll   *event,
846                                                          GtkTreeView      *tree_view);
847 static gboolean gtk_tree_view_search_key_press_event    (GtkWidget        *entry,
848                                                          GdkEventKey      *event,
849                                                          GtkTreeView      *tree_view);
850 static gboolean gtk_tree_view_search_move               (GtkWidget        *window,
851                                                          GtkTreeView      *tree_view,
852                                                          gboolean          up);
853 static gboolean gtk_tree_view_search_equal_func         (GtkTreeModel     *model,
854                                                          gint              column,
855                                                          const gchar      *key,
856                                                          GtkTreeIter      *iter,
857                                                          gpointer          search_data);
858 static gboolean gtk_tree_view_search_iter               (GtkTreeModel     *model,
859                                                          GtkTreeSelection *selection,
860                                                          GtkTreeIter      *iter,
861                                                          const gchar      *text,
862                                                          gint             *count,
863                                                          gint              n);
864 static void     gtk_tree_view_search_init               (GtkWidget        *entry,
865                                                          GtkTreeView      *tree_view);
866 static void     gtk_tree_view_put                       (GtkTreeView      *tree_view,
867                                                          GtkWidget        *child_widget,
868                                                          gint              x,
869                                                          gint              y,
870                                                          gint              width,
871                                                          gint              height);
872 static gboolean gtk_tree_view_start_editing             (GtkTreeView      *tree_view,
873                                                          GtkTreePath      *cursor_path,
874                                                          gboolean          edit_only);
875 static void gtk_tree_view_stop_editing                  (GtkTreeView *tree_view,
876                                                          gboolean     cancel_editing);
877 static gboolean gtk_tree_view_real_start_interactive_search (GtkTreeView *tree_view,
878                                                              GdkDevice   *device,
879                                                              gboolean     keybinding);
880 static gboolean gtk_tree_view_start_interactive_search      (GtkTreeView *tree_view);
881 static GtkTreeViewColumn *gtk_tree_view_get_drop_column (GtkTreeView       *tree_view,
882                                                          GtkTreeViewColumn *column,
883                                                          gint               drop_position);
884
885 /* GtkBuildable */
886 static void     gtk_tree_view_buildable_add_child          (GtkBuildable      *tree_view,
887                                                             GtkBuilder        *builder,
888                                                             GObject           *child,
889                                                             const gchar       *type);
890 static GObject *gtk_tree_view_buildable_get_internal_child (GtkBuildable      *buildable,
891                                                             GtkBuilder        *builder,
892                                                             const gchar       *childname);
893 static void     gtk_tree_view_buildable_init               (GtkBuildableIface *iface);
894
895
896 static gboolean scroll_row_timeout                   (gpointer     data);
897 static void     add_scroll_timeout                   (GtkTreeView *tree_view);
898 static void     remove_scroll_timeout                (GtkTreeView *tree_view);
899
900 static guint tree_view_signals [LAST_SIGNAL] = { 0 };
901
902 \f
903
904 /* GType Methods
905  */
906
907 G_DEFINE_TYPE_WITH_CODE (GtkTreeView, gtk_tree_view, GTK_TYPE_CONTAINER,
908                          G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
909                                                 gtk_tree_view_buildable_init)
910                          G_IMPLEMENT_INTERFACE (GTK_TYPE_SCROLLABLE, NULL))
911
912 static void
913 gtk_tree_view_class_init (GtkTreeViewClass *class)
914 {
915   GObjectClass *o_class;
916   GtkWidgetClass *widget_class;
917   GtkContainerClass *container_class;
918   GtkBindingSet *binding_set;
919
920   binding_set = gtk_binding_set_by_class (class);
921
922   o_class = (GObjectClass *) class;
923   widget_class = (GtkWidgetClass *) class;
924   container_class = (GtkContainerClass *) class;
925
926   /* GObject signals */
927   o_class->set_property = gtk_tree_view_set_property;
928   o_class->get_property = gtk_tree_view_get_property;
929   o_class->finalize = gtk_tree_view_finalize;
930
931   /* GtkWidget signals */
932   widget_class->destroy = gtk_tree_view_destroy;
933   widget_class->map = gtk_tree_view_map;
934   widget_class->realize = gtk_tree_view_realize;
935   widget_class->unrealize = gtk_tree_view_unrealize;
936   widget_class->get_preferred_width = gtk_tree_view_get_preferred_width;
937   widget_class->get_preferred_height = gtk_tree_view_get_preferred_height;
938   widget_class->size_allocate = gtk_tree_view_size_allocate;
939   widget_class->button_press_event = gtk_tree_view_button_press;
940   widget_class->button_release_event = gtk_tree_view_button_release;
941   widget_class->grab_broken_event = gtk_tree_view_grab_broken;
942   /*widget_class->configure_event = gtk_tree_view_configure;*/
943   widget_class->motion_notify_event = gtk_tree_view_motion;
944   widget_class->draw = gtk_tree_view_draw;
945   widget_class->key_press_event = gtk_tree_view_key_press;
946   widget_class->key_release_event = gtk_tree_view_key_release;
947   widget_class->enter_notify_event = gtk_tree_view_enter_notify;
948   widget_class->leave_notify_event = gtk_tree_view_leave_notify;
949   widget_class->focus_out_event = gtk_tree_view_focus_out;
950   widget_class->drag_begin = gtk_tree_view_drag_begin;
951   widget_class->drag_end = gtk_tree_view_drag_end;
952   widget_class->drag_data_get = gtk_tree_view_drag_data_get;
953   widget_class->drag_data_delete = gtk_tree_view_drag_data_delete;
954   widget_class->drag_leave = gtk_tree_view_drag_leave;
955   widget_class->drag_motion = gtk_tree_view_drag_motion;
956   widget_class->drag_drop = gtk_tree_view_drag_drop;
957   widget_class->drag_data_received = gtk_tree_view_drag_data_received;
958   widget_class->focus = gtk_tree_view_focus;
959   widget_class->grab_focus = gtk_tree_view_grab_focus;
960   widget_class->style_updated = gtk_tree_view_style_updated;
961   widget_class->grab_notify = gtk_tree_view_grab_notify;
962   widget_class->state_flags_changed = gtk_tree_view_state_flags_changed;
963
964   /* GtkContainer signals */
965   container_class->remove = gtk_tree_view_remove;
966   container_class->forall = gtk_tree_view_forall;
967   container_class->set_focus_child = gtk_tree_view_set_focus_child;
968   container_class->get_path_for_child = gtk_tree_view_get_path_for_child;
969
970   class->move_cursor = gtk_tree_view_real_move_cursor;
971   class->select_all = gtk_tree_view_real_select_all;
972   class->unselect_all = gtk_tree_view_real_unselect_all;
973   class->select_cursor_row = gtk_tree_view_real_select_cursor_row;
974   class->toggle_cursor_row = gtk_tree_view_real_toggle_cursor_row;
975   class->expand_collapse_cursor_row = gtk_tree_view_real_expand_collapse_cursor_row;
976   class->select_cursor_parent = gtk_tree_view_real_select_cursor_parent;
977   class->start_interactive_search = gtk_tree_view_start_interactive_search;
978
979   /* Properties */
980
981   g_object_class_install_property (o_class,
982                                    PROP_MODEL,
983                                    g_param_spec_object ("model",
984                                                         P_("TreeView Model"),
985                                                         P_("The model for the tree view"),
986                                                         GTK_TYPE_TREE_MODEL,
987                                                         GTK_PARAM_READWRITE));
988
989   g_object_class_override_property (o_class, PROP_HADJUSTMENT,    "hadjustment");
990   g_object_class_override_property (o_class, PROP_VADJUSTMENT,    "vadjustment");
991   g_object_class_override_property (o_class, PROP_HSCROLL_POLICY, "hscroll-policy");
992   g_object_class_override_property (o_class, PROP_VSCROLL_POLICY, "vscroll-policy");
993
994   g_object_class_install_property (o_class,
995                                    PROP_HEADERS_VISIBLE,
996                                    g_param_spec_boolean ("headers-visible",
997                                                          P_("Headers Visible"),
998                                                          P_("Show the column header buttons"),
999                                                          TRUE,
1000                                                          GTK_PARAM_READWRITE));
1001
1002   g_object_class_install_property (o_class,
1003                                    PROP_HEADERS_CLICKABLE,
1004                                    g_param_spec_boolean ("headers-clickable",
1005                                                          P_("Headers Clickable"),
1006                                                          P_("Column headers respond to click events"),
1007                                                          TRUE,
1008                                                          GTK_PARAM_READWRITE));
1009
1010   g_object_class_install_property (o_class,
1011                                    PROP_EXPANDER_COLUMN,
1012                                    g_param_spec_object ("expander-column",
1013                                                         P_("Expander Column"),
1014                                                         P_("Set the column for the expander column"),
1015                                                         GTK_TYPE_TREE_VIEW_COLUMN,
1016                                                         GTK_PARAM_READWRITE));
1017
1018   g_object_class_install_property (o_class,
1019                                    PROP_REORDERABLE,
1020                                    g_param_spec_boolean ("reorderable",
1021                                                          P_("Reorderable"),
1022                                                          P_("View is reorderable"),
1023                                                          FALSE,
1024                                                          GTK_PARAM_READWRITE));
1025
1026   g_object_class_install_property (o_class,
1027                                    PROP_RULES_HINT,
1028                                    g_param_spec_boolean ("rules-hint",
1029                                                          P_("Rules Hint"),
1030                                                          P_("Set a hint to the theme engine to draw rows in alternating colors"),
1031                                                          FALSE,
1032                                                          GTK_PARAM_READWRITE));
1033
1034     g_object_class_install_property (o_class,
1035                                      PROP_ENABLE_SEARCH,
1036                                      g_param_spec_boolean ("enable-search",
1037                                                            P_("Enable Search"),
1038                                                            P_("View allows user to search through columns interactively"),
1039                                                            TRUE,
1040                                                            GTK_PARAM_READWRITE));
1041
1042     g_object_class_install_property (o_class,
1043                                      PROP_SEARCH_COLUMN,
1044                                      g_param_spec_int ("search-column",
1045                                                        P_("Search Column"),
1046                                                        P_("Model column to search through during interactive search"),
1047                                                        -1,
1048                                                        G_MAXINT,
1049                                                        -1,
1050                                                        GTK_PARAM_READWRITE));
1051
1052     /**
1053      * GtkTreeView:fixed-height-mode:
1054      *
1055      * Setting the ::fixed-height-mode property to %TRUE speeds up 
1056      * #GtkTreeView by assuming that all rows have the same height. 
1057      * Only enable this option if all rows are the same height.  
1058      * Please see gtk_tree_view_set_fixed_height_mode() for more 
1059      * information on this option.
1060      *
1061      * Since: 2.4
1062      **/
1063     g_object_class_install_property (o_class,
1064                                      PROP_FIXED_HEIGHT_MODE,
1065                                      g_param_spec_boolean ("fixed-height-mode",
1066                                                            P_("Fixed Height Mode"),
1067                                                            P_("Speeds up GtkTreeView by assuming that all rows have the same height"),
1068                                                            FALSE,
1069                                                            GTK_PARAM_READWRITE));
1070     
1071     /**
1072      * GtkTreeView:hover-selection:
1073      * 
1074      * Enables or disables the hover selection mode of @tree_view.
1075      * Hover selection makes the selected row follow the pointer.
1076      * Currently, this works only for the selection modes 
1077      * %GTK_SELECTION_SINGLE and %GTK_SELECTION_BROWSE.
1078      *
1079      * This mode is primarily intended for treeviews in popups, e.g.
1080      * in #GtkComboBox or #GtkEntryCompletion.
1081      *
1082      * Since: 2.6
1083      */
1084     g_object_class_install_property (o_class,
1085                                      PROP_HOVER_SELECTION,
1086                                      g_param_spec_boolean ("hover-selection",
1087                                                            P_("Hover Selection"),
1088                                                            P_("Whether the selection should follow the pointer"),
1089                                                            FALSE,
1090                                                            GTK_PARAM_READWRITE));
1091
1092     /**
1093      * GtkTreeView:hover-expand:
1094      * 
1095      * Enables or disables the hover expansion mode of @tree_view.
1096      * Hover expansion makes rows expand or collapse if the pointer moves 
1097      * over them.
1098      *
1099      * This mode is primarily intended for treeviews in popups, e.g.
1100      * in #GtkComboBox or #GtkEntryCompletion.
1101      *
1102      * Since: 2.6
1103      */
1104     g_object_class_install_property (o_class,
1105                                      PROP_HOVER_EXPAND,
1106                                      g_param_spec_boolean ("hover-expand",
1107                                                            P_("Hover Expand"),
1108                                                            P_("Whether rows should be expanded/collapsed when the pointer moves over them"),
1109                                                            FALSE,
1110                                                            GTK_PARAM_READWRITE));
1111
1112     /**
1113      * GtkTreeView:show-expanders:
1114      *
1115      * %TRUE if the view has expanders.
1116      *
1117      * Since: 2.12
1118      */
1119     g_object_class_install_property (o_class,
1120                                      PROP_SHOW_EXPANDERS,
1121                                      g_param_spec_boolean ("show-expanders",
1122                                                            P_("Show Expanders"),
1123                                                            P_("View has expanders"),
1124                                                            TRUE,
1125                                                            GTK_PARAM_READWRITE));
1126
1127     /**
1128      * GtkTreeView:level-indentation:
1129      *
1130      * Extra indentation for each level.
1131      *
1132      * Since: 2.12
1133      */
1134     g_object_class_install_property (o_class,
1135                                      PROP_LEVEL_INDENTATION,
1136                                      g_param_spec_int ("level-indentation",
1137                                                        P_("Level Indentation"),
1138                                                        P_("Extra indentation for each level"),
1139                                                        0,
1140                                                        G_MAXINT,
1141                                                        0,
1142                                                        GTK_PARAM_READWRITE));
1143
1144     g_object_class_install_property (o_class,
1145                                      PROP_RUBBER_BANDING,
1146                                      g_param_spec_boolean ("rubber-banding",
1147                                                            P_("Rubber Banding"),
1148                                                            P_("Whether to enable selection of multiple items by dragging the mouse pointer"),
1149                                                            FALSE,
1150                                                            GTK_PARAM_READWRITE));
1151
1152     g_object_class_install_property (o_class,
1153                                      PROP_ENABLE_GRID_LINES,
1154                                      g_param_spec_enum ("enable-grid-lines",
1155                                                         P_("Enable Grid Lines"),
1156                                                         P_("Whether grid lines should be drawn in the tree view"),
1157                                                         GTK_TYPE_TREE_VIEW_GRID_LINES,
1158                                                         GTK_TREE_VIEW_GRID_LINES_NONE,
1159                                                         GTK_PARAM_READWRITE));
1160
1161     g_object_class_install_property (o_class,
1162                                      PROP_ENABLE_TREE_LINES,
1163                                      g_param_spec_boolean ("enable-tree-lines",
1164                                                            P_("Enable Tree Lines"),
1165                                                            P_("Whether tree lines should be drawn in the tree view"),
1166                                                            FALSE,
1167                                                            GTK_PARAM_READWRITE));
1168
1169     g_object_class_install_property (o_class,
1170                                      PROP_TOOLTIP_COLUMN,
1171                                      g_param_spec_int ("tooltip-column",
1172                                                        P_("Tooltip Column"),
1173                                                        P_("The column in the model containing the tooltip texts for the rows"),
1174                                                        -1,
1175                                                        G_MAXINT,
1176                                                        -1,
1177                                                        GTK_PARAM_READWRITE));
1178
1179   /* Style properties */
1180 #define _TREE_VIEW_EXPANDER_SIZE 14
1181 #define _TREE_VIEW_VERTICAL_SEPARATOR 2
1182 #define _TREE_VIEW_HORIZONTAL_SEPARATOR 2
1183
1184   gtk_widget_class_install_style_property (widget_class,
1185                                            g_param_spec_int ("expander-size",
1186                                                              P_("Expander Size"),
1187                                                              P_("Size of the expander arrow"),
1188                                                              0,
1189                                                              G_MAXINT,
1190                                                              _TREE_VIEW_EXPANDER_SIZE,
1191                                                              GTK_PARAM_READABLE));
1192
1193   gtk_widget_class_install_style_property (widget_class,
1194                                            g_param_spec_int ("vertical-separator",
1195                                                              P_("Vertical Separator Width"),
1196                                                              P_("Vertical space between cells.  Must be an even number"),
1197                                                              0,
1198                                                              G_MAXINT,
1199                                                              _TREE_VIEW_VERTICAL_SEPARATOR,
1200                                                              GTK_PARAM_READABLE));
1201
1202   gtk_widget_class_install_style_property (widget_class,
1203                                            g_param_spec_int ("horizontal-separator",
1204                                                              P_("Horizontal Separator Width"),
1205                                                              P_("Horizontal space between cells.  Must be an even number"),
1206                                                              0,
1207                                                              G_MAXINT,
1208                                                              _TREE_VIEW_HORIZONTAL_SEPARATOR,
1209                                                              GTK_PARAM_READABLE));
1210
1211   gtk_widget_class_install_style_property (widget_class,
1212                                            g_param_spec_boolean ("allow-rules",
1213                                                                  P_("Allow Rules"),
1214                                                                  P_("Allow drawing of alternating color rows"),
1215                                                                  TRUE,
1216                                                                  GTK_PARAM_READABLE));
1217
1218   gtk_widget_class_install_style_property (widget_class,
1219                                            g_param_spec_boolean ("indent-expanders",
1220                                                                  P_("Indent Expanders"),
1221                                                                  P_("Make the expanders indented"),
1222                                                                  TRUE,
1223                                                                  GTK_PARAM_READABLE));
1224
1225   gtk_widget_class_install_style_property (widget_class,
1226                                            g_param_spec_boxed ("even-row-color",
1227                                                                P_("Even Row Color"),
1228                                                                P_("Color to use for even rows"),
1229                                                                GDK_TYPE_COLOR,
1230                                                                GTK_PARAM_READABLE));
1231
1232   gtk_widget_class_install_style_property (widget_class,
1233                                            g_param_spec_boxed ("odd-row-color",
1234                                                                P_("Odd Row Color"),
1235                                                                P_("Color to use for odd rows"),
1236                                                                GDK_TYPE_COLOR,
1237                                                                GTK_PARAM_READABLE));
1238
1239   gtk_widget_class_install_style_property (widget_class,
1240                                            g_param_spec_int ("grid-line-width",
1241                                                              P_("Grid line width"),
1242                                                              P_("Width, in pixels, of the tree view grid lines"),
1243                                                              0, G_MAXINT, 1,
1244                                                              GTK_PARAM_READABLE));
1245
1246   gtk_widget_class_install_style_property (widget_class,
1247                                            g_param_spec_int ("tree-line-width",
1248                                                              P_("Tree line width"),
1249                                                              P_("Width, in pixels, of the tree view lines"),
1250                                                              0, G_MAXINT, 1,
1251                                                              GTK_PARAM_READABLE));
1252
1253   gtk_widget_class_install_style_property (widget_class,
1254                                            g_param_spec_string ("grid-line-pattern",
1255                                                                 P_("Grid line pattern"),
1256                                                                 P_("Dash pattern used to draw the tree view grid lines"),
1257                                                                 "\1\1",
1258                                                                 GTK_PARAM_READABLE));
1259
1260   gtk_widget_class_install_style_property (widget_class,
1261                                            g_param_spec_string ("tree-line-pattern",
1262                                                                 P_("Tree line pattern"),
1263                                                                 P_("Dash pattern used to draw the tree view lines"),
1264                                                                 "\1\1",
1265                                                                 GTK_PARAM_READABLE));
1266
1267   /* Signals */
1268   /**
1269    * GtkTreeView::row-activated:
1270    * @tree_view: the object on which the signal is emitted
1271    * @path: the #GtkTreePath for the activated row
1272    * @column: the #GtkTreeViewColumn in which the activation occurred
1273    *
1274    * The "row-activated" signal is emitted when the method
1275    * gtk_tree_view_row_activated() is called or the user double clicks 
1276    * a treeview row. It is also emitted when a non-editable row is 
1277    * selected and one of the keys: Space, Shift+Space, Return or 
1278    * Enter is pressed.
1279    * 
1280    * For selection handling refer to the <link linkend="TreeWidget">tree 
1281    * widget conceptual overview</link> as well as #GtkTreeSelection.
1282    */
1283   tree_view_signals[ROW_ACTIVATED] =
1284     g_signal_new (I_("row-activated"),
1285                   G_TYPE_FROM_CLASS (o_class),
1286                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1287                   G_STRUCT_OFFSET (GtkTreeViewClass, row_activated),
1288                   NULL, NULL,
1289                   _gtk_marshal_VOID__BOXED_OBJECT,
1290                   G_TYPE_NONE, 2,
1291                   GTK_TYPE_TREE_PATH,
1292                   GTK_TYPE_TREE_VIEW_COLUMN);
1293
1294   /**
1295    * GtkTreeView::test-expand-row:
1296    * @tree_view: the object on which the signal is emitted
1297    * @iter: the tree iter of the row to expand
1298    * @path: a tree path that points to the row 
1299    * 
1300    * The given row is about to be expanded (show its children nodes). Use this
1301    * signal if you need to control the expandability of individual rows.
1302    *
1303    * Returns: %FALSE to allow expansion, %TRUE to reject
1304    */
1305   tree_view_signals[TEST_EXPAND_ROW] =
1306     g_signal_new (I_("test-expand-row"),
1307                   G_TYPE_FROM_CLASS (o_class),
1308                   G_SIGNAL_RUN_LAST,
1309                   G_STRUCT_OFFSET (GtkTreeViewClass, test_expand_row),
1310                   _gtk_boolean_handled_accumulator, NULL,
1311                   _gtk_marshal_BOOLEAN__BOXED_BOXED,
1312                   G_TYPE_BOOLEAN, 2,
1313                   GTK_TYPE_TREE_ITER,
1314                   GTK_TYPE_TREE_PATH);
1315
1316   /**
1317    * GtkTreeView::test-collapse-row:
1318    * @tree_view: the object on which the signal is emitted
1319    * @iter: the tree iter of the row to collapse
1320    * @path: a tree path that points to the row 
1321    * 
1322    * The given row is about to be collapsed (hide its children nodes). Use this
1323    * signal if you need to control the collapsibility of individual rows.
1324    *
1325    * Returns: %FALSE to allow collapsing, %TRUE to reject
1326    */
1327   tree_view_signals[TEST_COLLAPSE_ROW] =
1328     g_signal_new (I_("test-collapse-row"),
1329                   G_TYPE_FROM_CLASS (o_class),
1330                   G_SIGNAL_RUN_LAST,
1331                   G_STRUCT_OFFSET (GtkTreeViewClass, test_collapse_row),
1332                   _gtk_boolean_handled_accumulator, NULL,
1333                   _gtk_marshal_BOOLEAN__BOXED_BOXED,
1334                   G_TYPE_BOOLEAN, 2,
1335                   GTK_TYPE_TREE_ITER,
1336                   GTK_TYPE_TREE_PATH);
1337
1338   /**
1339    * GtkTreeView::row-expanded:
1340    * @tree_view: the object on which the signal is emitted
1341    * @iter: the tree iter of the expanded row
1342    * @path: a tree path that points to the row 
1343    * 
1344    * The given row has been expanded (child nodes are shown).
1345    */
1346   tree_view_signals[ROW_EXPANDED] =
1347     g_signal_new (I_("row-expanded"),
1348                   G_TYPE_FROM_CLASS (o_class),
1349                   G_SIGNAL_RUN_LAST,
1350                   G_STRUCT_OFFSET (GtkTreeViewClass, row_expanded),
1351                   NULL, NULL,
1352                   _gtk_marshal_VOID__BOXED_BOXED,
1353                   G_TYPE_NONE, 2,
1354                   GTK_TYPE_TREE_ITER,
1355                   GTK_TYPE_TREE_PATH);
1356
1357   /**
1358    * GtkTreeView::row-collapsed:
1359    * @tree_view: the object on which the signal is emitted
1360    * @iter: the tree iter of the collapsed row
1361    * @path: a tree path that points to the row 
1362    * 
1363    * The given row has been collapsed (child nodes are hidden).
1364    */
1365   tree_view_signals[ROW_COLLAPSED] =
1366     g_signal_new (I_("row-collapsed"),
1367                   G_TYPE_FROM_CLASS (o_class),
1368                   G_SIGNAL_RUN_LAST,
1369                   G_STRUCT_OFFSET (GtkTreeViewClass, row_collapsed),
1370                   NULL, NULL,
1371                   _gtk_marshal_VOID__BOXED_BOXED,
1372                   G_TYPE_NONE, 2,
1373                   GTK_TYPE_TREE_ITER,
1374                   GTK_TYPE_TREE_PATH);
1375
1376   /**
1377    * GtkTreeView::columns-changed:
1378    * @tree_view: the object on which the signal is emitted 
1379    * 
1380    * The number of columns of the treeview has changed.
1381    */
1382   tree_view_signals[COLUMNS_CHANGED] =
1383     g_signal_new (I_("columns-changed"),
1384                   G_TYPE_FROM_CLASS (o_class),
1385                   G_SIGNAL_RUN_LAST,
1386                   G_STRUCT_OFFSET (GtkTreeViewClass, columns_changed),
1387                   NULL, NULL,
1388                   _gtk_marshal_VOID__VOID,
1389                   G_TYPE_NONE, 0);
1390
1391   /**
1392    * GtkTreeView::cursor-changed:
1393    * @tree_view: the object on which the signal is emitted
1394    * 
1395    * The position of the cursor (focused cell) has changed.
1396    */
1397   tree_view_signals[CURSOR_CHANGED] =
1398     g_signal_new (I_("cursor-changed"),
1399                   G_TYPE_FROM_CLASS (o_class),
1400                   G_SIGNAL_RUN_LAST,
1401                   G_STRUCT_OFFSET (GtkTreeViewClass, cursor_changed),
1402                   NULL, NULL,
1403                   _gtk_marshal_VOID__VOID,
1404                   G_TYPE_NONE, 0);
1405
1406   tree_view_signals[MOVE_CURSOR] =
1407     g_signal_new (I_("move-cursor"),
1408                   G_TYPE_FROM_CLASS (o_class),
1409                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1410                   G_STRUCT_OFFSET (GtkTreeViewClass, move_cursor),
1411                   NULL, NULL,
1412                   _gtk_marshal_BOOLEAN__ENUM_INT,
1413                   G_TYPE_BOOLEAN, 2,
1414                   GTK_TYPE_MOVEMENT_STEP,
1415                   G_TYPE_INT);
1416
1417   tree_view_signals[SELECT_ALL] =
1418     g_signal_new (I_("select-all"),
1419                   G_TYPE_FROM_CLASS (o_class),
1420                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1421                   G_STRUCT_OFFSET (GtkTreeViewClass, select_all),
1422                   NULL, NULL,
1423                   _gtk_marshal_BOOLEAN__VOID,
1424                   G_TYPE_BOOLEAN, 0);
1425
1426   tree_view_signals[UNSELECT_ALL] =
1427     g_signal_new (I_("unselect-all"),
1428                   G_TYPE_FROM_CLASS (o_class),
1429                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1430                   G_STRUCT_OFFSET (GtkTreeViewClass, unselect_all),
1431                   NULL, NULL,
1432                   _gtk_marshal_BOOLEAN__VOID,
1433                   G_TYPE_BOOLEAN, 0);
1434
1435   tree_view_signals[SELECT_CURSOR_ROW] =
1436     g_signal_new (I_("select-cursor-row"),
1437                   G_TYPE_FROM_CLASS (o_class),
1438                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1439                   G_STRUCT_OFFSET (GtkTreeViewClass, select_cursor_row),
1440                   NULL, NULL,
1441                   _gtk_marshal_BOOLEAN__BOOLEAN,
1442                   G_TYPE_BOOLEAN, 1,
1443                   G_TYPE_BOOLEAN);
1444
1445   tree_view_signals[TOGGLE_CURSOR_ROW] =
1446     g_signal_new (I_("toggle-cursor-row"),
1447                   G_TYPE_FROM_CLASS (o_class),
1448                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1449                   G_STRUCT_OFFSET (GtkTreeViewClass, toggle_cursor_row),
1450                   NULL, NULL,
1451                   _gtk_marshal_BOOLEAN__VOID,
1452                   G_TYPE_BOOLEAN, 0);
1453
1454   tree_view_signals[EXPAND_COLLAPSE_CURSOR_ROW] =
1455     g_signal_new (I_("expand-collapse-cursor-row"),
1456                   G_TYPE_FROM_CLASS (o_class),
1457                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1458                   G_STRUCT_OFFSET (GtkTreeViewClass, expand_collapse_cursor_row),
1459                   NULL, NULL,
1460                   _gtk_marshal_BOOLEAN__BOOLEAN_BOOLEAN_BOOLEAN,
1461                   G_TYPE_BOOLEAN, 3,
1462                   G_TYPE_BOOLEAN,
1463                   G_TYPE_BOOLEAN,
1464                   G_TYPE_BOOLEAN);
1465
1466   tree_view_signals[SELECT_CURSOR_PARENT] =
1467     g_signal_new (I_("select-cursor-parent"),
1468                   G_TYPE_FROM_CLASS (o_class),
1469                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1470                   G_STRUCT_OFFSET (GtkTreeViewClass, select_cursor_parent),
1471                   NULL, NULL,
1472                   _gtk_marshal_BOOLEAN__VOID,
1473                   G_TYPE_BOOLEAN, 0);
1474
1475   tree_view_signals[START_INTERACTIVE_SEARCH] =
1476     g_signal_new (I_("start-interactive-search"),
1477                   G_TYPE_FROM_CLASS (o_class),
1478                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1479                   G_STRUCT_OFFSET (GtkTreeViewClass, start_interactive_search),
1480                   NULL, NULL,
1481                   _gtk_marshal_BOOLEAN__VOID,
1482                   G_TYPE_BOOLEAN, 0);
1483
1484   /* Key bindings */
1485   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Up, 0, TRUE,
1486                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
1487   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Up, 0, TRUE,
1488                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
1489
1490   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Down, 0, TRUE,
1491                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
1492   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Down, 0, TRUE,
1493                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
1494
1495   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_p, GDK_CONTROL_MASK, FALSE,
1496                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
1497
1498   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_n, GDK_CONTROL_MASK, FALSE,
1499                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
1500
1501   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Home, 0, TRUE,
1502                                   GTK_MOVEMENT_BUFFER_ENDS, -1);
1503   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Home, 0, TRUE,
1504                                   GTK_MOVEMENT_BUFFER_ENDS, -1);
1505
1506   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_End, 0, TRUE,
1507                                   GTK_MOVEMENT_BUFFER_ENDS, 1);
1508   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_End, 0, TRUE,
1509                                   GTK_MOVEMENT_BUFFER_ENDS, 1);
1510
1511   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Page_Up, 0, TRUE,
1512                                   GTK_MOVEMENT_PAGES, -1);
1513   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Page_Up, 0, TRUE,
1514                                   GTK_MOVEMENT_PAGES, -1);
1515
1516   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Page_Down, 0, TRUE,
1517                                   GTK_MOVEMENT_PAGES, 1);
1518   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Page_Down, 0, TRUE,
1519                                   GTK_MOVEMENT_PAGES, 1);
1520
1521
1522   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Right, 0, "move-cursor", 2,
1523                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1524                                 G_TYPE_INT, 1);
1525
1526   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Left, 0, "move-cursor", 2,
1527                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1528                                 G_TYPE_INT, -1);
1529
1530   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Right, 0, "move-cursor", 2,
1531                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1532                                 G_TYPE_INT, 1);
1533
1534   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Left, 0, "move-cursor", 2,
1535                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1536                                 G_TYPE_INT, -1);
1537
1538   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Right, GDK_CONTROL_MASK,
1539                                 "move-cursor", 2,
1540                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1541                                 G_TYPE_INT, 1);
1542
1543   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Left, GDK_CONTROL_MASK,
1544                                 "move-cursor", 2,
1545                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1546                                 G_TYPE_INT, -1);
1547
1548   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Right, GDK_CONTROL_MASK,
1549                                 "move-cursor", 2,
1550                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1551                                 G_TYPE_INT, 1);
1552
1553   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Left, GDK_CONTROL_MASK,
1554                                 "move-cursor", 2,
1555                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1556                                 G_TYPE_INT, -1);
1557
1558   gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, GDK_CONTROL_MASK, "toggle-cursor-row", 0);
1559   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Space, GDK_CONTROL_MASK, "toggle-cursor-row", 0);
1560
1561   gtk_binding_entry_add_signal (binding_set, GDK_KEY_a, GDK_CONTROL_MASK, "select-all", 0);
1562   gtk_binding_entry_add_signal (binding_set, GDK_KEY_slash, GDK_CONTROL_MASK, "select-all", 0);
1563
1564   gtk_binding_entry_add_signal (binding_set, GDK_KEY_A, GDK_CONTROL_MASK | GDK_SHIFT_MASK, "unselect-all", 0);
1565   gtk_binding_entry_add_signal (binding_set, GDK_KEY_backslash, GDK_CONTROL_MASK, "unselect-all", 0);
1566
1567   gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, GDK_SHIFT_MASK, "select-cursor-row", 1,
1568                                 G_TYPE_BOOLEAN, TRUE);
1569   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Space, GDK_SHIFT_MASK, "select-cursor-row", 1,
1570                                 G_TYPE_BOOLEAN, TRUE);
1571
1572   gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, 0, "select-cursor-row", 1,
1573                                 G_TYPE_BOOLEAN, TRUE);
1574   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Space, 0, "select-cursor-row", 1,
1575                                 G_TYPE_BOOLEAN, TRUE);
1576   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Return, 0, "select-cursor-row", 1,
1577                                 G_TYPE_BOOLEAN, TRUE);
1578   gtk_binding_entry_add_signal (binding_set, GDK_KEY_ISO_Enter, 0, "select-cursor-row", 1,
1579                                 G_TYPE_BOOLEAN, TRUE);
1580   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Enter, 0, "select-cursor-row", 1,
1581                                 G_TYPE_BOOLEAN, TRUE);
1582
1583   /* expand and collapse rows */
1584   gtk_binding_entry_add_signal (binding_set, GDK_KEY_plus, 0, "expand-collapse-cursor-row", 3,
1585                                 G_TYPE_BOOLEAN, TRUE,
1586                                 G_TYPE_BOOLEAN, TRUE,
1587                                 G_TYPE_BOOLEAN, FALSE);
1588
1589   gtk_binding_entry_add_signal (binding_set, GDK_KEY_asterisk, 0,
1590                                 "expand-collapse-cursor-row", 3,
1591                                 G_TYPE_BOOLEAN, TRUE,
1592                                 G_TYPE_BOOLEAN, TRUE,
1593                                 G_TYPE_BOOLEAN, TRUE);
1594   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Multiply, 0,
1595                                 "expand-collapse-cursor-row", 3,
1596                                 G_TYPE_BOOLEAN, TRUE,
1597                                 G_TYPE_BOOLEAN, TRUE,
1598                                 G_TYPE_BOOLEAN, TRUE);
1599
1600   gtk_binding_entry_add_signal (binding_set, GDK_KEY_slash, 0,
1601                                 "expand-collapse-cursor-row", 3,
1602                                 G_TYPE_BOOLEAN, TRUE,
1603                                 G_TYPE_BOOLEAN, FALSE,
1604                                 G_TYPE_BOOLEAN, FALSE);
1605   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Divide, 0,
1606                                 "expand-collapse-cursor-row", 3,
1607                                 G_TYPE_BOOLEAN, TRUE,
1608                                 G_TYPE_BOOLEAN, FALSE,
1609                                 G_TYPE_BOOLEAN, FALSE);
1610
1611   /* Not doable on US keyboards */
1612   gtk_binding_entry_add_signal (binding_set, GDK_KEY_plus, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1613                                 G_TYPE_BOOLEAN, TRUE,
1614                                 G_TYPE_BOOLEAN, TRUE,
1615                                 G_TYPE_BOOLEAN, TRUE);
1616   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Add, 0, "expand-collapse-cursor-row", 3,
1617                                 G_TYPE_BOOLEAN, TRUE,
1618                                 G_TYPE_BOOLEAN, TRUE,
1619                                 G_TYPE_BOOLEAN, FALSE);
1620   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Add, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1621                                 G_TYPE_BOOLEAN, TRUE,
1622                                 G_TYPE_BOOLEAN, TRUE,
1623                                 G_TYPE_BOOLEAN, TRUE);
1624   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Add, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1625                                 G_TYPE_BOOLEAN, TRUE,
1626                                 G_TYPE_BOOLEAN, TRUE,
1627                                 G_TYPE_BOOLEAN, TRUE);
1628   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Right, GDK_SHIFT_MASK,
1629                                 "expand-collapse-cursor-row", 3,
1630                                 G_TYPE_BOOLEAN, FALSE,
1631                                 G_TYPE_BOOLEAN, TRUE,
1632                                 G_TYPE_BOOLEAN, TRUE);
1633   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Right, GDK_SHIFT_MASK,
1634                                 "expand-collapse-cursor-row", 3,
1635                                 G_TYPE_BOOLEAN, FALSE,
1636                                 G_TYPE_BOOLEAN, TRUE,
1637                                 G_TYPE_BOOLEAN, TRUE);
1638   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Right,
1639                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1640                                 "expand-collapse-cursor-row", 3,
1641                                 G_TYPE_BOOLEAN, FALSE,
1642                                 G_TYPE_BOOLEAN, TRUE,
1643                                 G_TYPE_BOOLEAN, TRUE);
1644   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Right,
1645                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1646                                 "expand-collapse-cursor-row", 3,
1647                                 G_TYPE_BOOLEAN, FALSE,
1648                                 G_TYPE_BOOLEAN, TRUE,
1649                                 G_TYPE_BOOLEAN, TRUE);
1650
1651   gtk_binding_entry_add_signal (binding_set, GDK_KEY_minus, 0, "expand-collapse-cursor-row", 3,
1652                                 G_TYPE_BOOLEAN, TRUE,
1653                                 G_TYPE_BOOLEAN, FALSE,
1654                                 G_TYPE_BOOLEAN, FALSE);
1655   gtk_binding_entry_add_signal (binding_set, GDK_KEY_minus, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1656                                 G_TYPE_BOOLEAN, TRUE,
1657                                 G_TYPE_BOOLEAN, FALSE,
1658                                 G_TYPE_BOOLEAN, TRUE);
1659   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Subtract, 0, "expand-collapse-cursor-row", 3,
1660                                 G_TYPE_BOOLEAN, TRUE,
1661                                 G_TYPE_BOOLEAN, FALSE,
1662                                 G_TYPE_BOOLEAN, FALSE);
1663   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Subtract, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1664                                 G_TYPE_BOOLEAN, TRUE,
1665                                 G_TYPE_BOOLEAN, FALSE,
1666                                 G_TYPE_BOOLEAN, TRUE);
1667   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Left, GDK_SHIFT_MASK,
1668                                 "expand-collapse-cursor-row", 3,
1669                                 G_TYPE_BOOLEAN, FALSE,
1670                                 G_TYPE_BOOLEAN, FALSE,
1671                                 G_TYPE_BOOLEAN, TRUE);
1672   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Left, GDK_SHIFT_MASK,
1673                                 "expand-collapse-cursor-row", 3,
1674                                 G_TYPE_BOOLEAN, FALSE,
1675                                 G_TYPE_BOOLEAN, FALSE,
1676                                 G_TYPE_BOOLEAN, TRUE);
1677   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Left,
1678                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1679                                 "expand-collapse-cursor-row", 3,
1680                                 G_TYPE_BOOLEAN, FALSE,
1681                                 G_TYPE_BOOLEAN, FALSE,
1682                                 G_TYPE_BOOLEAN, TRUE);
1683   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Left,
1684                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1685                                 "expand-collapse-cursor-row", 3,
1686                                 G_TYPE_BOOLEAN, FALSE,
1687                                 G_TYPE_BOOLEAN, FALSE,
1688                                 G_TYPE_BOOLEAN, TRUE);
1689
1690   gtk_binding_entry_add_signal (binding_set, GDK_KEY_BackSpace, 0, "select-cursor-parent", 0);
1691   gtk_binding_entry_add_signal (binding_set, GDK_KEY_BackSpace, GDK_CONTROL_MASK, "select-cursor-parent", 0);
1692
1693   gtk_binding_entry_add_signal (binding_set, GDK_KEY_f, GDK_CONTROL_MASK, "start-interactive-search", 0);
1694
1695   gtk_binding_entry_add_signal (binding_set, GDK_KEY_F, GDK_CONTROL_MASK, "start-interactive-search", 0);
1696
1697   g_type_class_add_private (o_class, sizeof (GtkTreeViewPrivate));
1698
1699   gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_TREE_VIEW_ACCESSIBLE);
1700 }
1701
1702 static void
1703 gtk_tree_view_init (GtkTreeView *tree_view)
1704 {
1705   tree_view->priv = G_TYPE_INSTANCE_GET_PRIVATE (tree_view, GTK_TYPE_TREE_VIEW, GtkTreeViewPrivate);
1706
1707   gtk_widget_set_can_focus (GTK_WIDGET (tree_view), TRUE);
1708   gtk_widget_set_redraw_on_allocate (GTK_WIDGET (tree_view), FALSE);
1709
1710   tree_view->priv->show_expanders = TRUE;
1711   tree_view->priv->draw_keyfocus = TRUE;
1712   tree_view->priv->headers_visible = TRUE;
1713
1714   /* We need some padding */
1715   tree_view->priv->dy = 0;
1716   tree_view->priv->cursor_offset = 0;
1717   tree_view->priv->n_columns = 0;
1718   tree_view->priv->header_height = 1;
1719   tree_view->priv->x_drag = 0;
1720   tree_view->priv->drag_pos = -1;
1721   tree_view->priv->header_has_focus = FALSE;
1722   tree_view->priv->pressed_button = -1;
1723   tree_view->priv->press_start_x = -1;
1724   tree_view->priv->press_start_y = -1;
1725   tree_view->priv->reorderable = FALSE;
1726   tree_view->priv->presize_handler_timer = 0;
1727   tree_view->priv->scroll_sync_timer = 0;
1728   tree_view->priv->fixed_height = -1;
1729   tree_view->priv->fixed_height_mode = FALSE;
1730   tree_view->priv->fixed_height_check = 0;
1731   tree_view->priv->selection = _gtk_tree_selection_new_with_tree_view (tree_view);
1732   tree_view->priv->enable_search = TRUE;
1733   tree_view->priv->search_column = -1;
1734   tree_view->priv->search_position_func = gtk_tree_view_search_position_func;
1735   tree_view->priv->search_equal_func = gtk_tree_view_search_equal_func;
1736   tree_view->priv->search_custom_entry_set = FALSE;
1737   tree_view->priv->typeselect_flush_timeout = 0;
1738   tree_view->priv->init_hadjust_value = TRUE;    
1739   tree_view->priv->width = 0;
1740           
1741   tree_view->priv->hover_selection = FALSE;
1742   tree_view->priv->hover_expand = FALSE;
1743
1744   tree_view->priv->level_indentation = 0;
1745
1746   tree_view->priv->rubber_banding_enable = FALSE;
1747
1748   tree_view->priv->grid_lines = GTK_TREE_VIEW_GRID_LINES_NONE;
1749   tree_view->priv->tree_lines_enabled = FALSE;
1750
1751   tree_view->priv->tooltip_column = -1;
1752
1753   tree_view->priv->post_validation_flag = FALSE;
1754
1755   tree_view->priv->last_button_x = -1;
1756   tree_view->priv->last_button_y = -1;
1757
1758   tree_view->priv->event_last_x = -10000;
1759   tree_view->priv->event_last_y = -10000;
1760
1761   gtk_tree_view_set_vadjustment (tree_view, NULL);
1762   gtk_tree_view_set_hadjustment (tree_view, NULL);
1763 }
1764
1765 \f
1766
1767 /* GObject Methods
1768  */
1769
1770 static void
1771 gtk_tree_view_set_property (GObject         *object,
1772                             guint            prop_id,
1773                             const GValue    *value,
1774                             GParamSpec      *pspec)
1775 {
1776   GtkTreeView *tree_view;
1777
1778   tree_view = GTK_TREE_VIEW (object);
1779
1780   switch (prop_id)
1781     {
1782     case PROP_MODEL:
1783       gtk_tree_view_set_model (tree_view, g_value_get_object (value));
1784       break;
1785     case PROP_HADJUSTMENT:
1786       gtk_tree_view_set_hadjustment (tree_view, g_value_get_object (value));
1787       break;
1788     case PROP_VADJUSTMENT:
1789       gtk_tree_view_set_vadjustment (tree_view, g_value_get_object (value));
1790       break;
1791     case PROP_HSCROLL_POLICY:
1792       tree_view->priv->hscroll_policy = g_value_get_enum (value);
1793       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
1794       break;
1795     case PROP_VSCROLL_POLICY:
1796       tree_view->priv->vscroll_policy = g_value_get_enum (value);
1797       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
1798       break;
1799     case PROP_HEADERS_VISIBLE:
1800       gtk_tree_view_set_headers_visible (tree_view, g_value_get_boolean (value));
1801       break;
1802     case PROP_HEADERS_CLICKABLE:
1803       gtk_tree_view_set_headers_clickable (tree_view, g_value_get_boolean (value));
1804       break;
1805     case PROP_EXPANDER_COLUMN:
1806       gtk_tree_view_set_expander_column (tree_view, g_value_get_object (value));
1807       break;
1808     case PROP_REORDERABLE:
1809       gtk_tree_view_set_reorderable (tree_view, g_value_get_boolean (value));
1810       break;
1811     case PROP_RULES_HINT:
1812       gtk_tree_view_set_rules_hint (tree_view, g_value_get_boolean (value));
1813       break;
1814     case PROP_ENABLE_SEARCH:
1815       gtk_tree_view_set_enable_search (tree_view, g_value_get_boolean (value));
1816       break;
1817     case PROP_SEARCH_COLUMN:
1818       gtk_tree_view_set_search_column (tree_view, g_value_get_int (value));
1819       break;
1820     case PROP_FIXED_HEIGHT_MODE:
1821       gtk_tree_view_set_fixed_height_mode (tree_view, g_value_get_boolean (value));
1822       break;
1823     case PROP_HOVER_SELECTION:
1824       tree_view->priv->hover_selection = g_value_get_boolean (value);
1825       break;
1826     case PROP_HOVER_EXPAND:
1827       tree_view->priv->hover_expand = g_value_get_boolean (value);
1828       break;
1829     case PROP_SHOW_EXPANDERS:
1830       gtk_tree_view_set_show_expanders (tree_view, g_value_get_boolean (value));
1831       break;
1832     case PROP_LEVEL_INDENTATION:
1833       tree_view->priv->level_indentation = g_value_get_int (value);
1834       break;
1835     case PROP_RUBBER_BANDING:
1836       tree_view->priv->rubber_banding_enable = g_value_get_boolean (value);
1837       break;
1838     case PROP_ENABLE_GRID_LINES:
1839       gtk_tree_view_set_grid_lines (tree_view, g_value_get_enum (value));
1840       break;
1841     case PROP_ENABLE_TREE_LINES:
1842       gtk_tree_view_set_enable_tree_lines (tree_view, g_value_get_boolean (value));
1843       break;
1844     case PROP_TOOLTIP_COLUMN:
1845       gtk_tree_view_set_tooltip_column (tree_view, g_value_get_int (value));
1846       break;
1847     default:
1848       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1849       break;
1850     }
1851 }
1852
1853 static void
1854 gtk_tree_view_get_property (GObject    *object,
1855                             guint       prop_id,
1856                             GValue     *value,
1857                             GParamSpec *pspec)
1858 {
1859   GtkTreeView *tree_view;
1860
1861   tree_view = GTK_TREE_VIEW (object);
1862
1863   switch (prop_id)
1864     {
1865     case PROP_MODEL:
1866       g_value_set_object (value, tree_view->priv->model);
1867       break;
1868     case PROP_HADJUSTMENT:
1869       g_value_set_object (value, tree_view->priv->hadjustment);
1870       break;
1871     case PROP_VADJUSTMENT:
1872       g_value_set_object (value, tree_view->priv->vadjustment);
1873       break;
1874     case PROP_HSCROLL_POLICY:
1875       g_value_set_enum (value, tree_view->priv->hscroll_policy);
1876       break;
1877     case PROP_VSCROLL_POLICY:
1878       g_value_set_enum (value, tree_view->priv->vscroll_policy);
1879       break;
1880     case PROP_HEADERS_VISIBLE:
1881       g_value_set_boolean (value, gtk_tree_view_get_headers_visible (tree_view));
1882       break;
1883     case PROP_HEADERS_CLICKABLE:
1884       g_value_set_boolean (value, gtk_tree_view_get_headers_clickable (tree_view));
1885       break;
1886     case PROP_EXPANDER_COLUMN:
1887       g_value_set_object (value, tree_view->priv->expander_column);
1888       break;
1889     case PROP_REORDERABLE:
1890       g_value_set_boolean (value, tree_view->priv->reorderable);
1891       break;
1892     case PROP_RULES_HINT:
1893       g_value_set_boolean (value, tree_view->priv->has_rules);
1894       break;
1895     case PROP_ENABLE_SEARCH:
1896       g_value_set_boolean (value, tree_view->priv->enable_search);
1897       break;
1898     case PROP_SEARCH_COLUMN:
1899       g_value_set_int (value, tree_view->priv->search_column);
1900       break;
1901     case PROP_FIXED_HEIGHT_MODE:
1902       g_value_set_boolean (value, tree_view->priv->fixed_height_mode);
1903       break;
1904     case PROP_HOVER_SELECTION:
1905       g_value_set_boolean (value, tree_view->priv->hover_selection);
1906       break;
1907     case PROP_HOVER_EXPAND:
1908       g_value_set_boolean (value, tree_view->priv->hover_expand);
1909       break;
1910     case PROP_SHOW_EXPANDERS:
1911       g_value_set_boolean (value, tree_view->priv->show_expanders);
1912       break;
1913     case PROP_LEVEL_INDENTATION:
1914       g_value_set_int (value, tree_view->priv->level_indentation);
1915       break;
1916     case PROP_RUBBER_BANDING:
1917       g_value_set_boolean (value, tree_view->priv->rubber_banding_enable);
1918       break;
1919     case PROP_ENABLE_GRID_LINES:
1920       g_value_set_enum (value, tree_view->priv->grid_lines);
1921       break;
1922     case PROP_ENABLE_TREE_LINES:
1923       g_value_set_boolean (value, tree_view->priv->tree_lines_enabled);
1924       break;
1925     case PROP_TOOLTIP_COLUMN:
1926       g_value_set_int (value, tree_view->priv->tooltip_column);
1927       break;
1928     default:
1929       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1930       break;
1931     }
1932 }
1933
1934 static void
1935 gtk_tree_view_finalize (GObject *object)
1936 {
1937   G_OBJECT_CLASS (gtk_tree_view_parent_class)->finalize (object);
1938 }
1939
1940
1941 static GtkBuildableIface *parent_buildable_iface;
1942
1943 static void
1944 gtk_tree_view_buildable_init (GtkBuildableIface *iface)
1945 {
1946   parent_buildable_iface = g_type_interface_peek_parent (iface);
1947   iface->add_child = gtk_tree_view_buildable_add_child;
1948   iface->get_internal_child = gtk_tree_view_buildable_get_internal_child;
1949 }
1950
1951 static void
1952 gtk_tree_view_buildable_add_child (GtkBuildable *tree_view,
1953                                    GtkBuilder  *builder,
1954                                    GObject     *child,
1955                                    const gchar *type)
1956 {
1957   gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), GTK_TREE_VIEW_COLUMN (child));
1958 }
1959
1960 static GObject *
1961 gtk_tree_view_buildable_get_internal_child (GtkBuildable      *buildable,
1962                                             GtkBuilder        *builder,
1963                                             const gchar       *childname)
1964 {
1965     if (strcmp (childname, "selection") == 0)
1966       return G_OBJECT (GTK_TREE_VIEW (buildable)->priv->selection);
1967     
1968     return parent_buildable_iface->get_internal_child (buildable,
1969                                                        builder,
1970                                                        childname);
1971 }
1972
1973 /* GtkWidget Methods
1974  */
1975
1976 static void
1977 gtk_tree_view_free_rbtree (GtkTreeView *tree_view)
1978 {
1979   _gtk_rbtree_free (tree_view->priv->tree);
1980   
1981   tree_view->priv->tree = NULL;
1982   tree_view->priv->button_pressed_node = NULL;
1983   tree_view->priv->button_pressed_tree = NULL;
1984   tree_view->priv->prelight_tree = NULL;
1985   tree_view->priv->prelight_node = NULL;
1986   tree_view->priv->expanded_collapsed_node = NULL;
1987   tree_view->priv->expanded_collapsed_tree = NULL;
1988 }
1989
1990 static void
1991 gtk_tree_view_destroy (GtkWidget *widget)
1992 {
1993   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
1994   GList *list;
1995
1996   gtk_tree_view_stop_editing (tree_view, TRUE);
1997
1998   if (tree_view->priv->columns != NULL)
1999     {
2000       list = tree_view->priv->columns;
2001       while (list)
2002         {
2003           GtkTreeViewColumn *column;
2004           column = GTK_TREE_VIEW_COLUMN (list->data);
2005           list = list->next;
2006           gtk_tree_view_remove_column (tree_view, column);
2007         }
2008       tree_view->priv->columns = NULL;
2009     }
2010
2011   if (tree_view->priv->tree != NULL)
2012     {
2013       gtk_tree_view_unref_and_check_selection_tree (tree_view, tree_view->priv->tree);
2014
2015       gtk_tree_view_free_rbtree (tree_view);
2016     }
2017
2018   if (tree_view->priv->selection != NULL)
2019     {
2020       _gtk_tree_selection_set_tree_view (tree_view->priv->selection, NULL);
2021       g_object_unref (tree_view->priv->selection);
2022       tree_view->priv->selection = NULL;
2023     }
2024
2025   if (tree_view->priv->scroll_to_path != NULL)
2026     {
2027       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
2028       tree_view->priv->scroll_to_path = NULL;
2029     }
2030
2031   if (tree_view->priv->drag_dest_row != NULL)
2032     {
2033       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
2034       tree_view->priv->drag_dest_row = NULL;
2035     }
2036
2037   if (tree_view->priv->top_row != NULL)
2038     {
2039       gtk_tree_row_reference_free (tree_view->priv->top_row);
2040       tree_view->priv->top_row = NULL;
2041     }
2042
2043   if (tree_view->priv->column_drop_func_data &&
2044       tree_view->priv->column_drop_func_data_destroy)
2045     {
2046       tree_view->priv->column_drop_func_data_destroy (tree_view->priv->column_drop_func_data);
2047       tree_view->priv->column_drop_func_data = NULL;
2048     }
2049
2050   if (tree_view->priv->destroy_count_destroy &&
2051       tree_view->priv->destroy_count_data)
2052     {
2053       tree_view->priv->destroy_count_destroy (tree_view->priv->destroy_count_data);
2054       tree_view->priv->destroy_count_data = NULL;
2055     }
2056
2057   gtk_tree_row_reference_free (tree_view->priv->cursor);
2058   tree_view->priv->cursor = NULL;
2059
2060   gtk_tree_row_reference_free (tree_view->priv->anchor);
2061   tree_view->priv->anchor = NULL;
2062
2063   /* destroy interactive search dialog */
2064   if (tree_view->priv->search_window)
2065     {
2066       gtk_widget_destroy (tree_view->priv->search_window);
2067       tree_view->priv->search_window = NULL;
2068       tree_view->priv->search_entry = NULL;
2069       if (tree_view->priv->typeselect_flush_timeout)
2070         {
2071           g_source_remove (tree_view->priv->typeselect_flush_timeout);
2072           tree_view->priv->typeselect_flush_timeout = 0;
2073         }
2074     }
2075
2076   if (tree_view->priv->search_destroy && tree_view->priv->search_user_data)
2077     {
2078       tree_view->priv->search_destroy (tree_view->priv->search_user_data);
2079       tree_view->priv->search_user_data = NULL;
2080     }
2081
2082   if (tree_view->priv->search_position_destroy && tree_view->priv->search_position_user_data)
2083     {
2084       tree_view->priv->search_position_destroy (tree_view->priv->search_position_user_data);
2085       tree_view->priv->search_position_user_data = NULL;
2086     }
2087
2088   if (tree_view->priv->row_separator_destroy && tree_view->priv->row_separator_data)
2089     {
2090       tree_view->priv->row_separator_destroy (tree_view->priv->row_separator_data);
2091       tree_view->priv->row_separator_data = NULL;
2092     }
2093   
2094   gtk_tree_view_set_model (tree_view, NULL);
2095
2096   if (tree_view->priv->hadjustment)
2097     {
2098       g_object_unref (tree_view->priv->hadjustment);
2099       tree_view->priv->hadjustment = NULL;
2100     }
2101   if (tree_view->priv->vadjustment)
2102     {
2103       g_object_unref (tree_view->priv->vadjustment);
2104       tree_view->priv->vadjustment = NULL;
2105     }
2106
2107   GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->destroy (widget);
2108 }
2109
2110 /* GtkWidget::map helper */
2111 static void
2112 gtk_tree_view_map_buttons (GtkTreeView *tree_view)
2113 {
2114   GList *list;
2115
2116   g_return_if_fail (gtk_widget_get_mapped (GTK_WIDGET (tree_view)));
2117
2118   if (tree_view->priv->headers_visible)
2119     {
2120       GtkTreeViewColumn *column;
2121       GtkWidget         *button;
2122       GdkWindow         *window;
2123
2124       for (list = tree_view->priv->columns; list; list = list->next)
2125         {
2126           column = list->data;
2127           button = gtk_tree_view_column_get_button (column);
2128
2129           if (gtk_tree_view_column_get_visible (column) && button)
2130             gtk_widget_show_now (button);
2131
2132           if (gtk_widget_get_visible (button) &&
2133               !gtk_widget_get_mapped (button))
2134             gtk_widget_map (button);
2135         }
2136       for (list = tree_view->priv->columns; list; list = list->next)
2137         {
2138           column = list->data;
2139           if (gtk_tree_view_column_get_visible (column) == FALSE)
2140             continue;
2141
2142           window = _gtk_tree_view_column_get_window (column);
2143           if (gtk_tree_view_column_get_resizable (column))
2144             {
2145               gdk_window_raise (window);
2146               gdk_window_show (window);
2147             }
2148           else
2149             gdk_window_hide (window);
2150         }
2151       gdk_window_show (tree_view->priv->header_window);
2152     }
2153 }
2154
2155 static void
2156 gtk_tree_view_map (GtkWidget *widget)
2157 {
2158   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2159   GList *tmp_list;
2160
2161   gtk_widget_set_mapped (widget, TRUE);
2162
2163   tmp_list = tree_view->priv->children;
2164   while (tmp_list)
2165     {
2166       GtkTreeViewChild *child = tmp_list->data;
2167       tmp_list = tmp_list->next;
2168
2169       if (gtk_widget_get_visible (child->widget))
2170         {
2171           if (!gtk_widget_get_mapped (child->widget))
2172             gtk_widget_map (child->widget);
2173         }
2174     }
2175   gdk_window_show (tree_view->priv->bin_window);
2176
2177   gtk_tree_view_map_buttons (tree_view);
2178
2179   gdk_window_show (gtk_widget_get_window (widget));
2180 }
2181
2182 static void
2183 gtk_tree_view_realize (GtkWidget *widget)
2184 {
2185   GtkAllocation allocation;
2186   GtkStyleContext *context;
2187   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2188   GdkWindow *window;
2189   GdkWindowAttr attributes;
2190   GList *tmp_list;
2191   gint attributes_mask;
2192
2193   gtk_widget_set_realized (widget, TRUE);
2194
2195   gtk_widget_get_allocation (widget, &allocation);
2196
2197   /* Make the main, clipping window */
2198   attributes.window_type = GDK_WINDOW_CHILD;
2199   attributes.x = allocation.x;
2200   attributes.y = allocation.y;
2201   attributes.width = allocation.width;
2202   attributes.height = allocation.height;
2203   attributes.wclass = GDK_INPUT_OUTPUT;
2204   attributes.visual = gtk_widget_get_visual (widget);
2205   attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK;
2206
2207   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
2208
2209   window = gdk_window_new (gtk_widget_get_parent_window (widget),
2210                            &attributes, attributes_mask);
2211   gtk_widget_set_window (widget, window);
2212   gdk_window_set_user_data (window, widget);
2213
2214   gtk_widget_get_allocation (widget, &allocation);
2215
2216   /* Make the window for the tree */
2217   attributes.x = 0;
2218   attributes.y = gtk_tree_view_get_effective_header_height (tree_view);
2219   attributes.width = MAX (tree_view->priv->width, allocation.width);
2220   attributes.height = allocation.height;
2221   attributes.event_mask = (GDK_EXPOSURE_MASK |
2222                            GDK_SCROLL_MASK |
2223                            GDK_POINTER_MOTION_MASK |
2224                            GDK_ENTER_NOTIFY_MASK |
2225                            GDK_LEAVE_NOTIFY_MASK |
2226                            GDK_BUTTON_PRESS_MASK |
2227                            GDK_BUTTON_RELEASE_MASK |
2228                            gtk_widget_get_events (widget));
2229
2230   tree_view->priv->bin_window = gdk_window_new (window,
2231                                                 &attributes, attributes_mask);
2232   gdk_window_set_user_data (tree_view->priv->bin_window, widget);
2233
2234   gtk_widget_get_allocation (widget, &allocation);
2235
2236   /* Make the column header window */
2237   attributes.x = 0;
2238   attributes.y = 0;
2239   attributes.width = MAX (tree_view->priv->width, allocation.width);
2240   attributes.height = tree_view->priv->header_height;
2241   attributes.event_mask = (GDK_EXPOSURE_MASK |
2242                            GDK_SCROLL_MASK |
2243                            GDK_ENTER_NOTIFY_MASK |
2244                            GDK_LEAVE_NOTIFY_MASK |
2245                            GDK_BUTTON_PRESS_MASK |
2246                            GDK_BUTTON_RELEASE_MASK |
2247                            GDK_KEY_PRESS_MASK |
2248                            GDK_KEY_RELEASE_MASK |
2249                            gtk_widget_get_events (widget));
2250
2251   tree_view->priv->header_window = gdk_window_new (window,
2252                                                    &attributes, attributes_mask);
2253   gdk_window_set_user_data (tree_view->priv->header_window, widget);
2254
2255   context = gtk_widget_get_style_context (widget);
2256
2257   gtk_style_context_save (context);
2258   gtk_style_context_add_class (context, GTK_STYLE_CLASS_VIEW);
2259   gtk_style_context_set_background (context, tree_view->priv->bin_window);
2260   gtk_style_context_restore (context);
2261
2262   gtk_style_context_set_background (context, tree_view->priv->header_window);
2263
2264   tmp_list = tree_view->priv->children;
2265   while (tmp_list)
2266     {
2267       GtkTreeViewChild *child = tmp_list->data;
2268       tmp_list = tmp_list->next;
2269
2270       gtk_widget_set_parent_window (child->widget, tree_view->priv->bin_window);
2271     }
2272
2273   for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
2274     _gtk_tree_view_column_realize_button (GTK_TREE_VIEW_COLUMN (tmp_list->data));
2275
2276   /* Need to call those here, since they create GCs */
2277   gtk_tree_view_set_grid_lines (tree_view, tree_view->priv->grid_lines);
2278   gtk_tree_view_set_enable_tree_lines (tree_view, tree_view->priv->tree_lines_enabled);
2279
2280   install_presize_handler (tree_view); 
2281 }
2282
2283 static void
2284 gtk_tree_view_unrealize (GtkWidget *widget)
2285 {
2286   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2287   GtkTreeViewPrivate *priv = tree_view->priv;
2288   GtkStyleContext *context;
2289   GList *list;
2290
2291   if (priv->scroll_timeout != 0)
2292     {
2293       g_source_remove (priv->scroll_timeout);
2294       priv->scroll_timeout = 0;
2295     }
2296
2297   if (priv->auto_expand_timeout != 0)
2298     {
2299       g_source_remove (priv->auto_expand_timeout);
2300       priv->auto_expand_timeout = 0;
2301     }
2302
2303   if (priv->open_dest_timeout != 0)
2304     {
2305       g_source_remove (priv->open_dest_timeout);
2306       priv->open_dest_timeout = 0;
2307     }
2308
2309   context = gtk_widget_get_style_context (widget);
2310   gtk_style_context_cancel_animations (context, NULL);
2311
2312   if (priv->presize_handler_timer != 0)
2313     {
2314       g_source_remove (priv->presize_handler_timer);
2315       priv->presize_handler_timer = 0;
2316     }
2317
2318   if (priv->validate_rows_timer != 0)
2319     {
2320       g_source_remove (priv->validate_rows_timer);
2321       priv->validate_rows_timer = 0;
2322     }
2323
2324   if (priv->scroll_sync_timer != 0)
2325     {
2326       g_source_remove (priv->scroll_sync_timer);
2327       priv->scroll_sync_timer = 0;
2328     }
2329
2330   if (priv->typeselect_flush_timeout)
2331     {
2332       g_source_remove (priv->typeselect_flush_timeout);
2333       priv->typeselect_flush_timeout = 0;
2334     }
2335   
2336   for (list = priv->columns; list; list = list->next)
2337     _gtk_tree_view_column_unrealize_button (GTK_TREE_VIEW_COLUMN (list->data));
2338
2339   gdk_window_set_user_data (priv->bin_window, NULL);
2340   gdk_window_destroy (priv->bin_window);
2341   priv->bin_window = NULL;
2342
2343   gdk_window_set_user_data (priv->header_window, NULL);
2344   gdk_window_destroy (priv->header_window);
2345   priv->header_window = NULL;
2346
2347   if (priv->drag_window)
2348     {
2349       gdk_window_set_user_data (priv->drag_window, NULL);
2350       gdk_window_destroy (priv->drag_window);
2351       priv->drag_window = NULL;
2352     }
2353
2354   if (priv->drag_highlight_window)
2355     {
2356       gdk_window_set_user_data (priv->drag_highlight_window, NULL);
2357       gdk_window_destroy (priv->drag_highlight_window);
2358       priv->drag_highlight_window = NULL;
2359     }
2360
2361   GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->unrealize (widget);
2362 }
2363
2364 /* GtkWidget::size_request helper */
2365 static void
2366 gtk_tree_view_size_request_columns (GtkTreeView *tree_view)
2367 {
2368   GList *list;
2369
2370   tree_view->priv->header_height = 0;
2371
2372   for (list = tree_view->priv->columns; list; list = list->next)
2373     {
2374       GtkRequisition     requisition;
2375       GtkTreeViewColumn *column = list->data;
2376       GtkWidget         *button = gtk_tree_view_column_get_button (column);
2377
2378       if (button == NULL)
2379         continue;
2380
2381       gtk_widget_get_preferred_size (button, &requisition, NULL);
2382       tree_view->priv->header_height = MAX (tree_view->priv->header_height, requisition.height);
2383     }
2384 }
2385
2386
2387 /* Called only by ::size_request */
2388 static void
2389 gtk_tree_view_update_size (GtkTreeView *tree_view)
2390 {
2391   GList *list;
2392   GtkTreeViewColumn *column;
2393   gint i;
2394
2395   if (tree_view->priv->model == NULL)
2396     {
2397       tree_view->priv->width = 0;
2398       tree_view->priv->prev_width = 0;                   
2399       tree_view->priv->height = 0;
2400       return;
2401     }
2402
2403   tree_view->priv->prev_width = tree_view->priv->width;  
2404   tree_view->priv->width = 0;
2405
2406   /* keep this in sync with size_allocate below */
2407   for (list = tree_view->priv->columns, i = 0; list; list = list->next, i++)
2408     {
2409       column = list->data;
2410       if (!gtk_tree_view_column_get_visible (column))
2411         continue;
2412
2413       tree_view->priv->width += _gtk_tree_view_column_request_width (column);
2414     }
2415
2416   if (tree_view->priv->tree == NULL)
2417     tree_view->priv->height = 0;
2418   else
2419     tree_view->priv->height = tree_view->priv->tree->root->offset;
2420 }
2421
2422 static void
2423 gtk_tree_view_size_request (GtkWidget      *widget,
2424                             GtkRequisition *requisition,
2425                             gboolean        may_validate)
2426 {
2427   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2428
2429   if (may_validate)
2430     {
2431       /* we validate some rows initially just to make sure we have some size.
2432        * In practice, with a lot of static lists, this should get a good width.
2433        */
2434       do_validate_rows (tree_view, FALSE);
2435     }
2436
2437   gtk_tree_view_size_request_columns (tree_view);
2438   gtk_tree_view_update_size (GTK_TREE_VIEW (widget));
2439
2440   requisition->width = tree_view->priv->width;
2441   requisition->height = tree_view->priv->height + gtk_tree_view_get_effective_header_height (tree_view);
2442 }
2443
2444 static void
2445 gtk_tree_view_get_preferred_width (GtkWidget *widget,
2446                                    gint      *minimum,
2447                                    gint      *natural)
2448 {
2449   GtkRequisition requisition;
2450
2451   gtk_tree_view_size_request (widget, &requisition, TRUE);
2452
2453   *minimum = *natural = requisition.width;
2454 }
2455
2456 static void
2457 gtk_tree_view_get_preferred_height (GtkWidget *widget,
2458                                     gint      *minimum,
2459                                     gint      *natural)
2460 {
2461   GtkRequisition requisition;
2462
2463   gtk_tree_view_size_request (widget, &requisition, TRUE);
2464
2465   *minimum = *natural = requisition.height;
2466 }
2467
2468 static int
2469 gtk_tree_view_calculate_width_before_expander (GtkTreeView *tree_view)
2470 {
2471   int width = 0;
2472   GList *list;
2473   gboolean rtl;
2474
2475   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2476   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
2477        list->data != tree_view->priv->expander_column;
2478        list = (rtl ? list->prev : list->next))
2479     {
2480       GtkTreeViewColumn *column = list->data;
2481
2482       width += gtk_tree_view_column_get_width (column);
2483     }
2484
2485   return width;
2486 }
2487
2488 /* GtkWidget::size_allocate helper */
2489 static void
2490 gtk_tree_view_size_allocate_columns (GtkWidget *widget,
2491                                      gboolean  *width_changed)
2492 {
2493   GtkTreeView *tree_view;
2494   GList *list, *first_column, *last_column;
2495   GtkTreeViewColumn *column;
2496   GtkAllocation widget_allocation;
2497   gint width = 0;
2498   gint extra, extra_per_column, extra_for_last;
2499   gint full_requested_width = 0;
2500   gint number_of_expand_columns = 0;
2501   gboolean rtl;
2502   gboolean update_expand;
2503   
2504   tree_view = GTK_TREE_VIEW (widget);
2505
2506   for (last_column = g_list_last (tree_view->priv->columns);
2507        last_column &&
2508        !(gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (last_column->data)));
2509        last_column = last_column->prev)
2510     ;
2511   if (last_column == NULL)
2512     return;
2513
2514   for (first_column = g_list_first (tree_view->priv->columns);
2515        first_column &&
2516        !(gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (first_column->data)));
2517        first_column = first_column->next)
2518     ;
2519
2520   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
2521
2522   /* find out how many extra space and expandable columns we have */
2523   for (list = tree_view->priv->columns; list != last_column->next; list = list->next)
2524     {
2525       column = (GtkTreeViewColumn *)list->data;
2526
2527       if (!gtk_tree_view_column_get_visible (column))
2528         continue;
2529
2530       full_requested_width += _gtk_tree_view_column_request_width (column);
2531
2532       if (gtk_tree_view_column_get_expand (column))
2533         number_of_expand_columns++;
2534     }
2535
2536   /* Only update the expand value if the width of the widget has changed,
2537    * or the number of expand columns has changed, or if there are no expand
2538    * columns, or if we didn't have an size-allocation yet after the
2539    * last validated node.
2540    */
2541   update_expand = (width_changed && *width_changed == TRUE)
2542       || number_of_expand_columns != tree_view->priv->last_number_of_expand_columns
2543       || number_of_expand_columns == 0
2544       || tree_view->priv->post_validation_flag == TRUE;
2545
2546   tree_view->priv->post_validation_flag = FALSE;
2547
2548   gtk_widget_get_allocation (widget, &widget_allocation);
2549   if (!update_expand)
2550     {
2551       extra = tree_view->priv->last_extra_space;
2552       extra_for_last = MAX (widget_allocation.width - full_requested_width - extra, 0);
2553     }
2554   else
2555     {
2556       extra = MAX (widget_allocation.width - full_requested_width, 0);
2557       extra_for_last = 0;
2558
2559       tree_view->priv->last_extra_space = extra;
2560     }
2561
2562   if (number_of_expand_columns > 0)
2563     extra_per_column = extra/number_of_expand_columns;
2564   else
2565     extra_per_column = 0;
2566
2567   if (update_expand)
2568     {
2569       tree_view->priv->last_extra_space_per_column = extra_per_column;
2570       tree_view->priv->last_number_of_expand_columns = number_of_expand_columns;
2571     }
2572
2573   for (list = (rtl ? last_column : first_column); 
2574        list != (rtl ? first_column->prev : last_column->next);
2575        list = (rtl ? list->prev : list->next)) 
2576     {
2577       gint column_width;
2578
2579       column = list->data;
2580
2581       if (!gtk_tree_view_column_get_visible (column))
2582         continue;
2583
2584       /* We need to handle the dragged button specially.
2585        */
2586       if (column == tree_view->priv->drag_column)
2587         {
2588           GtkAllocation drag_allocation;
2589           GtkWidget    *button;
2590
2591           button = gtk_tree_view_column_get_button (tree_view->priv->drag_column);
2592
2593           drag_allocation.x = 0;
2594           drag_allocation.y = 0;
2595           drag_allocation.width = gdk_window_get_width (tree_view->priv->drag_window);
2596           drag_allocation.height = gdk_window_get_height (tree_view->priv->drag_window);
2597           gtk_widget_size_allocate (button, &drag_allocation);
2598           width += drag_allocation.width;
2599           continue;
2600         }
2601
2602       column_width = _gtk_tree_view_column_request_width (column);
2603
2604       if (gtk_tree_view_column_get_expand (column))
2605         {
2606           if (number_of_expand_columns == 1)
2607             {
2608               /* We add the remander to the last column as
2609                * */
2610               column_width += extra;
2611             }
2612           else
2613             {
2614               column_width += extra_per_column;
2615               extra -= extra_per_column;
2616               number_of_expand_columns --;
2617             }
2618         }
2619       else if (number_of_expand_columns == 0 &&
2620                list == last_column)
2621         {
2622           column_width += extra;
2623         }
2624
2625       /* In addition to expand, the last column can get even more
2626        * extra space so all available space is filled up.
2627        */
2628       if (extra_for_last > 0 && list == last_column)
2629         column_width += extra_for_last;
2630
2631       _gtk_tree_view_column_allocate (column, width, column_width);
2632
2633       width += column_width;
2634     }
2635
2636   /* We change the width here.  The user might have been resizing columns,
2637    * which changes the total width of the tree view.  This is of
2638    * importance for getting the horizontal scroll bar right.
2639    */
2640   if (tree_view->priv->width != width)
2641     {
2642       tree_view->priv->width = width;
2643       if (width_changed)
2644         *width_changed = TRUE;
2645     }
2646 }
2647
2648
2649 static void
2650 gtk_tree_view_size_allocate (GtkWidget     *widget,
2651                              GtkAllocation *allocation)
2652 {
2653   GtkAllocation widget_allocation;
2654   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2655   GList *tmp_list;
2656   gboolean width_changed = FALSE;
2657   gint old_width;
2658
2659   gtk_widget_get_allocation (widget, &widget_allocation);
2660   old_width = widget_allocation.width;
2661   if (allocation->width != widget_allocation.width)
2662     width_changed = TRUE;
2663
2664   gtk_widget_set_allocation (widget, allocation);
2665
2666   tmp_list = tree_view->priv->children;
2667
2668   while (tmp_list)
2669     {
2670       GtkAllocation allocation;
2671
2672       GtkTreeViewChild *child = tmp_list->data;
2673       tmp_list = tmp_list->next;
2674
2675       /* totally ignore our child's requisition */
2676       allocation.x = child->x;
2677       allocation.y = child->y;
2678       allocation.width = child->width;
2679       allocation.height = child->height;
2680       gtk_widget_size_allocate (child->widget, &allocation);
2681     }
2682
2683   /* We size-allocate the columns first because the width of the
2684    * tree view (used in updating the adjustments below) might change.
2685    */
2686   gtk_tree_view_size_allocate_columns (widget, &width_changed);
2687
2688   g_object_freeze_notify (G_OBJECT (tree_view->priv->hadjustment));
2689   gtk_adjustment_set_page_size (tree_view->priv->hadjustment,
2690                                 allocation->width);
2691   gtk_adjustment_set_page_increment (tree_view->priv->hadjustment,
2692                                      allocation->width * 0.9);
2693   gtk_adjustment_set_step_increment (tree_view->priv->hadjustment,
2694                                      allocation->width * 0.1);
2695   gtk_adjustment_set_lower (tree_view->priv->hadjustment, 0);
2696   gtk_adjustment_set_upper (tree_view->priv->hadjustment,
2697                             MAX (gtk_adjustment_get_page_size (tree_view->priv->hadjustment),
2698                                  tree_view->priv->width));
2699   g_object_thaw_notify (G_OBJECT (tree_view->priv->hadjustment));
2700
2701   if (gtk_widget_get_direction(widget) == GTK_TEXT_DIR_RTL)   
2702     {
2703       if (allocation->width < tree_view->priv->width)
2704         {
2705           if (tree_view->priv->init_hadjust_value)
2706             {
2707               gtk_adjustment_set_value (tree_view->priv->hadjustment,
2708                                         MAX (tree_view->priv->width -
2709                                              allocation->width, 0));
2710               tree_view->priv->init_hadjust_value = FALSE;
2711             }
2712           else if (allocation->width != old_width)
2713             {
2714               gtk_adjustment_set_value (tree_view->priv->hadjustment,
2715                                         CLAMP (gtk_adjustment_get_value (tree_view->priv->hadjustment) - allocation->width + old_width,
2716                                                0,
2717                                                tree_view->priv->width - allocation->width));
2718             }
2719           else
2720             gtk_adjustment_set_value (tree_view->priv->hadjustment,
2721                                       CLAMP (tree_view->priv->width - (tree_view->priv->prev_width - gtk_adjustment_get_value (tree_view->priv->hadjustment)),
2722                                              0,
2723                                              tree_view->priv->width - allocation->width));
2724         }
2725       else
2726         {
2727           gtk_adjustment_set_value (tree_view->priv->hadjustment, 0);
2728           tree_view->priv->init_hadjust_value = TRUE;
2729         }
2730     }
2731   else
2732     if (gtk_adjustment_get_value (tree_view->priv->hadjustment) + allocation->width > tree_view->priv->width)
2733       gtk_adjustment_set_value (tree_view->priv->hadjustment,
2734                                 MAX (tree_view->priv->width -
2735                                      allocation->width, 0));
2736
2737   g_object_freeze_notify (G_OBJECT (tree_view->priv->vadjustment));
2738   gtk_adjustment_set_page_size (tree_view->priv->vadjustment,
2739                                 allocation->height -
2740                                 gtk_tree_view_get_effective_header_height (tree_view));
2741   gtk_adjustment_set_step_increment (tree_view->priv->vadjustment,
2742                                      gtk_adjustment_get_page_size (tree_view->priv->vadjustment) * 0.1);
2743   gtk_adjustment_set_page_increment (tree_view->priv->vadjustment,
2744                                      gtk_adjustment_get_page_size (tree_view->priv->vadjustment) * 0.9);
2745   gtk_adjustment_set_lower (tree_view->priv->vadjustment, 0);
2746   gtk_adjustment_set_upper (tree_view->priv->vadjustment,
2747                             MAX (gtk_adjustment_get_page_size (tree_view->priv->vadjustment),
2748                                  tree_view->priv->height));
2749   g_object_thaw_notify (G_OBJECT (tree_view->priv->vadjustment));
2750
2751   /* now the adjustments and window sizes are in sync, we can sync toprow/dy again */
2752   if (tree_view->priv->height <= gtk_adjustment_get_page_size (tree_view->priv->vadjustment))
2753     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
2754   else if (gtk_adjustment_get_value (tree_view->priv->vadjustment) + gtk_adjustment_get_page_size (tree_view->priv->vadjustment) > tree_view->priv->height)
2755     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment),
2756                               tree_view->priv->height - gtk_adjustment_get_page_size (tree_view->priv->vadjustment));
2757   else if (gtk_tree_row_reference_valid (tree_view->priv->top_row))
2758     gtk_tree_view_top_row_to_dy (tree_view);
2759   else
2760     gtk_tree_view_dy_to_top_row (tree_view);
2761   
2762   if (gtk_widget_get_realized (widget))
2763     {
2764       gdk_window_move_resize (gtk_widget_get_window (widget),
2765                               allocation->x, allocation->y,
2766                               allocation->width, allocation->height);
2767       gdk_window_move_resize (tree_view->priv->header_window,
2768                               - (gint) gtk_adjustment_get_value (tree_view->priv->hadjustment),
2769                               0,
2770                               MAX (tree_view->priv->width, allocation->width),
2771                               tree_view->priv->header_height);
2772       gdk_window_move_resize (tree_view->priv->bin_window,
2773                               - (gint) gtk_adjustment_get_value (tree_view->priv->hadjustment),
2774                               gtk_tree_view_get_effective_header_height (tree_view),
2775                               MAX (tree_view->priv->width, allocation->width),
2776                               allocation->height - gtk_tree_view_get_effective_header_height (tree_view));
2777
2778       if (tree_view->priv->tree == NULL)
2779         invalidate_empty_focus (tree_view);
2780
2781       if (width_changed && tree_view->priv->expander_column)
2782         {
2783           /* Might seem awkward, but is the best heuristic I could come up
2784            * with.  Only if the width of the columns before the expander
2785            * changes, we will update the prelight status.  It is this
2786            * width that makes the expander move vertically.  Always updating
2787            * prelight status causes trouble with hover selections.
2788            */
2789           gint width_before_expander;
2790
2791           width_before_expander = gtk_tree_view_calculate_width_before_expander (tree_view);
2792
2793           if (tree_view->priv->prev_width_before_expander
2794               != width_before_expander)
2795               update_prelight (tree_view,
2796                                tree_view->priv->event_last_x,
2797                                tree_view->priv->event_last_y);
2798
2799           tree_view->priv->prev_width_before_expander = width_before_expander;
2800         }
2801     }
2802 }
2803
2804 /* Grabs the focus and unsets the GTK_TREE_VIEW_DRAW_KEYFOCUS flag */
2805 static void
2806 grab_focus_and_unset_draw_keyfocus (GtkTreeView *tree_view)
2807 {
2808   GtkWidget *widget = GTK_WIDGET (tree_view);
2809
2810   if (gtk_widget_get_can_focus (widget) && !gtk_widget_has_focus (widget))
2811     gtk_widget_grab_focus (widget);
2812   tree_view->priv->draw_keyfocus = 0;
2813 }
2814
2815 static inline gboolean
2816 row_is_separator (GtkTreeView *tree_view,
2817                   GtkTreeIter *iter,
2818                   GtkTreePath *path)
2819 {
2820   gboolean is_separator = FALSE;
2821
2822   if (tree_view->priv->row_separator_func)
2823     {
2824       GtkTreeIter tmpiter;
2825
2826       if (iter)
2827         tmpiter = *iter;
2828       else
2829         {
2830           if (!gtk_tree_model_get_iter (tree_view->priv->model, &tmpiter, path))
2831             return FALSE;
2832         }
2833
2834       is_separator = tree_view->priv->row_separator_func (tree_view->priv->model,
2835                                                           &tmpiter,
2836                                                           tree_view->priv->row_separator_data);
2837     }
2838
2839   return is_separator;
2840 }
2841
2842 static gboolean
2843 gtk_tree_view_button_press (GtkWidget      *widget,
2844                             GdkEventButton *event)
2845 {
2846   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2847   GList *list;
2848   GtkTreeViewColumn *column = NULL;
2849   gint i;
2850   GdkRectangle background_area;
2851   GdkRectangle cell_area;
2852   gint vertical_separator;
2853   gint horizontal_separator;
2854   gboolean path_is_selectable;
2855   gboolean rtl;
2856
2857   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
2858   gtk_tree_view_stop_editing (tree_view, FALSE);
2859   gtk_widget_style_get (widget,
2860                         "vertical-separator", &vertical_separator,
2861                         "horizontal-separator", &horizontal_separator,
2862                         NULL);
2863
2864   /* Because grab_focus can cause reentrancy, we delay grab_focus until after
2865    * we're done handling the button press.
2866    */
2867
2868   if (event->window == tree_view->priv->bin_window)
2869     {
2870       GtkRBNode *node;
2871       GtkRBTree *tree;
2872       GtkTreePath *path;
2873       gint depth;
2874       gint new_y;
2875       gint y_offset;
2876       gint dval;
2877       gint pre_val, aft_val;
2878       GtkTreeViewColumn *column = NULL;
2879       gint column_handled_click = FALSE;
2880       gboolean row_double_click = FALSE;
2881       gboolean rtl;
2882       gboolean node_selected;
2883       GdkModifierType extend_mod_mask;
2884       GdkModifierType modify_mod_mask;
2885
2886       /* Empty tree? */
2887       if (tree_view->priv->tree == NULL)
2888         {
2889           grab_focus_and_unset_draw_keyfocus (tree_view);
2890           return TRUE;
2891         }
2892
2893       /* are we in an arrow? */
2894       if (tree_view->priv->prelight_node &&
2895           tree_view->priv->arrow_prelit &&
2896           gtk_tree_view_draw_expanders (tree_view))
2897         {
2898           if (event->button == 1)
2899             {
2900               gtk_grab_add (widget);
2901               tree_view->priv->button_pressed_node = tree_view->priv->prelight_node;
2902               tree_view->priv->button_pressed_tree = tree_view->priv->prelight_tree;
2903               gtk_tree_view_queue_draw_arrow (GTK_TREE_VIEW (widget),
2904                                               tree_view->priv->prelight_tree,
2905                                               tree_view->priv->prelight_node);
2906             }
2907
2908           grab_focus_and_unset_draw_keyfocus (tree_view);
2909           return TRUE;
2910         }
2911
2912       /* find the node that was clicked */
2913       new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
2914       if (new_y < 0)
2915         new_y = 0;
2916       y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
2917
2918       if (node == NULL)
2919         {
2920           /* We clicked in dead space */
2921           grab_focus_and_unset_draw_keyfocus (tree_view);
2922           return TRUE;
2923         }
2924
2925       /* Get the path and the node */
2926       path = _gtk_tree_view_find_path (tree_view, tree, node);
2927       path_is_selectable = !row_is_separator (tree_view, NULL, path);
2928
2929       if (!path_is_selectable)
2930         {
2931           gtk_tree_path_free (path);
2932           grab_focus_and_unset_draw_keyfocus (tree_view);
2933           return TRUE;
2934         }
2935
2936       depth = gtk_tree_path_get_depth (path);
2937       background_area.y = y_offset + event->y;
2938       background_area.height = gtk_tree_view_get_row_height (tree_view, node);
2939       background_area.x = 0;
2940
2941
2942       /* Let the column have a chance at selecting it. */
2943       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2944       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
2945            list; list = (rtl ? list->prev : list->next))
2946         {
2947           GtkTreeViewColumn *candidate = list->data;
2948
2949           if (!gtk_tree_view_column_get_visible (candidate))
2950             continue;
2951
2952           background_area.width = gtk_tree_view_column_get_width (candidate);
2953           if ((background_area.x > (gint) event->x) ||
2954               (background_area.x + background_area.width <= (gint) event->x))
2955             {
2956               background_area.x += background_area.width;
2957               continue;
2958             }
2959
2960           /* we found the focus column */
2961           column = candidate;
2962           cell_area = background_area;
2963           cell_area.width -= horizontal_separator;
2964           cell_area.height -= vertical_separator;
2965           cell_area.x += horizontal_separator/2;
2966           cell_area.y += vertical_separator/2;
2967           if (gtk_tree_view_is_expander_column (tree_view, column))
2968             {
2969               if (!rtl)
2970                 cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
2971               cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
2972
2973               if (gtk_tree_view_draw_expanders (tree_view))
2974                 {
2975                   if (!rtl)
2976                     cell_area.x += depth * tree_view->priv->expander_size;
2977                   cell_area.width -= depth * tree_view->priv->expander_size;
2978                 }
2979             }
2980           break;
2981         }
2982
2983       if (column == NULL)
2984         {
2985           gtk_tree_path_free (path);
2986           grab_focus_and_unset_draw_keyfocus (tree_view);
2987           return FALSE;
2988         }
2989
2990       tree_view->priv->focus_column = column;
2991
2992       /* decide if we edit */
2993       if (event->type == GDK_BUTTON_PRESS && event->button == 1 &&
2994           !(event->state & gtk_accelerator_get_default_mod_mask ()))
2995         {
2996           GtkTreePath *anchor;
2997           GtkTreeIter iter;
2998
2999           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
3000           gtk_tree_view_column_cell_set_cell_data (column,
3001                                                    tree_view->priv->model,
3002                                                    &iter,
3003                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
3004                                                    node->children?TRUE:FALSE);
3005
3006           if (tree_view->priv->anchor)
3007             anchor = gtk_tree_row_reference_get_path (tree_view->priv->anchor);
3008           else
3009             anchor = NULL;
3010
3011           if ((anchor && !gtk_tree_path_compare (anchor, path))
3012               || !_gtk_tree_view_column_has_editable_cell (column))
3013             {
3014               GtkCellEditable *cell_editable = NULL;
3015
3016               /* FIXME: get the right flags */
3017               guint flags = 0;
3018
3019               if (_gtk_tree_view_column_cell_event (column,
3020                                                     (GdkEvent *)event,
3021                                                     &cell_area, flags))
3022                 {
3023                   GtkCellArea *area = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (column));
3024                   cell_editable = gtk_cell_area_get_edit_widget (area);
3025
3026                   if (cell_editable != NULL)
3027                     {
3028                       gtk_tree_path_free (path);
3029                       gtk_tree_path_free (anchor);
3030                       return TRUE;
3031                     }
3032                   column_handled_click = TRUE;
3033                 }
3034             }
3035           if (anchor)
3036             gtk_tree_path_free (anchor);
3037         }
3038
3039       extend_mod_mask =
3040         gtk_widget_get_modifier_mask (widget, GDK_MODIFIER_INTENT_EXTEND_SELECTION);
3041
3042       modify_mod_mask =
3043         gtk_widget_get_modifier_mask (widget, GDK_MODIFIER_INTENT_MODIFY_SELECTION);
3044
3045       /* select */
3046       node_selected = GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED);
3047       pre_val = gtk_adjustment_get_value (tree_view->priv->vadjustment);
3048
3049       /* we only handle selection modifications on the first button press
3050        */
3051       if (event->type == GDK_BUTTON_PRESS)
3052         {
3053           GtkCellRenderer *focus_cell;
3054
3055           if ((event->state & modify_mod_mask) == modify_mod_mask)
3056             tree_view->priv->modify_selection_pressed = TRUE;
3057           if ((event->state & extend_mod_mask) == extend_mod_mask)
3058             tree_view->priv->extend_selection_pressed = TRUE;
3059
3060           /* We update the focus cell here, this is also needed if the
3061            * column does not contain an editable cell.  In this case,
3062            * GtkCellArea did not receive the event for processing (and
3063            * could not update the focus cell).
3064            */
3065           focus_cell = _gtk_tree_view_column_get_cell_at_pos (column,
3066                                                               &cell_area,
3067                                                               &background_area,
3068                                                               event->x,
3069                                                               event->y);
3070
3071           if (focus_cell)
3072             gtk_tree_view_column_focus_cell (column, focus_cell);
3073
3074           if (event->state & modify_mod_mask)
3075             {
3076               gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
3077               gtk_tree_view_real_toggle_cursor_row (tree_view);
3078             }
3079           else if (event->state & extend_mod_mask)
3080             {
3081               gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
3082               gtk_tree_view_real_select_cursor_row (tree_view, FALSE);
3083             }
3084           else
3085             {
3086               gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
3087             }
3088
3089           tree_view->priv->modify_selection_pressed = FALSE;
3090           tree_view->priv->extend_selection_pressed = FALSE;
3091         }
3092
3093       /* the treeview may have been scrolled because of _set_cursor,
3094        * correct here
3095        */
3096
3097       aft_val = gtk_adjustment_get_value (tree_view->priv->vadjustment);
3098       dval = pre_val - aft_val;
3099
3100       cell_area.y += dval;
3101       background_area.y += dval;
3102
3103       /* Save press to possibly begin a drag
3104        */
3105       if (!column_handled_click &&
3106           !tree_view->priv->in_grab &&
3107           tree_view->priv->pressed_button < 0)
3108         {
3109           tree_view->priv->pressed_button = event->button;
3110           tree_view->priv->press_start_x = event->x;
3111           tree_view->priv->press_start_y = event->y;
3112
3113           if (tree_view->priv->rubber_banding_enable
3114               && !node_selected
3115               && gtk_tree_selection_get_mode (tree_view->priv->selection) == GTK_SELECTION_MULTIPLE)
3116             {
3117               tree_view->priv->press_start_y += tree_view->priv->dy;
3118               tree_view->priv->rubber_band_x = event->x;
3119               tree_view->priv->rubber_band_y = event->y + tree_view->priv->dy;
3120               tree_view->priv->rubber_band_status = RUBBER_BAND_MAYBE_START;
3121
3122               if ((event->state & modify_mod_mask) == modify_mod_mask)
3123                 tree_view->priv->rubber_band_modify = TRUE;
3124               if ((event->state & extend_mod_mask) == extend_mod_mask)
3125                 tree_view->priv->rubber_band_extend = TRUE;
3126             }
3127         }
3128
3129       /* Test if a double click happened on the same row. */
3130       if (event->button == 1 && event->type == GDK_BUTTON_PRESS)
3131         {
3132           int double_click_time, double_click_distance;
3133
3134           g_object_get (gtk_settings_get_default (),
3135                         "gtk-double-click-time", &double_click_time,
3136                         "gtk-double-click-distance", &double_click_distance,
3137                         NULL);
3138
3139           /* Same conditions as _gdk_event_button_generate */
3140           if (tree_view->priv->last_button_x != -1 &&
3141               (event->time < tree_view->priv->last_button_time + double_click_time) &&
3142               (ABS (event->x - tree_view->priv->last_button_x) <= double_click_distance) &&
3143               (ABS (event->y - tree_view->priv->last_button_y) <= double_click_distance))
3144             {
3145               /* We do no longer compare paths of this row and the
3146                * row clicked previously.  We use the double click
3147                * distance to decide whether this is a valid click,
3148                * allowing the mouse to slightly move over another row.
3149                */
3150               row_double_click = TRUE;
3151
3152               tree_view->priv->last_button_time = 0;
3153               tree_view->priv->last_button_x = -1;
3154               tree_view->priv->last_button_y = -1;
3155             }
3156           else
3157             {
3158               tree_view->priv->last_button_time = event->time;
3159               tree_view->priv->last_button_x = event->x;
3160               tree_view->priv->last_button_y = event->y;
3161             }
3162         }
3163
3164       if (row_double_click)
3165         {
3166           gtk_grab_remove (widget);
3167           gtk_tree_view_row_activated (tree_view, path, column);
3168
3169           if (tree_view->priv->pressed_button == event->button)
3170             tree_view->priv->pressed_button = -1;
3171         }
3172
3173       gtk_tree_path_free (path);
3174
3175       /* If we activated the row through a double click we don't want to grab
3176        * focus back, as moving focus to another widget is pretty common.
3177        */
3178       if (!row_double_click)
3179         grab_focus_and_unset_draw_keyfocus (tree_view);
3180
3181       return TRUE;
3182     }
3183
3184   /* We didn't click in the window.  Let's check to see if we clicked on a column resize window.
3185    */
3186   for (i = 0, list = tree_view->priv->columns; list; list = list->next, i++)
3187     {
3188       column = list->data;
3189       if (event->window == _gtk_tree_view_column_get_window (column) &&
3190           gtk_tree_view_column_get_resizable (column) &&
3191           _gtk_tree_view_column_get_window (column))
3192         {
3193           gpointer drag_data;
3194
3195           if (event->type == GDK_2BUTTON_PRESS &&
3196               gtk_tree_view_column_get_sizing (column) != GTK_TREE_VIEW_COLUMN_AUTOSIZE)
3197             {
3198               _gtk_tree_view_column_set_use_resized_width (column, FALSE);
3199               _gtk_tree_view_column_autosize (tree_view, column);
3200               return TRUE;
3201             }
3202
3203           if (gdk_device_grab (gdk_event_get_device ((GdkEvent*)event),
3204                                _gtk_tree_view_column_get_window (column),
3205                                GDK_OWNERSHIP_NONE,
3206                                FALSE,
3207                                GDK_POINTER_MOTION_HINT_MASK
3208                                 | GDK_BUTTON1_MOTION_MASK
3209                                 | GDK_BUTTON_RELEASE_MASK,
3210                                NULL,
3211                                event->time) != GDK_GRAB_SUCCESS)
3212             return FALSE;
3213
3214           gtk_grab_add (widget);
3215           tree_view->priv->in_column_resize = TRUE;
3216
3217           _gtk_tree_view_column_set_resized_width (column, gtk_tree_view_column_get_width (column) -
3218                                                    tree_view->priv->last_extra_space_per_column);
3219
3220           /* block attached dnd signal handler */
3221           drag_data = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
3222           if (drag_data)
3223             g_signal_handlers_block_matched (widget,
3224                                              G_SIGNAL_MATCH_DATA,
3225                                              0, 0, NULL, NULL,
3226                                              drag_data);
3227
3228           tree_view->priv->drag_pos = i;
3229           tree_view->priv->x_drag = gtk_tree_view_column_get_x_offset (column) + (rtl ? 0 : gtk_tree_view_column_get_width (column));
3230
3231           if (!gtk_widget_has_focus (widget))
3232             gtk_widget_grab_focus (widget);
3233
3234           return TRUE;
3235         }
3236     }
3237   return FALSE;
3238 }
3239
3240 /* GtkWidget::button_release_event helper */
3241 static gboolean
3242 gtk_tree_view_button_release_drag_column (GtkWidget      *widget,
3243                                           GdkEventButton *event)
3244 {
3245   GtkTreeView *tree_view;
3246   GtkWidget *button;
3247   GList *l;
3248   gboolean rtl;
3249   GdkDevice *device, *other;
3250
3251   tree_view = GTK_TREE_VIEW (widget);
3252
3253   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
3254   device = gdk_event_get_device ((GdkEvent*)event);
3255   other = gdk_device_get_associated_device (device);
3256   gdk_device_ungrab (device, event->time);
3257   gdk_device_ungrab (other, event->time);
3258
3259   /* Move the button back */
3260   button = gtk_tree_view_column_get_button (tree_view->priv->drag_column);
3261   g_object_ref (button);
3262   gtk_container_remove (GTK_CONTAINER (tree_view), button);
3263   gtk_widget_set_parent_window (button, tree_view->priv->header_window);
3264   gtk_widget_set_parent (button, GTK_WIDGET (tree_view));
3265   g_object_unref (button);
3266   gtk_widget_queue_resize (widget);
3267   if (gtk_tree_view_column_get_resizable (tree_view->priv->drag_column))
3268     {
3269       gdk_window_raise (_gtk_tree_view_column_get_window (tree_view->priv->drag_column));
3270       gdk_window_show (_gtk_tree_view_column_get_window (tree_view->priv->drag_column));
3271     }
3272   else
3273     gdk_window_hide (_gtk_tree_view_column_get_window (tree_view->priv->drag_column));
3274
3275   gtk_widget_grab_focus (button);
3276
3277   if (rtl)
3278     {
3279       if (tree_view->priv->cur_reorder &&
3280           tree_view->priv->cur_reorder->right_column != tree_view->priv->drag_column)
3281         gtk_tree_view_move_column_after (tree_view, tree_view->priv->drag_column,
3282                                          tree_view->priv->cur_reorder->right_column);
3283     }
3284   else
3285     {
3286       if (tree_view->priv->cur_reorder &&
3287           tree_view->priv->cur_reorder->left_column != tree_view->priv->drag_column)
3288         gtk_tree_view_move_column_after (tree_view, tree_view->priv->drag_column,
3289                                          tree_view->priv->cur_reorder->left_column);
3290     }
3291   tree_view->priv->drag_column = NULL;
3292   gdk_window_hide (tree_view->priv->drag_window);
3293
3294   for (l = tree_view->priv->column_drag_info; l != NULL; l = l->next)
3295     g_slice_free (GtkTreeViewColumnReorder, l->data);
3296   g_list_free (tree_view->priv->column_drag_info);
3297   tree_view->priv->column_drag_info = NULL;
3298   tree_view->priv->cur_reorder = NULL;
3299
3300   if (tree_view->priv->drag_highlight_window)
3301     gdk_window_hide (tree_view->priv->drag_highlight_window);
3302
3303   /* Reset our flags */
3304   tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_UNSET;
3305   tree_view->priv->in_column_drag = FALSE;
3306
3307   return TRUE;
3308 }
3309
3310 /* GtkWidget::button_release_event helper */
3311 static gboolean
3312 gtk_tree_view_button_release_column_resize (GtkWidget      *widget,
3313                                             GdkEventButton *event)
3314 {
3315   GtkTreeView *tree_view;
3316   gpointer drag_data;
3317
3318   tree_view = GTK_TREE_VIEW (widget);
3319
3320   tree_view->priv->drag_pos = -1;
3321
3322   /* unblock attached dnd signal handler */
3323   drag_data = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
3324   if (drag_data)
3325     g_signal_handlers_unblock_matched (widget,
3326                                        G_SIGNAL_MATCH_DATA,
3327                                        0, 0, NULL, NULL,
3328                                        drag_data);
3329
3330   tree_view->priv->in_column_resize = FALSE;
3331   gtk_grab_remove (widget);
3332   gdk_device_ungrab (gdk_event_get_device ((GdkEvent*)event), event->time);
3333   return TRUE;
3334 }
3335
3336 static gboolean
3337 gtk_tree_view_button_release (GtkWidget      *widget,
3338                               GdkEventButton *event)
3339 {
3340   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
3341
3342   if (tree_view->priv->in_column_drag)
3343     return gtk_tree_view_button_release_drag_column (widget, event);
3344
3345   if (tree_view->priv->rubber_band_status)
3346     gtk_tree_view_stop_rubber_band (tree_view);
3347
3348   if (tree_view->priv->pressed_button == event->button)
3349     tree_view->priv->pressed_button = -1;
3350
3351   if (tree_view->priv->in_column_resize)
3352     return gtk_tree_view_button_release_column_resize (widget, event);
3353
3354   if (tree_view->priv->button_pressed_node == NULL)
3355     return FALSE;
3356
3357   if (event->button == 1)
3358     {
3359       if (tree_view->priv->button_pressed_node == tree_view->priv->prelight_node &&
3360           tree_view->priv->arrow_prelit)
3361         {
3362           GtkTreePath *path = NULL;
3363
3364           path = _gtk_tree_view_find_path (tree_view,
3365                                            tree_view->priv->button_pressed_tree,
3366                                            tree_view->priv->button_pressed_node);
3367           /* Actually activate the node */
3368           if (tree_view->priv->button_pressed_node->children == NULL)
3369             gtk_tree_view_real_expand_row (tree_view, path,
3370                                            tree_view->priv->button_pressed_tree,
3371                                            tree_view->priv->button_pressed_node,
3372                                            FALSE, TRUE);
3373           else
3374             gtk_tree_view_real_collapse_row (GTK_TREE_VIEW (widget), path,
3375                                              tree_view->priv->button_pressed_tree,
3376                                              tree_view->priv->button_pressed_node, TRUE);
3377           gtk_tree_path_free (path);
3378         }
3379
3380       gtk_grab_remove (widget);
3381       tree_view->priv->button_pressed_tree = NULL;
3382       tree_view->priv->button_pressed_node = NULL;
3383     }
3384
3385   return TRUE;
3386 }
3387
3388 static gboolean
3389 gtk_tree_view_grab_broken (GtkWidget          *widget,
3390                            GdkEventGrabBroken *event)
3391 {
3392   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
3393
3394   if (tree_view->priv->in_column_drag)
3395     gtk_tree_view_button_release_drag_column (widget, (GdkEventButton *)event);
3396
3397   if (tree_view->priv->in_column_resize)
3398     gtk_tree_view_button_release_column_resize (widget, (GdkEventButton *)event);
3399
3400   return TRUE;
3401 }
3402
3403 #if 0
3404 static gboolean
3405 gtk_tree_view_configure (GtkWidget *widget,
3406                          GdkEventConfigure *event)
3407 {
3408   GtkTreeView *tree_view;
3409
3410   tree_view = GTK_TREE_VIEW (widget);
3411   tree_view->priv->search_position_func (tree_view, tree_view->priv->search_window);
3412
3413   return FALSE;
3414 }
3415 #endif
3416
3417 /* GtkWidget::motion_event function set.
3418  */
3419
3420 static gboolean
3421 coords_are_over_arrow (GtkTreeView *tree_view,
3422                        GtkRBTree   *tree,
3423                        GtkRBNode   *node,
3424                        /* these are in bin window coords */
3425                        gint         x,
3426                        gint         y)
3427 {
3428   GdkRectangle arrow;
3429   gint x2;
3430
3431   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
3432     return FALSE;
3433
3434   if ((node->flags & GTK_RBNODE_IS_PARENT) == 0)
3435     return FALSE;
3436
3437   arrow.y = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
3438   arrow.height = gtk_tree_view_get_row_height (tree_view, node);
3439
3440   gtk_tree_view_get_arrow_xrange (tree_view, tree, &arrow.x, &x2);
3441
3442   arrow.width = x2 - arrow.x;
3443
3444   return (x >= arrow.x &&
3445           x < (arrow.x + arrow.width) &&
3446           y >= arrow.y &&
3447           y < (arrow.y + arrow.height));
3448 }
3449
3450 static gboolean
3451 auto_expand_timeout (gpointer data)
3452 {
3453   GtkTreeView *tree_view = GTK_TREE_VIEW (data);
3454   GtkTreePath *path;
3455
3456   if (tree_view->priv->prelight_node)
3457     {
3458       path = _gtk_tree_view_find_path (tree_view,
3459                                        tree_view->priv->prelight_tree,
3460                                        tree_view->priv->prelight_node);   
3461
3462       if (tree_view->priv->prelight_node->children)
3463         gtk_tree_view_collapse_row (tree_view, path);
3464       else
3465         gtk_tree_view_expand_row (tree_view, path, FALSE);
3466
3467       gtk_tree_path_free (path);
3468     }
3469
3470   tree_view->priv->auto_expand_timeout = 0;
3471
3472   return FALSE;
3473 }
3474
3475 static void
3476 remove_auto_expand_timeout (GtkTreeView *tree_view)
3477 {
3478   if (tree_view->priv->auto_expand_timeout != 0)
3479     {
3480       g_source_remove (tree_view->priv->auto_expand_timeout);
3481       tree_view->priv->auto_expand_timeout = 0;
3482     }
3483 }
3484
3485 static void
3486 do_prelight (GtkTreeView *tree_view,
3487              GtkRBTree   *tree,
3488              GtkRBNode   *node,
3489              /* these are in bin_window coords */
3490              gint         x,
3491              gint         y)
3492 {
3493   if (tree_view->priv->prelight_tree == tree &&
3494       tree_view->priv->prelight_node == node)
3495     {
3496       /*  We are still on the same node,
3497           but we might need to take care of the arrow  */
3498
3499       if (tree && node && gtk_tree_view_draw_expanders (tree_view))
3500         {
3501           gboolean over_arrow;
3502
3503           over_arrow = coords_are_over_arrow (tree_view, tree, node, x, y);
3504
3505           if (over_arrow != tree_view->priv->arrow_prelit)
3506             {
3507               if (over_arrow)
3508                 tree_view->priv->arrow_prelit = TRUE;
3509               else
3510                 tree_view->priv->arrow_prelit = FALSE;
3511
3512               gtk_tree_view_queue_draw_arrow (tree_view, tree, node);
3513             }
3514         }
3515
3516       return;
3517     }
3518
3519   if (tree_view->priv->prelight_tree && tree_view->priv->prelight_node)
3520     {
3521       /*  Unprelight the old node and arrow  */
3522
3523       GTK_RBNODE_UNSET_FLAG (tree_view->priv->prelight_node,
3524                              GTK_RBNODE_IS_PRELIT);
3525
3526       if (tree_view->priv->arrow_prelit
3527           && gtk_tree_view_draw_expanders (tree_view))
3528         {
3529           tree_view->priv->arrow_prelit = FALSE;
3530           
3531           gtk_tree_view_queue_draw_arrow (tree_view,
3532                                           tree_view->priv->prelight_tree,
3533                                           tree_view->priv->prelight_node);
3534         }
3535
3536       _gtk_tree_view_queue_draw_node (tree_view,
3537                                       tree_view->priv->prelight_tree,
3538                                       tree_view->priv->prelight_node,
3539                                       NULL);
3540     }
3541
3542
3543   if (tree_view->priv->hover_expand)
3544     remove_auto_expand_timeout (tree_view);
3545
3546   /*  Set the new prelight values  */
3547   tree_view->priv->prelight_node = node;
3548   tree_view->priv->prelight_tree = tree;
3549
3550   if (!node || !tree)
3551     return;
3552
3553   /*  Prelight the new node and arrow  */
3554
3555   if (gtk_tree_view_draw_expanders (tree_view)
3556       && coords_are_over_arrow (tree_view, tree, node, x, y))
3557     {
3558       tree_view->priv->arrow_prelit = TRUE;
3559
3560       gtk_tree_view_queue_draw_arrow (tree_view, tree, node);
3561     }
3562
3563   GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_PRELIT);
3564
3565   _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
3566
3567   if (tree_view->priv->hover_expand)
3568     {
3569       tree_view->priv->auto_expand_timeout = 
3570         gdk_threads_add_timeout (AUTO_EXPAND_TIMEOUT, auto_expand_timeout, tree_view);
3571     }
3572 }
3573
3574 static void
3575 prelight_or_select (GtkTreeView *tree_view,
3576                     GtkRBTree   *tree,
3577                     GtkRBNode   *node,
3578                     /* these are in bin_window coords */
3579                     gint         x,
3580                     gint         y)
3581 {
3582   GtkSelectionMode mode = gtk_tree_selection_get_mode (tree_view->priv->selection);
3583   
3584   if (tree_view->priv->hover_selection &&
3585       (mode == GTK_SELECTION_SINGLE || mode == GTK_SELECTION_BROWSE) &&
3586       !(tree_view->priv->edited_column &&
3587         gtk_cell_area_get_edit_widget 
3588         (gtk_cell_layout_get_area (GTK_CELL_LAYOUT (tree_view->priv->edited_column)))))
3589     {
3590       if (node)
3591         {
3592           if (!GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
3593             {
3594               GtkTreePath *path;
3595               
3596               path = _gtk_tree_view_find_path (tree_view, tree, node);
3597               gtk_tree_selection_select_path (tree_view->priv->selection, path);
3598               if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
3599                 {
3600                   tree_view->priv->draw_keyfocus = FALSE;
3601                   gtk_tree_view_real_set_cursor (tree_view, path, FALSE, FALSE);
3602                 }
3603               gtk_tree_path_free (path);
3604             }
3605         }
3606
3607       else if (mode == GTK_SELECTION_SINGLE)
3608         gtk_tree_selection_unselect_all (tree_view->priv->selection);
3609     }
3610
3611     do_prelight (tree_view, tree, node, x, y);
3612 }
3613
3614 static void
3615 ensure_unprelighted (GtkTreeView *tree_view)
3616 {
3617   do_prelight (tree_view,
3618                NULL, NULL,
3619                -1000, -1000); /* coords not possibly over an arrow */
3620
3621   g_assert (tree_view->priv->prelight_node == NULL);
3622 }
3623
3624 static void
3625 update_prelight (GtkTreeView *tree_view,
3626                  gint         x,
3627                  gint         y)
3628 {
3629   int new_y;
3630   GtkRBTree *tree;
3631   GtkRBNode *node;
3632
3633   if (tree_view->priv->tree == NULL)
3634     return;
3635
3636   if (x == -10000)
3637     {
3638       ensure_unprelighted (tree_view);
3639       return;
3640     }
3641
3642   new_y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, y);
3643   if (new_y < 0)
3644     new_y = 0;
3645
3646   _gtk_rbtree_find_offset (tree_view->priv->tree,
3647                            new_y, &tree, &node);
3648
3649   if (node)
3650     prelight_or_select (tree_view, tree, node, x, y);
3651 }
3652
3653
3654
3655
3656 /* Our motion arrow is either a box (in the case of the original spot)
3657  * or an arrow.  It is expander_size wide.
3658  */
3659 /*
3660  * 11111111111111
3661  * 01111111111110
3662  * 00111111111100
3663  * 00011111111000
3664  * 00001111110000
3665  * 00000111100000
3666  * 00000111100000
3667  * 00000111100000
3668  * ~ ~ ~ ~ ~ ~ ~
3669  * 00000111100000
3670  * 00000111100000
3671  * 00000111100000
3672  * 00001111110000
3673  * 00011111111000
3674  * 00111111111100
3675  * 01111111111110
3676  * 11111111111111
3677  */
3678
3679 static void
3680 gtk_tree_view_motion_draw_column_motion_arrow (GtkTreeView *tree_view)
3681 {
3682   GtkTreeViewColumnReorder *reorder = tree_view->priv->cur_reorder;
3683   GtkWidget *widget = GTK_WIDGET (tree_view);
3684   cairo_surface_t *mask_image;
3685   cairo_region_t *mask_region;
3686   gint x;
3687   gint y;
3688   gint width;
3689   gint height;
3690   gint arrow_type = DRAG_COLUMN_WINDOW_STATE_UNSET;
3691   GdkWindowAttr attributes;
3692   guint attributes_mask;
3693   cairo_t *cr;
3694
3695   if (!reorder ||
3696       reorder->left_column == tree_view->priv->drag_column ||
3697       reorder->right_column == tree_view->priv->drag_column)
3698     arrow_type = DRAG_COLUMN_WINDOW_STATE_ORIGINAL;
3699   else if (reorder->left_column || reorder->right_column)
3700     {
3701       GtkAllocation left_allocation, right_allocation;
3702       GdkRectangle visible_rect;
3703       GtkWidget *button;
3704
3705       gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
3706       if (reorder->left_column)
3707         {
3708           button = gtk_tree_view_column_get_button (reorder->left_column);
3709           gtk_widget_get_allocation (button, &left_allocation);
3710           x = left_allocation.x + left_allocation.width;
3711         }
3712       else
3713         {
3714           button = gtk_tree_view_column_get_button (reorder->right_column);
3715           gtk_widget_get_allocation (button, &right_allocation);
3716           x = right_allocation.x;
3717         }
3718
3719       if (x < visible_rect.x)
3720         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT;
3721       else if (x > visible_rect.x + visible_rect.width)
3722         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT;
3723       else
3724         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW;
3725     }
3726
3727   /* We want to draw the rectangle over the initial location. */
3728   if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ORIGINAL)
3729     {
3730       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ORIGINAL)
3731         {
3732           GtkAllocation drag_allocation;
3733           GtkWidget    *button;
3734
3735           if (tree_view->priv->drag_highlight_window)
3736             {
3737               gdk_window_set_user_data (tree_view->priv->drag_highlight_window,
3738                                         NULL);
3739               gdk_window_destroy (tree_view->priv->drag_highlight_window);
3740             }
3741
3742           button = gtk_tree_view_column_get_button (tree_view->priv->drag_column);
3743           attributes.window_type = GDK_WINDOW_CHILD;
3744           attributes.wclass = GDK_INPUT_OUTPUT;
3745           attributes.x = tree_view->priv->drag_column_x;
3746           attributes.y = 0;
3747           gtk_widget_get_allocation (button, &drag_allocation);
3748           width = attributes.width = drag_allocation.width;
3749           height = attributes.height = drag_allocation.height;
3750           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
3751           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3752           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
3753           tree_view->priv->drag_highlight_window = gdk_window_new (tree_view->priv->header_window, &attributes, attributes_mask);
3754           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
3755
3756           mask_image = cairo_image_surface_create (CAIRO_FORMAT_A1, width, height);
3757           cr = cairo_create (mask_image);
3758
3759           cairo_rectangle (cr, 1, 1, width - 2, height - 2);
3760           cairo_stroke (cr);
3761           cairo_destroy (cr);
3762
3763           mask_region = gdk_cairo_region_create_from_surface (mask_image);
3764           gdk_window_shape_combine_region (tree_view->priv->drag_highlight_window,
3765                                            mask_region, 0, 0);
3766
3767           cairo_region_destroy (mask_region);
3768           cairo_surface_destroy (mask_image);
3769
3770           tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_ORIGINAL;
3771         }
3772     }
3773   else if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW)
3774     {
3775       GtkAllocation button_allocation;
3776       GtkWidget    *button;
3777
3778       width = tree_view->priv->expander_size;
3779
3780       /* Get x, y, width, height of arrow */
3781       gdk_window_get_origin (tree_view->priv->header_window, &x, &y);
3782       if (reorder->left_column)
3783         {
3784           button = gtk_tree_view_column_get_button (reorder->left_column);
3785           gtk_widget_get_allocation (button, &button_allocation);
3786           x += button_allocation.x + button_allocation.width - width/2;
3787           height = button_allocation.height;
3788         }
3789       else
3790         {
3791           button = gtk_tree_view_column_get_button (reorder->right_column);
3792           gtk_widget_get_allocation (button, &button_allocation);
3793           x += button_allocation.x - width/2;
3794           height = button_allocation.height;
3795         }
3796       y -= tree_view->priv->expander_size/2; /* The arrow takes up only half the space */
3797       height += tree_view->priv->expander_size;
3798
3799       /* Create the new window */
3800       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW)
3801         {
3802           if (tree_view->priv->drag_highlight_window)
3803             {
3804               gdk_window_set_user_data (tree_view->priv->drag_highlight_window,
3805                                         NULL);
3806               gdk_window_destroy (tree_view->priv->drag_highlight_window);
3807             }
3808
3809           attributes.window_type = GDK_WINDOW_TEMP;
3810           attributes.wclass = GDK_INPUT_OUTPUT;
3811           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
3812           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3813           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
3814           attributes.x = x;
3815           attributes.y = y;
3816           attributes.width = width;
3817           attributes.height = height;
3818           tree_view->priv->drag_highlight_window = gdk_window_new (gtk_widget_get_root_window (widget),
3819                                                                    &attributes, attributes_mask);
3820           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
3821
3822           mask_image = cairo_image_surface_create (CAIRO_FORMAT_A1, width, height);
3823
3824           cr = cairo_create (mask_image);
3825           cairo_move_to (cr, 0, 0);
3826           cairo_line_to (cr, width, 0);
3827           cairo_line_to (cr, width / 2., width / 2);
3828           cairo_move_to (cr, 0, height);
3829           cairo_line_to (cr, width, height);
3830           cairo_line_to (cr, width / 2., height - width / 2.);
3831           cairo_fill (cr);
3832           cairo_destroy (cr);
3833
3834           mask_region = gdk_cairo_region_create_from_surface (mask_image);
3835           gdk_window_shape_combine_region (tree_view->priv->drag_highlight_window,
3836                                            mask_region, 0, 0);
3837
3838           cairo_region_destroy (mask_region);
3839           cairo_surface_destroy (mask_image);
3840         }
3841
3842       tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_ARROW;
3843       gdk_window_move (tree_view->priv->drag_highlight_window, x, y);
3844     }
3845   else if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT ||
3846            arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
3847     {
3848       GtkAllocation allocation;
3849       GtkWidget    *button;
3850
3851       width = tree_view->priv->expander_size;
3852
3853       /* Get x, y, width, height of arrow */
3854       width = width/2; /* remember, the arrow only takes half the available width */
3855       gdk_window_get_origin (gtk_widget_get_window (widget),
3856                              &x, &y);
3857       if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
3858         {
3859           gtk_widget_get_allocation (widget, &allocation);
3860           x += allocation.width - width;
3861         }
3862
3863       if (reorder->left_column)
3864         {
3865           button = gtk_tree_view_column_get_button (reorder->left_column);
3866           gtk_widget_get_allocation (button, &allocation);
3867           height = allocation.height;
3868         }
3869       else
3870         {
3871           button = gtk_tree_view_column_get_button (reorder->right_column);
3872           gtk_widget_get_allocation (button, &allocation);
3873           height = allocation.height;
3874         }
3875
3876       y -= tree_view->priv->expander_size;
3877       height += 2*tree_view->priv->expander_size;
3878
3879       /* Create the new window */
3880       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT &&
3881           tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
3882         {
3883           if (tree_view->priv->drag_highlight_window)
3884             {
3885               gdk_window_set_user_data (tree_view->priv->drag_highlight_window,
3886                                         NULL);
3887               gdk_window_destroy (tree_view->priv->drag_highlight_window);
3888             }
3889
3890           attributes.window_type = GDK_WINDOW_TEMP;
3891           attributes.wclass = GDK_INPUT_OUTPUT;
3892           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
3893           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3894           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
3895           attributes.x = x;
3896           attributes.y = y;
3897           attributes.width = width;
3898           attributes.height = height;
3899           tree_view->priv->drag_highlight_window = gdk_window_new (NULL, &attributes, attributes_mask);
3900           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
3901
3902           mask_image = cairo_image_surface_create (CAIRO_FORMAT_A1, width, height);
3903
3904           cr = cairo_create (mask_image);
3905           /* mirror if we're on the left */
3906           if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT)
3907             {
3908               cairo_translate (cr, width, 0);
3909               cairo_scale (cr, -1, 1);
3910             }
3911           cairo_move_to (cr, 0, 0);
3912           cairo_line_to (cr, width, width);
3913           cairo_line_to (cr, 0, tree_view->priv->expander_size);
3914           cairo_move_to (cr, 0, height);
3915           cairo_line_to (cr, width, height - width);
3916           cairo_line_to (cr, 0, height - tree_view->priv->expander_size);
3917           cairo_fill (cr);
3918           cairo_destroy (cr);
3919
3920           mask_region = gdk_cairo_region_create_from_surface (mask_image);
3921           gdk_window_shape_combine_region (tree_view->priv->drag_highlight_window,
3922                                            mask_region, 0, 0);
3923
3924           cairo_region_destroy (mask_region);
3925           cairo_surface_destroy (mask_image);
3926         }
3927
3928       tree_view->priv->drag_column_window_state = arrow_type;
3929       gdk_window_move (tree_view->priv->drag_highlight_window, x, y);
3930    }
3931   else
3932     {
3933       g_warning (G_STRLOC"Invalid GtkTreeViewColumnReorder struct");
3934       gdk_window_hide (tree_view->priv->drag_highlight_window);
3935       return;
3936     }
3937
3938   gdk_window_show (tree_view->priv->drag_highlight_window);
3939   gdk_window_raise (tree_view->priv->drag_highlight_window);
3940 }
3941
3942 static gboolean
3943 gtk_tree_view_motion_resize_column (GtkWidget      *widget,
3944                                     GdkEventMotion *event)
3945 {
3946   gint x;
3947   gint new_width;
3948   GtkTreeViewColumn *column;
3949   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
3950
3951   column = gtk_tree_view_get_column (tree_view, tree_view->priv->drag_pos);
3952
3953   if (event->is_hint || event->window != gtk_widget_get_window (widget))
3954     gtk_widget_get_pointer (widget, &x, NULL);
3955   else
3956     x = event->x;
3957
3958   if (tree_view->priv->hadjustment)
3959     x += gtk_adjustment_get_value (tree_view->priv->hadjustment);
3960
3961   new_width = gtk_tree_view_new_column_width (tree_view,
3962                                               tree_view->priv->drag_pos, &x);
3963   if (x != tree_view->priv->x_drag &&
3964       (new_width != gtk_tree_view_column_get_fixed_width (column)))
3965     {
3966       _gtk_tree_view_column_set_use_resized_width (column, TRUE);
3967
3968       if (gtk_tree_view_column_get_expand (column))
3969         new_width -= tree_view->priv->last_extra_space_per_column;
3970
3971       _gtk_tree_view_column_set_resized_width (column, new_width);
3972
3973
3974       gtk_widget_queue_resize (widget);
3975     }
3976
3977   return FALSE;
3978 }
3979
3980
3981 static void
3982 gtk_tree_view_update_current_reorder (GtkTreeView *tree_view)
3983 {
3984   GtkTreeViewColumnReorder *reorder = NULL;
3985   GList *list;
3986   gint mouse_x;
3987
3988   gdk_window_get_pointer (tree_view->priv->header_window, &mouse_x, NULL, NULL);
3989   for (list = tree_view->priv->column_drag_info; list; list = list->next)
3990     {
3991       reorder = (GtkTreeViewColumnReorder *) list->data;
3992       if (mouse_x >= reorder->left_align && mouse_x < reorder->right_align)
3993         break;
3994       reorder = NULL;
3995     }
3996
3997   /*  if (reorder && reorder == tree_view->priv->cur_reorder)
3998       return;*/
3999
4000   tree_view->priv->cur_reorder = reorder;
4001   gtk_tree_view_motion_draw_column_motion_arrow (tree_view);
4002 }
4003
4004 static void
4005 gtk_tree_view_vertical_autoscroll (GtkTreeView *tree_view)
4006 {
4007   GdkRectangle visible_rect;
4008   gint y;
4009   gint offset;
4010
4011   gdk_window_get_pointer (tree_view->priv->bin_window, NULL, &y, NULL);
4012   y += tree_view->priv->dy;
4013
4014   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
4015
4016   /* see if we are near the edge. */
4017   offset = y - (visible_rect.y + 2 * SCROLL_EDGE_SIZE);
4018   if (offset > 0)
4019     {
4020       offset = y - (visible_rect.y + visible_rect.height - 2 * SCROLL_EDGE_SIZE);
4021       if (offset < 0)
4022         return;
4023     }
4024
4025   gtk_adjustment_set_value (tree_view->priv->vadjustment,
4026                             MAX (gtk_adjustment_get_value (tree_view->priv->vadjustment) + offset, 0.0));
4027 }
4028
4029 static gboolean
4030 gtk_tree_view_horizontal_autoscroll (GtkTreeView *tree_view)
4031 {
4032   GdkRectangle visible_rect;
4033   gint x;
4034   gint offset;
4035
4036   gdk_window_get_pointer (tree_view->priv->bin_window, &x, NULL, NULL);
4037
4038   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
4039
4040   /* See if we are near the edge. */
4041   offset = x - (visible_rect.x + SCROLL_EDGE_SIZE);
4042   if (offset > 0)
4043     {
4044       offset = x - (visible_rect.x + visible_rect.width - SCROLL_EDGE_SIZE);
4045       if (offset < 0)
4046         return TRUE;
4047     }
4048   offset = offset/3;
4049
4050   gtk_adjustment_set_value (tree_view->priv->hadjustment,
4051                             MAX (gtk_adjustment_get_value (tree_view->priv->hadjustment) + offset, 0.0));
4052
4053   return TRUE;
4054
4055 }
4056
4057 static gboolean
4058 gtk_tree_view_motion_drag_column (GtkWidget      *widget,
4059                                   GdkEventMotion *event)
4060 {
4061   GtkAllocation allocation, button_allocation;
4062   GtkTreeView *tree_view = (GtkTreeView *) widget;
4063   GtkTreeViewColumn *column = tree_view->priv->drag_column;
4064   GtkWidget *button;
4065   gint x, y;
4066
4067   /* Sanity Check */
4068   if ((column == NULL) ||
4069       (event->window != tree_view->priv->drag_window))
4070     return FALSE;
4071
4072   button = gtk_tree_view_column_get_button (column);
4073
4074   /* Handle moving the header */
4075   gdk_window_get_position (tree_view->priv->drag_window, &x, &y);
4076   gtk_widget_get_allocation (widget, &allocation);
4077   gtk_widget_get_allocation (button, &button_allocation);
4078   x = CLAMP (x + (gint)event->x - _gtk_tree_view_column_get_drag_x (column), 0,
4079              MAX (tree_view->priv->width, allocation.width) - button_allocation.width);
4080   gdk_window_move (tree_view->priv->drag_window, x, y);
4081   
4082   /* autoscroll, if needed */
4083   gtk_tree_view_horizontal_autoscroll (tree_view);
4084   /* Update the current reorder position and arrow; */
4085   gtk_tree_view_update_current_reorder (tree_view);
4086
4087   return TRUE;
4088 }
4089
4090 static void
4091 gtk_tree_view_stop_rubber_band (GtkTreeView *tree_view)
4092 {
4093   remove_scroll_timeout (tree_view);
4094   gtk_grab_remove (GTK_WIDGET (tree_view));
4095
4096   if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
4097     {
4098       GtkTreePath *tmp_path;
4099
4100       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
4101
4102       /* The anchor path should be set to the start path */
4103       tmp_path = _gtk_tree_view_find_path (tree_view,
4104                                            tree_view->priv->rubber_band_start_tree,
4105                                            tree_view->priv->rubber_band_start_node);
4106
4107       if (tree_view->priv->anchor)
4108         gtk_tree_row_reference_free (tree_view->priv->anchor);
4109
4110       tree_view->priv->anchor =
4111         gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
4112                                           tree_view->priv->model,
4113                                           tmp_path);
4114
4115       gtk_tree_path_free (tmp_path);
4116
4117       /* ... and the cursor to the end path */
4118       tmp_path = _gtk_tree_view_find_path (tree_view,
4119                                            tree_view->priv->rubber_band_end_tree,
4120                                            tree_view->priv->rubber_band_end_node);
4121       gtk_tree_view_real_set_cursor (GTK_TREE_VIEW (tree_view), tmp_path, FALSE, FALSE);
4122       gtk_tree_path_free (tmp_path);
4123
4124       _gtk_tree_selection_emit_changed (tree_view->priv->selection);
4125     }
4126
4127   /* Clear status variables */
4128   tree_view->priv->rubber_band_status = RUBBER_BAND_OFF;
4129   tree_view->priv->rubber_band_extend = FALSE;
4130   tree_view->priv->rubber_band_modify = FALSE;
4131
4132   tree_view->priv->rubber_band_start_node = NULL;
4133   tree_view->priv->rubber_band_start_tree = NULL;
4134   tree_view->priv->rubber_band_end_node = NULL;
4135   tree_view->priv->rubber_band_end_tree = NULL;
4136 }
4137
4138 static void
4139 gtk_tree_view_update_rubber_band_selection_range (GtkTreeView *tree_view,
4140                                                  GtkRBTree   *start_tree,
4141                                                  GtkRBNode   *start_node,
4142                                                  GtkRBTree   *end_tree,
4143                                                  GtkRBNode   *end_node,
4144                                                  gboolean     select,
4145                                                  gboolean     skip_start,
4146                                                  gboolean     skip_end)
4147 {
4148   if (start_node == end_node)
4149     return;
4150
4151   /* We skip the first node and jump inside the loop */
4152   if (skip_start)
4153     goto skip_first;
4154
4155   do
4156     {
4157       /* Small optimization by assuming insensitive nodes are never
4158        * selected.
4159        */
4160       if (!GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
4161         {
4162           GtkTreePath *path;
4163           gboolean selectable;
4164
4165           path = _gtk_tree_view_find_path (tree_view, start_tree, start_node);
4166           selectable = _gtk_tree_selection_row_is_selectable (tree_view->priv->selection, start_node, path);
4167           gtk_tree_path_free (path);
4168
4169           if (!selectable)
4170             goto node_not_selectable;
4171         }
4172
4173       if (select)
4174         {
4175           if (tree_view->priv->rubber_band_extend)
4176             GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4177           else if (tree_view->priv->rubber_band_modify)
4178             {
4179               /* Toggle the selection state */
4180               if (GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
4181                 GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4182               else
4183                 GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4184             }
4185           else
4186             GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4187         }
4188       else
4189         {
4190           /* Mirror the above */
4191           if (tree_view->priv->rubber_band_extend)
4192             GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4193           else if (tree_view->priv->rubber_band_modify)
4194             {
4195               /* Toggle the selection state */
4196               if (GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
4197                 GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4198               else
4199                 GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4200             }
4201           else
4202             GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4203         }
4204
4205       _gtk_tree_view_queue_draw_node (tree_view, start_tree, start_node, NULL);
4206
4207 node_not_selectable:
4208       if (start_node == end_node)
4209         break;
4210
4211 skip_first:
4212
4213       if (start_node->children)
4214         {
4215           start_tree = start_node->children;
4216           start_node = start_tree->root;
4217           while (start_node->left != start_tree->nil)
4218             start_node = start_node->left;
4219         }
4220       else
4221         {
4222           _gtk_rbtree_next_full (start_tree, start_node, &start_tree, &start_node);
4223
4224           if (!start_tree)
4225             /* Ran out of tree */
4226             break;
4227         }
4228
4229       if (skip_end && start_node == end_node)
4230         break;
4231     }
4232   while (TRUE);
4233 }
4234
4235 static void
4236 gtk_tree_view_update_rubber_band_selection (GtkTreeView *tree_view)
4237 {
4238   GtkRBTree *start_tree, *end_tree;
4239   GtkRBNode *start_node, *end_node;
4240
4241   _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);
4242   _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);
4243
4244   /* Handle the start area first */
4245   if (!tree_view->priv->rubber_band_start_node)
4246     {
4247       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4248                                                        start_tree,
4249                                                        start_node,
4250                                                        end_tree,
4251                                                        end_node,
4252                                                        TRUE,
4253                                                        FALSE,
4254                                                        FALSE);
4255     }
4256   else if (_gtk_rbtree_node_find_offset (start_tree, start_node) <
4257            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_start_tree, tree_view->priv->rubber_band_start_node))
4258     {
4259       /* New node is above the old one; selection became bigger */
4260       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4261                                                        start_tree,
4262                                                        start_node,
4263                                                        tree_view->priv->rubber_band_start_tree,
4264                                                        tree_view->priv->rubber_band_start_node,
4265                                                        TRUE,
4266                                                        FALSE,
4267                                                        TRUE);
4268     }
4269   else if (_gtk_rbtree_node_find_offset (start_tree, start_node) >
4270            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_start_tree, tree_view->priv->rubber_band_start_node))
4271     {
4272       /* New node is below the old one; selection became smaller */
4273       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4274                                                        tree_view->priv->rubber_band_start_tree,
4275                                                        tree_view->priv->rubber_band_start_node,
4276                                                        start_tree,
4277                                                        start_node,
4278                                                        FALSE,
4279                                                        FALSE,
4280                                                        TRUE);
4281     }
4282
4283   tree_view->priv->rubber_band_start_tree = start_tree;
4284   tree_view->priv->rubber_band_start_node = start_node;
4285
4286   /* Next, handle the end area */
4287   if (!tree_view->priv->rubber_band_end_node)
4288     {
4289       /* In the event this happens, start_node was also NULL; this case is
4290        * handled above.
4291        */
4292     }
4293   else if (!end_node)
4294     {
4295       /* Find the last node in the tree */
4296       _gtk_rbtree_find_offset (tree_view->priv->tree, tree_view->priv->height - 1,
4297                                &end_tree, &end_node);
4298
4299       /* Selection reached end of the tree */
4300       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4301                                                        tree_view->priv->rubber_band_end_tree,
4302                                                        tree_view->priv->rubber_band_end_node,
4303                                                        end_tree,
4304                                                        end_node,
4305                                                        TRUE,
4306                                                        TRUE,
4307                                                        FALSE);
4308     }
4309   else if (_gtk_rbtree_node_find_offset (end_tree, end_node) >
4310            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_end_tree, tree_view->priv->rubber_band_end_node))
4311     {
4312       /* New node is below the old one; selection became bigger */
4313       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4314                                                        tree_view->priv->rubber_band_end_tree,
4315                                                        tree_view->priv->rubber_band_end_node,
4316                                                        end_tree,
4317                                                        end_node,
4318                                                        TRUE,
4319                                                        TRUE,
4320                                                        FALSE);
4321     }
4322   else if (_gtk_rbtree_node_find_offset (end_tree, end_node) <
4323            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_end_tree, tree_view->priv->rubber_band_end_node))
4324     {
4325       /* New node is above the old one; selection became smaller */
4326       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4327                                                        end_tree,
4328                                                        end_node,
4329                                                        tree_view->priv->rubber_band_end_tree,
4330                                                        tree_view->priv->rubber_band_end_node,
4331                                                        FALSE,
4332                                                        TRUE,
4333                                                        FALSE);
4334     }
4335
4336   tree_view->priv->rubber_band_end_tree = end_tree;
4337   tree_view->priv->rubber_band_end_node = end_node;
4338 }
4339
4340 static void
4341 gtk_tree_view_update_rubber_band (GtkTreeView *tree_view)
4342 {
4343   gint x, y;
4344   GdkRectangle old_area;
4345   GdkRectangle new_area;
4346   GdkRectangle common;
4347   cairo_region_t *invalid_region;
4348
4349   old_area.x = MIN (tree_view->priv->press_start_x, tree_view->priv->rubber_band_x);
4350   old_area.y = MIN (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y) - tree_view->priv->dy;
4351   old_area.width = ABS (tree_view->priv->rubber_band_x - tree_view->priv->press_start_x) + 1;
4352   old_area.height = ABS (tree_view->priv->rubber_band_y - tree_view->priv->press_start_y) + 1;
4353
4354   gdk_window_get_pointer (tree_view->priv->bin_window, &x, &y, NULL);
4355
4356   x = MAX (x, 0);
4357   y = MAX (y, 0) + tree_view->priv->dy;
4358
4359   new_area.x = MIN (tree_view->priv->press_start_x, x);
4360   new_area.y = MIN (tree_view->priv->press_start_y, y) - tree_view->priv->dy;
4361   new_area.width = ABS (x - tree_view->priv->press_start_x) + 1;
4362   new_area.height = ABS (y - tree_view->priv->press_start_y) + 1;
4363
4364   invalid_region = cairo_region_create_rectangle (&old_area);
4365   cairo_region_union_rectangle (invalid_region, &new_area);
4366
4367   gdk_rectangle_intersect (&old_area, &new_area, &common);
4368   if (common.width > 2 && common.height > 2)
4369     {
4370       cairo_region_t *common_region;
4371
4372       /* make sure the border is invalidated */
4373       common.x += 1;
4374       common.y += 1;
4375       common.width -= 2;
4376       common.height -= 2;
4377
4378       common_region = cairo_region_create_rectangle (&common);
4379
4380       cairo_region_subtract (invalid_region, common_region);
4381       cairo_region_destroy (common_region);
4382     }
4383
4384   gdk_window_invalidate_region (tree_view->priv->bin_window, invalid_region, TRUE);
4385
4386   cairo_region_destroy (invalid_region);
4387
4388   tree_view->priv->rubber_band_x = x;
4389   tree_view->priv->rubber_band_y = y;
4390
4391   gtk_tree_view_update_rubber_band_selection (tree_view);
4392 }
4393
4394 static void
4395 gtk_tree_view_paint_rubber_band (GtkTreeView  *tree_view,
4396                                  cairo_t      *cr)
4397 {
4398   GdkRectangle rect;
4399   GtkStyleContext *context;
4400
4401   cairo_save (cr);
4402
4403   context = gtk_widget_get_style_context (GTK_WIDGET (tree_view));
4404
4405   gtk_style_context_save (context);
4406   gtk_style_context_add_class (context, GTK_STYLE_CLASS_RUBBERBAND);
4407
4408   rect.x = MIN (tree_view->priv->press_start_x, tree_view->priv->rubber_band_x);
4409   rect.y = MIN (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y) - tree_view->priv->dy;
4410   rect.width = ABS (tree_view->priv->press_start_x - tree_view->priv->rubber_band_x) + 1;
4411   rect.height = ABS (tree_view->priv->press_start_y - tree_view->priv->rubber_band_y) + 1;
4412
4413   gdk_cairo_rectangle (cr, &rect);
4414   cairo_clip (cr);
4415
4416   gtk_render_background (context, cr,
4417                          rect.x, rect.y,
4418                          rect.width, rect.height);
4419   gtk_render_frame (context, cr,
4420                     rect.x, rect.y,
4421                     rect.width, rect.height);
4422
4423   gtk_style_context_restore (context);
4424   cairo_restore (cr);
4425 }
4426
4427 static gboolean
4428 gtk_tree_view_motion_bin_window (GtkWidget      *widget,
4429                                  GdkEventMotion *event)
4430 {
4431   GtkTreeView *tree_view;
4432   GtkRBTree *tree;
4433   GtkRBNode *node;
4434   gint new_y;
4435
4436   tree_view = (GtkTreeView *) widget;
4437
4438   if (tree_view->priv->tree == NULL)
4439     return FALSE;
4440
4441   if (tree_view->priv->rubber_band_status == RUBBER_BAND_MAYBE_START)
4442     {
4443       gtk_grab_add (GTK_WIDGET (tree_view));
4444       gtk_tree_view_update_rubber_band (tree_view);
4445
4446       tree_view->priv->rubber_band_status = RUBBER_BAND_ACTIVE;
4447     }
4448   else if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
4449     {
4450       gtk_tree_view_update_rubber_band (tree_view);
4451
4452       add_scroll_timeout (tree_view);
4453     }
4454
4455   /* only check for an initiated drag when a button is pressed */
4456   if (tree_view->priv->pressed_button >= 0
4457       && !tree_view->priv->rubber_band_status)
4458     gtk_tree_view_maybe_begin_dragging_row (tree_view, event);
4459
4460   new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
4461   if (new_y < 0)
4462     new_y = 0;
4463
4464   _gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
4465
4466   /* If we are currently pressing down a button, we don't want to prelight anything else. */
4467   if ((tree_view->priv->button_pressed_node != NULL) &&
4468       (tree_view->priv->button_pressed_node != node))
4469     node = NULL;
4470
4471   tree_view->priv->event_last_x = event->x;
4472   tree_view->priv->event_last_y = event->y;
4473
4474   prelight_or_select (tree_view, tree, node, event->x, event->y);
4475
4476   return TRUE;
4477 }
4478
4479 static gboolean
4480 gtk_tree_view_motion (GtkWidget      *widget,
4481                       GdkEventMotion *event)
4482 {
4483   GtkTreeView *tree_view;
4484
4485   tree_view = (GtkTreeView *) widget;
4486
4487   /* Resizing a column */
4488   if (tree_view->priv->in_column_resize)
4489     return gtk_tree_view_motion_resize_column (widget, event);
4490
4491   /* Drag column */
4492   if (tree_view->priv->in_column_drag)
4493     return gtk_tree_view_motion_drag_column (widget, event);
4494
4495   /* Sanity check it */
4496   if (event->window == tree_view->priv->bin_window)
4497     return gtk_tree_view_motion_bin_window (widget, event);
4498
4499   return FALSE;
4500 }
4501
4502 /* Invalidate the focus rectangle near the edge of the bin_window; used when
4503  * the tree is empty.
4504  */
4505 static void
4506 invalidate_empty_focus (GtkTreeView *tree_view)
4507 {
4508   GdkRectangle area;
4509
4510   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
4511     return;
4512
4513   area.x = 0;
4514   area.y = 0;
4515   area.width = gdk_window_get_width (tree_view->priv->bin_window);
4516   area.height = gdk_window_get_height (tree_view->priv->bin_window);
4517   gdk_window_invalidate_rect (tree_view->priv->bin_window, &area, FALSE);
4518 }
4519
4520 /* Draws a focus rectangle near the edge of the bin_window; used when the tree
4521  * is empty.
4522  */
4523 static void
4524 draw_empty_focus (GtkTreeView *tree_view, cairo_t *cr)
4525 {
4526   GtkWidget *widget = GTK_WIDGET (tree_view);
4527   gint w, h;
4528
4529   if (!gtk_widget_has_visible_focus (widget))
4530     return;
4531
4532   w = gdk_window_get_width (tree_view->priv->bin_window) - 2;
4533   h = gdk_window_get_height (tree_view->priv->bin_window) - 2;
4534
4535   if (w > 0 && h > 0)
4536     {
4537       GtkStyleContext *context;
4538       GtkStateFlags state;
4539
4540       context = gtk_widget_get_style_context (widget);
4541       state = gtk_widget_get_state_flags (widget);
4542
4543       gtk_style_context_save (context);
4544       gtk_style_context_set_state (context, state);
4545
4546       gtk_render_focus (context, cr, 1, 1, w, h);
4547
4548       gtk_style_context_restore (context);
4549     }
4550 }
4551
4552 typedef enum {
4553   GTK_TREE_VIEW_GRID_LINE,
4554   GTK_TREE_VIEW_TREE_LINE,
4555   GTK_TREE_VIEW_FOREGROUND_LINE
4556 } GtkTreeViewLineType;
4557
4558 static void
4559 gtk_tree_view_draw_line (GtkTreeView         *tree_view,
4560                          cairo_t             *cr,
4561                          GtkTreeViewLineType  type,
4562                          int                  x1,
4563                          int                  y1,
4564                          int                  x2,
4565                          int                  y2)
4566 {
4567   cairo_save (cr);
4568
4569   switch (type)
4570     {
4571     case GTK_TREE_VIEW_TREE_LINE:
4572       cairo_set_source_rgb (cr, 0, 0, 0);
4573       cairo_set_line_width (cr, tree_view->priv->tree_line_width);
4574       if (tree_view->priv->tree_line_dashes[0])
4575         cairo_set_dash (cr, 
4576                         tree_view->priv->tree_line_dashes,
4577                         2, 0.5);
4578       break;
4579     case GTK_TREE_VIEW_GRID_LINE:
4580       cairo_set_source_rgb (cr, 0, 0, 0);
4581       cairo_set_line_width (cr, tree_view->priv->grid_line_width);
4582       if (tree_view->priv->grid_line_dashes[0])
4583         cairo_set_dash (cr, 
4584                         tree_view->priv->grid_line_dashes,
4585                         2, 0.5);
4586       break;
4587     default:
4588       g_assert_not_reached ();
4589       /* fall through */
4590     case GTK_TREE_VIEW_FOREGROUND_LINE:
4591       {
4592         GtkStyleContext *context;
4593         GtkStateFlags state;
4594         GdkRGBA color;
4595
4596         context = gtk_widget_get_style_context (GTK_WIDGET (tree_view));
4597         state = gtk_widget_get_state_flags (GTK_WIDGET (tree_view));
4598
4599         cairo_set_line_width (cr, 1.0);
4600         gtk_style_context_get_color (context, state, &color);
4601         gdk_cairo_set_source_rgba (cr, &color);
4602       }
4603
4604       break;
4605     }
4606
4607   cairo_move_to (cr, x1 + 0.5, y1 + 0.5);
4608   cairo_line_to (cr, x2 + 0.5, y2 + 0.5);
4609   cairo_stroke (cr);
4610
4611   cairo_restore (cr);
4612 }
4613                          
4614 static void
4615 gtk_tree_view_draw_grid_lines (GtkTreeView    *tree_view,
4616                                cairo_t        *cr,
4617                                gint            n_visible_columns)
4618 {
4619   GList *list = tree_view->priv->columns;
4620   gint i = 0;
4621   gint current_x = 0;
4622
4623   if (tree_view->priv->grid_lines != GTK_TREE_VIEW_GRID_LINES_VERTICAL
4624       && tree_view->priv->grid_lines != GTK_TREE_VIEW_GRID_LINES_BOTH)
4625     return;
4626
4627   /* Only draw the lines for visible rows and columns */
4628   for (list = tree_view->priv->columns; list; list = list->next, i++)
4629     {
4630       GtkTreeViewColumn *column = list->data;
4631
4632       /* We don't want a line for the last column */
4633       if (i == n_visible_columns - 1)
4634         break;
4635
4636       if (!gtk_tree_view_column_get_visible (column))
4637         continue;
4638
4639       current_x += gtk_tree_view_column_get_width (column);
4640
4641       gtk_tree_view_draw_line (tree_view, cr,
4642                                GTK_TREE_VIEW_GRID_LINE,
4643                                current_x - 1, 0,
4644                                current_x - 1, tree_view->priv->height);
4645     }
4646 }
4647
4648 /* Warning: Very scary function.
4649  * Modify at your own risk
4650  *
4651  * KEEP IN SYNC WITH gtk_tree_view_create_row_drag_icon()!
4652  * FIXME: It's not...
4653  */
4654 static gboolean
4655 gtk_tree_view_bin_draw (GtkWidget      *widget,
4656                         cairo_t        *cr)
4657 {
4658   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
4659   GtkTreePath *path;
4660   GtkRBTree *tree;
4661   GList *list;
4662   GtkRBNode *node;
4663   GtkRBNode *cursor = NULL;
4664   GtkRBTree *cursor_tree = NULL;
4665   GtkRBNode *drag_highlight = NULL;
4666   GtkRBTree *drag_highlight_tree = NULL;
4667   GtkTreeIter iter;
4668   gint new_y;
4669   gint y_offset, cell_offset;
4670   gint max_height;
4671   gint depth;
4672   GdkRectangle background_area;
4673   GdkRectangle cell_area;
4674   GdkRectangle clip;
4675   guint flags;
4676   gint highlight_x;
4677   gint expander_cell_width;
4678   gint bin_window_width;
4679   gint bin_window_height;
4680   GtkTreePath *cursor_path;
4681   GtkTreePath *drag_dest_path;
4682   GList *first_column, *last_column;
4683   gint vertical_separator;
4684   gint horizontal_separator;
4685   gint focus_line_width;
4686   gboolean allow_rules;
4687   gboolean has_can_focus_cell;
4688   gboolean rtl;
4689   gint n_visible_columns;
4690   gint pointer_x, pointer_y;
4691   gint grid_line_width;
4692   gboolean got_pointer = FALSE;
4693   gboolean draw_vgrid_lines, draw_hgrid_lines;
4694   GtkStyleContext *context;
4695   GtkStateFlags state;
4696
4697   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
4698   context = gtk_widget_get_style_context (widget);
4699   state = gtk_widget_get_state_flags (widget);
4700
4701   gtk_widget_style_get (widget,
4702                         "horizontal-separator", &horizontal_separator,
4703                         "vertical-separator", &vertical_separator,
4704                         "allow-rules", &allow_rules,
4705                         "focus-line-width", &focus_line_width,
4706                         NULL);
4707
4708   if (tree_view->priv->tree == NULL)
4709     {
4710       draw_empty_focus (tree_view, cr);
4711       return TRUE;
4712     }
4713
4714   bin_window_width = gdk_window_get_width (tree_view->priv->bin_window);
4715   bin_window_height = gdk_window_get_height (tree_view->priv->bin_window);
4716   cairo_rectangle (cr, 0, 0, bin_window_width, bin_window_height);
4717   cairo_clip (cr);
4718   if (!gdk_cairo_get_clip_rectangle (cr, &clip))
4719     return TRUE;
4720
4721   new_y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, clip.y);
4722
4723   if (new_y < 0)
4724     new_y = 0;
4725   y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
4726
4727   if (tree_view->priv->height < bin_window_height)
4728     {
4729       gtk_style_context_save (context);
4730       gtk_style_context_set_state (context, state);
4731       gtk_style_context_add_class (context, GTK_STYLE_CLASS_CELL);
4732
4733       gtk_render_background (context, cr,
4734                              0, tree_view->priv->height,
4735                              bin_window_width,
4736                              bin_window_height - tree_view->priv->height);
4737
4738       gtk_style_context_restore (context);
4739     }
4740
4741   if (node == NULL)
4742     return TRUE;
4743
4744   /* find the path for the node */
4745   path = _gtk_tree_view_find_path ((GtkTreeView *)widget,
4746                                    tree,
4747                                    node);
4748   gtk_tree_model_get_iter (tree_view->priv->model,
4749                            &iter,
4750                            path);
4751   depth = gtk_tree_path_get_depth (path);
4752   gtk_tree_path_free (path);
4753   
4754   cursor_path = NULL;
4755   drag_dest_path = NULL;
4756
4757   if (tree_view->priv->cursor)
4758     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
4759
4760   if (cursor_path)
4761     _gtk_tree_view_find_node (tree_view, cursor_path,
4762                               &cursor_tree, &cursor);
4763
4764   if (tree_view->priv->drag_dest_row)
4765     drag_dest_path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
4766
4767   if (drag_dest_path)
4768     _gtk_tree_view_find_node (tree_view, drag_dest_path,
4769                               &drag_highlight_tree, &drag_highlight);
4770
4771   draw_vgrid_lines =
4772     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_VERTICAL
4773     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
4774   draw_hgrid_lines =
4775     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_HORIZONTAL
4776     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
4777
4778   if (draw_vgrid_lines || draw_hgrid_lines)
4779     gtk_widget_style_get (widget, "grid-line-width", &grid_line_width, NULL);
4780   
4781   n_visible_columns = 0;
4782   for (list = tree_view->priv->columns; list; list = list->next)
4783     {
4784       if (!gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (list->data)))
4785         continue;
4786       n_visible_columns ++;
4787     }
4788
4789   /* Find the last column */
4790   for (last_column = g_list_last (tree_view->priv->columns);
4791        last_column &&
4792        !(gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (last_column->data)));
4793        last_column = last_column->prev)
4794     ;
4795
4796   /* and the first */
4797   for (first_column = g_list_first (tree_view->priv->columns);
4798        first_column &&
4799        !(gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (first_column->data)));
4800        first_column = first_column->next)
4801     ;
4802
4803   /* Actually process the expose event.  To do this, we want to
4804    * start at the first node of the event, and walk the tree in
4805    * order, drawing each successive node.
4806    */
4807
4808   do
4809     {
4810       gboolean parity;
4811       gboolean is_separator = FALSE;
4812       gboolean is_first = FALSE;
4813       gboolean is_last = FALSE;
4814       gint n_col = 0;
4815
4816       is_separator = row_is_separator (tree_view, &iter, NULL);
4817
4818       max_height = gtk_tree_view_get_row_height (tree_view, node);
4819
4820       cell_offset = 0;
4821       highlight_x = 0; /* should match x coord of first cell */
4822       expander_cell_width = 0;
4823
4824       background_area.y = y_offset + clip.y;
4825       background_area.height = max_height;
4826
4827       flags = 0;
4828
4829       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PRELIT))
4830         flags |= GTK_CELL_RENDERER_PRELIT;
4831
4832       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
4833         flags |= GTK_CELL_RENDERER_SELECTED;
4834
4835       parity = _gtk_rbtree_node_find_parity (tree, node);
4836
4837       /* we *need* to set cell data on all cells before the call
4838        * to _has_can_focus_cell, else _has_can_focus_cell() does not
4839        * return a correct value.
4840        */
4841       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
4842            list;
4843            list = (rtl ? list->prev : list->next))
4844         {
4845           GtkTreeViewColumn *column = list->data;
4846           gtk_tree_view_column_cell_set_cell_data (column,
4847                                                    tree_view->priv->model,
4848                                                    &iter,
4849                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
4850                                                    node->children?TRUE:FALSE);
4851         }
4852
4853       has_can_focus_cell = gtk_tree_view_has_can_focus_cell (tree_view);
4854
4855       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
4856            list;
4857            list = (rtl ? list->prev : list->next))
4858         {
4859           GtkTreeViewColumn *column = list->data;
4860           GtkRegionFlags row_flags = 0, column_flags = 0;
4861           GtkStateFlags state = 0;
4862           gint width;
4863           gboolean draw_focus;
4864
4865           if (!gtk_tree_view_column_get_visible (column))
4866             continue;
4867
4868           n_col++;
4869           width = gtk_tree_view_column_get_width (column);
4870
4871           if (cell_offset > clip.x + clip.width ||
4872               cell_offset + width < clip.x)
4873             {
4874               cell_offset += width;
4875               continue;
4876             }
4877
4878           if (gtk_tree_view_column_get_sort_indicator (column))
4879             flags |= GTK_CELL_RENDERER_SORTED;
4880           else
4881             flags &= ~GTK_CELL_RENDERER_SORTED;
4882
4883           if (cursor == node)
4884             flags |= GTK_CELL_RENDERER_FOCUSED;
4885           else
4886             flags &= ~GTK_CELL_RENDERER_FOCUSED;
4887
4888           background_area.x = cell_offset;
4889           background_area.width = width;
4890
4891           cell_area = background_area;
4892           cell_area.y += vertical_separator / 2;
4893           cell_area.x += horizontal_separator / 2;
4894           cell_area.height -= vertical_separator;
4895           cell_area.width -= horizontal_separator;
4896
4897           if (draw_vgrid_lines)
4898             {
4899               if (list == first_column)
4900                 {
4901                   cell_area.width -= grid_line_width / 2;
4902                 }
4903               else if (list == last_column)
4904                 {
4905                   cell_area.x += grid_line_width / 2;
4906                   cell_area.width -= grid_line_width / 2;
4907                 }
4908               else
4909                 {
4910                   cell_area.x += grid_line_width / 2;
4911                   cell_area.width -= grid_line_width;
4912                 }
4913             }
4914
4915           if (draw_hgrid_lines)
4916             {
4917               cell_area.y += grid_line_width / 2;
4918               cell_area.height -= grid_line_width;
4919             }
4920
4921           if (!gdk_rectangle_intersect (&clip, &background_area, NULL))
4922             {
4923               cell_offset += gtk_tree_view_column_get_width (column);
4924               continue;
4925             }
4926
4927           gtk_tree_view_column_cell_set_cell_data (column,
4928                                                    tree_view->priv->model,
4929                                                    &iter,
4930                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
4931                                                    node->children?TRUE:FALSE);
4932
4933           /* Select the detail for drawing the cell.  relevant
4934            * factors are parity, sortedness, and whether to
4935            * display rules.
4936            */
4937           if (allow_rules && tree_view->priv->has_rules)
4938             {
4939               if (parity)
4940                 row_flags |= GTK_REGION_ODD;
4941               else
4942                 row_flags |= GTK_REGION_EVEN;
4943             }
4944
4945           if ((flags & GTK_CELL_RENDERER_SORTED) &&
4946               n_visible_columns >= 3)
4947             column_flags |= GTK_REGION_SORTED;
4948
4949           is_first = (rtl ? !list->next : !list->prev);
4950           is_last = (rtl ? !list->prev : !list->next);
4951
4952           if (is_first)
4953             column_flags |= GTK_REGION_FIRST;
4954
4955           if (is_last)
4956             column_flags |= GTK_REGION_LAST;
4957
4958           if ((n_col % 2) == 0)
4959             column_flags |= GTK_REGION_EVEN;
4960           else
4961             column_flags |= GTK_REGION_ODD;
4962
4963           gtk_style_context_save (context);
4964
4965           state = gtk_cell_renderer_get_state (NULL, widget, flags);
4966           gtk_style_context_set_state (context, state);
4967
4968           gtk_style_context_add_class (context, GTK_STYLE_CLASS_CELL);
4969           gtk_style_context_add_region (context, GTK_STYLE_REGION_ROW, row_flags);
4970           gtk_style_context_add_region (context, GTK_STYLE_REGION_COLUMN, column_flags);
4971
4972           if (node == cursor && has_can_focus_cell
4973               && ((column == tree_view->priv->focus_column
4974                    && tree_view->priv->draw_keyfocus &&
4975                    gtk_widget_has_visible_focus (widget))
4976                   || (column == tree_view->priv->edited_column)))
4977             draw_focus = TRUE;
4978           else
4979             draw_focus = FALSE;
4980
4981           /* Draw background */
4982           gtk_render_background (context, cr,
4983                                  background_area.x,
4984                                  background_area.y,
4985                                  background_area.width,
4986                                  background_area.height);
4987
4988           /* Draw frame */
4989           gtk_render_frame (context, cr,
4990                             background_area.x,
4991                             background_area.y,
4992                             background_area.width,
4993                             background_area.height);
4994
4995           if (gtk_tree_view_is_expander_column (tree_view, column))
4996             {
4997               if (!rtl)
4998                 cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
4999               cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
5000
5001               if (gtk_tree_view_draw_expanders (tree_view))
5002                 {
5003                   if (!rtl)
5004                     cell_area.x += depth * tree_view->priv->expander_size;
5005                   cell_area.width -= depth * tree_view->priv->expander_size;
5006                 }
5007
5008               /* If we have an expander column, the highlight underline
5009                * starts with that column, so that it indicates which
5010                * level of the tree we're dropping at.
5011                */
5012               highlight_x = cell_area.x;
5013               expander_cell_width = cell_area.width;
5014
5015               if (is_separator)
5016                 {
5017                   gtk_style_context_save (context);
5018                   gtk_style_context_add_class (context, GTK_STYLE_CLASS_SEPARATOR);
5019
5020                   gtk_render_line (context, cr,
5021                                    cell_area.x,
5022                                    cell_area.y + cell_area.height / 2,
5023                                    cell_area.x + cell_area.width,
5024                                    cell_area.y + cell_area.height / 2);
5025
5026                   gtk_style_context_restore (context);
5027                 }
5028               else
5029                 {
5030                   _gtk_tree_view_column_cell_render (column,
5031                                                      cr,
5032                                                      &background_area,
5033                                                      &cell_area,
5034                                                      flags,
5035                                                      draw_focus);
5036                 }
5037
5038               if (gtk_tree_view_draw_expanders (tree_view)
5039                   && (node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT)
5040                 {
5041                   if (!got_pointer)
5042                     {
5043                       gdk_window_get_pointer (tree_view->priv->bin_window, 
5044                                               &pointer_x, &pointer_y, NULL);
5045                       got_pointer = TRUE;
5046                     }
5047
5048                   gtk_tree_view_draw_arrow (GTK_TREE_VIEW (widget),
5049                                             cr,
5050                                             tree,
5051                                             node,
5052                                             pointer_x, pointer_y);
5053                 }
5054             }
5055           else
5056             {
5057               if (is_separator)
5058                 {
5059                   gtk_style_context_save (context);
5060                   gtk_style_context_add_class (context, GTK_STYLE_CLASS_SEPARATOR);
5061
5062                   gtk_render_line (context, cr,
5063                                    cell_area.x,
5064                                    cell_area.y + cell_area.height / 2,
5065                                    cell_area.x + cell_area.width,
5066                                    cell_area.y + cell_area.height / 2);
5067
5068                   gtk_style_context_restore (context);
5069                 }
5070               else
5071                 _gtk_tree_view_column_cell_render (column,
5072                                                    cr,
5073                                                    &background_area,
5074                                                    &cell_area,
5075                                                    flags,
5076                                                    draw_focus);
5077             }
5078
5079           if (draw_hgrid_lines)
5080             {
5081               if (background_area.y > 0)
5082                 gtk_tree_view_draw_line (tree_view, cr,
5083                                          GTK_TREE_VIEW_GRID_LINE,
5084                                          background_area.x, background_area.y,
5085                                          background_area.x + background_area.width,
5086                                          background_area.y);
5087
5088               if (y_offset + max_height >= clip.height)
5089                 gtk_tree_view_draw_line (tree_view, cr,
5090                                          GTK_TREE_VIEW_GRID_LINE,
5091                                          background_area.x, background_area.y + max_height,
5092                                          background_area.x + background_area.width,
5093                                          background_area.y + max_height);
5094             }
5095
5096           if (gtk_tree_view_is_expander_column (tree_view, column) &&
5097               tree_view->priv->tree_lines_enabled)
5098             {
5099               gint x = background_area.x;
5100               gint mult = rtl ? -1 : 1;
5101               gint y0 = background_area.y;
5102               gint y1 = background_area.y + background_area.height/2;
5103               gint y2 = background_area.y + background_area.height;
5104
5105               if (rtl)
5106                 x += background_area.width - 1;
5107
5108               if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT
5109                   && depth > 1)
5110                 {
5111                   gtk_tree_view_draw_line (tree_view, cr,
5112                                            GTK_TREE_VIEW_TREE_LINE,
5113                                            x + tree_view->priv->expander_size * (depth - 1.5) * mult,
5114                                            y1,
5115                                            x + tree_view->priv->expander_size * (depth - 1.1) * mult,
5116                                            y1);
5117                 }
5118               else if (depth > 1)
5119                 {
5120                   gtk_tree_view_draw_line (tree_view, cr,
5121                                            GTK_TREE_VIEW_TREE_LINE,
5122                                            x + tree_view->priv->expander_size * (depth - 1.5) * mult,
5123                                            y1,
5124                                            x + tree_view->priv->expander_size * (depth - 0.5) * mult,
5125                                            y1);
5126                 }
5127
5128               if (depth > 1)
5129                 {
5130                   gint i;
5131                   GtkRBNode *tmp_node;
5132                   GtkRBTree *tmp_tree;
5133
5134                   if (!_gtk_rbtree_next (tree, node))
5135                     gtk_tree_view_draw_line (tree_view, cr,
5136                                              GTK_TREE_VIEW_TREE_LINE,
5137                                              x + tree_view->priv->expander_size * (depth - 1.5) * mult,
5138                                              y0,
5139                                              x + tree_view->priv->expander_size * (depth - 1.5) * mult,
5140                                              y1);
5141                   else
5142                     gtk_tree_view_draw_line (tree_view, cr,
5143                                              GTK_TREE_VIEW_TREE_LINE,
5144                                              x + tree_view->priv->expander_size * (depth - 1.5) * mult,
5145                                              y0,
5146                                              x + tree_view->priv->expander_size * (depth - 1.5) * mult,
5147                                              y2);
5148
5149                   tmp_node = tree->parent_node;
5150                   tmp_tree = tree->parent_tree;
5151
5152                   for (i = depth - 2; i > 0; i--)
5153                     {
5154                       if (_gtk_rbtree_next (tmp_tree, tmp_node))
5155                         gtk_tree_view_draw_line (tree_view, cr,
5156                                                  GTK_TREE_VIEW_TREE_LINE,
5157                                                  x + tree_view->priv->expander_size * (i - 0.5) * mult,
5158                                                  y0,
5159                                                  x + tree_view->priv->expander_size * (i - 0.5) * mult,
5160                                                  y2);
5161
5162                       tmp_node = tmp_tree->parent_node;
5163                       tmp_tree = tmp_tree->parent_tree;
5164                     }
5165                 }
5166             }
5167
5168           gtk_style_context_restore (context);
5169           cell_offset += gtk_tree_view_column_get_width (column);
5170         }
5171
5172       if (node == drag_highlight)
5173         {
5174           /* Draw indicator for the drop
5175            */
5176           gint highlight_y = -1;
5177           GtkRBTree *tree = NULL;
5178           GtkRBNode *node = NULL;
5179
5180           switch (tree_view->priv->drag_dest_pos)
5181             {
5182             case GTK_TREE_VIEW_DROP_BEFORE:
5183               highlight_y = background_area.y - 1;
5184               if (highlight_y < 0)
5185                       highlight_y = 0;
5186               break;
5187
5188             case GTK_TREE_VIEW_DROP_AFTER:
5189               highlight_y = background_area.y + background_area.height - 1;
5190               break;
5191
5192             case GTK_TREE_VIEW_DROP_INTO_OR_BEFORE:
5193             case GTK_TREE_VIEW_DROP_INTO_OR_AFTER:
5194               _gtk_tree_view_find_node (tree_view, drag_dest_path, &tree, &node);
5195
5196               if (tree == NULL)
5197                 break;
5198
5199               gtk_render_focus (context, cr,
5200                                 0, gtk_tree_view_get_row_y_offset (tree_view, tree, node)
5201                                    - focus_line_width / 2,
5202                                 gdk_window_get_width (tree_view->priv->bin_window),
5203                                 gtk_tree_view_get_row_height (tree_view, node)
5204                                    - focus_line_width + 1);
5205               break;
5206             }
5207
5208           if (highlight_y >= 0)
5209             {
5210               gtk_tree_view_draw_line (tree_view, cr,
5211                                        GTK_TREE_VIEW_FOREGROUND_LINE,
5212                                        rtl ? highlight_x + expander_cell_width : highlight_x,
5213                                        highlight_y,
5214                                        rtl ? 0 : bin_window_width,
5215                                        highlight_y);
5216             }
5217         }
5218
5219       /* draw the big row-spanning focus rectangle, if needed */
5220       if (!has_can_focus_cell && node == cursor &&
5221           tree_view->priv->draw_keyfocus &&
5222           gtk_widget_has_visible_focus (widget))
5223         {
5224           gint tmp_y, tmp_height;
5225           GtkStateFlags focus_rect_state = 0;
5226
5227           gtk_style_context_save (context);
5228
5229           focus_rect_state = gtk_cell_renderer_get_state (NULL, widget, flags);
5230           gtk_style_context_set_state (context, focus_rect_state);
5231
5232           if (draw_hgrid_lines)
5233             {
5234               tmp_y = gtk_tree_view_get_row_y_offset (tree_view, tree, node) + grid_line_width / 2;
5235               tmp_height = gtk_tree_view_get_row_height (tree_view, node) - grid_line_width;
5236             }
5237           else
5238             {
5239               tmp_y = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
5240               tmp_height = gtk_tree_view_get_row_height (tree_view, node);
5241             }
5242
5243           gtk_render_focus (context, cr,
5244                             0, tmp_y,
5245                             gdk_window_get_width (tree_view->priv->bin_window),
5246                             tmp_height);
5247
5248           gtk_style_context_restore (context);
5249         }
5250
5251       y_offset += max_height;
5252       if (node->children)
5253         {
5254           GtkTreeIter parent = iter;
5255           gboolean has_child;
5256
5257           tree = node->children;
5258           node = tree->root;
5259
5260           g_assert (node != tree->nil);
5261
5262           while (node->left != tree->nil)
5263             node = node->left;
5264           has_child = gtk_tree_model_iter_children (tree_view->priv->model,
5265                                                     &iter,
5266                                                     &parent);
5267           depth++;
5268
5269           /* Sanity Check! */
5270           TREE_VIEW_INTERNAL_ASSERT (has_child, FALSE);
5271         }
5272       else
5273         {
5274           gboolean done = FALSE;
5275
5276           do
5277             {
5278               node = _gtk_rbtree_next (tree, node);
5279               if (node != NULL)
5280                 {
5281                   gboolean has_next = gtk_tree_model_iter_next (tree_view->priv->model, &iter);
5282                   done = TRUE;
5283
5284                   /* Sanity Check! */
5285                   TREE_VIEW_INTERNAL_ASSERT (has_next, FALSE);
5286                 }
5287               else
5288                 {
5289                   GtkTreeIter parent_iter = iter;
5290                   gboolean has_parent;
5291
5292                   node = tree->parent_node;
5293                   tree = tree->parent_tree;
5294                   if (tree == NULL)
5295                     /* we should go to done to free some memory */
5296                     goto done;
5297                   has_parent = gtk_tree_model_iter_parent (tree_view->priv->model,
5298                                                            &iter,
5299                                                            &parent_iter);
5300                   depth--;
5301
5302                   /* Sanity check */
5303                   TREE_VIEW_INTERNAL_ASSERT (has_parent, FALSE);
5304                 }
5305             }
5306           while (!done);
5307         }
5308     }
5309   while (y_offset < clip.height);
5310
5311 done:
5312   gtk_tree_view_draw_grid_lines (tree_view, cr, n_visible_columns);
5313
5314   if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
5315     gtk_tree_view_paint_rubber_band (tree_view, cr);
5316
5317   if (cursor_path)
5318     gtk_tree_path_free (cursor_path);
5319
5320   if (drag_dest_path)
5321     gtk_tree_path_free (drag_dest_path);
5322
5323   return FALSE;
5324 }
5325
5326 static gboolean
5327 gtk_tree_view_draw (GtkWidget *widget,
5328                     cairo_t   *cr)
5329 {
5330   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
5331   GtkWidget   *button;
5332
5333   if (gtk_cairo_should_draw_window (cr, tree_view->priv->bin_window))
5334     {
5335       GtkStyleContext *context;
5336       GList *tmp_list;
5337
5338       context = gtk_widget_get_style_context (widget);
5339
5340       cairo_save (cr);
5341
5342       gtk_style_context_save (context);
5343       gtk_style_context_add_class (context, GTK_STYLE_CLASS_VIEW);
5344
5345       gtk_cairo_transform_to_window (cr, widget, tree_view->priv->bin_window);
5346
5347       gtk_tree_view_bin_draw (widget, cr);
5348
5349       gtk_style_context_restore (context);
5350       cairo_restore (cr);
5351
5352       /* We can't just chain up to Container::draw as it will try to send the
5353        * event to the headers, so we handle propagating it to our children
5354        * (eg. widgets being edited) ourselves.
5355        */
5356       tmp_list = tree_view->priv->children;
5357       while (tmp_list)
5358         {
5359           GtkTreeViewChild *child = tmp_list->data;
5360           tmp_list = tmp_list->next;
5361
5362           gtk_container_propagate_draw (GTK_CONTAINER (tree_view), child->widget, cr);
5363         }
5364     }
5365
5366   if (gtk_cairo_should_draw_window (cr, tree_view->priv->header_window))
5367     {
5368       GList *list;
5369       
5370       for (list = tree_view->priv->columns; list != NULL; list = list->next)
5371         {
5372           GtkTreeViewColumn *column = list->data;
5373
5374           if (column == tree_view->priv->drag_column)
5375             continue;
5376
5377           if (gtk_tree_view_column_get_visible (column))
5378             {
5379               button = gtk_tree_view_column_get_button (column);
5380               gtk_container_propagate_draw (GTK_CONTAINER (tree_view),
5381                                             button, cr);
5382             }
5383         }
5384     }
5385   
5386   if (tree_view->priv->drag_window &&
5387       gtk_cairo_should_draw_window (cr, tree_view->priv->drag_window))
5388     {
5389       button = gtk_tree_view_column_get_button (tree_view->priv->drag_column);
5390       gtk_container_propagate_draw (GTK_CONTAINER (tree_view),
5391                                     button, cr);
5392     }
5393
5394   return FALSE;
5395 }
5396
5397 enum
5398 {
5399   DROP_HOME,
5400   DROP_RIGHT,
5401   DROP_LEFT,
5402   DROP_END
5403 };
5404
5405 /* returns 0x1 when no column has been found -- yes it's hackish */
5406 static GtkTreeViewColumn *
5407 gtk_tree_view_get_drop_column (GtkTreeView       *tree_view,
5408                                GtkTreeViewColumn *column,
5409                                gint               drop_position)
5410 {
5411   GtkTreeViewColumn *left_column = NULL;
5412   GtkTreeViewColumn *cur_column = NULL;
5413   GList *tmp_list;
5414
5415   if (!gtk_tree_view_column_get_reorderable (column))
5416     return (GtkTreeViewColumn *)0x1;
5417
5418   switch (drop_position)
5419     {
5420       case DROP_HOME:
5421         /* find first column where we can drop */
5422         tmp_list = tree_view->priv->columns;
5423         if (column == GTK_TREE_VIEW_COLUMN (tmp_list->data))
5424           return (GtkTreeViewColumn *)0x1;
5425
5426         while (tmp_list)
5427           {
5428             g_assert (tmp_list);
5429
5430             cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5431             tmp_list = tmp_list->next;
5432
5433             if (left_column &&
5434                 gtk_tree_view_column_get_visible (left_column) == FALSE)
5435               continue;
5436
5437             if (!tree_view->priv->column_drop_func)
5438               return left_column;
5439
5440             if (!tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5441               {
5442                 left_column = cur_column;
5443                 continue;
5444               }
5445
5446             return left_column;
5447           }
5448
5449         if (!tree_view->priv->column_drop_func)
5450           return left_column;
5451
5452         if (tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data))
5453           return left_column;
5454         else
5455           return (GtkTreeViewColumn *)0x1;
5456         break;
5457
5458       case DROP_RIGHT:
5459         /* find first column after column where we can drop */
5460         tmp_list = tree_view->priv->columns;
5461
5462         for (; tmp_list; tmp_list = tmp_list->next)
5463           if (GTK_TREE_VIEW_COLUMN (tmp_list->data) == column)
5464             break;
5465
5466         if (!tmp_list || !tmp_list->next)
5467           return (GtkTreeViewColumn *)0x1;
5468
5469         tmp_list = tmp_list->next;
5470         left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5471         tmp_list = tmp_list->next;
5472
5473         while (tmp_list)
5474           {
5475             g_assert (tmp_list);
5476
5477             cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5478             tmp_list = tmp_list->next;
5479
5480             if (left_column &&
5481                 gtk_tree_view_column_get_visible (left_column) == FALSE)
5482               {
5483                 left_column = cur_column;
5484                 if (tmp_list)
5485                   tmp_list = tmp_list->next;
5486                 continue;
5487               }
5488
5489             if (!tree_view->priv->column_drop_func)
5490               return left_column;
5491
5492             if (!tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5493               {
5494                 left_column = cur_column;
5495                 continue;
5496               }
5497
5498             return left_column;
5499           }
5500
5501         if (!tree_view->priv->column_drop_func)
5502           return left_column;
5503
5504         if (tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data))
5505           return left_column;
5506         else
5507           return (GtkTreeViewColumn *)0x1;
5508         break;
5509
5510       case DROP_LEFT:
5511         /* find first column before column where we can drop */
5512         tmp_list = tree_view->priv->columns;
5513
5514         for (; tmp_list; tmp_list = tmp_list->next)
5515           if (GTK_TREE_VIEW_COLUMN (tmp_list->data) == column)
5516             break;
5517
5518         if (!tmp_list || !tmp_list->prev)
5519           return (GtkTreeViewColumn *)0x1;
5520
5521         tmp_list = tmp_list->prev;
5522         cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5523         tmp_list = tmp_list->prev;
5524
5525         while (tmp_list)
5526           {
5527             g_assert (tmp_list);
5528
5529             left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5530
5531             if (left_column &&
5532                 gtk_tree_view_column_get_visible (left_column) == FALSE)
5533               {
5534                 /*if (!tmp_list->prev)
5535                   return (GtkTreeViewColumn *)0x1;
5536                   */
5537 /*
5538                 cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->prev->data);
5539                 tmp_list = tmp_list->prev->prev;
5540                 continue;*/
5541
5542                 cur_column = left_column;
5543                 if (tmp_list)
5544                   tmp_list = tmp_list->prev;
5545                 continue;
5546               }
5547
5548             if (!tree_view->priv->column_drop_func)
5549               return left_column;
5550
5551             if (tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5552               return left_column;
5553
5554             cur_column = left_column;
5555             tmp_list = tmp_list->prev;
5556           }
5557
5558         if (!tree_view->priv->column_drop_func)
5559           return NULL;
5560
5561         if (tree_view->priv->column_drop_func (tree_view, column, NULL, cur_column, tree_view->priv->column_drop_func_data))
5562           return NULL;
5563         else
5564           return (GtkTreeViewColumn *)0x1;
5565         break;
5566
5567       case DROP_END:
5568         /* same as DROP_HOME case, but doing it backwards */
5569         tmp_list = g_list_last (tree_view->priv->columns);
5570         cur_column = NULL;
5571
5572         if (column == GTK_TREE_VIEW_COLUMN (tmp_list->data))
5573           return (GtkTreeViewColumn *)0x1;
5574
5575         while (tmp_list)
5576           {
5577             g_assert (tmp_list);
5578
5579             left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5580
5581             if (left_column &&
5582                 gtk_tree_view_column_get_visible (left_column) == FALSE)
5583               {
5584                 cur_column = left_column;
5585                 tmp_list = tmp_list->prev;
5586               }
5587
5588             if (!tree_view->priv->column_drop_func)
5589               return left_column;
5590
5591             if (tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5592               return left_column;
5593
5594             cur_column = left_column;
5595             tmp_list = tmp_list->prev;
5596           }
5597
5598         if (!tree_view->priv->column_drop_func)
5599           return NULL;
5600
5601         if (tree_view->priv->column_drop_func (tree_view, column, NULL, cur_column, tree_view->priv->column_drop_func_data))
5602           return NULL;
5603         else
5604           return (GtkTreeViewColumn *)0x1;
5605         break;
5606     }
5607
5608   return (GtkTreeViewColumn *)0x1;
5609 }
5610
5611 static gboolean
5612 gtk_tree_view_key_press (GtkWidget   *widget,
5613                          GdkEventKey *event)
5614 {
5615   GtkTreeView *tree_view = (GtkTreeView *) widget;
5616   GtkWidget   *button;
5617
5618   if (tree_view->priv->rubber_band_status)
5619     {
5620       if (event->keyval == GDK_KEY_Escape)
5621         gtk_tree_view_stop_rubber_band (tree_view);
5622
5623       return TRUE;
5624     }
5625
5626   if (tree_view->priv->in_column_drag)
5627     {
5628       if (event->keyval == GDK_KEY_Escape)
5629         {
5630           tree_view->priv->cur_reorder = NULL;
5631           gtk_tree_view_button_release_drag_column (widget, NULL);
5632         }
5633       return TRUE;
5634     }
5635
5636   if (tree_view->priv->headers_visible)
5637     {
5638       GList *focus_column;
5639       gboolean rtl;
5640
5641       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
5642
5643       for (focus_column = tree_view->priv->columns;
5644            focus_column;
5645            focus_column = focus_column->next)
5646         {
5647           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
5648           
5649           button = gtk_tree_view_column_get_button (column);
5650           if (gtk_widget_has_focus (button))
5651             break;
5652         }
5653
5654       if (focus_column &&
5655           (event->state & GDK_SHIFT_MASK) && (event->state & GDK_MOD1_MASK) &&
5656           (event->keyval == GDK_KEY_Left || event->keyval == GDK_KEY_KP_Left
5657            || event->keyval == GDK_KEY_Right || event->keyval == GDK_KEY_KP_Right))
5658         {
5659           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
5660           gint max_width, min_width;
5661
5662           if (!gtk_tree_view_column_get_resizable (column))
5663             {
5664               gtk_widget_error_bell (widget);
5665               return TRUE;
5666             }
5667
5668           if (event->keyval == (rtl ? GDK_KEY_Right : GDK_KEY_Left)
5669               || event->keyval == (rtl ? GDK_KEY_KP_Right : GDK_KEY_KP_Left))
5670             {
5671               GtkRequisition button_req;
5672               gint old_width = _gtk_tree_view_column_get_resized_width (column);
5673               gint new_width;
5674
5675               button = gtk_tree_view_column_get_button (column);
5676
5677               gtk_widget_get_preferred_size (button, &button_req, NULL);
5678
5679               new_width = MAX (old_width, gtk_tree_view_column_get_width (column));
5680               new_width -= 2;
5681               if (new_width < 0)
5682                 new_width = 0;
5683
5684               _gtk_tree_view_column_set_resized_width (column, new_width);
5685
5686               min_width = gtk_tree_view_column_get_min_width (column);
5687               if (min_width == -1)
5688                 new_width = MAX (button_req.width, new_width);
5689               else
5690                 {
5691                   new_width = MAX (min_width, new_width);
5692                 }
5693
5694               max_width = gtk_tree_view_column_get_max_width (column);
5695               if (max_width != -1)
5696                 new_width = MIN (new_width, max_width);
5697
5698               _gtk_tree_view_column_set_use_resized_width (column, TRUE);
5699
5700               if (new_width != old_width)
5701                 {
5702                   _gtk_tree_view_column_set_resized_width (column, new_width);
5703                   gtk_widget_queue_resize (widget);
5704                 }
5705               else
5706                 gtk_widget_error_bell (widget);
5707             }
5708           else if (event->keyval == (rtl ? GDK_KEY_Left : GDK_KEY_Right)
5709                    || event->keyval == (rtl ? GDK_KEY_KP_Left : GDK_KEY_KP_Right))
5710             {
5711               gint old_width = _gtk_tree_view_column_get_resized_width (column);
5712               gint new_width;
5713
5714               new_width = MAX (old_width, gtk_tree_view_column_get_width (column));
5715               new_width += 2;
5716
5717               max_width = gtk_tree_view_column_get_max_width (column);
5718               if (max_width != -1)
5719                 new_width = MIN (new_width, max_width);
5720
5721               _gtk_tree_view_column_set_use_resized_width (column, TRUE);
5722
5723               if (new_width != old_width)
5724                 {
5725                   _gtk_tree_view_column_set_resized_width (column, new_width);
5726                   gtk_widget_queue_resize (widget);
5727                 }
5728               else
5729                 gtk_widget_error_bell (widget);
5730             }
5731
5732           return TRUE;
5733         }
5734
5735       if (focus_column &&
5736           (event->state & GDK_MOD1_MASK) &&
5737           (event->keyval == GDK_KEY_Left || event->keyval == GDK_KEY_KP_Left
5738            || event->keyval == GDK_KEY_Right || event->keyval == GDK_KEY_KP_Right
5739            || event->keyval == GDK_KEY_Home || event->keyval == GDK_KEY_KP_Home
5740            || event->keyval == GDK_KEY_End || event->keyval == GDK_KEY_KP_End))
5741         {
5742           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
5743
5744           if (event->keyval == (rtl ? GDK_KEY_Right : GDK_KEY_Left)
5745               || event->keyval == (rtl ? GDK_KEY_KP_Right : GDK_KEY_KP_Left))
5746             {
5747               GtkTreeViewColumn *col;
5748               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_LEFT);
5749               if (col != (GtkTreeViewColumn *)0x1)
5750                 gtk_tree_view_move_column_after (tree_view, column, col);
5751               else
5752                 gtk_widget_error_bell (widget);
5753             }
5754           else if (event->keyval == (rtl ? GDK_KEY_Left : GDK_KEY_Right)
5755                    || event->keyval == (rtl ? GDK_KEY_KP_Left : GDK_KEY_KP_Right))
5756             {
5757               GtkTreeViewColumn *col;
5758               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_RIGHT);
5759               if (col != (GtkTreeViewColumn *)0x1)
5760                 gtk_tree_view_move_column_after (tree_view, column, col);
5761               else
5762                 gtk_widget_error_bell (widget);
5763             }
5764           else if (event->keyval == GDK_KEY_Home || event->keyval == GDK_KEY_KP_Home)
5765             {
5766               GtkTreeViewColumn *col;
5767               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_HOME);
5768               if (col != (GtkTreeViewColumn *)0x1)
5769                 gtk_tree_view_move_column_after (tree_view, column, col);
5770               else
5771                 gtk_widget_error_bell (widget);
5772             }
5773           else if (event->keyval == GDK_KEY_End || event->keyval == GDK_KEY_KP_End)
5774             {
5775               GtkTreeViewColumn *col;
5776               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_END);
5777               if (col != (GtkTreeViewColumn *)0x1)
5778                 gtk_tree_view_move_column_after (tree_view, column, col);
5779               else
5780                 gtk_widget_error_bell (widget);
5781             }
5782
5783           return TRUE;
5784         }
5785     }
5786
5787   /* Chain up to the parent class.  It handles the keybindings. */
5788   if (GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->key_press_event (widget, event))
5789     return TRUE;
5790
5791   if (tree_view->priv->search_entry_avoid_unhandled_binding)
5792     {
5793       tree_view->priv->search_entry_avoid_unhandled_binding = FALSE;
5794       return FALSE;
5795     }
5796
5797   /* We pass the event to the search_entry.  If its text changes, then we start
5798    * the typeahead find capabilities. */
5799   if (gtk_widget_has_focus (GTK_WIDGET (tree_view))
5800       && tree_view->priv->enable_search
5801       && !tree_view->priv->search_custom_entry_set)
5802     {
5803       GdkEvent *new_event;
5804       char *old_text;
5805       const char *new_text;
5806       gboolean retval;
5807       GdkScreen *screen;
5808       gboolean text_modified;
5809       gulong popup_menu_id;
5810
5811       gtk_tree_view_ensure_interactive_directory (tree_view);
5812
5813       /* Make a copy of the current text */
5814       old_text = g_strdup (gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry)));
5815       new_event = gdk_event_copy ((GdkEvent *) event);
5816       g_object_unref (((GdkEventKey *) new_event)->window);
5817       ((GdkEventKey *) new_event)->window = g_object_ref (gtk_widget_get_window (tree_view->priv->search_window));
5818       gtk_widget_realize (tree_view->priv->search_window);
5819
5820       popup_menu_id = g_signal_connect (tree_view->priv->search_entry, 
5821                                         "popup-menu", G_CALLBACK (gtk_true),
5822                                         NULL);
5823
5824       /* Move the entry off screen */
5825       screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
5826       gtk_window_move (GTK_WINDOW (tree_view->priv->search_window),
5827                        gdk_screen_get_width (screen) + 1,
5828                        gdk_screen_get_height (screen) + 1);
5829       gtk_widget_show (tree_view->priv->search_window);
5830
5831       /* Send the event to the window.  If the preedit_changed signal is emitted
5832        * during this event, we will set priv->imcontext_changed  */
5833       tree_view->priv->imcontext_changed = FALSE;
5834       retval = gtk_widget_event (tree_view->priv->search_window, new_event);
5835       gdk_event_free (new_event);
5836       gtk_widget_hide (tree_view->priv->search_window);
5837
5838       g_signal_handler_disconnect (tree_view->priv->search_entry, 
5839                                    popup_menu_id);
5840
5841       /* We check to make sure that the entry tried to handle the text, and that
5842        * the text has changed.
5843        */
5844       new_text = gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry));
5845       text_modified = strcmp (old_text, new_text) != 0;
5846       g_free (old_text);
5847       if (tree_view->priv->imcontext_changed ||    /* we're in a preedit */
5848           (retval && text_modified))               /* ...or the text was modified */
5849         {
5850           if (gtk_tree_view_real_start_interactive_search (tree_view,
5851                                                            gdk_event_get_device ((GdkEvent *) event),
5852                                                            FALSE))
5853             {
5854               gtk_widget_grab_focus (GTK_WIDGET (tree_view));
5855               return TRUE;
5856             }
5857           else
5858             {
5859               gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
5860               return FALSE;
5861             }
5862         }
5863     }
5864
5865   return FALSE;
5866 }
5867
5868 static gboolean
5869 gtk_tree_view_key_release (GtkWidget   *widget,
5870                            GdkEventKey *event)
5871 {
5872   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
5873
5874   if (tree_view->priv->rubber_band_status)
5875     return TRUE;
5876
5877   return GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->key_release_event (widget, event);
5878 }
5879
5880 /* FIXME Is this function necessary? Can I get an enter_notify event
5881  * w/o either an expose event or a mouse motion event?
5882  */
5883 static gboolean
5884 gtk_tree_view_enter_notify (GtkWidget        *widget,
5885                             GdkEventCrossing *event)
5886 {
5887   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
5888   GtkRBTree *tree;
5889   GtkRBNode *node;
5890   gint new_y;
5891
5892   /* Sanity check it */
5893   if (event->window != tree_view->priv->bin_window)
5894     return FALSE;
5895
5896   if (tree_view->priv->tree == NULL)
5897     return FALSE;
5898
5899   if (event->mode == GDK_CROSSING_GRAB ||
5900       event->mode == GDK_CROSSING_GTK_GRAB ||
5901       event->mode == GDK_CROSSING_GTK_UNGRAB ||
5902       event->mode == GDK_CROSSING_STATE_CHANGED)
5903     return TRUE;
5904
5905   /* find the node internally */
5906   new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
5907   if (new_y < 0)
5908     new_y = 0;
5909   _gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
5910
5911   tree_view->priv->event_last_x = event->x;
5912   tree_view->priv->event_last_y = event->y;
5913
5914   if ((tree_view->priv->button_pressed_node == NULL) ||
5915       (tree_view->priv->button_pressed_node == node))
5916     prelight_or_select (tree_view, tree, node, event->x, event->y);
5917
5918   return TRUE;
5919 }
5920
5921 static gboolean
5922 gtk_tree_view_leave_notify (GtkWidget        *widget,
5923                             GdkEventCrossing *event)
5924 {
5925   GtkTreeView *tree_view;
5926
5927   if (event->mode == GDK_CROSSING_GRAB)
5928     return TRUE;
5929
5930   tree_view = GTK_TREE_VIEW (widget);
5931
5932   if (tree_view->priv->prelight_node)
5933     _gtk_tree_view_queue_draw_node (tree_view,
5934                                    tree_view->priv->prelight_tree,
5935                                    tree_view->priv->prelight_node,
5936                                    NULL);
5937
5938   tree_view->priv->event_last_x = -10000;
5939   tree_view->priv->event_last_y = -10000;
5940
5941   prelight_or_select (tree_view,
5942                       NULL, NULL,
5943                       -1000, -1000); /* coords not possibly over an arrow */
5944
5945   return TRUE;
5946 }
5947
5948
5949 static gint
5950 gtk_tree_view_focus_out (GtkWidget     *widget,
5951                          GdkEventFocus *event)
5952 {
5953   GtkTreeView *tree_view;
5954
5955   tree_view = GTK_TREE_VIEW (widget);
5956
5957   gtk_widget_queue_draw (widget);
5958
5959   /* destroy interactive search dialog */
5960   if (tree_view->priv->search_window)
5961     gtk_tree_view_search_dialog_hide (tree_view->priv->search_window, tree_view,
5962                                       gdk_event_get_device ((GdkEvent *) event));
5963
5964   return FALSE;
5965 }
5966
5967
5968 /* Incremental Reflow
5969  */
5970
5971 static void
5972 gtk_tree_view_node_queue_redraw (GtkTreeView *tree_view,
5973                                  GtkRBTree   *tree,
5974                                  GtkRBNode   *node)
5975 {
5976   GtkAllocation allocation;
5977   gint y;
5978
5979   y = _gtk_rbtree_node_find_offset (tree, node)
5980     - gtk_adjustment_get_value (tree_view->priv->vadjustment)
5981     + gtk_tree_view_get_effective_header_height (tree_view);
5982
5983   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
5984   gtk_widget_queue_draw_area (GTK_WIDGET (tree_view),
5985                               0, y,
5986                               allocation.width,
5987                               GTK_RBNODE_GET_HEIGHT (node));
5988 }
5989
5990 static gboolean
5991 node_is_visible (GtkTreeView *tree_view,
5992                  GtkRBTree   *tree,
5993                  GtkRBNode   *node)
5994 {
5995   int y;
5996   int height;
5997
5998   y = _gtk_rbtree_node_find_offset (tree, node);
5999   height = gtk_tree_view_get_row_height (tree_view, node);
6000
6001   if (y >= gtk_adjustment_get_value (tree_view->priv->vadjustment) &&
6002       y + height <= (gtk_adjustment_get_value (tree_view->priv->vadjustment)
6003                      + gtk_adjustment_get_page_size (tree_view->priv->vadjustment)))
6004     return TRUE;
6005
6006   return FALSE;
6007 }
6008
6009 /* Returns TRUE if it updated the size
6010  */
6011 static gboolean
6012 validate_row (GtkTreeView *tree_view,
6013               GtkRBTree   *tree,
6014               GtkRBNode   *node,
6015               GtkTreeIter *iter,
6016               GtkTreePath *path)
6017 {
6018   GtkTreeViewColumn *column;
6019   GList *list, *first_column, *last_column;
6020   gint height = 0;
6021   gint horizontal_separator;
6022   gint vertical_separator;
6023   gint depth = gtk_tree_path_get_depth (path);
6024   gboolean retval = FALSE;
6025   gboolean is_separator = FALSE;
6026   gboolean draw_vgrid_lines, draw_hgrid_lines;
6027   gint focus_pad;
6028   gint grid_line_width;
6029   gboolean wide_separators;
6030   gint separator_height;
6031
6032   /* double check the row needs validating */
6033   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) &&
6034       ! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6035     return FALSE;
6036
6037   is_separator = row_is_separator (tree_view, iter, NULL);
6038
6039   gtk_widget_style_get (GTK_WIDGET (tree_view),
6040                         "focus-padding", &focus_pad,
6041                         "horizontal-separator", &horizontal_separator,
6042                         "vertical-separator", &vertical_separator,
6043                         "grid-line-width", &grid_line_width,
6044                         "wide-separators",  &wide_separators,
6045                         "separator-height", &separator_height,
6046                         NULL);
6047   
6048   draw_vgrid_lines =
6049     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_VERTICAL
6050     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
6051   draw_hgrid_lines =
6052     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_HORIZONTAL
6053     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
6054
6055   for (last_column = g_list_last (tree_view->priv->columns);
6056        last_column &&
6057        !(gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (last_column->data)));
6058        last_column = last_column->prev)
6059     ;
6060
6061   for (first_column = g_list_first (tree_view->priv->columns);
6062        first_column &&
6063        !(gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (first_column->data)));
6064        first_column = first_column->next)
6065     ;
6066
6067   for (list = tree_view->priv->columns; list; list = list->next)
6068     {
6069       gint padding = 0;
6070       gint original_width;
6071       gint new_width;
6072       gint row_height;
6073
6074       column = list->data;
6075
6076       if (!gtk_tree_view_column_get_visible (column))
6077         continue;
6078
6079       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID) && 
6080           !_gtk_tree_view_column_cell_get_dirty (column))
6081         continue;
6082
6083       original_width = _gtk_tree_view_column_get_requested_width (column);
6084
6085       gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, iter,
6086                                                GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
6087                                                node->children?TRUE:FALSE);
6088       gtk_tree_view_column_cell_get_size (column,
6089                                           NULL, NULL, NULL,
6090                                           NULL, &row_height);
6091
6092       if (!is_separator)
6093         {
6094           row_height += vertical_separator;
6095           height = MAX (height, row_height);
6096           height = MAX (height, tree_view->priv->expander_size);
6097         }
6098       else
6099         {
6100           if (wide_separators)
6101             height = separator_height + 2 * focus_pad;
6102           else
6103             height = 2 + 2 * focus_pad;
6104         }
6105
6106       if (gtk_tree_view_is_expander_column (tree_view, column))
6107         {
6108           padding += horizontal_separator + (depth - 1) * tree_view->priv->level_indentation;
6109
6110           if (gtk_tree_view_draw_expanders (tree_view))
6111             padding += depth * tree_view->priv->expander_size;
6112         }
6113       else
6114         padding += horizontal_separator;
6115
6116       if (draw_vgrid_lines)
6117         {
6118           if (list->data == first_column || list->data == last_column)
6119             padding += grid_line_width / 2.0;
6120           else
6121             padding += grid_line_width;
6122         }
6123
6124       /* Update the padding for the column */
6125       _gtk_tree_view_column_push_padding (column, padding);
6126       new_width = _gtk_tree_view_column_get_requested_width (column);
6127
6128       if (new_width > original_width)
6129         retval = TRUE;
6130     }
6131
6132   if (draw_hgrid_lines)
6133     height += grid_line_width;
6134
6135   if (height != GTK_RBNODE_GET_HEIGHT (node))
6136     {
6137       retval = TRUE;
6138       _gtk_rbtree_node_set_height (tree, node, height);
6139     }
6140   _gtk_rbtree_node_mark_valid (tree, node);
6141   tree_view->priv->post_validation_flag = TRUE;
6142
6143   return retval;
6144 }
6145
6146
6147 static void
6148 validate_visible_area (GtkTreeView *tree_view)
6149 {
6150   GtkAllocation allocation;
6151   GtkTreePath *path = NULL;
6152   GtkTreePath *above_path = NULL;
6153   GtkTreeIter iter;
6154   GtkRBTree *tree = NULL;
6155   GtkRBNode *node = NULL;
6156   gboolean need_redraw = FALSE;
6157   gboolean size_changed = FALSE;
6158   gint total_height;
6159   gint area_above = 0;
6160   gint area_below = 0;
6161
6162   if (tree_view->priv->tree == NULL)
6163     return;
6164
6165   if (! GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID) &&
6166       tree_view->priv->scroll_to_path == NULL)
6167     return;
6168
6169   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
6170   total_height = allocation.height - gtk_tree_view_get_effective_header_height (tree_view);
6171
6172   if (total_height == 0)
6173     return;
6174
6175   /* First, we check to see if we need to scroll anywhere
6176    */
6177   if (tree_view->priv->scroll_to_path)
6178     {
6179       path = gtk_tree_row_reference_get_path (tree_view->priv->scroll_to_path);
6180       if (path && !_gtk_tree_view_find_node (tree_view, path, &tree, &node))
6181         {
6182           /* we are going to scroll, and will update dy */
6183           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6184           if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6185               GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6186             {
6187               _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
6188               if (validate_row (tree_view, tree, node, &iter, path))
6189                 size_changed = TRUE;
6190             }
6191
6192           if (tree_view->priv->scroll_to_use_align)
6193             {
6194               gint height = gtk_tree_view_get_row_height (tree_view, node);
6195               area_above = (total_height - height) *
6196                 tree_view->priv->scroll_to_row_align;
6197               area_below = total_height - area_above - height;
6198               area_above = MAX (area_above, 0);
6199               area_below = MAX (area_below, 0);
6200             }
6201           else
6202             {
6203               /* two cases:
6204                * 1) row not visible
6205                * 2) row visible
6206                */
6207               gint dy;
6208               gint height = gtk_tree_view_get_row_height (tree_view, node);
6209
6210               dy = _gtk_rbtree_node_find_offset (tree, node);
6211
6212               if (dy >= gtk_adjustment_get_value (tree_view->priv->vadjustment) &&
6213                   dy + height <= (gtk_adjustment_get_value (tree_view->priv->vadjustment)
6214                                   + gtk_adjustment_get_page_size (tree_view->priv->vadjustment)))
6215                 {
6216                   /* row visible: keep the row at the same position */
6217                   area_above = dy - gtk_adjustment_get_value (tree_view->priv->vadjustment);
6218                   area_below = (gtk_adjustment_get_value (tree_view->priv->vadjustment) +
6219                                 gtk_adjustment_get_page_size (tree_view->priv->vadjustment))
6220                                - dy - height;
6221                 }
6222               else
6223                 {
6224                   /* row not visible */
6225                   if (dy >= 0
6226                       && dy + height <= gtk_adjustment_get_page_size (tree_view->priv->vadjustment))
6227                     {
6228                       /* row at the beginning -- fixed */
6229                       area_above = dy;
6230                       area_below = gtk_adjustment_get_page_size (tree_view->priv->vadjustment)
6231                                    - area_above - height;
6232                     }
6233                   else if (dy >= (gtk_adjustment_get_upper (tree_view->priv->vadjustment) -
6234                                   gtk_adjustment_get_page_size (tree_view->priv->vadjustment)))
6235                     {
6236                       /* row at the end -- fixed */
6237                       area_above = dy - (gtk_adjustment_get_upper (tree_view->priv->vadjustment) -
6238                                    gtk_adjustment_get_page_size (tree_view->priv->vadjustment));
6239                       area_below = gtk_adjustment_get_page_size (tree_view->priv->vadjustment) -
6240                                    area_above - height;
6241
6242                       if (area_below < 0)
6243                         {
6244                           area_above = gtk_adjustment_get_page_size (tree_view->priv->vadjustment) - height;
6245                           area_below = 0;
6246                         }
6247                     }
6248                   else
6249                     {
6250                       /* row somewhere in the middle, bring it to the top
6251                        * of the view
6252                        */
6253                       area_above = 0;
6254                       area_below = total_height - height;
6255                     }
6256                 }
6257             }
6258         }
6259       else
6260         /* the scroll to isn't valid; ignore it.
6261          */
6262         {
6263           if (tree_view->priv->scroll_to_path && !path)
6264             {
6265               gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
6266               tree_view->priv->scroll_to_path = NULL;
6267             }
6268           if (path)
6269             gtk_tree_path_free (path);
6270           path = NULL;
6271         }      
6272     }
6273
6274   /* We didn't have a scroll_to set, so we just handle things normally
6275    */
6276   if (path == NULL)
6277     {
6278       gint offset;
6279
6280       offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
6281                                         TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, 0),
6282                                         &tree, &node);
6283       if (node == NULL)
6284         {
6285           /* In this case, nothing has been validated */
6286           path = gtk_tree_path_new_first ();
6287           _gtk_tree_view_find_node (tree_view, path, &tree, &node);
6288         }
6289       else
6290         {
6291           path = _gtk_tree_view_find_path (tree_view, tree, node);
6292           total_height += offset;
6293         }
6294
6295       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6296
6297       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6298           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6299         {
6300           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
6301           if (validate_row (tree_view, tree, node, &iter, path))
6302             size_changed = TRUE;
6303         }
6304       area_above = 0;
6305       area_below = total_height - gtk_tree_view_get_row_height (tree_view, node);
6306     }
6307
6308   above_path = gtk_tree_path_copy (path);
6309
6310   /* if we do not validate any row above the new top_row, we will make sure
6311    * that the row immediately above top_row has been validated. (if we do not
6312    * do this, _gtk_rbtree_find_offset will find the row above top_row, because
6313    * when invalidated that row's height will be zero. and this will mess up
6314    * scrolling).
6315    */
6316   if (area_above == 0)
6317     {
6318       GtkRBTree *tmptree;
6319       GtkRBNode *tmpnode;
6320
6321       _gtk_tree_view_find_node (tree_view, above_path, &tmptree, &tmpnode);
6322       _gtk_rbtree_prev_full (tmptree, tmpnode, &tmptree, &tmpnode);
6323
6324       if (tmpnode)
6325         {
6326           GtkTreePath *tmppath;
6327           GtkTreeIter tmpiter;
6328
6329           tmppath = _gtk_tree_view_find_path (tree_view, tmptree, tmpnode);
6330           gtk_tree_model_get_iter (tree_view->priv->model, &tmpiter, tmppath);
6331
6332           if (GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_INVALID) ||
6333               GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_COLUMN_INVALID))
6334             {
6335               _gtk_tree_view_queue_draw_node (tree_view, tmptree, tmpnode, NULL);
6336               if (validate_row (tree_view, tmptree, tmpnode, &tmpiter, tmppath))
6337                 size_changed = TRUE;
6338             }
6339
6340           gtk_tree_path_free (tmppath);
6341         }
6342     }
6343
6344   /* Now, we walk forwards and backwards, measuring rows. Unfortunately,
6345    * backwards is much slower then forward, as there is no iter_prev function.
6346    * We go forwards first in case we run out of tree.  Then we go backwards to
6347    * fill out the top.
6348    */
6349   while (node && area_below > 0)
6350     {
6351       if (node->children)
6352         {
6353           GtkTreeIter parent = iter;
6354           gboolean has_child;
6355
6356           tree = node->children;
6357           node = tree->root;
6358
6359           g_assert (node != tree->nil);
6360
6361           while (node->left != tree->nil)
6362             node = node->left;
6363           has_child = gtk_tree_model_iter_children (tree_view->priv->model,
6364                                                     &iter,
6365                                                     &parent);
6366           TREE_VIEW_INTERNAL_ASSERT_VOID (has_child);
6367           gtk_tree_path_down (path);
6368         }
6369       else
6370         {
6371           gboolean done = FALSE;
6372           do
6373             {
6374               node = _gtk_rbtree_next (tree, node);
6375               if (node != NULL)
6376                 {
6377                   gboolean has_next = gtk_tree_model_iter_next (tree_view->priv->model, &iter);
6378                   done = TRUE;
6379                   gtk_tree_path_next (path);
6380
6381                   /* Sanity Check! */
6382                   TREE_VIEW_INTERNAL_ASSERT_VOID (has_next);
6383                 }
6384               else
6385                 {
6386                   GtkTreeIter parent_iter = iter;
6387                   gboolean has_parent;
6388
6389                   node = tree->parent_node;
6390                   tree = tree->parent_tree;
6391                   if (tree == NULL)
6392                     break;
6393                   has_parent = gtk_tree_model_iter_parent (tree_view->priv->model,
6394                                                            &iter,
6395                                                            &parent_iter);
6396                   gtk_tree_path_up (path);
6397
6398                   /* Sanity check */
6399                   TREE_VIEW_INTERNAL_ASSERT_VOID (has_parent);
6400                 }
6401             }
6402           while (!done);
6403         }
6404
6405       if (!node)
6406         break;
6407
6408       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6409           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6410         {
6411           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
6412           if (validate_row (tree_view, tree, node, &iter, path))
6413               size_changed = TRUE;
6414         }
6415
6416       area_below -= gtk_tree_view_get_row_height (tree_view, node);
6417     }
6418   gtk_tree_path_free (path);
6419
6420   /* If we ran out of tree, and have extra area_below left, we need to add it
6421    * to area_above */
6422   if (area_below > 0)
6423     area_above += area_below;
6424
6425   _gtk_tree_view_find_node (tree_view, above_path, &tree, &node);
6426
6427   /* We walk backwards */
6428   while (area_above > 0)
6429     {
6430       _gtk_rbtree_prev_full (tree, node, &tree, &node);
6431
6432       /* Always find the new path in the tree.  We cannot just assume
6433        * a gtk_tree_path_prev() is enough here, as there might be children
6434        * in between this node and the previous sibling node.  If this
6435        * appears to be a performance hotspot in profiles, we can look into
6436        * intrigate logic for keeping path, node and iter in sync like
6437        * we do for forward walks.  (Which will be hard because of the lacking
6438        * iter_prev).
6439        */
6440
6441       if (node == NULL)
6442         break;
6443
6444       gtk_tree_path_free (above_path);
6445       above_path = _gtk_tree_view_find_path (tree_view, tree, node);
6446
6447       gtk_tree_model_get_iter (tree_view->priv->model, &iter, above_path);
6448
6449       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6450           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6451         {
6452           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
6453           if (validate_row (tree_view, tree, node, &iter, above_path))
6454             size_changed = TRUE;
6455         }
6456       area_above -= gtk_tree_view_get_row_height (tree_view, node);
6457     }
6458
6459   /* if we scrolled to a path, we need to set the dy here,
6460    * and sync the top row accordingly
6461    */
6462   if (tree_view->priv->scroll_to_path)
6463     {
6464       gtk_tree_view_set_top_row (tree_view, above_path, -area_above);
6465       gtk_tree_view_top_row_to_dy (tree_view);
6466
6467       need_redraw = TRUE;
6468     }
6469   else if (tree_view->priv->height <= gtk_adjustment_get_page_size (tree_view->priv->vadjustment))
6470     {
6471       /* when we are not scrolling, we should never set dy to something
6472        * else than zero. we update top_row to be in sync with dy = 0.
6473        */
6474       gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
6475       gtk_tree_view_dy_to_top_row (tree_view);
6476     }
6477   else if (gtk_adjustment_get_value (tree_view->priv->vadjustment) + gtk_adjustment_get_page_size (tree_view->priv->vadjustment) > tree_view->priv->height)
6478     {
6479       gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), tree_view->priv->height - gtk_adjustment_get_page_size (tree_view->priv->vadjustment));
6480       gtk_tree_view_dy_to_top_row (tree_view);
6481     }
6482   else
6483     gtk_tree_view_top_row_to_dy (tree_view);
6484
6485   /* update width/height and queue a resize */
6486   if (size_changed)
6487     {
6488       GtkRequisition requisition;
6489
6490       /* We temporarily guess a size, under the assumption that it will be the
6491        * same when we get our next size_allocate.  If we don't do this, we'll be
6492        * in an inconsistent state if we call top_row_to_dy. */
6493
6494       gtk_widget_get_preferred_size (GTK_WIDGET (tree_view),
6495                                      &requisition, NULL);
6496       gtk_adjustment_set_upper (tree_view->priv->hadjustment,
6497                                 MAX (gtk_adjustment_get_upper (tree_view->priv->hadjustment), requisition.width));
6498       gtk_adjustment_set_upper (tree_view->priv->vadjustment,
6499                                 MAX (gtk_adjustment_get_upper (tree_view->priv->vadjustment), requisition.height));
6500       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6501     }
6502
6503   if (tree_view->priv->scroll_to_path)
6504     {
6505       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
6506       tree_view->priv->scroll_to_path = NULL;
6507     }
6508
6509   if (above_path)
6510     gtk_tree_path_free (above_path);
6511
6512   if (tree_view->priv->scroll_to_column)
6513     {
6514       tree_view->priv->scroll_to_column = NULL;
6515     }
6516   if (need_redraw)
6517     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
6518 }
6519
6520 static void
6521 initialize_fixed_height_mode (GtkTreeView *tree_view)
6522 {
6523   if (!tree_view->priv->tree)
6524     return;
6525
6526   if (tree_view->priv->fixed_height < 0)
6527     {
6528       GtkTreeIter iter;
6529       GtkTreePath *path;
6530
6531       GtkRBTree *tree = NULL;
6532       GtkRBNode *node = NULL;
6533
6534       tree = tree_view->priv->tree;
6535       node = tree->root;
6536
6537       path = _gtk_tree_view_find_path (tree_view, tree, node);
6538       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6539
6540       validate_row (tree_view, tree, node, &iter, path);
6541
6542       gtk_tree_path_free (path);
6543
6544       tree_view->priv->fixed_height = gtk_tree_view_get_row_height (tree_view, node);
6545     }
6546
6547    _gtk_rbtree_set_fixed_height (tree_view->priv->tree,
6548                                  tree_view->priv->fixed_height, TRUE);
6549 }
6550
6551 /* Our strategy for finding nodes to validate is a little convoluted.  We find
6552  * the left-most uninvalidated node.  We then try walking right, validating
6553  * nodes.  Once we find a valid node, we repeat the previous process of finding
6554  * the first invalid node.
6555  */
6556
6557 static gboolean
6558 do_validate_rows (GtkTreeView *tree_view, gboolean queue_resize)
6559 {
6560   GtkRBTree *tree = NULL;
6561   GtkRBNode *node = NULL;
6562   gboolean validated_area = FALSE;
6563   gint retval = TRUE;
6564   GtkTreePath *path = NULL;
6565   GtkTreeIter iter;
6566   GTimer *timer;
6567   gint i = 0;
6568
6569   gint y = -1;
6570   gint prev_height = -1;
6571   gboolean fixed_height = TRUE;
6572
6573   g_assert (tree_view);
6574
6575   if (tree_view->priv->tree == NULL)
6576       return FALSE;
6577
6578   if (tree_view->priv->fixed_height_mode)
6579     {
6580       if (tree_view->priv->fixed_height < 0)
6581         initialize_fixed_height_mode (tree_view);
6582
6583       return FALSE;
6584     }
6585
6586   timer = g_timer_new ();
6587   g_timer_start (timer);
6588
6589   do
6590     {
6591       gboolean changed = FALSE;
6592
6593       if (! GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID))
6594         {
6595           retval = FALSE;
6596           goto done;
6597         }
6598
6599       if (path != NULL)
6600         {
6601           node = _gtk_rbtree_next (tree, node);
6602           if (node != NULL)
6603             {
6604               TREE_VIEW_INTERNAL_ASSERT (gtk_tree_model_iter_next (tree_view->priv->model, &iter), FALSE);
6605               gtk_tree_path_next (path);
6606             }
6607           else
6608             {
6609               gtk_tree_path_free (path);
6610               path = NULL;
6611             }
6612         }
6613
6614       if (path == NULL)
6615         {
6616           tree = tree_view->priv->tree;
6617           node = tree_view->priv->tree->root;
6618
6619           g_assert (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_DESCENDANTS_INVALID));
6620
6621           do
6622             {
6623               if (node->left != tree->nil &&
6624                   GTK_RBNODE_FLAG_SET (node->left, GTK_RBNODE_DESCENDANTS_INVALID))
6625                 {
6626                   node = node->left;
6627                 }
6628               else if (node->right != tree->nil &&
6629                        GTK_RBNODE_FLAG_SET (node->right, GTK_RBNODE_DESCENDANTS_INVALID))
6630                 {
6631                   node = node->right;
6632                 }
6633               else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6634                        GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6635                 {
6636                   break;
6637                 }
6638               else if (node->children != NULL)
6639                 {
6640                   tree = node->children;
6641                   node = tree->root;
6642                 }
6643               else
6644                 /* RBTree corruption!  All bad */
6645                 g_assert_not_reached ();
6646             }
6647           while (TRUE);
6648           path = _gtk_tree_view_find_path (tree_view, tree, node);
6649           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6650         }
6651
6652       changed = validate_row (tree_view, tree, node, &iter, path);
6653       validated_area = changed || validated_area;
6654
6655       if (changed)
6656         {
6657           gint offset = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
6658
6659           if (y == -1 || y > offset)
6660             y = offset;
6661         }
6662
6663       if (!tree_view->priv->fixed_height_check)
6664         {
6665           gint height;
6666
6667           height = gtk_tree_view_get_row_height (tree_view, node);
6668           if (prev_height < 0)
6669             prev_height = height;
6670           else if (prev_height != height)
6671             fixed_height = FALSE;
6672         }
6673
6674       i++;
6675     }
6676   while (g_timer_elapsed (timer, NULL) < GTK_TREE_VIEW_TIME_MS_PER_IDLE / 1000.);
6677
6678   if (!tree_view->priv->fixed_height_check)
6679    {
6680      if (fixed_height)
6681        _gtk_rbtree_set_fixed_height (tree_view->priv->tree, prev_height, FALSE);
6682
6683      tree_view->priv->fixed_height_check = 1;
6684    }
6685   
6686  done:
6687   if (validated_area)
6688     {
6689       GtkRequisition requisition;
6690
6691       /* We temporarily guess a size, under the assumption that it will be the
6692        * same when we get our next size_allocate.  If we don't do this, we'll be
6693        * in an inconsistent state when we call top_row_to_dy. */
6694
6695       /* FIXME: This is called from size_request, for some reason it is not infinitely
6696        * recursing, we cannot call gtk_widget_get_preferred_size() here because that's
6697        * not allowed (from inside ->get_preferred_width/height() implementations, one
6698        * should call the vfuncs directly). However what is desired here is the full
6699        * size including any margins and limited by any alignment (i.e. after 
6700        * GtkWidget:adjust_size_request() is called).
6701        *
6702        * Currently bypassing this but the real solution is to not update the scroll adjustments
6703        * untill we've recieved an allocation (never update scroll adjustments from size-requests).
6704        */
6705       gtk_tree_view_size_request (GTK_WIDGET (tree_view), &requisition, FALSE);
6706
6707       /* If rows above the current position have changed height, this has
6708        * affected the current view and thus needs a redraw.
6709        */
6710       if (y != -1 && y < gtk_adjustment_get_value (tree_view->priv->vadjustment))
6711         gtk_widget_queue_draw (GTK_WIDGET (tree_view));
6712
6713       gtk_adjustment_set_upper (tree_view->priv->hadjustment,
6714                                 MAX (gtk_adjustment_get_upper (tree_view->priv->hadjustment), requisition.width));
6715       gtk_adjustment_set_upper (tree_view->priv->vadjustment,
6716                                 MAX (gtk_adjustment_get_upper (tree_view->priv->vadjustment), requisition.height));
6717
6718       if (queue_resize)
6719         gtk_widget_queue_resize_no_redraw (GTK_WIDGET (tree_view));
6720     }
6721
6722   if (path) gtk_tree_path_free (path);
6723   g_timer_destroy (timer);
6724
6725   return retval;
6726 }
6727
6728 static gboolean
6729 validate_rows (GtkTreeView *tree_view)
6730 {
6731   gboolean retval;
6732   
6733   retval = do_validate_rows (tree_view, TRUE);
6734   
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 validate_rows_handler (GtkTreeView *tree_view)
6746 {
6747   gboolean retval;
6748
6749   retval = do_validate_rows (tree_view, TRUE);
6750   if (! retval && tree_view->priv->validate_rows_timer)
6751     {
6752       g_source_remove (tree_view->priv->validate_rows_timer);
6753       tree_view->priv->validate_rows_timer = 0;
6754     }
6755
6756   return retval;
6757 }
6758
6759 static gboolean
6760 do_presize_handler (GtkTreeView *tree_view)
6761 {
6762   if (tree_view->priv->mark_rows_col_dirty)
6763     {
6764       if (tree_view->priv->tree)
6765         _gtk_rbtree_column_invalid (tree_view->priv->tree);
6766       tree_view->priv->mark_rows_col_dirty = FALSE;
6767     }
6768   validate_visible_area (tree_view);
6769   tree_view->priv->presize_handler_timer = 0;
6770
6771   if (tree_view->priv->fixed_height_mode)
6772     {
6773       GtkRequisition requisition;
6774
6775       gtk_widget_get_preferred_size (GTK_WIDGET (tree_view),
6776                                      &requisition, NULL);
6777
6778       gtk_adjustment_set_upper (tree_view->priv->hadjustment,
6779                                 MAX (gtk_adjustment_get_upper (tree_view->priv->hadjustment), requisition.width));
6780       gtk_adjustment_set_upper (tree_view->priv->vadjustment,
6781                                 MAX (gtk_adjustment_get_upper (tree_view->priv->vadjustment), requisition.height));
6782       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6783     }
6784                    
6785   return FALSE;
6786 }
6787
6788 static gboolean
6789 presize_handler_callback (gpointer data)
6790 {
6791   do_presize_handler (GTK_TREE_VIEW (data));
6792                    
6793   return FALSE;
6794 }
6795
6796 static void
6797 install_presize_handler (GtkTreeView *tree_view)
6798 {
6799   if (! gtk_widget_get_realized (GTK_WIDGET (tree_view)))
6800     return;
6801
6802   if (! tree_view->priv->presize_handler_timer)
6803     {
6804       tree_view->priv->presize_handler_timer =
6805         gdk_threads_add_idle_full (GTK_PRIORITY_RESIZE - 2, presize_handler_callback, tree_view, NULL);
6806     }
6807   if (! tree_view->priv->validate_rows_timer)
6808     {
6809       tree_view->priv->validate_rows_timer =
6810         gdk_threads_add_idle_full (GTK_TREE_VIEW_PRIORITY_VALIDATE, (GSourceFunc) validate_rows_handler, tree_view, NULL);
6811     }
6812 }
6813
6814 static void
6815 gtk_tree_view_bin_process_updates (GtkTreeView *tree_view)
6816 {
6817   /* Prior to drawing, we make sure the visible area is validated. */
6818   if (tree_view->priv->presize_handler_timer)
6819     {
6820       g_source_remove (tree_view->priv->presize_handler_timer);
6821       tree_view->priv->presize_handler_timer = 0;
6822
6823       do_presize_handler (tree_view);
6824     }
6825
6826   gdk_window_process_updates (tree_view->priv->bin_window, TRUE);
6827 }
6828
6829 static gboolean
6830 scroll_sync_handler (GtkTreeView *tree_view)
6831 {
6832   if (tree_view->priv->height <= gtk_adjustment_get_page_size (tree_view->priv->vadjustment))
6833     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
6834   else if (gtk_tree_row_reference_valid (tree_view->priv->top_row))
6835     gtk_tree_view_top_row_to_dy (tree_view);
6836   else
6837     gtk_tree_view_dy_to_top_row (tree_view);
6838
6839   tree_view->priv->scroll_sync_timer = 0;
6840
6841   return FALSE;
6842 }
6843
6844 static void
6845 install_scroll_sync_handler (GtkTreeView *tree_view)
6846 {
6847   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
6848     return;
6849
6850   if (!tree_view->priv->scroll_sync_timer)
6851     {
6852       tree_view->priv->scroll_sync_timer =
6853         gdk_threads_add_idle_full (GTK_TREE_VIEW_PRIORITY_SCROLL_SYNC, (GSourceFunc) scroll_sync_handler, tree_view, NULL);
6854     }
6855 }
6856
6857 static void
6858 gtk_tree_view_set_top_row (GtkTreeView *tree_view,
6859                            GtkTreePath *path,
6860                            gint         offset)
6861 {
6862   gtk_tree_row_reference_free (tree_view->priv->top_row);
6863
6864   if (!path)
6865     {
6866       tree_view->priv->top_row = NULL;
6867       tree_view->priv->top_row_dy = 0;
6868     }
6869   else
6870     {
6871       tree_view->priv->top_row = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
6872       tree_view->priv->top_row_dy = offset;
6873     }
6874 }
6875
6876 /* Always call this iff dy is in the visible range.  If the tree is empty, then
6877  * it's set to be NULL, and top_row_dy is 0;
6878  */
6879 static void
6880 gtk_tree_view_dy_to_top_row (GtkTreeView *tree_view)
6881 {
6882   gint offset;
6883   GtkTreePath *path;
6884   GtkRBTree *tree;
6885   GtkRBNode *node;
6886
6887   if (tree_view->priv->tree == NULL)
6888     {
6889       gtk_tree_view_set_top_row (tree_view, NULL, 0);
6890     }
6891   else
6892     {
6893       offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
6894                                         tree_view->priv->dy,
6895                                         &tree, &node);
6896
6897       if (tree == NULL)
6898         {
6899           gtk_tree_view_set_top_row (tree_view, NULL, 0);
6900         }
6901       else
6902         {
6903           path = _gtk_tree_view_find_path (tree_view, tree, node);
6904           gtk_tree_view_set_top_row (tree_view, path, offset);
6905           gtk_tree_path_free (path);
6906         }
6907     }
6908 }
6909
6910 static void
6911 gtk_tree_view_top_row_to_dy (GtkTreeView *tree_view)
6912 {
6913   GtkTreePath *path;
6914   GtkRBTree *tree;
6915   GtkRBNode *node;
6916   int new_dy;
6917
6918   /* Avoid recursive calls */
6919   if (tree_view->priv->in_top_row_to_dy)
6920     return;
6921
6922   if (tree_view->priv->top_row)
6923     path = gtk_tree_row_reference_get_path (tree_view->priv->top_row);
6924   else
6925     path = NULL;
6926
6927   if (!path)
6928     tree = NULL;
6929   else
6930     _gtk_tree_view_find_node (tree_view, path, &tree, &node);
6931
6932   if (path)
6933     gtk_tree_path_free (path);
6934
6935   if (tree == NULL)
6936     {
6937       /* keep dy and set new toprow */
6938       gtk_tree_row_reference_free (tree_view->priv->top_row);
6939       tree_view->priv->top_row = NULL;
6940       tree_view->priv->top_row_dy = 0;
6941       /* DO NOT install the idle handler */
6942       gtk_tree_view_dy_to_top_row (tree_view);
6943       return;
6944     }
6945
6946   if (gtk_tree_view_get_row_height (tree_view, node)
6947       < tree_view->priv->top_row_dy)
6948     {
6949       /* new top row -- do NOT install the idle handler */
6950       gtk_tree_view_dy_to_top_row (tree_view);
6951       return;
6952     }
6953
6954   new_dy = _gtk_rbtree_node_find_offset (tree, node);
6955   new_dy += tree_view->priv->top_row_dy;
6956
6957   if (new_dy + gtk_adjustment_get_page_size (tree_view->priv->vadjustment) > tree_view->priv->height)
6958     new_dy = tree_view->priv->height - gtk_adjustment_get_page_size (tree_view->priv->vadjustment);
6959
6960   new_dy = MAX (0, new_dy);
6961
6962   tree_view->priv->in_top_row_to_dy = TRUE;
6963   gtk_adjustment_set_value (tree_view->priv->vadjustment, (gdouble)new_dy);
6964   tree_view->priv->in_top_row_to_dy = FALSE;
6965 }
6966
6967
6968 void
6969 _gtk_tree_view_install_mark_rows_col_dirty (GtkTreeView *tree_view,
6970                                             gboolean     install_handler)
6971 {
6972   tree_view->priv->mark_rows_col_dirty = TRUE;
6973
6974   if (install_handler)
6975     install_presize_handler (tree_view);
6976 }
6977
6978 /*
6979  * This function works synchronously (due to the while (validate_rows...)
6980  * loop).
6981  *
6982  * There was a check for column_type != GTK_TREE_VIEW_COLUMN_AUTOSIZE
6983  * here. You now need to check that yourself.
6984  */
6985 void
6986 _gtk_tree_view_column_autosize (GtkTreeView *tree_view,
6987                                 GtkTreeViewColumn *column)
6988 {
6989   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
6990   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (column));
6991
6992   _gtk_tree_view_column_cell_set_dirty (column, FALSE);
6993
6994   do_presize_handler (tree_view);
6995   while (validate_rows (tree_view));
6996
6997   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6998 }
6999
7000 /* Drag-and-drop */
7001
7002 static void
7003 set_source_row (GdkDragContext *context,
7004                 GtkTreeModel   *model,
7005                 GtkTreePath    *source_row)
7006 {
7007   g_object_set_data_full (G_OBJECT (context),
7008                           I_("gtk-tree-view-source-row"),
7009                           source_row ? gtk_tree_row_reference_new (model, source_row) : NULL,
7010                           (GDestroyNotify) (source_row ? gtk_tree_row_reference_free : NULL));
7011 }
7012
7013 static GtkTreePath*
7014 get_source_row (GdkDragContext *context)
7015 {
7016   GtkTreeRowReference *ref =
7017     g_object_get_data (G_OBJECT (context), "gtk-tree-view-source-row");
7018
7019   if (ref)
7020     return gtk_tree_row_reference_get_path (ref);
7021   else
7022     return NULL;
7023 }
7024
7025 typedef struct
7026 {
7027   GtkTreeRowReference *dest_row;
7028   guint                path_down_mode   : 1;
7029   guint                empty_view_drop  : 1;
7030   guint                drop_append_mode : 1;
7031 }
7032 DestRow;
7033
7034 static void
7035 dest_row_free (gpointer data)
7036 {
7037   DestRow *dr = (DestRow *)data;
7038
7039   gtk_tree_row_reference_free (dr->dest_row);
7040   g_slice_free (DestRow, dr);
7041 }
7042
7043 static void
7044 set_dest_row (GdkDragContext *context,
7045               GtkTreeModel   *model,
7046               GtkTreePath    *dest_row,
7047               gboolean        path_down_mode,
7048               gboolean        empty_view_drop,
7049               gboolean        drop_append_mode)
7050 {
7051   DestRow *dr;
7052
7053   if (!dest_row)
7054     {
7055       g_object_set_data_full (G_OBJECT (context), I_("gtk-tree-view-dest-row"),
7056                               NULL, NULL);
7057       return;
7058     }
7059
7060   dr = g_slice_new (DestRow);
7061
7062   dr->dest_row = gtk_tree_row_reference_new (model, dest_row);
7063   dr->path_down_mode = path_down_mode != FALSE;
7064   dr->empty_view_drop = empty_view_drop != FALSE;
7065   dr->drop_append_mode = drop_append_mode != FALSE;
7066
7067   g_object_set_data_full (G_OBJECT (context), I_("gtk-tree-view-dest-row"),
7068                           dr, (GDestroyNotify) dest_row_free);
7069 }
7070
7071 static GtkTreePath*
7072 get_dest_row (GdkDragContext *context,
7073               gboolean       *path_down_mode)
7074 {
7075   DestRow *dr =
7076     g_object_get_data (G_OBJECT (context), "gtk-tree-view-dest-row");
7077
7078   if (dr)
7079     {
7080       GtkTreePath *path = NULL;
7081
7082       if (path_down_mode)
7083         *path_down_mode = dr->path_down_mode;
7084
7085       if (dr->dest_row)
7086         path = gtk_tree_row_reference_get_path (dr->dest_row);
7087       else if (dr->empty_view_drop)
7088         path = gtk_tree_path_new_from_indices (0, -1);
7089       else
7090         path = NULL;
7091
7092       if (path && dr->drop_append_mode)
7093         gtk_tree_path_next (path);
7094
7095       return path;
7096     }
7097   else
7098     return NULL;
7099 }
7100
7101 /* Get/set whether drag_motion requested the drag data and
7102  * drag_data_received should thus not actually insert the data,
7103  * since the data doesn't result from a drop.
7104  */
7105 static void
7106 set_status_pending (GdkDragContext *context,
7107                     GdkDragAction   suggested_action)
7108 {
7109   g_object_set_data (G_OBJECT (context),
7110                      I_("gtk-tree-view-status-pending"),
7111                      GINT_TO_POINTER (suggested_action));
7112 }
7113
7114 static GdkDragAction
7115 get_status_pending (GdkDragContext *context)
7116 {
7117   return GPOINTER_TO_INT (g_object_get_data (G_OBJECT (context),
7118                                              "gtk-tree-view-status-pending"));
7119 }
7120
7121 static TreeViewDragInfo*
7122 get_info (GtkTreeView *tree_view)
7123 {
7124   return g_object_get_data (G_OBJECT (tree_view), "gtk-tree-view-drag-info");
7125 }
7126
7127 static void
7128 destroy_info (TreeViewDragInfo *di)
7129 {
7130   g_slice_free (TreeViewDragInfo, di);
7131 }
7132
7133 static TreeViewDragInfo*
7134 ensure_info (GtkTreeView *tree_view)
7135 {
7136   TreeViewDragInfo *di;
7137
7138   di = get_info (tree_view);
7139
7140   if (di == NULL)
7141     {
7142       di = g_slice_new0 (TreeViewDragInfo);
7143
7144       g_object_set_data_full (G_OBJECT (tree_view),
7145                               I_("gtk-tree-view-drag-info"),
7146                               di,
7147                               (GDestroyNotify) destroy_info);
7148     }
7149
7150   return di;
7151 }
7152
7153 static void
7154 remove_info (GtkTreeView *tree_view)
7155 {
7156   g_object_set_data (G_OBJECT (tree_view), I_("gtk-tree-view-drag-info"), NULL);
7157 }
7158
7159 #if 0
7160 static gint
7161 drag_scan_timeout (gpointer data)
7162 {
7163   GtkTreeView *tree_view;
7164   gint x, y;
7165   GdkModifierType state;
7166   GtkTreePath *path = NULL;
7167   GtkTreeViewColumn *column = NULL;
7168   GdkRectangle visible_rect;
7169
7170   GDK_THREADS_ENTER ();
7171
7172   tree_view = GTK_TREE_VIEW (data);
7173
7174   gdk_window_get_pointer (tree_view->priv->bin_window,
7175                           &x, &y, &state);
7176
7177   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
7178
7179   /* See if we are near the edge. */
7180   if ((x - visible_rect.x) < SCROLL_EDGE_SIZE ||
7181       (visible_rect.x + visible_rect.width - x) < SCROLL_EDGE_SIZE ||
7182       (y - visible_rect.y) < SCROLL_EDGE_SIZE ||
7183       (visible_rect.y + visible_rect.height - y) < SCROLL_EDGE_SIZE)
7184     {
7185       gtk_tree_view_get_path_at_pos (tree_view,
7186                                      tree_view->priv->bin_window,
7187                                      x, y,
7188                                      &path,
7189                                      &column,
7190                                      NULL,
7191                                      NULL);
7192
7193       if (path != NULL)
7194         {
7195           gtk_tree_view_scroll_to_cell (tree_view,
7196                                         path,
7197                                         column,
7198                                         TRUE,
7199                                         0.5, 0.5);
7200
7201           gtk_tree_path_free (path);
7202         }
7203     }
7204
7205   GDK_THREADS_LEAVE ();
7206
7207   return TRUE;
7208 }
7209 #endif /* 0 */
7210
7211 static void
7212 add_scroll_timeout (GtkTreeView *tree_view)
7213 {
7214   if (tree_view->priv->scroll_timeout == 0)
7215     {
7216       tree_view->priv->scroll_timeout =
7217         gdk_threads_add_timeout (150, scroll_row_timeout, tree_view);
7218     }
7219 }
7220
7221 static void
7222 remove_scroll_timeout (GtkTreeView *tree_view)
7223 {
7224   if (tree_view->priv->scroll_timeout != 0)
7225     {
7226       g_source_remove (tree_view->priv->scroll_timeout);
7227       tree_view->priv->scroll_timeout = 0;
7228     }
7229 }
7230
7231 static gboolean
7232 check_model_dnd (GtkTreeModel *model,
7233                  GType         required_iface,
7234                  const gchar  *signal)
7235 {
7236   if (model == NULL || !G_TYPE_CHECK_INSTANCE_TYPE ((model), required_iface))
7237     {
7238       g_warning ("You must override the default '%s' handler "
7239                  "on GtkTreeView when using models that don't support "
7240                  "the %s interface and enabling drag-and-drop. The simplest way to do this "
7241                  "is to connect to '%s' and call "
7242                  "g_signal_stop_emission_by_name() in your signal handler to prevent "
7243                  "the default handler from running. Look at the source code "
7244                  "for the default handler in gtktreeview.c to get an idea what "
7245                  "your handler should do. (gtktreeview.c is in the GTK source "
7246                  "code.) If you're using GTK from a language other than C, "
7247                  "there may be a more natural way to override default handlers, e.g. via derivation.",
7248                  signal, g_type_name (required_iface), signal);
7249       return FALSE;
7250     }
7251   else
7252     return TRUE;
7253 }
7254
7255 static void
7256 remove_open_timeout (GtkTreeView *tree_view)
7257 {
7258   if (tree_view->priv->open_dest_timeout != 0)
7259     {
7260       g_source_remove (tree_view->priv->open_dest_timeout);
7261       tree_view->priv->open_dest_timeout = 0;
7262     }
7263 }
7264
7265
7266 static gint
7267 open_row_timeout (gpointer data)
7268 {
7269   GtkTreeView *tree_view = data;
7270   GtkTreePath *dest_path = NULL;
7271   GtkTreeViewDropPosition pos;
7272   gboolean result = FALSE;
7273
7274   gtk_tree_view_get_drag_dest_row (tree_view,
7275                                    &dest_path,
7276                                    &pos);
7277
7278   if (dest_path &&
7279       (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
7280        pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
7281     {
7282       gtk_tree_view_expand_row (tree_view, dest_path, FALSE);
7283       tree_view->priv->open_dest_timeout = 0;
7284
7285       gtk_tree_path_free (dest_path);
7286     }
7287   else
7288     {
7289       if (dest_path)
7290         gtk_tree_path_free (dest_path);
7291
7292       result = TRUE;
7293     }
7294
7295   return result;
7296 }
7297
7298 static gboolean
7299 scroll_row_timeout (gpointer data)
7300 {
7301   GtkTreeView *tree_view = data;
7302
7303   gtk_tree_view_vertical_autoscroll (tree_view);
7304
7305   if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
7306     gtk_tree_view_update_rubber_band (tree_view);
7307
7308   return TRUE;
7309 }
7310
7311 /* Returns TRUE if event should not be propagated to parent widgets */
7312 static gboolean
7313 set_destination_row (GtkTreeView    *tree_view,
7314                      GdkDragContext *context,
7315                      /* coordinates relative to the widget */
7316                      gint            x,
7317                      gint            y,
7318                      GdkDragAction  *suggested_action,
7319                      GdkAtom        *target)
7320 {
7321   GtkTreePath *path = NULL;
7322   GtkTreeViewDropPosition pos;
7323   GtkTreeViewDropPosition old_pos;
7324   TreeViewDragInfo *di;
7325   GtkWidget *widget;
7326   GtkTreePath *old_dest_path = NULL;
7327   gboolean can_drop = FALSE;
7328
7329   *suggested_action = 0;
7330   *target = GDK_NONE;
7331
7332   widget = GTK_WIDGET (tree_view);
7333
7334   di = get_info (tree_view);
7335
7336   if (di == NULL || y - gtk_tree_view_get_effective_header_height (tree_view) < 0)
7337     {
7338       /* someone unset us as a drag dest, note that if
7339        * we return FALSE drag_leave isn't called
7340        */
7341
7342       gtk_tree_view_set_drag_dest_row (tree_view,
7343                                        NULL,
7344                                        GTK_TREE_VIEW_DROP_BEFORE);
7345
7346       remove_scroll_timeout (GTK_TREE_VIEW (widget));
7347       remove_open_timeout (GTK_TREE_VIEW (widget));
7348
7349       return FALSE; /* no longer a drop site */
7350     }
7351
7352   *target = gtk_drag_dest_find_target (widget, context,
7353                                        gtk_drag_dest_get_target_list (widget));
7354   if (*target == GDK_NONE)
7355     {
7356       return FALSE;
7357     }
7358
7359   if (!gtk_tree_view_get_dest_row_at_pos (tree_view,
7360                                           x, y,
7361                                           &path,
7362                                           &pos))
7363     {
7364       gint n_children;
7365       GtkTreeModel *model;
7366
7367       remove_open_timeout (tree_view);
7368
7369       /* the row got dropped on empty space, let's setup a special case
7370        */
7371
7372       if (path)
7373         gtk_tree_path_free (path);
7374
7375       model = gtk_tree_view_get_model (tree_view);
7376
7377       n_children = gtk_tree_model_iter_n_children (model, NULL);
7378       if (n_children)
7379         {
7380           pos = GTK_TREE_VIEW_DROP_AFTER;
7381           path = gtk_tree_path_new_from_indices (n_children - 1, -1);
7382         }
7383       else
7384         {
7385           pos = GTK_TREE_VIEW_DROP_BEFORE;
7386           path = gtk_tree_path_new_from_indices (0, -1);
7387         }
7388
7389       can_drop = TRUE;
7390
7391       goto out;
7392     }
7393
7394   g_assert (path);
7395
7396   /* If we left the current row's "open" zone, unset the timeout for
7397    * opening the row
7398    */
7399   gtk_tree_view_get_drag_dest_row (tree_view,
7400                                    &old_dest_path,
7401                                    &old_pos);
7402
7403   if (old_dest_path &&
7404       (gtk_tree_path_compare (path, old_dest_path) != 0 ||
7405        !(pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
7406          pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE)))
7407     remove_open_timeout (tree_view);
7408
7409   if (old_dest_path)
7410     gtk_tree_path_free (old_dest_path);
7411
7412   if (TRUE /* FIXME if the location droppable predicate */)
7413     {
7414       can_drop = TRUE;
7415     }
7416
7417 out:
7418   if (can_drop)
7419     {
7420       GtkWidget *source_widget;
7421
7422       *suggested_action = gdk_drag_context_get_suggested_action (context);
7423       source_widget = gtk_drag_get_source_widget (context);
7424
7425       if (source_widget == widget)
7426         {
7427           /* Default to MOVE, unless the user has
7428            * pressed ctrl or shift to affect available actions
7429            */
7430           if ((gdk_drag_context_get_actions (context) & GDK_ACTION_MOVE) != 0)
7431             *suggested_action = GDK_ACTION_MOVE;
7432         }
7433
7434       gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7435                                        path, pos);
7436     }
7437   else
7438     {
7439       /* can't drop here */
7440       remove_open_timeout (tree_view);
7441
7442       gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7443                                        NULL,
7444                                        GTK_TREE_VIEW_DROP_BEFORE);
7445     }
7446
7447   if (path)
7448     gtk_tree_path_free (path);
7449
7450   return TRUE;
7451 }
7452
7453 static GtkTreePath*
7454 get_logical_dest_row (GtkTreeView *tree_view,
7455                       gboolean    *path_down_mode,
7456                       gboolean    *drop_append_mode)
7457 {
7458   /* adjust path to point to the row the drop goes in front of */
7459   GtkTreePath *path = NULL;
7460   GtkTreeViewDropPosition pos;
7461
7462   g_return_val_if_fail (path_down_mode != NULL, NULL);
7463   g_return_val_if_fail (drop_append_mode != NULL, NULL);
7464
7465   *path_down_mode = FALSE;
7466   *drop_append_mode = 0;
7467
7468   gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
7469
7470   if (path == NULL)
7471     return NULL;
7472
7473   if (pos == GTK_TREE_VIEW_DROP_BEFORE)
7474     ; /* do nothing */
7475   else if (pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE ||
7476            pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER)
7477     *path_down_mode = TRUE;
7478   else
7479     {
7480       GtkTreeIter iter;
7481       GtkTreeModel *model = gtk_tree_view_get_model (tree_view);
7482
7483       g_assert (pos == GTK_TREE_VIEW_DROP_AFTER);
7484
7485       if (!gtk_tree_model_get_iter (model, &iter, path) ||
7486           !gtk_tree_model_iter_next (model, &iter))
7487         *drop_append_mode = 1;
7488       else
7489         {
7490           *drop_append_mode = 0;
7491           gtk_tree_path_next (path);
7492         }
7493     }
7494
7495   return path;
7496 }
7497
7498 static gboolean
7499 gtk_tree_view_maybe_begin_dragging_row (GtkTreeView      *tree_view,
7500                                         GdkEventMotion   *event)
7501 {
7502   GtkWidget *widget = GTK_WIDGET (tree_view);
7503   GdkDragContext *context;
7504   TreeViewDragInfo *di;
7505   GtkTreePath *path = NULL;
7506   gint button;
7507   gint cell_x, cell_y;
7508   GtkTreeModel *model;
7509   gboolean retval = FALSE;
7510
7511   di = get_info (tree_view);
7512
7513   if (di == NULL || !di->source_set)
7514     goto out;
7515
7516   if (tree_view->priv->pressed_button < 0)
7517     goto out;
7518
7519   if (!gtk_drag_check_threshold (widget,
7520                                  tree_view->priv->press_start_x,
7521                                  tree_view->priv->press_start_y,
7522                                  event->x, event->y))
7523     goto out;
7524
7525   model = gtk_tree_view_get_model (tree_view);
7526
7527   if (model == NULL)
7528     goto out;
7529
7530   button = tree_view->priv->pressed_button;
7531   tree_view->priv->pressed_button = -1;
7532
7533   gtk_tree_view_get_path_at_pos (tree_view,
7534                                  tree_view->priv->press_start_x,
7535                                  tree_view->priv->press_start_y,
7536                                  &path,
7537                                  NULL,
7538                                  &cell_x,
7539                                  &cell_y);
7540
7541   if (path == NULL)
7542     goto out;
7543
7544   if (!GTK_IS_TREE_DRAG_SOURCE (model) ||
7545       !gtk_tree_drag_source_row_draggable (GTK_TREE_DRAG_SOURCE (model),
7546                                            path))
7547     goto out;
7548
7549   if (!(GDK_BUTTON1_MASK << (button - 1) & di->start_button_mask))
7550     goto out;
7551
7552   /* Now we can begin the drag */
7553
7554   retval = TRUE;
7555
7556   context = gtk_drag_begin (widget,
7557                             gtk_drag_source_get_target_list (widget),
7558                             di->source_actions,
7559                             button,
7560                             (GdkEvent*)event);
7561
7562   set_source_row (context, model, path);
7563
7564  out:
7565   if (path)
7566     gtk_tree_path_free (path);
7567
7568   return retval;
7569 }
7570
7571
7572 static void
7573 gtk_tree_view_drag_begin (GtkWidget      *widget,
7574                           GdkDragContext *context)
7575 {
7576   GtkTreeView *tree_view;
7577   GtkTreePath *path = NULL;
7578   gint cell_x, cell_y;
7579   cairo_surface_t *row_pix;
7580   TreeViewDragInfo *di;
7581
7582   tree_view = GTK_TREE_VIEW (widget);
7583
7584   /* if the user uses a custom DND source impl, we don't set the icon here */
7585   di = get_info (tree_view);
7586
7587   if (di == NULL || !di->source_set)
7588     return;
7589
7590   gtk_tree_view_get_path_at_pos (tree_view,
7591                                  tree_view->priv->press_start_x,
7592                                  tree_view->priv->press_start_y,
7593                                  &path,
7594                                  NULL,
7595                                  &cell_x,
7596                                  &cell_y);
7597
7598   g_return_if_fail (path != NULL);
7599
7600   row_pix = gtk_tree_view_create_row_drag_icon (tree_view,
7601                                                 path);
7602   cairo_surface_set_device_offset (row_pix,
7603                                    /* the + 1 is for the black border in the icon */
7604                                    - (tree_view->priv->press_start_x + 1),
7605                                    - (cell_y + 1));
7606
7607   gtk_drag_set_icon_surface (context, row_pix);
7608
7609   cairo_surface_destroy (row_pix);
7610   gtk_tree_path_free (path);
7611 }
7612
7613 static void
7614 gtk_tree_view_drag_end (GtkWidget      *widget,
7615                         GdkDragContext *context)
7616 {
7617   /* do nothing */
7618 }
7619
7620 /* Default signal implementations for the drag signals */
7621 static void
7622 gtk_tree_view_drag_data_get (GtkWidget        *widget,
7623                              GdkDragContext   *context,
7624                              GtkSelectionData *selection_data,
7625                              guint             info,
7626                              guint             time)
7627 {
7628   GtkTreeView *tree_view;
7629   GtkTreeModel *model;
7630   TreeViewDragInfo *di;
7631   GtkTreePath *source_row;
7632
7633   tree_view = GTK_TREE_VIEW (widget);
7634
7635   model = gtk_tree_view_get_model (tree_view);
7636
7637   if (model == NULL)
7638     return;
7639
7640   di = get_info (GTK_TREE_VIEW (widget));
7641
7642   if (di == NULL)
7643     return;
7644
7645   source_row = get_source_row (context);
7646
7647   if (source_row == NULL)
7648     return;
7649
7650   /* We can implement the GTK_TREE_MODEL_ROW target generically for
7651    * any model; for DragSource models there are some other targets
7652    * we also support.
7653    */
7654
7655   if (GTK_IS_TREE_DRAG_SOURCE (model) &&
7656       gtk_tree_drag_source_drag_data_get (GTK_TREE_DRAG_SOURCE (model),
7657                                           source_row,
7658                                           selection_data))
7659     goto done;
7660
7661   /* If drag_data_get does nothing, try providing row data. */
7662   if (gtk_selection_data_get_target (selection_data) == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
7663     {
7664       gtk_tree_set_row_drag_data (selection_data,
7665                                   model,
7666                                   source_row);
7667     }
7668
7669  done:
7670   gtk_tree_path_free (source_row);
7671 }
7672
7673
7674 static void
7675 gtk_tree_view_drag_data_delete (GtkWidget      *widget,
7676                                 GdkDragContext *context)
7677 {
7678   TreeViewDragInfo *di;
7679   GtkTreeModel *model;
7680   GtkTreeView *tree_view;
7681   GtkTreePath *source_row;
7682
7683   tree_view = GTK_TREE_VIEW (widget);
7684   model = gtk_tree_view_get_model (tree_view);
7685
7686   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_SOURCE, "drag_data_delete"))
7687     return;
7688
7689   di = get_info (tree_view);
7690
7691   if (di == NULL)
7692     return;
7693
7694   source_row = get_source_row (context);
7695
7696   if (source_row == NULL)
7697     return;
7698
7699   gtk_tree_drag_source_drag_data_delete (GTK_TREE_DRAG_SOURCE (model),
7700                                          source_row);
7701
7702   gtk_tree_path_free (source_row);
7703
7704   set_source_row (context, NULL, NULL);
7705 }
7706
7707 static void
7708 gtk_tree_view_drag_leave (GtkWidget      *widget,
7709                           GdkDragContext *context,
7710                           guint             time)
7711 {
7712   /* unset any highlight row */
7713   gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7714                                    NULL,
7715                                    GTK_TREE_VIEW_DROP_BEFORE);
7716
7717   remove_scroll_timeout (GTK_TREE_VIEW (widget));
7718   remove_open_timeout (GTK_TREE_VIEW (widget));
7719 }
7720
7721
7722 static gboolean
7723 gtk_tree_view_drag_motion (GtkWidget        *widget,
7724                            GdkDragContext   *context,
7725                            /* coordinates relative to the widget */
7726                            gint              x,
7727                            gint              y,
7728                            guint             time)
7729 {
7730   gboolean empty;
7731   GtkTreePath *path = NULL;
7732   GtkTreeViewDropPosition pos;
7733   GtkTreeView *tree_view;
7734   GdkDragAction suggested_action = 0;
7735   GdkAtom target;
7736
7737   tree_view = GTK_TREE_VIEW (widget);
7738
7739   if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
7740     return FALSE;
7741
7742   gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
7743
7744   /* we only know this *after* set_desination_row */
7745   empty = tree_view->priv->empty_view_drop;
7746
7747   if (path == NULL && !empty)
7748     {
7749       /* Can't drop here. */
7750       gdk_drag_status (context, 0, time);
7751     }
7752   else
7753     {
7754       if (tree_view->priv->open_dest_timeout == 0 &&
7755           (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
7756            pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
7757         {
7758           tree_view->priv->open_dest_timeout =
7759             gdk_threads_add_timeout (AUTO_EXPAND_TIMEOUT, open_row_timeout, tree_view);
7760         }
7761       else
7762         {
7763           add_scroll_timeout (tree_view);
7764         }
7765
7766       if (target == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
7767         {
7768           /* Request data so we can use the source row when
7769            * determining whether to accept the drop
7770            */
7771           set_status_pending (context, suggested_action);
7772           gtk_drag_get_data (widget, context, target, time);
7773         }
7774       else
7775         {
7776           set_status_pending (context, 0);
7777           gdk_drag_status (context, suggested_action, time);
7778         }
7779     }
7780
7781   if (path)
7782     gtk_tree_path_free (path);
7783
7784   return TRUE;
7785 }
7786
7787
7788 static gboolean
7789 gtk_tree_view_drag_drop (GtkWidget        *widget,
7790                          GdkDragContext   *context,
7791                          /* coordinates relative to the widget */
7792                          gint              x,
7793                          gint              y,
7794                          guint             time)
7795 {
7796   GtkTreeView *tree_view;
7797   GtkTreePath *path;
7798   GdkDragAction suggested_action = 0;
7799   GdkAtom target = GDK_NONE;
7800   TreeViewDragInfo *di;
7801   GtkTreeModel *model;
7802   gboolean path_down_mode;
7803   gboolean drop_append_mode;
7804
7805   tree_view = GTK_TREE_VIEW (widget);
7806
7807   model = gtk_tree_view_get_model (tree_view);
7808
7809   remove_scroll_timeout (GTK_TREE_VIEW (widget));
7810   remove_open_timeout (GTK_TREE_VIEW (widget));
7811
7812   di = get_info (tree_view);
7813
7814   if (di == NULL)
7815     return FALSE;
7816
7817   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_drop"))
7818     return FALSE;
7819
7820   if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
7821     return FALSE;
7822
7823   path = get_logical_dest_row (tree_view, &path_down_mode, &drop_append_mode);
7824
7825   if (target != GDK_NONE && path != NULL)
7826     {
7827       /* in case a motion had requested drag data, change things so we
7828        * treat drag data receives as a drop.
7829        */
7830       set_status_pending (context, 0);
7831       set_dest_row (context, model, path,
7832                     path_down_mode, tree_view->priv->empty_view_drop,
7833                     drop_append_mode);
7834     }
7835
7836   if (path)
7837     gtk_tree_path_free (path);
7838
7839   /* Unset this thing */
7840   gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7841                                    NULL,
7842                                    GTK_TREE_VIEW_DROP_BEFORE);
7843
7844   if (target != GDK_NONE)
7845     {
7846       gtk_drag_get_data (widget, context, target, time);
7847       return TRUE;
7848     }
7849   else
7850     return FALSE;
7851 }
7852
7853 static void
7854 gtk_tree_view_drag_data_received (GtkWidget        *widget,
7855                                   GdkDragContext   *context,
7856                                   /* coordinates relative to the widget */
7857                                   gint              x,
7858                                   gint              y,
7859                                   GtkSelectionData *selection_data,
7860                                   guint             info,
7861                                   guint             time)
7862 {
7863   GtkTreePath *path;
7864   TreeViewDragInfo *di;
7865   gboolean accepted = FALSE;
7866   GtkTreeModel *model;
7867   GtkTreeView *tree_view;
7868   GtkTreePath *dest_row;
7869   GdkDragAction suggested_action;
7870   gboolean path_down_mode;
7871   gboolean drop_append_mode;
7872
7873   tree_view = GTK_TREE_VIEW (widget);
7874
7875   model = gtk_tree_view_get_model (tree_view);
7876
7877   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_data_received"))
7878     return;
7879
7880   di = get_info (tree_view);
7881
7882   if (di == NULL)
7883     return;
7884
7885   suggested_action = get_status_pending (context);
7886
7887   if (suggested_action)
7888     {
7889       /* We are getting this data due to a request in drag_motion,
7890        * rather than due to a request in drag_drop, so we are just
7891        * supposed to call drag_status, not actually paste in the
7892        * data.
7893        */
7894       path = get_logical_dest_row (tree_view, &path_down_mode,
7895                                    &drop_append_mode);
7896
7897       if (path == NULL)
7898         suggested_action = 0;
7899       else if (path_down_mode)
7900         gtk_tree_path_down (path);
7901
7902       if (suggested_action)
7903         {
7904           if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
7905                                                      path,
7906                                                      selection_data))
7907             {
7908               if (path_down_mode)
7909                 {
7910                   path_down_mode = FALSE;
7911                   gtk_tree_path_up (path);
7912
7913                   if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
7914                                                              path,
7915                                                              selection_data))
7916                     suggested_action = 0;
7917                 }
7918               else
7919                 suggested_action = 0;
7920             }
7921         }
7922
7923       gdk_drag_status (context, suggested_action, time);
7924
7925       if (path)
7926         gtk_tree_path_free (path);
7927
7928       /* If you can't drop, remove user drop indicator until the next motion */
7929       if (suggested_action == 0)
7930         gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7931                                          NULL,
7932                                          GTK_TREE_VIEW_DROP_BEFORE);
7933
7934       return;
7935     }
7936
7937   dest_row = get_dest_row (context, &path_down_mode);
7938
7939   if (dest_row == NULL)
7940     return;
7941
7942   if (gtk_selection_data_get_length (selection_data) >= 0)
7943     {
7944       if (path_down_mode)
7945         {
7946           gtk_tree_path_down (dest_row);
7947           if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
7948                                                      dest_row, selection_data))
7949             gtk_tree_path_up (dest_row);
7950         }
7951     }
7952
7953   if (gtk_selection_data_get_length (selection_data) >= 0)
7954     {
7955       if (gtk_tree_drag_dest_drag_data_received (GTK_TREE_DRAG_DEST (model),
7956                                                  dest_row,
7957                                                  selection_data))
7958         accepted = TRUE;
7959     }
7960
7961   gtk_drag_finish (context,
7962                    accepted,
7963                    (gdk_drag_context_get_selected_action (context) == GDK_ACTION_MOVE),
7964                    time);
7965
7966   if (gtk_tree_path_get_depth (dest_row) == 1
7967       && gtk_tree_path_get_indices (dest_row)[0] == 0)
7968     {
7969       /* special special case drag to "0", scroll to first item */
7970       if (!tree_view->priv->scroll_to_path)
7971         gtk_tree_view_scroll_to_cell (tree_view, dest_row, NULL, FALSE, 0.0, 0.0);
7972     }
7973
7974   gtk_tree_path_free (dest_row);
7975
7976   /* drop dest_row */
7977   set_dest_row (context, NULL, NULL, FALSE, FALSE, FALSE);
7978 }
7979
7980
7981
7982 /* GtkContainer Methods
7983  */
7984
7985
7986 static void
7987 gtk_tree_view_remove (GtkContainer *container,
7988                       GtkWidget    *widget)
7989 {
7990   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
7991   GtkTreeViewChild *child = NULL;
7992   GList *tmp_list;
7993
7994   tmp_list = tree_view->priv->children;
7995   while (tmp_list)
7996     {
7997       child = tmp_list->data;
7998       if (child->widget == widget)
7999         {
8000           gtk_widget_unparent (widget);
8001
8002           tree_view->priv->children = g_list_remove_link (tree_view->priv->children, tmp_list);
8003           g_list_free_1 (tmp_list);
8004           g_slice_free (GtkTreeViewChild, child);
8005           return;
8006         }
8007
8008       tmp_list = tmp_list->next;
8009     }
8010
8011   tmp_list = tree_view->priv->columns;
8012
8013   while (tmp_list)
8014     {
8015       GtkTreeViewColumn *column;
8016       GtkWidget         *button;
8017
8018       column = tmp_list->data;
8019       button = gtk_tree_view_column_get_button (column);
8020
8021       if (button == widget)
8022         {
8023           gtk_widget_unparent (widget);
8024           return;
8025         }
8026       tmp_list = tmp_list->next;
8027     }
8028 }
8029
8030 static void
8031 gtk_tree_view_forall (GtkContainer *container,
8032                       gboolean      include_internals,
8033                       GtkCallback   callback,
8034                       gpointer      callback_data)
8035 {
8036   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
8037   GtkTreeViewChild *child = NULL;
8038   GtkTreeViewColumn *column;
8039   GtkWidget *button;
8040   GList *tmp_list;
8041
8042   tmp_list = tree_view->priv->children;
8043   while (tmp_list)
8044     {
8045       child = tmp_list->data;
8046       tmp_list = tmp_list->next;
8047
8048       (* callback) (child->widget, callback_data);
8049     }
8050   if (include_internals == FALSE)
8051     return;
8052
8053   for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
8054     {
8055       column = tmp_list->data;
8056       button = gtk_tree_view_column_get_button (column);
8057
8058       if (button)
8059         (* callback) (button, callback_data);
8060     }
8061 }
8062
8063 /* Returns TRUE is any of the columns contains a cell that can-focus.
8064  * If this is not the case, a column-spanning focus rectangle will be
8065  * drawn.
8066  */
8067 static gboolean
8068 gtk_tree_view_has_can_focus_cell (GtkTreeView *tree_view)
8069 {
8070   GList *list;
8071
8072   for (list = tree_view->priv->columns; list; list = list->next)
8073     {
8074       GtkTreeViewColumn *column = list->data;
8075
8076       if (!gtk_tree_view_column_get_visible (column))
8077         continue;
8078       if (gtk_cell_area_is_activatable (gtk_cell_layout_get_area (GTK_CELL_LAYOUT (column))))
8079         return TRUE;
8080     }
8081
8082   return FALSE;
8083 }
8084
8085 static void
8086 column_sizing_notify (GObject    *object,
8087                       GParamSpec *pspec,
8088                       gpointer    data)
8089 {
8090   GtkTreeViewColumn *c = GTK_TREE_VIEW_COLUMN (object);
8091
8092   if (gtk_tree_view_column_get_sizing (c) != GTK_TREE_VIEW_COLUMN_FIXED)
8093     /* disable fixed height mode */
8094     g_object_set (data, "fixed-height-mode", FALSE, NULL);
8095 }
8096
8097 /**
8098  * gtk_tree_view_set_fixed_height_mode:
8099  * @tree_view: a #GtkTreeView 
8100  * @enable: %TRUE to enable fixed height mode
8101  * 
8102  * Enables or disables the fixed height mode of @tree_view. 
8103  * Fixed height mode speeds up #GtkTreeView by assuming that all 
8104  * rows have the same height. 
8105  * Only enable this option if all rows are the same height and all
8106  * columns are of type %GTK_TREE_VIEW_COLUMN_FIXED.
8107  *
8108  * Since: 2.6 
8109  **/
8110 void
8111 gtk_tree_view_set_fixed_height_mode (GtkTreeView *tree_view,
8112                                      gboolean     enable)
8113 {
8114   GList *l;
8115   
8116   enable = enable != FALSE;
8117
8118   if (enable == tree_view->priv->fixed_height_mode)
8119     return;
8120
8121   if (!enable)
8122     {
8123       tree_view->priv->fixed_height_mode = 0;
8124       tree_view->priv->fixed_height = -1;
8125
8126       /* force a revalidation */
8127       install_presize_handler (tree_view);
8128     }
8129   else 
8130     {
8131       /* make sure all columns are of type FIXED */
8132       for (l = tree_view->priv->columns; l; l = l->next)
8133         {
8134           GtkTreeViewColumn *c = l->data;
8135           
8136           g_return_if_fail (gtk_tree_view_column_get_sizing (c) == GTK_TREE_VIEW_COLUMN_FIXED);
8137         }
8138       
8139       /* yes, we really have to do this is in a separate loop */
8140       for (l = tree_view->priv->columns; l; l = l->next)
8141         g_signal_connect (l->data, "notify::sizing",
8142                           G_CALLBACK (column_sizing_notify), tree_view);
8143       
8144       tree_view->priv->fixed_height_mode = 1;
8145       tree_view->priv->fixed_height = -1;
8146       
8147       if (tree_view->priv->tree)
8148         initialize_fixed_height_mode (tree_view);
8149     }
8150
8151   g_object_notify (G_OBJECT (tree_view), "fixed-height-mode");
8152 }
8153
8154 /**
8155  * gtk_tree_view_get_fixed_height_mode:
8156  * @tree_view: a #GtkTreeView
8157  * 
8158  * Returns whether fixed height mode is turned on for @tree_view.
8159  * 
8160  * Return value: %TRUE if @tree_view is in fixed height mode
8161  * 
8162  * Since: 2.6
8163  **/
8164 gboolean
8165 gtk_tree_view_get_fixed_height_mode (GtkTreeView *tree_view)
8166 {
8167   return tree_view->priv->fixed_height_mode;
8168 }
8169
8170 /* Returns TRUE if the focus is within the headers, after the focus operation is
8171  * done
8172  */
8173 static gboolean
8174 gtk_tree_view_header_focus (GtkTreeView      *tree_view,
8175                             GtkDirectionType  dir,
8176                             gboolean          clamp_column_visible)
8177 {
8178   GtkTreeViewColumn *column;
8179   GtkWidget *focus_child;
8180   GtkWidget *button;
8181   GList *last_column, *first_column;
8182   GList *tmp_list;
8183   gboolean rtl;
8184
8185   if (! tree_view->priv->headers_visible)
8186     return FALSE;
8187
8188   focus_child = gtk_container_get_focus_child (GTK_CONTAINER (tree_view));
8189
8190   first_column = tree_view->priv->columns;
8191   while (first_column)
8192     {
8193       column = GTK_TREE_VIEW_COLUMN (first_column->data);
8194       button = gtk_tree_view_column_get_button (column);
8195
8196       if (gtk_widget_get_can_focus (button) &&
8197           gtk_tree_view_column_get_visible (column) &&
8198           (gtk_tree_view_column_get_clickable (column) ||
8199            gtk_tree_view_column_get_reorderable (column)))
8200         break;
8201       first_column = first_column->next;
8202     }
8203
8204   /* No headers are visible, or are focusable.  We can't focus in or out.
8205    */
8206   if (first_column == NULL)
8207     return FALSE;
8208
8209   last_column = g_list_last (tree_view->priv->columns);
8210   while (last_column)
8211     {
8212       column = GTK_TREE_VIEW_COLUMN (last_column->data);
8213       button = gtk_tree_view_column_get_button (column);
8214
8215       if (gtk_widget_get_can_focus (button) &&
8216           gtk_tree_view_column_get_visible (column) &&
8217           (gtk_tree_view_column_get_clickable (column) ||
8218            gtk_tree_view_column_get_reorderable (column)))
8219         break;
8220       last_column = last_column->prev;
8221     }
8222
8223
8224   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
8225
8226   switch (dir)
8227     {
8228     case GTK_DIR_TAB_BACKWARD:
8229     case GTK_DIR_TAB_FORWARD:
8230     case GTK_DIR_UP:
8231     case GTK_DIR_DOWN:
8232       if (focus_child == NULL)
8233         {
8234           if (tree_view->priv->focus_column != NULL)
8235             button = gtk_tree_view_column_get_button (tree_view->priv->focus_column);
8236           else 
8237             button = NULL;
8238
8239           if (button && gtk_widget_get_can_focus (button))
8240             focus_child = button;
8241           else
8242             focus_child = gtk_tree_view_column_get_button (GTK_TREE_VIEW_COLUMN (first_column->data));
8243
8244           gtk_widget_grab_focus (focus_child);
8245           break;
8246         }
8247       return FALSE;
8248
8249     case GTK_DIR_LEFT:
8250     case GTK_DIR_RIGHT:
8251       if (focus_child == NULL)
8252         {
8253           if (tree_view->priv->focus_column != NULL)
8254             focus_child = gtk_tree_view_column_get_button (tree_view->priv->focus_column);
8255           else if (dir == GTK_DIR_LEFT)
8256             focus_child = gtk_tree_view_column_get_button (GTK_TREE_VIEW_COLUMN (last_column->data));
8257           else
8258             focus_child = gtk_tree_view_column_get_button (GTK_TREE_VIEW_COLUMN (first_column->data));
8259
8260           gtk_widget_grab_focus (focus_child);
8261           break;
8262         }
8263
8264       if (gtk_widget_child_focus (focus_child, dir))
8265         {
8266           /* The focus moves inside the button. */
8267           /* This is probably a great example of bad UI */
8268           break;
8269         }
8270
8271       /* We need to move the focus among the row of buttons. */
8272       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
8273         if (gtk_tree_view_column_get_button (GTK_TREE_VIEW_COLUMN (tmp_list->data)) == focus_child)
8274           break;
8275
8276       if ((tmp_list == first_column && dir == (rtl ? GTK_DIR_RIGHT : GTK_DIR_LEFT))
8277           || (tmp_list == last_column && dir == (rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT)))
8278         {
8279           gtk_widget_error_bell (GTK_WIDGET (tree_view));
8280           break;
8281         }
8282
8283       while (tmp_list)
8284         {
8285           GtkTreeViewColumn *column;
8286           GtkWidget         *button;
8287
8288           if (dir == (rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT))
8289             tmp_list = tmp_list->next;
8290           else
8291             tmp_list = tmp_list->prev;
8292
8293           if (tmp_list == NULL)
8294             {
8295               g_warning ("Internal button not found");
8296               break;
8297             }
8298           column = tmp_list->data;
8299           button = gtk_tree_view_column_get_button (column);
8300           if (button &&
8301               gtk_tree_view_column_get_visible (column) &&
8302               gtk_widget_get_can_focus (button))
8303             {
8304               focus_child = button;
8305               gtk_widget_grab_focus (button);
8306               break;
8307             }
8308         }
8309       break;
8310     default:
8311       g_assert_not_reached ();
8312       break;
8313     }
8314
8315   /* if focus child is non-null, we assume it's been set to the current focus child
8316    */
8317   if (focus_child)
8318     {
8319       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
8320         if (gtk_tree_view_column_get_button (GTK_TREE_VIEW_COLUMN (tmp_list->data)) == focus_child)
8321           {
8322             tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
8323             break;
8324           }
8325
8326       if (clamp_column_visible)
8327         {
8328           gtk_tree_view_clamp_column_visible (tree_view,
8329                                               tree_view->priv->focus_column,
8330                                               FALSE);
8331         }
8332     }
8333
8334   return (focus_child != NULL);
8335 }
8336
8337 /* This function returns in 'path' the first focusable path, if the given path
8338  * is already focusable, it's the returned one.
8339  */
8340 static gboolean
8341 search_first_focusable_path (GtkTreeView  *tree_view,
8342                              GtkTreePath **path,
8343                              gboolean      search_forward,
8344                              GtkRBTree   **new_tree,
8345                              GtkRBNode   **new_node)
8346 {
8347   GtkRBTree *tree = NULL;
8348   GtkRBNode *node = NULL;
8349
8350   if (!path || !*path)
8351     return FALSE;
8352
8353   _gtk_tree_view_find_node (tree_view, *path, &tree, &node);
8354
8355   if (!tree || !node)
8356     return FALSE;
8357
8358   while (node && row_is_separator (tree_view, NULL, *path))
8359     {
8360       if (search_forward)
8361         _gtk_rbtree_next_full (tree, node, &tree, &node);
8362       else
8363         _gtk_rbtree_prev_full (tree, node, &tree, &node);
8364
8365       if (*path)
8366         gtk_tree_path_free (*path);
8367
8368       if (node)
8369         *path = _gtk_tree_view_find_path (tree_view, tree, node);
8370       else
8371         *path = NULL;
8372     }
8373
8374   if (new_tree)
8375     *new_tree = tree;
8376
8377   if (new_node)
8378     *new_node = node;
8379
8380   return (*path != NULL);
8381 }
8382
8383 static gint
8384 gtk_tree_view_focus (GtkWidget        *widget,
8385                      GtkDirectionType  direction)
8386 {
8387   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
8388   GtkContainer *container = GTK_CONTAINER (widget);
8389   GtkWidget *focus_child;
8390
8391   if (!gtk_widget_is_sensitive (widget) || !gtk_widget_get_can_focus (widget))
8392     return FALSE;
8393
8394   focus_child = gtk_container_get_focus_child (container);
8395
8396   gtk_tree_view_stop_editing (GTK_TREE_VIEW (widget), FALSE);
8397   /* Case 1.  Headers currently have focus. */
8398   if (focus_child)
8399     {
8400       switch (direction)
8401         {
8402         case GTK_DIR_LEFT:
8403         case GTK_DIR_RIGHT:
8404           gtk_tree_view_header_focus (tree_view, direction, TRUE);
8405           return TRUE;
8406         case GTK_DIR_TAB_BACKWARD:
8407         case GTK_DIR_UP:
8408           return FALSE;
8409         case GTK_DIR_TAB_FORWARD:
8410         case GTK_DIR_DOWN:
8411           gtk_widget_grab_focus (widget);
8412           return TRUE;
8413         default:
8414           g_assert_not_reached ();
8415           return FALSE;
8416         }
8417     }
8418
8419   /* Case 2. We don't have focus at all. */
8420   if (!gtk_widget_has_focus (widget))
8421     {
8422       gtk_widget_grab_focus (widget);
8423       return TRUE;
8424     }
8425
8426   /* Case 3. We have focus already. */
8427   if (direction == GTK_DIR_TAB_BACKWARD)
8428     return (gtk_tree_view_header_focus (tree_view, direction, FALSE));
8429   else if (direction == GTK_DIR_TAB_FORWARD)
8430     return FALSE;
8431
8432   /* Other directions caught by the keybindings */
8433   gtk_widget_grab_focus (widget);
8434   return TRUE;
8435 }
8436
8437 static void
8438 gtk_tree_view_grab_focus (GtkWidget *widget)
8439 {
8440   GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->grab_focus (widget);
8441
8442   gtk_tree_view_focus_to_cursor (GTK_TREE_VIEW (widget));
8443 }
8444
8445 static void
8446 gtk_tree_view_style_updated (GtkWidget *widget)
8447 {
8448   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
8449   GList *list;
8450   GtkTreeViewColumn *column;
8451
8452   GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->style_updated (widget);
8453
8454   if (gtk_widget_get_realized (widget))
8455     {
8456       GtkStyleContext *context;
8457
8458       context = gtk_widget_get_style_context (widget);
8459
8460       gtk_style_context_save (context);
8461       gtk_style_context_add_class (context, GTK_STYLE_CLASS_VIEW);
8462       gtk_style_context_set_background (context, tree_view->priv->bin_window);
8463       gtk_style_context_restore (context);
8464
8465       gtk_style_context_set_background (context, tree_view->priv->header_window);
8466
8467       gtk_tree_view_set_grid_lines (tree_view, tree_view->priv->grid_lines);
8468       gtk_tree_view_set_enable_tree_lines (tree_view, tree_view->priv->tree_lines_enabled);
8469     }
8470
8471   gtk_widget_style_get (widget,
8472                         "expander-size", &tree_view->priv->expander_size,
8473                         NULL);
8474   tree_view->priv->expander_size += EXPANDER_EXTRA_PADDING;
8475
8476   for (list = tree_view->priv->columns; list; list = list->next)
8477     {
8478       column = list->data;
8479       _gtk_tree_view_column_cell_set_dirty (column, TRUE);
8480     }
8481
8482   tree_view->priv->fixed_height = -1;
8483   _gtk_rbtree_mark_invalid (tree_view->priv->tree);
8484
8485   gtk_widget_queue_resize (widget);
8486 }
8487
8488
8489 static void
8490 gtk_tree_view_set_focus_child (GtkContainer *container,
8491                                GtkWidget    *child)
8492 {
8493   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
8494   GList *list;
8495
8496   for (list = tree_view->priv->columns; list; list = list->next)
8497     {
8498       if (gtk_tree_view_column_get_button (GTK_TREE_VIEW_COLUMN (list->data)) == child)
8499         {
8500           tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (list->data);
8501           break;
8502         }
8503     }
8504
8505   GTK_CONTAINER_CLASS (gtk_tree_view_parent_class)->set_focus_child (container, child);
8506 }
8507
8508 static GtkWidgetPath *
8509 gtk_tree_view_get_path_for_child (GtkContainer *container,
8510                                   GtkWidget    *child)
8511 {
8512   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
8513   GtkWidgetPath *path;
8514   gboolean rtl;
8515   GList *list;
8516   gint n_col = 0;
8517
8518   path = GTK_CONTAINER_CLASS (gtk_tree_view_parent_class)->get_path_for_child (container, child);
8519   rtl = (gtk_widget_get_direction (GTK_WIDGET (container)) == GTK_TEXT_DIR_RTL);
8520
8521   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
8522        list;
8523        list = (rtl ? list->prev : list->next))
8524     {
8525       GtkTreeViewColumn *column = list->data;
8526       GtkRegionFlags flags = 0;
8527
8528       if (!gtk_tree_view_column_get_visible (column))
8529         continue;
8530
8531       n_col++;
8532
8533       if (gtk_tree_view_column_get_widget (column) != child &&
8534           gtk_tree_view_column_get_button (column) != child)
8535         continue;
8536
8537       if ((n_col % 2) == 0)
8538         flags |= GTK_REGION_EVEN;
8539       else
8540         flags |= GTK_REGION_ODD;
8541
8542       if (n_col == 1)
8543         flags |= GTK_REGION_FIRST;
8544
8545       if ((rtl && !list->prev) ||
8546           (!rtl && !list->next))
8547         flags |= GTK_REGION_LAST;
8548
8549       gtk_widget_path_iter_add_region (path, -1, GTK_STYLE_REGION_COLUMN_HEADER, flags);
8550       break;
8551     }
8552
8553   gtk_widget_path_append_for_widget (path, child);
8554
8555   return path;
8556 }
8557
8558 static gboolean
8559 gtk_tree_view_real_move_cursor (GtkTreeView       *tree_view,
8560                                 GtkMovementStep    step,
8561                                 gint               count)
8562 {
8563   GdkModifierType state;
8564
8565   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
8566   g_return_val_if_fail (step == GTK_MOVEMENT_LOGICAL_POSITIONS ||
8567                         step == GTK_MOVEMENT_VISUAL_POSITIONS ||
8568                         step == GTK_MOVEMENT_DISPLAY_LINES ||
8569                         step == GTK_MOVEMENT_PAGES ||
8570                         step == GTK_MOVEMENT_BUFFER_ENDS, FALSE);
8571
8572   if (tree_view->priv->tree == NULL)
8573     return FALSE;
8574   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
8575     return FALSE;
8576
8577   gtk_tree_view_stop_editing (tree_view, FALSE);
8578   tree_view->priv->draw_keyfocus = TRUE;
8579   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
8580
8581   if (gtk_get_current_event_state (&state))
8582     {
8583       GdkModifierType extend_mod_mask;
8584       GdkModifierType modify_mod_mask;
8585
8586       extend_mod_mask =
8587         gtk_widget_get_modifier_mask (GTK_WIDGET (tree_view),
8588                                       GDK_MODIFIER_INTENT_EXTEND_SELECTION);
8589
8590       modify_mod_mask =
8591         gtk_widget_get_modifier_mask (GTK_WIDGET (tree_view),
8592                                       GDK_MODIFIER_INTENT_MODIFY_SELECTION);
8593
8594       if ((state & modify_mod_mask) == modify_mod_mask)
8595         tree_view->priv->modify_selection_pressed = TRUE;
8596       if ((state & extend_mod_mask) == extend_mod_mask)
8597         tree_view->priv->extend_selection_pressed = TRUE;
8598     }
8599   /* else we assume not pressed */
8600
8601   switch (step)
8602     {
8603       /* currently we make no distinction.  When we go bi-di, we need to */
8604     case GTK_MOVEMENT_LOGICAL_POSITIONS:
8605     case GTK_MOVEMENT_VISUAL_POSITIONS:
8606       gtk_tree_view_move_cursor_left_right (tree_view, count);
8607       break;
8608     case GTK_MOVEMENT_DISPLAY_LINES:
8609       gtk_tree_view_move_cursor_up_down (tree_view, count);
8610       break;
8611     case GTK_MOVEMENT_PAGES:
8612       gtk_tree_view_move_cursor_page_up_down (tree_view, count);
8613       break;
8614     case GTK_MOVEMENT_BUFFER_ENDS:
8615       gtk_tree_view_move_cursor_start_end (tree_view, count);
8616       break;
8617     default:
8618       g_assert_not_reached ();
8619     }
8620
8621   tree_view->priv->modify_selection_pressed = FALSE;
8622   tree_view->priv->extend_selection_pressed = FALSE;
8623
8624   return TRUE;
8625 }
8626
8627 static void
8628 gtk_tree_view_put (GtkTreeView *tree_view,
8629                    GtkWidget   *child_widget,
8630                    /* in bin_window coordinates */
8631                    gint         x,
8632                    gint         y,
8633                    gint         width,
8634                    gint         height)
8635 {
8636   GtkTreeViewChild *child;
8637   
8638   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8639   g_return_if_fail (GTK_IS_WIDGET (child_widget));
8640
8641   child = g_slice_new (GtkTreeViewChild);
8642
8643   child->widget = child_widget;
8644   child->x = x;
8645   child->y = y;
8646   child->width = width;
8647   child->height = height;
8648
8649   tree_view->priv->children = g_list_append (tree_view->priv->children, child);
8650
8651   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
8652     gtk_widget_set_parent_window (child->widget, tree_view->priv->bin_window);
8653   
8654   gtk_widget_set_parent (child_widget, GTK_WIDGET (tree_view));
8655 }
8656
8657 void
8658 _gtk_tree_view_child_move_resize (GtkTreeView *tree_view,
8659                                   GtkWidget   *widget,
8660                                   /* in tree coordinates */
8661                                   gint         x,
8662                                   gint         y,
8663                                   gint         width,
8664                                   gint         height)
8665 {
8666   GtkTreeViewChild *child = NULL;
8667   GList *list;
8668   GdkRectangle allocation;
8669
8670   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8671   g_return_if_fail (GTK_IS_WIDGET (widget));
8672
8673   for (list = tree_view->priv->children; list; list = list->next)
8674     {
8675       if (((GtkTreeViewChild *)list->data)->widget == widget)
8676         {
8677           child = list->data;
8678           break;
8679         }
8680     }
8681   if (child == NULL)
8682     return;
8683
8684   allocation.x = child->x = x;
8685   allocation.y = child->y = y;
8686   allocation.width = child->width = width;
8687   allocation.height = child->height = height;
8688
8689   if (gtk_widget_get_realized (widget))
8690     gtk_widget_size_allocate (widget, &allocation);
8691 }
8692
8693
8694 /* TreeModel Callbacks
8695  */
8696
8697 static void
8698 gtk_tree_view_row_changed (GtkTreeModel *model,
8699                            GtkTreePath  *path,
8700                            GtkTreeIter  *iter,
8701                            gpointer      data)
8702 {
8703   GtkTreeView *tree_view = (GtkTreeView *)data;
8704   GtkRBTree *tree;
8705   GtkRBNode *node;
8706   gboolean free_path = FALSE;
8707   GList *list;
8708   GtkTreePath *cursor_path;
8709
8710   g_return_if_fail (path != NULL || iter != NULL);
8711
8712   if (tree_view->priv->cursor != NULL)
8713     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
8714   else
8715     cursor_path = NULL;
8716
8717   if (tree_view->priv->edited_column &&
8718       (cursor_path == NULL || gtk_tree_path_compare (cursor_path, path) == 0))
8719     gtk_tree_view_stop_editing (tree_view, TRUE);
8720
8721   if (cursor_path != NULL)
8722     gtk_tree_path_free (cursor_path);
8723
8724   if (path == NULL)
8725     {
8726       path = gtk_tree_model_get_path (model, iter);
8727       free_path = TRUE;
8728     }
8729   else if (iter == NULL)
8730     gtk_tree_model_get_iter (model, iter, path);
8731
8732   if (_gtk_tree_view_find_node (tree_view,
8733                                 path,
8734                                 &tree,
8735                                 &node))
8736     /* We aren't actually showing the node */
8737     goto done;
8738
8739   if (tree == NULL)
8740     goto done;
8741
8742   if (tree_view->priv->fixed_height_mode
8743       && tree_view->priv->fixed_height >= 0)
8744     {
8745       _gtk_rbtree_node_set_height (tree, node, tree_view->priv->fixed_height);
8746       if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
8747         gtk_tree_view_node_queue_redraw (tree_view, tree, node);
8748     }
8749   else
8750     {
8751       _gtk_rbtree_node_mark_invalid (tree, node);
8752       for (list = tree_view->priv->columns; list; list = list->next)
8753         {
8754           GtkTreeViewColumn *column;
8755
8756           column = list->data;
8757           if (!gtk_tree_view_column_get_visible (column))
8758             continue;
8759
8760           if (gtk_tree_view_column_get_sizing (column) == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
8761             {
8762               _gtk_tree_view_column_cell_set_dirty (column, TRUE);
8763             }
8764         }
8765     }
8766
8767  done:
8768   if (!tree_view->priv->fixed_height_mode &&
8769       gtk_widget_get_realized (GTK_WIDGET (tree_view)))
8770     install_presize_handler (tree_view);
8771   if (free_path)
8772     gtk_tree_path_free (path);
8773 }
8774
8775 static void
8776 gtk_tree_view_row_inserted (GtkTreeModel *model,
8777                             GtkTreePath  *path,
8778                             GtkTreeIter  *iter,
8779                             gpointer      data)
8780 {
8781   GtkTreeView *tree_view = (GtkTreeView *) data;
8782   gint *indices;
8783   GtkRBTree *tmptree, *tree;
8784   GtkRBNode *tmpnode = NULL;
8785   gint depth;
8786   gint i = 0;
8787   gint height;
8788   gboolean free_path = FALSE;
8789   gboolean node_visible = TRUE;
8790
8791   g_return_if_fail (path != NULL || iter != NULL);
8792
8793   if (tree_view->priv->fixed_height_mode
8794       && tree_view->priv->fixed_height >= 0)
8795     height = tree_view->priv->fixed_height;
8796   else
8797     height = 0;
8798
8799   if (path == NULL)
8800     {
8801       path = gtk_tree_model_get_path (model, iter);
8802       free_path = TRUE;
8803     }
8804   else if (iter == NULL)
8805     gtk_tree_model_get_iter (model, iter, path);
8806
8807   if (tree_view->priv->tree == NULL)
8808     tree_view->priv->tree = _gtk_rbtree_new ();
8809
8810   tmptree = tree = tree_view->priv->tree;
8811
8812   /* Update all row-references */
8813   gtk_tree_row_reference_inserted (G_OBJECT (data), path);
8814   depth = gtk_tree_path_get_depth (path);
8815   indices = gtk_tree_path_get_indices (path);
8816
8817   /* First, find the parent tree */
8818   while (i < depth - 1)
8819     {
8820       if (tmptree == NULL)
8821         {
8822           /* We aren't showing the node */
8823           node_visible = FALSE;
8824           goto done;
8825         }
8826
8827       tmpnode = _gtk_rbtree_find_count (tmptree, indices[i] + 1);
8828       if (tmpnode == NULL)
8829         {
8830           g_warning ("A node was inserted with a parent that's not in the tree.\n" \
8831                      "This possibly means that a GtkTreeModel inserted a child node\n" \
8832                      "before the parent was inserted.");
8833           goto done;
8834         }
8835       else if (!GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_IS_PARENT))
8836         {
8837           /* FIXME enforce correct behavior on model, probably */
8838           /* In theory, the model should have emitted has_child_toggled here.  We
8839            * try to catch it anyway, just to be safe, in case the model hasn't.
8840            */
8841           GtkTreePath *tmppath = _gtk_tree_view_find_path (tree_view,
8842                                                            tree,
8843                                                            tmpnode);
8844           gtk_tree_view_row_has_child_toggled (model, tmppath, NULL, data);
8845           gtk_tree_path_free (tmppath);
8846           goto done;
8847         }
8848
8849       tmptree = tmpnode->children;
8850       tree = tmptree;
8851       i++;
8852     }
8853
8854   if (tree == NULL)
8855     {
8856       node_visible = FALSE;
8857       goto done;
8858     }
8859
8860   /* ref the node */
8861   gtk_tree_model_ref_node (tree_view->priv->model, iter);
8862   if (indices[depth - 1] == 0)
8863     {
8864       tmpnode = _gtk_rbtree_find_count (tree, 1);
8865       tmpnode = _gtk_rbtree_insert_before (tree, tmpnode, height, FALSE);
8866     }
8867   else
8868     {
8869       tmpnode = _gtk_rbtree_find_count (tree, indices[depth - 1]);
8870       tmpnode = _gtk_rbtree_insert_after (tree, tmpnode, height, FALSE);
8871     }
8872
8873  done:
8874   if (height > 0)
8875     {
8876       if (tree)
8877         _gtk_rbtree_node_mark_valid (tree, tmpnode);
8878
8879       if (node_visible && node_is_visible (tree_view, tree, tmpnode))
8880         gtk_widget_queue_resize (GTK_WIDGET (tree_view));
8881       else
8882         gtk_widget_queue_resize_no_redraw (GTK_WIDGET (tree_view));
8883     }
8884   else
8885     install_presize_handler (tree_view);
8886   if (free_path)
8887     gtk_tree_path_free (path);
8888 }
8889
8890 static void
8891 gtk_tree_view_row_has_child_toggled (GtkTreeModel *model,
8892                                      GtkTreePath  *path,
8893                                      GtkTreeIter  *iter,
8894                                      gpointer      data)
8895 {
8896   GtkTreeView *tree_view = (GtkTreeView *)data;
8897   GtkTreeIter real_iter;
8898   gboolean has_child;
8899   GtkRBTree *tree;
8900   GtkRBNode *node;
8901   gboolean free_path = FALSE;
8902
8903   g_return_if_fail (path != NULL || iter != NULL);
8904
8905   if (iter)
8906     real_iter = *iter;
8907
8908   if (path == NULL)
8909     {
8910       path = gtk_tree_model_get_path (model, iter);
8911       free_path = TRUE;
8912     }
8913   else if (iter == NULL)
8914     gtk_tree_model_get_iter (model, &real_iter, path);
8915
8916   if (_gtk_tree_view_find_node (tree_view,
8917                                 path,
8918                                 &tree,
8919                                 &node))
8920     /* We aren't actually showing the node */
8921     goto done;
8922
8923   if (tree == NULL)
8924     goto done;
8925
8926   has_child = gtk_tree_model_iter_has_child (model, &real_iter);
8927   /* Sanity check.
8928    */
8929   if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT) == has_child)
8930     goto done;
8931
8932   if (has_child)
8933     GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_PARENT);
8934   else
8935     GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_PARENT);
8936
8937   if (has_child && tree_view->priv->is_list)
8938     {
8939       tree_view->priv->is_list = FALSE;
8940       if (tree_view->priv->show_expanders)
8941         {
8942           GList *list;
8943
8944           for (list = tree_view->priv->columns; list; list = list->next)
8945             if (gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (list->data)))
8946               {
8947                 _gtk_tree_view_column_cell_set_dirty (GTK_TREE_VIEW_COLUMN (list->data), TRUE);
8948                 break;
8949               }
8950         }
8951       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
8952     }
8953   else
8954     {
8955       _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
8956     }
8957
8958  done:
8959   if (free_path)
8960     gtk_tree_path_free (path);
8961 }
8962
8963 static void
8964 count_children_helper (GtkRBTree *tree,
8965                        GtkRBNode *node,
8966                        gpointer   data)
8967 {
8968   if (node->children)
8969     _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, data);
8970   (*((gint *)data))++;
8971 }
8972
8973 static void
8974 check_selection_helper (GtkRBTree *tree,
8975                         GtkRBNode *node,
8976                         gpointer   data)
8977 {
8978   gint *value = (gint *)data;
8979
8980   *value = GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED);
8981
8982   if (node->children && !*value)
8983     _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, check_selection_helper, data);
8984 }
8985
8986 static void
8987 gtk_tree_view_row_deleted (GtkTreeModel *model,
8988                            GtkTreePath  *path,
8989                            gpointer      data)
8990 {
8991   GtkTreeView *tree_view = (GtkTreeView *)data;
8992   GtkRBTree *tree;
8993   GtkRBNode *node;
8994   GList *list;
8995   gint selection_changed = FALSE;
8996   GtkStyleContext *context;
8997
8998   g_return_if_fail (path != NULL);
8999
9000   gtk_tree_row_reference_deleted (G_OBJECT (data), path);
9001
9002   if (_gtk_tree_view_find_node (tree_view, path, &tree, &node))
9003     return;
9004
9005   if (tree == NULL)
9006     return;
9007
9008   /* check if the selection has been changed */
9009   _gtk_rbtree_traverse (tree, node, G_POST_ORDER,
9010                         check_selection_helper, &selection_changed);
9011
9012   for (list = tree_view->priv->columns; list; list = list->next)
9013     if (gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (list->data)) &&
9014         gtk_tree_view_column_get_sizing (GTK_TREE_VIEW_COLUMN (list->data)) == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
9015       _gtk_tree_view_column_cell_set_dirty ((GtkTreeViewColumn *)list->data, TRUE);
9016
9017   /* Ensure we don't have a dangling pointer to a dead node */
9018   ensure_unprelighted (tree_view);
9019
9020   /* Cancel editting if we've started */
9021   gtk_tree_view_stop_editing (tree_view, TRUE);
9022
9023   if (tree_view->priv->destroy_count_func)
9024     {
9025       gint child_count = 0;
9026       if (node->children)
9027         _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, &child_count);
9028       tree_view->priv->destroy_count_func (tree_view, path, child_count, tree_view->priv->destroy_count_data);
9029     }
9030
9031   if (tree->root->count == 1)
9032     {
9033       if (tree_view->priv->tree == tree)
9034         tree_view->priv->tree = NULL;
9035
9036       _gtk_rbtree_remove (tree);
9037     }
9038   else
9039     {
9040       _gtk_rbtree_remove_node (tree, node);
9041     }
9042
9043   if (! gtk_tree_row_reference_valid (tree_view->priv->top_row))
9044     {
9045       gtk_tree_row_reference_free (tree_view->priv->top_row);
9046       tree_view->priv->top_row = NULL;
9047     }
9048
9049   /* Cancel any ongoing animation happening within the row */
9050   context = gtk_widget_get_style_context (GTK_WIDGET (tree_view));
9051   gtk_style_context_cancel_animations (context, node);
9052
9053   install_scroll_sync_handler (tree_view);
9054
9055   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
9056
9057   if (selection_changed)
9058     g_signal_emit_by_name (tree_view->priv->selection, "changed");
9059 }
9060
9061 static void
9062 gtk_tree_view_rows_reordered (GtkTreeModel *model,
9063                               GtkTreePath  *parent,
9064                               GtkTreeIter  *iter,
9065                               gint         *new_order,
9066                               gpointer      data)
9067 {
9068   GtkTreeView *tree_view = GTK_TREE_VIEW (data);
9069   GtkRBTree *tree;
9070   GtkRBNode *node;
9071   gint len;
9072
9073   len = gtk_tree_model_iter_n_children (model, iter);
9074
9075   if (len < 2)
9076     return;
9077
9078   gtk_tree_row_reference_reordered (G_OBJECT (data),
9079                                     parent,
9080                                     iter,
9081                                     new_order);
9082
9083   if (_gtk_tree_view_find_node (tree_view,
9084                                 parent,
9085                                 &tree,
9086                                 &node))
9087     return;
9088
9089   /* We need to special case the parent path */
9090   if (tree == NULL)
9091     tree = tree_view->priv->tree;
9092   else
9093     tree = node->children;
9094
9095   if (tree == NULL)
9096     return;
9097
9098   if (tree_view->priv->edited_column)
9099     gtk_tree_view_stop_editing (tree_view, TRUE);
9100
9101   /* we need to be unprelighted */
9102   ensure_unprelighted (tree_view);
9103
9104   _gtk_rbtree_reorder (tree, new_order, len);
9105
9106   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
9107
9108   gtk_tree_view_dy_to_top_row (tree_view);
9109 }
9110
9111
9112 /* Internal tree functions
9113  */
9114
9115
9116 static void
9117 gtk_tree_view_get_background_xrange (GtkTreeView       *tree_view,
9118                                      GtkRBTree         *tree,
9119                                      GtkTreeViewColumn *column,
9120                                      gint              *x1,
9121                                      gint              *x2)
9122 {
9123   GtkTreeViewColumn *tmp_column = NULL;
9124   gint total_width;
9125   GList *list;
9126   gboolean rtl;
9127
9128   if (x1)
9129     *x1 = 0;
9130
9131   if (x2)
9132     *x2 = 0;
9133
9134   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
9135
9136   total_width = 0;
9137   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
9138        list;
9139        list = (rtl ? list->prev : list->next))
9140     {
9141       tmp_column = list->data;
9142
9143       if (tmp_column == column)
9144         break;
9145
9146       if (gtk_tree_view_column_get_visible (tmp_column))
9147         total_width += gtk_tree_view_column_get_width (tmp_column);
9148     }
9149
9150   if (tmp_column != column)
9151     {
9152       g_warning (G_STRLOC": passed-in column isn't in the tree");
9153       return;
9154     }
9155
9156   if (x1)
9157     *x1 = total_width;
9158
9159   if (x2)
9160     {
9161       if (gtk_tree_view_column_get_visible (column))
9162         *x2 = total_width + gtk_tree_view_column_get_width (column);
9163       else
9164         *x2 = total_width; /* width of 0 */
9165     }
9166 }
9167
9168 static void
9169 gtk_tree_view_get_arrow_xrange (GtkTreeView *tree_view,
9170                                 GtkRBTree   *tree,
9171                                 gint        *x1,
9172                                 gint        *x2)
9173 {
9174   gint x_offset = 0;
9175   GList *list;
9176   GtkTreeViewColumn *tmp_column = NULL;
9177   gint total_width;
9178   gboolean indent_expanders;
9179   gboolean rtl;
9180
9181   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
9182
9183   total_width = 0;
9184   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
9185        list;
9186        list = (rtl ? list->prev : list->next))
9187     {
9188       tmp_column = list->data;
9189
9190       if (gtk_tree_view_is_expander_column (tree_view, tmp_column))
9191         {
9192           if (rtl)
9193             x_offset = total_width + gtk_tree_view_column_get_width (tmp_column) - tree_view->priv->expander_size;
9194           else
9195             x_offset = total_width;
9196           break;
9197         }
9198
9199       if (gtk_tree_view_column_get_visible (tmp_column))
9200         total_width += gtk_tree_view_column_get_width (tmp_column);
9201     }
9202
9203   gtk_widget_style_get (GTK_WIDGET (tree_view),
9204                         "indent-expanders", &indent_expanders,
9205                         NULL);
9206
9207   if (indent_expanders)
9208     {
9209       if (rtl)
9210         x_offset -= tree_view->priv->expander_size * _gtk_rbtree_get_depth (tree);
9211       else
9212         x_offset += tree_view->priv->expander_size * _gtk_rbtree_get_depth (tree);
9213     }
9214
9215   *x1 = x_offset;
9216
9217   if (tmp_column &&
9218       gtk_tree_view_column_get_visible (tmp_column))
9219     /* +1 because x2 isn't included in the range. */
9220     *x2 = *x1 + tree_view->priv->expander_size + 1;
9221   else
9222     *x2 = *x1;
9223 }
9224
9225 static void
9226 gtk_tree_view_build_tree (GtkTreeView *tree_view,
9227                           GtkRBTree   *tree,
9228                           GtkTreeIter *iter,
9229                           gint         depth,
9230                           gboolean     recurse)
9231 {
9232   GtkRBNode *temp = NULL;
9233   GtkTreePath *path = NULL;
9234
9235   do
9236     {
9237       gtk_tree_model_ref_node (tree_view->priv->model, iter);
9238       temp = _gtk_rbtree_insert_after (tree, temp, 0, FALSE);
9239
9240       if (tree_view->priv->fixed_height > 0)
9241         {
9242           if (GTK_RBNODE_FLAG_SET (temp, GTK_RBNODE_INVALID))
9243             {
9244               _gtk_rbtree_node_set_height (tree, temp, tree_view->priv->fixed_height);
9245               _gtk_rbtree_node_mark_valid (tree, temp);
9246             }
9247         }
9248
9249       if (tree_view->priv->is_list)
9250         continue;
9251
9252       if (recurse)
9253         {
9254           GtkTreeIter child;
9255
9256           if (!path)
9257             path = gtk_tree_model_get_path (tree_view->priv->model, iter);
9258           else
9259             gtk_tree_path_next (path);
9260
9261           if (gtk_tree_model_iter_children (tree_view->priv->model, &child, iter))
9262             {
9263               gboolean expand;
9264
9265               g_signal_emit (tree_view, tree_view_signals[TEST_EXPAND_ROW], 0, iter, path, &expand);
9266
9267               if (gtk_tree_model_iter_has_child (tree_view->priv->model, iter)
9268                   && !expand)
9269                 {
9270                   temp->children = _gtk_rbtree_new ();
9271                   temp->children->parent_tree = tree;
9272                   temp->children->parent_node = temp;
9273                   gtk_tree_view_build_tree (tree_view, temp->children, &child, depth + 1, recurse);
9274                 }
9275             }
9276         }
9277
9278       if (gtk_tree_model_iter_has_child (tree_view->priv->model, iter))
9279         {
9280           if ((temp->flags&GTK_RBNODE_IS_PARENT) != GTK_RBNODE_IS_PARENT)
9281             temp->flags ^= GTK_RBNODE_IS_PARENT;
9282         }
9283     }
9284   while (gtk_tree_model_iter_next (tree_view->priv->model, iter));
9285
9286   if (path)
9287     gtk_tree_path_free (path);
9288 }
9289
9290 /* Make sure the node is visible vertically */
9291 static void
9292 gtk_tree_view_clamp_node_visible (GtkTreeView *tree_view,
9293                                   GtkRBTree   *tree,
9294                                   GtkRBNode   *node)
9295 {
9296   gint node_dy, height;
9297   GtkTreePath *path = NULL;
9298
9299   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
9300     return;
9301
9302   /* just return if the node is visible, avoiding a costly expose */
9303   node_dy = _gtk_rbtree_node_find_offset (tree, node);
9304   height = gtk_tree_view_get_row_height (tree_view, node);
9305   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID)
9306       && node_dy >= gtk_adjustment_get_value (tree_view->priv->vadjustment)
9307       && node_dy + height <= (gtk_adjustment_get_value (tree_view->priv->vadjustment)
9308                               + gtk_adjustment_get_page_size (tree_view->priv->vadjustment)))
9309     return;
9310
9311   path = _gtk_tree_view_find_path (tree_view, tree, node);
9312   if (path)
9313     {
9314       /* We process updates because we want to clear old selected items when we scroll.
9315        * if this is removed, we get a "selection streak" at the bottom. */
9316       gtk_tree_view_bin_process_updates (tree_view);
9317
9318       gtk_tree_view_scroll_to_cell (tree_view, path, NULL, FALSE, 0.0, 0.0);
9319       gtk_tree_path_free (path);
9320     }
9321 }
9322
9323 static void
9324 gtk_tree_view_clamp_column_visible (GtkTreeView       *tree_view,
9325                                     GtkTreeViewColumn *column,
9326                                     gboolean           focus_to_cell)
9327 {
9328   GtkAllocation allocation;
9329   gint x, width;
9330
9331   if (column == NULL)
9332     return;
9333
9334   gtk_widget_get_allocation (gtk_tree_view_column_get_button (column), &allocation);
9335   x = allocation.x;
9336   width = allocation.width;
9337
9338   if (width > gtk_adjustment_get_page_size (tree_view->priv->hadjustment))
9339     {
9340       /* The column is larger than the horizontal page size.  If the
9341        * column has cells which can be focussed individually, then we make
9342        * sure the cell which gets focus is fully visible (if even the
9343        * focus cell is bigger than the page size, we make sure the
9344        * left-hand side of the cell is visible).
9345        *
9346        * If the column does not have an activatable cell, we
9347        * make sure the left-hand side of the column is visible.
9348        */
9349
9350       if (focus_to_cell && gtk_tree_view_has_can_focus_cell (tree_view))
9351         {
9352           GtkCellArea *cell_area;
9353           GtkCellRenderer *focus_cell;
9354
9355           cell_area = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (column));
9356           focus_cell = gtk_cell_area_get_focus_cell (cell_area);
9357
9358           if (gtk_tree_view_column_cell_get_position (column, focus_cell,
9359                                                       &x, &width))
9360             {
9361               if (width < gtk_adjustment_get_page_size (tree_view->priv->hadjustment))
9362                 {
9363                   if (gtk_adjustment_get_value (tree_view->priv->hadjustment) + gtk_adjustment_get_page_size (tree_view->priv->hadjustment) < x + width)
9364                     gtk_adjustment_set_value (tree_view->priv->hadjustment,
9365                                               x + width - gtk_adjustment_get_page_size (tree_view->priv->hadjustment));
9366                   else if (gtk_adjustment_get_value (tree_view->priv->hadjustment) > x)
9367                     gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
9368                 }
9369             }
9370         }
9371
9372       gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
9373     }
9374   else
9375     {
9376       if ((gtk_adjustment_get_value (tree_view->priv->hadjustment) + gtk_adjustment_get_page_size (tree_view->priv->hadjustment)) < (x + width))
9377           gtk_adjustment_set_value (tree_view->priv->hadjustment,
9378                                     x + width - gtk_adjustment_get_page_size (tree_view->priv->hadjustment));
9379       else if (gtk_adjustment_get_value (tree_view->priv->hadjustment) > x)
9380         gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
9381   }
9382 }
9383
9384 /* This function could be more efficient.  I'll optimize it if profiling seems
9385  * to imply that it is important */
9386 GtkTreePath *
9387 _gtk_tree_view_find_path (GtkTreeView *tree_view,
9388                           GtkRBTree   *tree,
9389                           GtkRBNode   *node)
9390 {
9391   GtkTreePath *path;
9392   GtkRBTree *tmp_tree;
9393   GtkRBNode *tmp_node, *last;
9394   gint count;
9395
9396   path = gtk_tree_path_new ();
9397
9398   g_return_val_if_fail (node != NULL, path);
9399   g_return_val_if_fail (node != tree->nil, path);
9400
9401   count = 1 + node->left->count;
9402
9403   last = node;
9404   tmp_node = node->parent;
9405   tmp_tree = tree;
9406   while (tmp_tree)
9407     {
9408       while (tmp_node != tmp_tree->nil)
9409         {
9410           if (tmp_node->right == last)
9411             count += 1 + tmp_node->left->count;
9412           last = tmp_node;
9413           tmp_node = tmp_node->parent;
9414         }
9415       gtk_tree_path_prepend_index (path, count - 1);
9416       last = tmp_tree->parent_node;
9417       tmp_tree = tmp_tree->parent_tree;
9418       if (last)
9419         {
9420           count = 1 + last->left->count;
9421           tmp_node = last->parent;
9422         }
9423     }
9424   return path;
9425 }
9426
9427 /* Returns TRUE if we ran out of tree before finding the path.  If the path is
9428  * invalid (ie. points to a node that's not in the tree), *tree and *node are
9429  * both set to NULL.
9430  */
9431 gboolean
9432 _gtk_tree_view_find_node (GtkTreeView  *tree_view,
9433                           GtkTreePath  *path,
9434                           GtkRBTree   **tree,
9435                           GtkRBNode   **node)
9436 {
9437   GtkRBNode *tmpnode = NULL;
9438   GtkRBTree *tmptree = tree_view->priv->tree;
9439   gint *indices = gtk_tree_path_get_indices (path);
9440   gint depth = gtk_tree_path_get_depth (path);
9441   gint i = 0;
9442
9443   *node = NULL;
9444   *tree = NULL;
9445
9446   if (depth == 0 || tmptree == NULL)
9447     return FALSE;
9448   do
9449     {
9450       tmpnode = _gtk_rbtree_find_count (tmptree, indices[i] + 1);
9451       ++i;
9452       if (tmpnode == NULL)
9453         {
9454           *tree = NULL;
9455           *node = NULL;
9456           return FALSE;
9457         }
9458       if (i >= depth)
9459         {
9460           *tree = tmptree;
9461           *node = tmpnode;
9462           return FALSE;
9463         }
9464       *tree = tmptree;
9465       *node = tmpnode;
9466       tmptree = tmpnode->children;
9467       if (tmptree == NULL)
9468         return TRUE;
9469     }
9470   while (1);
9471 }
9472
9473 static gboolean
9474 gtk_tree_view_is_expander_column (GtkTreeView       *tree_view,
9475                                   GtkTreeViewColumn *column)
9476 {
9477   GList *list;
9478
9479   if (tree_view->priv->is_list)
9480     return FALSE;
9481
9482   if (tree_view->priv->expander_column != NULL)
9483     {
9484       if (tree_view->priv->expander_column == column)
9485         return TRUE;
9486       return FALSE;
9487     }
9488   else
9489     {
9490       for (list = tree_view->priv->columns;
9491            list;
9492            list = list->next)
9493         if (gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (list->data)))
9494           break;
9495       if (list && list->data == column)
9496         return TRUE;
9497     }
9498   return FALSE;
9499 }
9500
9501 static inline gboolean
9502 gtk_tree_view_draw_expanders (GtkTreeView *tree_view)
9503 {
9504   if (!tree_view->priv->is_list && tree_view->priv->show_expanders)
9505     return TRUE;
9506   /* else */
9507   return FALSE;
9508 }
9509
9510 static void
9511 gtk_tree_view_add_move_binding (GtkBindingSet  *binding_set,
9512                                 guint           keyval,
9513                                 guint           modmask,
9514                                 gboolean        add_shifted_binding,
9515                                 GtkMovementStep step,
9516                                 gint            count)
9517 {
9518   
9519   gtk_binding_entry_add_signal (binding_set, keyval, modmask,
9520                                 "move-cursor", 2,
9521                                 G_TYPE_ENUM, step,
9522                                 G_TYPE_INT, count);
9523
9524   if (add_shifted_binding)
9525     gtk_binding_entry_add_signal (binding_set, keyval, GDK_SHIFT_MASK,
9526                                   "move-cursor", 2,
9527                                   G_TYPE_ENUM, step,
9528                                   G_TYPE_INT, count);
9529
9530   if ((modmask & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
9531    return;
9532
9533   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK | GDK_SHIFT_MASK,
9534                                 "move-cursor", 2,
9535                                 G_TYPE_ENUM, step,
9536                                 G_TYPE_INT, count);
9537
9538   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK,
9539                                 "move-cursor", 2,
9540                                 G_TYPE_ENUM, step,
9541                                 G_TYPE_INT, count);
9542 }
9543
9544 static gint
9545 gtk_tree_view_unref_tree_helper (GtkTreeModel *model,
9546                                  GtkTreeIter  *iter,
9547                                  GtkRBTree    *tree,
9548                                  GtkRBNode    *node)
9549 {
9550   gint retval = FALSE;
9551   do
9552     {
9553       g_return_val_if_fail (node != NULL, FALSE);
9554
9555       if (node->children)
9556         {
9557           GtkTreeIter child;
9558           GtkRBTree *new_tree;
9559           GtkRBNode *new_node;
9560
9561           new_tree = node->children;
9562           new_node = new_tree->root;
9563
9564           while (new_node && new_node->left != new_tree->nil)
9565             new_node = new_node->left;
9566
9567           if (!gtk_tree_model_iter_children (model, &child, iter))
9568             return FALSE;
9569
9570           retval = retval || gtk_tree_view_unref_tree_helper (model, &child, new_tree, new_node);
9571         }
9572
9573       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
9574         retval = TRUE;
9575       gtk_tree_model_unref_node (model, iter);
9576       node = _gtk_rbtree_next (tree, node);
9577     }
9578   while (gtk_tree_model_iter_next (model, iter));
9579
9580   return retval;
9581 }
9582
9583 static gint
9584 gtk_tree_view_unref_and_check_selection_tree (GtkTreeView *tree_view,
9585                                               GtkRBTree   *tree)
9586 {
9587   GtkTreeIter iter;
9588   GtkTreePath *path;
9589   GtkRBNode *node;
9590   gint retval;
9591
9592   if (!tree)
9593     return FALSE;
9594
9595   node = tree->root;
9596   while (node && node->left != tree->nil)
9597     node = node->left;
9598
9599   g_return_val_if_fail (node != NULL, FALSE);
9600   path = _gtk_tree_view_find_path (tree_view, tree, node);
9601   gtk_tree_model_get_iter (GTK_TREE_MODEL (tree_view->priv->model),
9602                            &iter, path);
9603   retval = gtk_tree_view_unref_tree_helper (GTK_TREE_MODEL (tree_view->priv->model), &iter, tree, node);
9604   gtk_tree_path_free (path);
9605
9606   return retval;
9607 }
9608
9609 static void
9610 gtk_tree_view_set_column_drag_info (GtkTreeView       *tree_view,
9611                                     GtkTreeViewColumn *column)
9612 {
9613   GtkTreeViewColumn *left_column;
9614   GtkTreeViewColumn *cur_column = NULL;
9615   GtkTreeViewColumnReorder *reorder;
9616   gboolean rtl;
9617   GList *tmp_list;
9618   gint left;
9619
9620   /* We want to precalculate the motion list such that we know what column slots
9621    * are available.
9622    */
9623   left_column = NULL;
9624   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
9625
9626   /* First, identify all possible drop spots */
9627   if (rtl)
9628     tmp_list = g_list_last (tree_view->priv->columns);
9629   else
9630     tmp_list = g_list_first (tree_view->priv->columns);
9631
9632   while (tmp_list)
9633     {
9634       cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
9635       tmp_list = rtl?g_list_previous (tmp_list):g_list_next (tmp_list);
9636
9637       if (gtk_tree_view_column_get_visible (cur_column) == FALSE)
9638         continue;
9639
9640       /* If it's not the column moving and func tells us to skip over the column, we continue. */
9641       if (left_column != column && cur_column != column &&
9642           tree_view->priv->column_drop_func &&
9643           ! tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
9644         {
9645           left_column = cur_column;
9646           continue;
9647         }
9648       reorder = g_slice_new0 (GtkTreeViewColumnReorder);
9649       reorder->left_column = left_column;
9650       left_column = reorder->right_column = cur_column;
9651
9652       tree_view->priv->column_drag_info = g_list_append (tree_view->priv->column_drag_info, reorder);
9653     }
9654
9655   /* Add the last one */
9656   if (tree_view->priv->column_drop_func == NULL ||
9657       ((left_column != column) &&
9658        tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data)))
9659     {
9660       reorder = g_slice_new0 (GtkTreeViewColumnReorder);
9661       reorder->left_column = left_column;
9662       reorder->right_column = NULL;
9663       tree_view->priv->column_drag_info = g_list_append (tree_view->priv->column_drag_info, reorder);
9664     }
9665
9666   /* We quickly check to see if it even makes sense to reorder columns. */
9667   /* If there is nothing that can be moved, then we return */
9668
9669   if (tree_view->priv->column_drag_info == NULL)
9670     return;
9671
9672   /* We know there are always 2 slots possbile, as you can always return column. */
9673   /* If that's all there is, return */
9674   if (tree_view->priv->column_drag_info->next == NULL || 
9675       (tree_view->priv->column_drag_info->next->next == NULL &&
9676        ((GtkTreeViewColumnReorder *)tree_view->priv->column_drag_info->data)->right_column == column &&
9677        ((GtkTreeViewColumnReorder *)tree_view->priv->column_drag_info->next->data)->left_column == column))
9678     {
9679       for (tmp_list = tree_view->priv->column_drag_info; tmp_list; tmp_list = tmp_list->next)
9680         g_slice_free (GtkTreeViewColumnReorder, tmp_list->data);
9681       g_list_free (tree_view->priv->column_drag_info);
9682       tree_view->priv->column_drag_info = NULL;
9683       return;
9684     }
9685   /* We fill in the ranges for the columns, now that we've isolated them */
9686   left = - TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER (tree_view);
9687
9688   for (tmp_list = tree_view->priv->column_drag_info; tmp_list; tmp_list = tmp_list->next)
9689     {
9690       reorder = (GtkTreeViewColumnReorder *) tmp_list->data;
9691
9692       reorder->left_align = left;
9693       if (tmp_list->next != NULL)
9694         {
9695           GtkAllocation right_allocation, left_allocation;
9696           GtkWidget    *left_button, *right_button;
9697
9698           g_assert (tmp_list->next->data);
9699
9700           right_button = gtk_tree_view_column_get_button (reorder->right_column);
9701           left_button  = gtk_tree_view_column_get_button
9702             (((GtkTreeViewColumnReorder *)tmp_list->next->data)->left_column);
9703
9704           gtk_widget_get_allocation (right_button, &right_allocation);
9705           gtk_widget_get_allocation (left_button, &left_allocation);
9706           left = reorder->right_align = (right_allocation.x + right_allocation.width + left_allocation.x) / 2;
9707         }
9708       else
9709         {
9710           reorder->right_align = gdk_window_get_width (tree_view->priv->header_window)
9711                                  + TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER (tree_view);
9712         }
9713     }
9714 }
9715
9716 void
9717 _gtk_tree_view_column_start_drag (GtkTreeView       *tree_view,
9718                                   GtkTreeViewColumn *column,
9719                                   GdkDevice         *device)
9720 {
9721   GdkEvent *send_event;
9722   GtkAllocation allocation;
9723   GtkAllocation button_allocation;
9724   GdkScreen *screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
9725   GtkWidget *button;
9726   GdkDevice *pointer, *keyboard;
9727
9728   g_return_if_fail (tree_view->priv->column_drag_info == NULL);
9729   g_return_if_fail (tree_view->priv->cur_reorder == NULL);
9730
9731   gtk_tree_view_set_column_drag_info (tree_view, column);
9732
9733   if (tree_view->priv->column_drag_info == NULL)
9734     return;
9735
9736   button = gtk_tree_view_column_get_button (column);
9737
9738   if (tree_view->priv->drag_window == NULL)
9739     {
9740       GdkWindowAttr attributes;
9741       guint attributes_mask;
9742
9743       gtk_widget_get_allocation (button, &button_allocation);
9744
9745       attributes.window_type = GDK_WINDOW_CHILD;
9746       attributes.wclass = GDK_INPUT_OUTPUT;
9747       attributes.x = button_allocation.x;
9748       attributes.y = 0;
9749       attributes.width = button_allocation.width;
9750       attributes.height = button_allocation.height;
9751       attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
9752       attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
9753       attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
9754
9755       tree_view->priv->drag_window = gdk_window_new (tree_view->priv->bin_window,
9756                                                      &attributes,
9757                                                      attributes_mask);
9758       gdk_window_set_user_data (tree_view->priv->drag_window, GTK_WIDGET (tree_view));
9759     }
9760
9761   if (gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD)
9762     {
9763       keyboard = device;
9764       pointer = gdk_device_get_associated_device (device);
9765     }
9766   else
9767     {
9768       pointer = device;
9769       keyboard = gdk_device_get_associated_device (device);
9770     }
9771
9772   gdk_device_ungrab (pointer, GDK_CURRENT_TIME);
9773   gdk_device_ungrab (keyboard, GDK_CURRENT_TIME);
9774
9775   gtk_grab_remove (button);
9776
9777   send_event = gdk_event_new (GDK_LEAVE_NOTIFY);
9778   send_event->crossing.send_event = TRUE;
9779   send_event->crossing.window = g_object_ref (gtk_button_get_event_window (GTK_BUTTON (button)));
9780   send_event->crossing.subwindow = NULL;
9781   send_event->crossing.detail = GDK_NOTIFY_ANCESTOR;
9782   send_event->crossing.time = GDK_CURRENT_TIME;
9783   gdk_event_set_device (send_event, device);
9784
9785   gtk_propagate_event (button, send_event);
9786   gdk_event_free (send_event);
9787
9788   send_event = gdk_event_new (GDK_BUTTON_RELEASE);
9789   send_event->button.window = g_object_ref (gdk_screen_get_root_window (screen));
9790   send_event->button.send_event = TRUE;
9791   send_event->button.time = GDK_CURRENT_TIME;
9792   send_event->button.x = -1;
9793   send_event->button.y = -1;
9794   send_event->button.axes = NULL;
9795   send_event->button.state = 0;
9796   send_event->button.button = 1;
9797   send_event->button.x_root = 0;
9798   send_event->button.y_root = 0;
9799   gdk_event_set_device (send_event, device);
9800
9801   gtk_propagate_event (button, send_event);
9802   gdk_event_free (send_event);
9803
9804   /* Kids, don't try this at home */
9805   g_object_ref (button);
9806   gtk_container_remove (GTK_CONTAINER (tree_view), button);
9807   gtk_widget_set_parent_window (button, tree_view->priv->drag_window);
9808   gtk_widget_set_parent (button, GTK_WIDGET (tree_view));
9809   g_object_unref (button);
9810
9811   gtk_widget_get_allocation (button, &button_allocation);
9812   tree_view->priv->drag_column_x = button_allocation.x;
9813   allocation = button_allocation;
9814   allocation.x = 0;
9815   gtk_widget_size_allocate (button, &allocation);
9816   gtk_widget_set_parent_window (button, tree_view->priv->drag_window);
9817
9818   tree_view->priv->drag_column = column;
9819   gdk_window_show (tree_view->priv->drag_window);
9820
9821   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
9822   while (gtk_events_pending ())
9823     gtk_main_iteration ();
9824
9825   tree_view->priv->in_column_drag = TRUE;
9826
9827   gdk_device_grab (pointer,
9828                    tree_view->priv->drag_window,
9829                    GDK_OWNERSHIP_NONE,
9830                    FALSE,
9831                    GDK_POINTER_MOTION_MASK|GDK_BUTTON_RELEASE_MASK,
9832                    NULL,
9833                    GDK_CURRENT_TIME);
9834   gdk_device_grab (keyboard,
9835                    tree_view->priv->drag_window,
9836                    GDK_OWNERSHIP_NONE,
9837                    FALSE,
9838                    GDK_KEY_PRESS_MASK|GDK_KEY_RELEASE_MASK,
9839                    NULL,
9840                    GDK_CURRENT_TIME);
9841 }
9842
9843 static void
9844 gtk_tree_view_queue_draw_arrow (GtkTreeView        *tree_view,
9845                                 GtkRBTree          *tree,
9846                                 GtkRBNode          *node)
9847 {
9848   GtkAllocation allocation;
9849   GdkRectangle rect;
9850
9851   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
9852     return;
9853
9854   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
9855   rect.x = 0;
9856   rect.width = MAX (tree_view->priv->expander_size, MAX (tree_view->priv->width, allocation.width));
9857
9858   rect.y = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
9859   rect.height = gtk_tree_view_get_row_height (tree_view, node);
9860
9861   gdk_window_invalidate_rect (tree_view->priv->bin_window, &rect, TRUE);
9862 }
9863
9864 void
9865 _gtk_tree_view_queue_draw_node (GtkTreeView        *tree_view,
9866                                 GtkRBTree          *tree,
9867                                 GtkRBNode          *node,
9868                                 const GdkRectangle *clip_rect)
9869 {
9870   GtkAllocation allocation;
9871   GdkRectangle rect;
9872
9873   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
9874     return;
9875
9876   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
9877   rect.x = 0;
9878   rect.width = MAX (tree_view->priv->width, allocation.width);
9879
9880   rect.y = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
9881   rect.height = gtk_tree_view_get_row_height (tree_view, node);
9882
9883   if (clip_rect)
9884     {
9885       GdkRectangle new_rect;
9886
9887       gdk_rectangle_intersect (clip_rect, &rect, &new_rect);
9888
9889       gdk_window_invalidate_rect (tree_view->priv->bin_window, &new_rect, TRUE);
9890     }
9891   else
9892     {
9893       gdk_window_invalidate_rect (tree_view->priv->bin_window, &rect, TRUE);
9894     }
9895 }
9896
9897 static inline gint
9898 gtk_tree_view_get_effective_header_height (GtkTreeView *tree_view)
9899 {
9900   if (tree_view->priv->headers_visible)
9901     return tree_view->priv->header_height;
9902   /* else */
9903   return 0;
9904 }
9905
9906 gint
9907 _gtk_tree_view_get_header_height (GtkTreeView *tree_view)
9908 {
9909   return tree_view->priv->header_height;
9910 }
9911
9912 void
9913 _gtk_tree_view_get_row_separator_func (GtkTreeView                 *tree_view,
9914                                        GtkTreeViewRowSeparatorFunc *func,
9915                                        gpointer                    *data)
9916 {
9917   *func = tree_view->priv->row_separator_func;
9918   *data = tree_view->priv->row_separator_data;
9919 }
9920
9921 GtkTreePath *
9922 _gtk_tree_view_get_anchor_path (GtkTreeView *tree_view)
9923 {
9924   if (tree_view->priv->anchor)
9925     return gtk_tree_row_reference_get_path (tree_view->priv->anchor);
9926
9927   return NULL;
9928 }
9929
9930 void
9931 _gtk_tree_view_set_anchor_path (GtkTreeView *tree_view,
9932                                 GtkTreePath *anchor_path)
9933 {
9934   if (tree_view->priv->anchor)
9935     {
9936       gtk_tree_row_reference_free (tree_view->priv->anchor);
9937       tree_view->priv->anchor = NULL;
9938     }
9939
9940   if (anchor_path && tree_view->priv->model)
9941     tree_view->priv->anchor =
9942       gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), 
9943                                         tree_view->priv->model, anchor_path);
9944 }
9945
9946 GtkRBTree *
9947 _gtk_tree_view_get_rbtree (GtkTreeView *tree_view)
9948 {
9949   return tree_view->priv->tree;
9950 }
9951
9952 GdkWindow *
9953 _gtk_tree_view_get_header_window (GtkTreeView *tree_view)
9954 {
9955   return tree_view->priv->header_window;
9956 }
9957
9958 void
9959 _gtk_tree_view_set_focus_column (GtkTreeView       *tree_view,
9960                                  GtkTreeViewColumn *column)
9961 {
9962   tree_view->priv->focus_column = column;
9963 }
9964
9965
9966 static void
9967 gtk_tree_view_queue_draw_path (GtkTreeView        *tree_view,
9968                                GtkTreePath        *path,
9969                                const GdkRectangle *clip_rect)
9970 {
9971   GtkRBTree *tree = NULL;
9972   GtkRBNode *node = NULL;
9973
9974   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
9975
9976   if (tree)
9977     _gtk_tree_view_queue_draw_node (tree_view, tree, node, clip_rect);
9978 }
9979
9980 /* x and y are the mouse position
9981  */
9982 static void
9983 gtk_tree_view_draw_arrow (GtkTreeView *tree_view,
9984                           cairo_t     *cr,
9985                           GtkRBTree   *tree,
9986                           GtkRBNode   *node,
9987                           /* in bin_window coordinates */
9988                           gint         x,
9989                           gint         y)
9990 {
9991   GdkRectangle area;
9992   GtkStateFlags state = 0;
9993   GtkStyleContext *context;
9994   GtkWidget *widget;
9995   gint x_offset = 0;
9996   gint x2;
9997   gint vertical_separator;
9998   gint expander_size;
9999   GtkCellRendererState flags;
10000
10001   widget = GTK_WIDGET (tree_view);
10002   context = gtk_widget_get_style_context (widget);
10003
10004   gtk_widget_style_get (widget,
10005                         "vertical-separator", &vertical_separator,
10006                         NULL);
10007   expander_size = tree_view->priv->expander_size - EXPANDER_EXTRA_PADDING;
10008
10009   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
10010     return;
10011
10012   gtk_tree_view_get_arrow_xrange (tree_view, tree, &x_offset, &x2);
10013
10014   area.x = x_offset;
10015   area.y = gtk_tree_view_get_cell_area_y_offset (tree_view, tree, node,
10016                                                  vertical_separator);
10017   area.width = expander_size;
10018   area.height = gtk_tree_view_get_cell_area_height (tree_view, node,
10019                                                     vertical_separator);
10020
10021   if (!gtk_widget_get_sensitive (widget))
10022     state |= GTK_STATE_FLAG_INSENSITIVE;
10023   else
10024     {
10025       flags = 0;
10026
10027       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
10028         flags |= GTK_CELL_RENDERER_SELECTED;
10029
10030       state = gtk_cell_renderer_get_state (NULL, widget, flags);
10031
10032       if (node == tree_view->priv->button_pressed_node &&
10033           x >= area.x && x <= (area.x + area.width) &&
10034           y >= area.y && y <= (area.y + area.height))
10035         state |= GTK_STATE_FLAG_FOCUSED;
10036
10037       if (node == tree_view->priv->prelight_node &&
10038           tree_view->priv->arrow_prelit)
10039         state |= GTK_STATE_FLAG_PRELIGHT;
10040     }
10041
10042   if (node->children != NULL)
10043     state |= GTK_STATE_FLAG_ACTIVE;
10044
10045   gtk_style_context_save (context);
10046
10047   gtk_style_context_set_state (context, state);
10048   gtk_style_context_add_class (context, GTK_STYLE_CLASS_EXPANDER);
10049
10050   gtk_style_context_push_animatable_region (context, node);
10051
10052   gtk_render_expander (context, cr,
10053                        area.x, area.y,
10054                        area.width, area.height);
10055
10056   gtk_style_context_pop_animatable_region (context);
10057   gtk_style_context_restore (context);
10058 }
10059
10060 static void
10061 gtk_tree_view_focus_to_cursor (GtkTreeView *tree_view)
10062
10063 {
10064   GtkTreePath *cursor_path;
10065
10066   if ((tree_view->priv->tree == NULL) ||
10067       (! gtk_widget_get_realized (GTK_WIDGET (tree_view))))
10068     return;
10069
10070   cursor_path = NULL;
10071   if (tree_view->priv->cursor)
10072     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10073
10074   if (cursor_path == NULL)
10075     {
10076       /* Consult the selection before defaulting to the
10077        * first focusable element
10078        */
10079       GList *selected_rows;
10080       GtkTreeModel *model;
10081       GtkTreeSelection *selection;
10082
10083       selection = gtk_tree_view_get_selection (tree_view);
10084       selected_rows = gtk_tree_selection_get_selected_rows (selection, &model);
10085
10086       if (selected_rows)
10087         {
10088           cursor_path = gtk_tree_path_copy((const GtkTreePath *)(selected_rows->data));
10089           g_list_foreach (selected_rows, (GFunc)gtk_tree_path_free, NULL);
10090           g_list_free (selected_rows);
10091         }
10092       else
10093         {
10094           cursor_path = gtk_tree_path_new_first ();
10095           search_first_focusable_path (tree_view, &cursor_path,
10096                                        TRUE, NULL, NULL);
10097         }
10098
10099       gtk_tree_row_reference_free (tree_view->priv->cursor);
10100       tree_view->priv->cursor = NULL;
10101
10102       if (cursor_path)
10103         {
10104           if (gtk_tree_selection_get_mode (tree_view->priv->selection) == GTK_SELECTION_MULTIPLE)
10105             gtk_tree_view_real_set_cursor (tree_view, cursor_path, FALSE, FALSE);
10106           else
10107             gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE);
10108         }
10109     }
10110
10111   if (cursor_path)
10112     {
10113       tree_view->priv->draw_keyfocus = TRUE;
10114
10115       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10116       gtk_tree_path_free (cursor_path);
10117
10118       if (tree_view->priv->focus_column == NULL)
10119         {
10120           GList *list;
10121           for (list = tree_view->priv->columns; list; list = list->next)
10122             {
10123               if (gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (list->data)))
10124                 {
10125                   GtkCellArea *cell_area;
10126
10127                   tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (list->data);
10128
10129                   /* This happens when the treeview initially grabs focus and there
10130                    * is no column in focus, here we explicitly focus into the first cell */
10131                   cell_area = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (tree_view->priv->focus_column));
10132                   if (!gtk_cell_area_get_focus_cell (cell_area))
10133                     {
10134                       gboolean rtl;
10135
10136                       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
10137                       gtk_cell_area_focus (cell_area,
10138                                            rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT);
10139                     }
10140
10141                   break;
10142                 }
10143             }
10144         }
10145     }
10146 }
10147
10148 static void
10149 gtk_tree_view_move_cursor_up_down (GtkTreeView *tree_view,
10150                                    gint         count)
10151 {
10152   gint selection_count;
10153   GtkRBTree *cursor_tree = NULL;
10154   GtkRBNode *cursor_node = NULL;
10155   GtkRBTree *new_cursor_tree = NULL;
10156   GtkRBNode *new_cursor_node = NULL;
10157   GtkTreePath *cursor_path = NULL;
10158   gboolean grab_focus = TRUE;
10159   gboolean selectable;
10160   GtkDirectionType direction;
10161   GtkCellArea *cell_area = NULL;
10162   GtkCellRenderer *last_focus_cell = NULL;
10163   GtkTreeIter iter;
10164
10165   if (! gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10166     return;
10167
10168   cursor_path = NULL;
10169   if (!gtk_tree_row_reference_valid (tree_view->priv->cursor))
10170     /* FIXME: we lost the cursor; should we get the first? */
10171     return;
10172
10173   cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10174   _gtk_tree_view_find_node (tree_view, cursor_path,
10175                             &cursor_tree, &cursor_node);
10176
10177   if (cursor_tree == NULL)
10178     /* FIXME: we lost the cursor; should we get the first? */
10179     return;
10180
10181   direction = count < 0 ? GTK_DIR_UP : GTK_DIR_DOWN;
10182
10183   if (tree_view->priv->focus_column)
10184     cell_area = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (tree_view->priv->focus_column));
10185
10186   /* If focus stays in the area for this row, then just return for this round */
10187   if (cell_area && (count == -1 || count == 1) &&
10188       gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path))
10189     {
10190       gtk_tree_view_column_cell_set_cell_data (tree_view->priv->focus_column,
10191                                                tree_view->priv->model,
10192                                                &iter,
10193                                                GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_PARENT),
10194                                                cursor_node->children?TRUE:FALSE);
10195
10196       /* Save the last cell that had focus, if we hit the end of the view we'll give
10197        * focus back to it. */
10198       last_focus_cell = gtk_cell_area_get_focus_cell (cell_area);
10199
10200       /* If focus stays in the area, no need to change the cursor row */
10201       if (gtk_cell_area_focus (cell_area, direction))
10202         return;
10203     }
10204
10205   selection_count = gtk_tree_selection_count_selected_rows (tree_view->priv->selection);
10206   selectable = _gtk_tree_selection_row_is_selectable (tree_view->priv->selection,
10207                                                       cursor_node,
10208                                                       cursor_path);
10209
10210   if (selection_count == 0
10211       && gtk_tree_selection_get_mode (tree_view->priv->selection) != GTK_SELECTION_NONE
10212       && !tree_view->priv->modify_selection_pressed
10213       && selectable)
10214     {
10215       /* Don't move the cursor, but just select the current node */
10216       new_cursor_tree = cursor_tree;
10217       new_cursor_node = cursor_node;
10218     }
10219   else
10220     {
10221       if (count == -1)
10222         _gtk_rbtree_prev_full (cursor_tree, cursor_node,
10223                                &new_cursor_tree, &new_cursor_node);
10224       else
10225         _gtk_rbtree_next_full (cursor_tree, cursor_node,
10226                                &new_cursor_tree, &new_cursor_node);
10227     }
10228
10229   gtk_tree_path_free (cursor_path);
10230
10231   if (new_cursor_node)
10232     {
10233       cursor_path = _gtk_tree_view_find_path (tree_view,
10234                                               new_cursor_tree, new_cursor_node);
10235
10236       search_first_focusable_path (tree_view, &cursor_path,
10237                                    (count != -1),
10238                                    &new_cursor_tree,
10239                                    &new_cursor_node);
10240
10241       if (cursor_path)
10242         gtk_tree_path_free (cursor_path);
10243     }
10244
10245   /*
10246    * If the list has only one item and multi-selection is set then select
10247    * the row (if not yet selected).
10248    */
10249   if (gtk_tree_selection_get_mode (tree_view->priv->selection) == GTK_SELECTION_MULTIPLE &&
10250       new_cursor_node == NULL)
10251     {
10252       if (count == -1)
10253         _gtk_rbtree_next_full (cursor_tree, cursor_node,
10254                                &new_cursor_tree, &new_cursor_node);
10255       else
10256         _gtk_rbtree_prev_full (cursor_tree, cursor_node,
10257                                &new_cursor_tree, &new_cursor_node);
10258
10259       if (new_cursor_node == NULL
10260           && !GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_SELECTED))
10261         {
10262           new_cursor_node = cursor_node;
10263           new_cursor_tree = cursor_tree;
10264         }
10265       else
10266         {
10267           new_cursor_node = NULL;
10268         }
10269     }
10270
10271   if (new_cursor_node)
10272     {
10273       cursor_path = _gtk_tree_view_find_path (tree_view, new_cursor_tree, new_cursor_node);
10274       gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, TRUE);
10275       gtk_tree_path_free (cursor_path);
10276
10277       /* Give focus to the area in the new row */
10278       if (cell_area)
10279         gtk_cell_area_focus (cell_area, direction);
10280     }
10281   else
10282     {
10283       gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10284
10285       if (!tree_view->priv->extend_selection_pressed)
10286         {
10287           if (! gtk_widget_keynav_failed (GTK_WIDGET (tree_view),
10288                                           count < 0 ?
10289                                           GTK_DIR_UP : GTK_DIR_DOWN))
10290             {
10291               GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (tree_view));
10292
10293               if (toplevel)
10294                 gtk_widget_child_focus (toplevel,
10295                                         count < 0 ?
10296                                         GTK_DIR_TAB_BACKWARD :
10297                                         GTK_DIR_TAB_FORWARD);
10298
10299               grab_focus = FALSE;
10300             }
10301         }
10302       else
10303         {
10304           gtk_widget_error_bell (GTK_WIDGET (tree_view));
10305         }
10306
10307       if (cell_area)
10308         gtk_cell_area_set_focus_cell (cell_area, last_focus_cell);
10309     }
10310
10311   if (grab_focus)
10312     gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10313 }
10314
10315 static void
10316 gtk_tree_view_move_cursor_page_up_down (GtkTreeView *tree_view,
10317                                         gint         count)
10318 {
10319   GtkRBTree *cursor_tree = NULL;
10320   GtkRBNode *cursor_node = NULL;
10321   GtkTreePath *old_cursor_path = NULL;
10322   GtkTreePath *cursor_path = NULL;
10323   GtkRBTree *start_cursor_tree = NULL;
10324   GtkRBNode *start_cursor_node = NULL;
10325   gint y;
10326   gint window_y;
10327   gint vertical_separator;
10328
10329   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10330     return;
10331
10332   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
10333     old_cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10334   else
10335     /* This is sorta weird.  Focus in should give us a cursor */
10336     return;
10337
10338   gtk_widget_style_get (GTK_WIDGET (tree_view), "vertical-separator", &vertical_separator, NULL);
10339   _gtk_tree_view_find_node (tree_view, old_cursor_path,
10340                             &cursor_tree, &cursor_node);
10341
10342   if (cursor_tree == NULL)
10343     {
10344       /* FIXME: we lost the cursor.  Should we try to get one? */
10345       gtk_tree_path_free (old_cursor_path);
10346       return;
10347     }
10348   g_return_if_fail (cursor_node != NULL);
10349
10350   y = _gtk_rbtree_node_find_offset (cursor_tree, cursor_node);
10351   window_y = RBTREE_Y_TO_TREE_WINDOW_Y (tree_view, y);
10352   y += tree_view->priv->cursor_offset;
10353   y += count * (int)gtk_adjustment_get_page_increment (tree_view->priv->vadjustment);
10354   y = CLAMP (y, (gint)gtk_adjustment_get_lower (tree_view->priv->vadjustment),  (gint)gtk_adjustment_get_upper (tree_view->priv->vadjustment) - vertical_separator);
10355
10356   if (y >= tree_view->priv->height)
10357     y = tree_view->priv->height - 1;
10358
10359   tree_view->priv->cursor_offset =
10360     _gtk_rbtree_find_offset (tree_view->priv->tree, y,
10361                              &cursor_tree, &cursor_node);
10362
10363   if (cursor_tree == NULL)
10364     {
10365       /* FIXME: we lost the cursor.  Should we try to get one? */
10366       gtk_tree_path_free (old_cursor_path);
10367       return;
10368     }
10369
10370   if (tree_view->priv->cursor_offset
10371       > gtk_tree_view_get_row_height (tree_view, cursor_node))
10372     {
10373       _gtk_rbtree_next_full (cursor_tree, cursor_node,
10374                              &cursor_tree, &cursor_node);
10375       tree_view->priv->cursor_offset -= gtk_tree_view_get_row_height (tree_view, cursor_node);
10376     }
10377
10378   y -= tree_view->priv->cursor_offset;
10379   cursor_path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
10380
10381   start_cursor_tree = cursor_tree;
10382   start_cursor_node = cursor_node;
10383
10384   if (! search_first_focusable_path (tree_view, &cursor_path,
10385                                      (count != -1),
10386                                      &cursor_tree, &cursor_node))
10387     {
10388       /* It looks like we reached the end of the view without finding
10389        * a focusable row.  We will step backwards to find the last
10390        * focusable row.
10391        */
10392       cursor_tree = start_cursor_tree;
10393       cursor_node = start_cursor_node;
10394       cursor_path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
10395
10396       search_first_focusable_path (tree_view, &cursor_path,
10397                                    (count == -1),
10398                                    &cursor_tree, &cursor_node);
10399     }
10400
10401   if (!cursor_path)
10402     goto cleanup;
10403
10404   /* update y */
10405   y = _gtk_rbtree_node_find_offset (cursor_tree, cursor_node);
10406
10407   gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE);
10408
10409   y -= window_y;
10410   gtk_tree_view_scroll_to_point (tree_view, -1, y);
10411   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10412   _gtk_tree_view_queue_draw_node (tree_view, cursor_tree, cursor_node, NULL);
10413
10414   if (!gtk_tree_path_compare (old_cursor_path, cursor_path))
10415     gtk_widget_error_bell (GTK_WIDGET (tree_view));
10416
10417   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10418
10419 cleanup:
10420   gtk_tree_path_free (old_cursor_path);
10421   gtk_tree_path_free (cursor_path);
10422 }
10423
10424 static void
10425 gtk_tree_view_move_cursor_left_right (GtkTreeView *tree_view,
10426                                       gint         count)
10427 {
10428   GtkRBTree *cursor_tree = NULL;
10429   GtkRBNode *cursor_node = NULL;
10430   GtkTreePath *cursor_path = NULL;
10431   GtkTreeViewColumn *column;
10432   GtkTreeIter iter;
10433   GList *list;
10434   gboolean found_column = FALSE;
10435   gboolean rtl;
10436   GtkDirectionType direction;
10437   GtkCellArea     *cell_area;
10438   GtkCellRenderer *last_focus_cell = NULL;
10439   GtkCellArea     *last_focus_area = NULL;
10440
10441   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
10442
10443   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10444     return;
10445
10446   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
10447     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10448   else
10449     return;
10450
10451   _gtk_tree_view_find_node (tree_view, cursor_path, &cursor_tree, &cursor_node);
10452   if (cursor_tree == NULL)
10453     return;
10454   if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path) == FALSE)
10455     {
10456       gtk_tree_path_free (cursor_path);
10457       return;
10458     }
10459   gtk_tree_path_free (cursor_path);
10460
10461   list = rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns);
10462   if (tree_view->priv->focus_column)
10463     {
10464       /* Save the cell/area we are moving focus from, if moving the cursor
10465        * by one step hits the end we'll set focus back here */
10466       last_focus_area = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (tree_view->priv->focus_column));
10467       last_focus_cell = gtk_cell_area_get_focus_cell (last_focus_area);
10468
10469       for (; list; list = (rtl ? list->prev : list->next))
10470         {
10471           if (list->data == tree_view->priv->focus_column)
10472             break;
10473         }
10474     }
10475
10476   direction = count > 0 ? GTK_DIR_RIGHT : GTK_DIR_LEFT;
10477
10478   while (list)
10479     {
10480       column = list->data;
10481       if (gtk_tree_view_column_get_visible (column) == FALSE)
10482         goto loop_end;
10483
10484       gtk_tree_view_column_cell_set_cell_data (column,
10485                                                tree_view->priv->model,
10486                                                &iter,
10487                                                GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_PARENT),
10488                                                cursor_node->children?TRUE:FALSE);
10489
10490       cell_area = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (column));
10491       if (gtk_cell_area_focus (cell_area, direction))
10492         {
10493           tree_view->priv->focus_column = column;
10494           found_column = TRUE;
10495           break;
10496         }
10497
10498     loop_end:
10499       if (count == 1)
10500         list = rtl ? list->prev : list->next;
10501       else
10502         list = rtl ? list->next : list->prev;
10503     }
10504
10505   if (found_column)
10506     {
10507       if (!gtk_tree_view_has_can_focus_cell (tree_view))
10508         _gtk_tree_view_queue_draw_node (tree_view,
10509                                         cursor_tree,
10510                                         cursor_node,
10511                                         NULL);
10512       g_signal_emit (tree_view, tree_view_signals[CURSOR_CHANGED], 0);
10513       gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10514     }
10515   else
10516     {
10517       gtk_widget_error_bell (GTK_WIDGET (tree_view));
10518
10519       if (last_focus_area)
10520         gtk_cell_area_set_focus_cell (last_focus_area, last_focus_cell);
10521     }
10522
10523   gtk_tree_view_clamp_column_visible (tree_view,
10524                                       tree_view->priv->focus_column, TRUE);
10525 }
10526
10527 static void
10528 gtk_tree_view_move_cursor_start_end (GtkTreeView *tree_view,
10529                                      gint         count)
10530 {
10531   GtkRBTree *cursor_tree;
10532   GtkRBNode *cursor_node;
10533   GtkTreePath *path;
10534   GtkTreePath *old_path;
10535
10536   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10537     return;
10538
10539   g_return_if_fail (tree_view->priv->tree != NULL);
10540
10541   gtk_tree_view_get_cursor (tree_view, &old_path, NULL);
10542
10543   cursor_tree = tree_view->priv->tree;
10544   cursor_node = cursor_tree->root;
10545
10546   if (count == -1)
10547     {
10548       while (cursor_node && cursor_node->left != cursor_tree->nil)
10549         cursor_node = cursor_node->left;
10550
10551       /* Now go forward to find the first focusable row. */
10552       path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
10553       search_first_focusable_path (tree_view, &path,
10554                                    TRUE, &cursor_tree, &cursor_node);
10555     }
10556   else
10557     {
10558       do
10559         {
10560           while (cursor_node && cursor_node->right != cursor_tree->nil)
10561             cursor_node = cursor_node->right;
10562           if (cursor_node->children == NULL)
10563             break;
10564
10565           cursor_tree = cursor_node->children;
10566           cursor_node = cursor_tree->root;
10567         }
10568       while (1);
10569
10570       /* Now go backwards to find last focusable row. */
10571       path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
10572       search_first_focusable_path (tree_view, &path,
10573                                    FALSE, &cursor_tree, &cursor_node);
10574     }
10575
10576   if (!path)
10577     goto cleanup;
10578
10579   if (gtk_tree_path_compare (old_path, path))
10580     {
10581       gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
10582       gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10583     }
10584   else
10585     {
10586       gtk_widget_error_bell (GTK_WIDGET (tree_view));
10587     }
10588
10589 cleanup:
10590   gtk_tree_path_free (old_path);
10591   gtk_tree_path_free (path);
10592 }
10593
10594 static gboolean
10595 gtk_tree_view_real_select_all (GtkTreeView *tree_view)
10596 {
10597   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10598     return FALSE;
10599
10600   if (gtk_tree_selection_get_mode (tree_view->priv->selection) != GTK_SELECTION_MULTIPLE)
10601     return FALSE;
10602
10603   gtk_tree_selection_select_all (tree_view->priv->selection);
10604
10605   return TRUE;
10606 }
10607
10608 static gboolean
10609 gtk_tree_view_real_unselect_all (GtkTreeView *tree_view)
10610 {
10611   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10612     return FALSE;
10613
10614   if (gtk_tree_selection_get_mode (tree_view->priv->selection) != GTK_SELECTION_MULTIPLE)
10615     return FALSE;
10616
10617   gtk_tree_selection_unselect_all (tree_view->priv->selection);
10618
10619   return TRUE;
10620 }
10621
10622 static gboolean
10623 gtk_tree_view_real_select_cursor_row (GtkTreeView *tree_view,
10624                                       gboolean     start_editing)
10625 {
10626   GtkRBTree *new_tree = NULL;
10627   GtkRBNode *new_node = NULL;
10628   GtkRBTree *cursor_tree = NULL;
10629   GtkRBNode *cursor_node = NULL;
10630   GtkTreePath *cursor_path = NULL;
10631   GtkTreeSelectMode mode = 0;
10632
10633   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10634     return FALSE;
10635
10636   if (tree_view->priv->cursor)
10637     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10638
10639   if (cursor_path == NULL)
10640     return FALSE;
10641
10642   _gtk_tree_view_find_node (tree_view, cursor_path,
10643                             &cursor_tree, &cursor_node);
10644
10645   if (cursor_tree == NULL)
10646     {
10647       gtk_tree_path_free (cursor_path);
10648       return FALSE;
10649     }
10650
10651   if (!tree_view->priv->extend_selection_pressed && start_editing &&
10652       tree_view->priv->focus_column)
10653     {
10654       if (gtk_tree_view_start_editing (tree_view, cursor_path, FALSE))
10655         {
10656           gtk_tree_path_free (cursor_path);
10657           return TRUE;
10658         }
10659     }
10660
10661   if (tree_view->priv->modify_selection_pressed)
10662     mode |= GTK_TREE_SELECT_MODE_TOGGLE;
10663   if (tree_view->priv->extend_selection_pressed)
10664     mode |= GTK_TREE_SELECT_MODE_EXTEND;
10665
10666   _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
10667                                             cursor_node,
10668                                             cursor_tree,
10669                                             cursor_path,
10670                                             mode,
10671                                             FALSE);
10672
10673   /* We bail out if the original (tree, node) don't exist anymore after
10674    * handling the selection-changed callback.  We do return TRUE because
10675    * the key press has been handled at this point.
10676    */
10677   _gtk_tree_view_find_node (tree_view, cursor_path, &new_tree, &new_node);
10678
10679   if (cursor_tree != new_tree || cursor_node != new_node)
10680     return FALSE;
10681
10682   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10683
10684   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10685   _gtk_tree_view_queue_draw_node (tree_view, cursor_tree, cursor_node, NULL);
10686
10687   if (!tree_view->priv->extend_selection_pressed)
10688     gtk_tree_view_row_activated (tree_view, cursor_path,
10689                                  tree_view->priv->focus_column);
10690     
10691   gtk_tree_path_free (cursor_path);
10692
10693   return TRUE;
10694 }
10695
10696 static gboolean
10697 gtk_tree_view_real_toggle_cursor_row (GtkTreeView *tree_view)
10698 {
10699   GtkRBTree *new_tree = NULL;
10700   GtkRBNode *new_node = NULL;
10701   GtkRBTree *cursor_tree = NULL;
10702   GtkRBNode *cursor_node = NULL;
10703   GtkTreePath *cursor_path = NULL;
10704
10705   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10706     return FALSE;
10707
10708   cursor_path = NULL;
10709   if (tree_view->priv->cursor)
10710     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10711
10712   if (cursor_path == NULL)
10713     return FALSE;
10714
10715   _gtk_tree_view_find_node (tree_view, cursor_path,
10716                             &cursor_tree, &cursor_node);
10717   if (cursor_tree == NULL)
10718     {
10719       gtk_tree_path_free (cursor_path);
10720       return FALSE;
10721     }
10722
10723   _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
10724                                             cursor_node,
10725                                             cursor_tree,
10726                                             cursor_path,
10727                                             GTK_TREE_SELECT_MODE_TOGGLE,
10728                                             FALSE);
10729
10730   /* We bail out if the original (tree, node) don't exist anymore after
10731    * handling the selection-changed callback.  We do return TRUE because
10732    * the key press has been handled at this point.
10733    */
10734   _gtk_tree_view_find_node (tree_view, cursor_path, &new_tree, &new_node);
10735
10736   if (cursor_tree != new_tree || cursor_node != new_node)
10737     return FALSE;
10738
10739   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10740
10741   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10742   gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10743   gtk_tree_path_free (cursor_path);
10744
10745   return TRUE;
10746 }
10747
10748 static gboolean
10749 gtk_tree_view_real_expand_collapse_cursor_row (GtkTreeView *tree_view,
10750                                                gboolean     logical,
10751                                                gboolean     expand,
10752                                                gboolean     open_all)
10753 {
10754   GtkTreePath *cursor_path = NULL;
10755   GtkRBTree *tree;
10756   GtkRBNode *node;
10757
10758   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10759     return FALSE;
10760
10761   cursor_path = NULL;
10762   if (tree_view->priv->cursor)
10763     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10764
10765   if (cursor_path == NULL)
10766     return FALSE;
10767
10768   if (_gtk_tree_view_find_node (tree_view, cursor_path, &tree, &node))
10769     return FALSE;
10770
10771   /* Don't handle the event if we aren't an expander */
10772   if (!((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT))
10773     return FALSE;
10774
10775   if (!logical
10776       && gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL)
10777     expand = !expand;
10778
10779   if (expand)
10780     gtk_tree_view_real_expand_row (tree_view, cursor_path, tree, node, open_all, TRUE);
10781   else
10782     gtk_tree_view_real_collapse_row (tree_view, cursor_path, tree, node, TRUE);
10783
10784   gtk_tree_path_free (cursor_path);
10785
10786   return TRUE;
10787 }
10788
10789 static gboolean
10790 gtk_tree_view_real_select_cursor_parent (GtkTreeView *tree_view)
10791 {
10792   GtkRBTree *cursor_tree = NULL;
10793   GtkRBNode *cursor_node = NULL;
10794   GtkTreePath *cursor_path = NULL;
10795   GdkModifierType state;
10796
10797   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10798     goto out;
10799
10800   cursor_path = NULL;
10801   if (tree_view->priv->cursor)
10802     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10803
10804   if (cursor_path == NULL)
10805     goto out;
10806
10807   _gtk_tree_view_find_node (tree_view, cursor_path,
10808                             &cursor_tree, &cursor_node);
10809   if (cursor_tree == NULL)
10810     {
10811       gtk_tree_path_free (cursor_path);
10812       goto out;
10813     }
10814
10815   if (cursor_tree->parent_node)
10816     {
10817       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10818       cursor_node = cursor_tree->parent_node;
10819       cursor_tree = cursor_tree->parent_tree;
10820
10821       gtk_tree_path_up (cursor_path);
10822
10823       if (gtk_get_current_event_state (&state))
10824         {
10825           GdkModifierType modify_mod_mask;
10826
10827           modify_mod_mask =
10828             gtk_widget_get_modifier_mask (GTK_WIDGET (tree_view),
10829                                           GDK_MODIFIER_INTENT_MODIFY_SELECTION);
10830
10831           if ((state & modify_mod_mask) == modify_mod_mask)
10832             tree_view->priv->modify_selection_pressed = TRUE;
10833         }
10834
10835       gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE);
10836       gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10837
10838       gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10839       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10840       gtk_tree_path_free (cursor_path);
10841
10842       tree_view->priv->modify_selection_pressed = FALSE;
10843
10844       return TRUE;
10845     }
10846
10847  out:
10848
10849   tree_view->priv->search_entry_avoid_unhandled_binding = TRUE;
10850   return FALSE;
10851 }
10852
10853 static gboolean
10854 gtk_tree_view_search_entry_flush_timeout (GtkTreeView *tree_view)
10855 {
10856   gtk_tree_view_search_dialog_hide (tree_view->priv->search_window, tree_view, NULL);
10857   tree_view->priv->typeselect_flush_timeout = 0;
10858
10859   return FALSE;
10860 }
10861
10862 /* Cut and paste from gtkwindow.c */
10863 static void
10864 send_focus_change (GtkWidget *widget,
10865                    GdkDevice *device,
10866                    gboolean   in)
10867 {
10868   GdkDeviceManager *device_manager;
10869   GList *devices, *d;
10870
10871   device_manager = gdk_display_get_device_manager (gtk_widget_get_display (widget));
10872   devices = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER);
10873   devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_SLAVE));
10874   devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_FLOATING));
10875
10876   for (d = devices; d; d = d->next)
10877     {
10878       GdkDevice *dev = d->data;
10879       GdkEvent *fevent;
10880       GdkWindow *window;
10881
10882       if (gdk_device_get_source (dev) != GDK_SOURCE_KEYBOARD)
10883         continue;
10884
10885       window = gtk_widget_get_window (widget);
10886
10887       /* Skip non-master keyboards that haven't
10888        * selected for events from this window
10889        */
10890       if (gdk_device_get_device_type (dev) != GDK_DEVICE_TYPE_MASTER &&
10891           !gdk_window_get_device_events (window, dev))
10892         continue;
10893
10894       fevent = gdk_event_new (GDK_FOCUS_CHANGE);
10895
10896       fevent->focus_change.type = GDK_FOCUS_CHANGE;
10897       fevent->focus_change.window = g_object_ref (window);
10898       fevent->focus_change.in = in;
10899       gdk_event_set_device (fevent, device);
10900
10901       gtk_widget_send_focus_change (widget, fevent);
10902
10903       gdk_event_free (fevent);
10904     }
10905
10906   g_list_free (devices);
10907 }
10908
10909 static void
10910 gtk_tree_view_ensure_interactive_directory (GtkTreeView *tree_view)
10911 {
10912   GtkWidget *frame, *vbox, *toplevel;
10913   GdkScreen *screen;
10914
10915   if (tree_view->priv->search_custom_entry_set)
10916     return;
10917
10918   toplevel = gtk_widget_get_toplevel (GTK_WIDGET (tree_view));
10919   screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
10920
10921    if (tree_view->priv->search_window != NULL)
10922      {
10923        if (gtk_window_has_group (GTK_WINDOW (toplevel)))
10924          gtk_window_group_add_window (gtk_window_get_group (GTK_WINDOW (toplevel)),
10925                                       GTK_WINDOW (tree_view->priv->search_window));
10926        else if (gtk_window_has_group (GTK_WINDOW (tree_view->priv->search_window)))
10927          gtk_window_group_remove_window (gtk_window_get_group (GTK_WINDOW (tree_view->priv->search_window)),
10928                                          GTK_WINDOW (tree_view->priv->search_window));
10929
10930        gtk_window_set_screen (GTK_WINDOW (tree_view->priv->search_window), screen);
10931
10932        return;
10933      }
10934    
10935   tree_view->priv->search_window = gtk_window_new (GTK_WINDOW_POPUP);
10936   gtk_window_set_screen (GTK_WINDOW (tree_view->priv->search_window), screen);
10937
10938   if (gtk_window_has_group (GTK_WINDOW (toplevel)))
10939     gtk_window_group_add_window (gtk_window_get_group (GTK_WINDOW (toplevel)),
10940                                  GTK_WINDOW (tree_view->priv->search_window));
10941
10942   gtk_window_set_type_hint (GTK_WINDOW (tree_view->priv->search_window),
10943                             GDK_WINDOW_TYPE_HINT_UTILITY);
10944   gtk_window_set_modal (GTK_WINDOW (tree_view->priv->search_window), TRUE);
10945   g_signal_connect (tree_view->priv->search_window, "delete-event",
10946                     G_CALLBACK (gtk_tree_view_search_delete_event),
10947                     tree_view);
10948   g_signal_connect (tree_view->priv->search_window, "key-press-event",
10949                     G_CALLBACK (gtk_tree_view_search_key_press_event),
10950                     tree_view);
10951   g_signal_connect (tree_view->priv->search_window, "button-press-event",
10952                     G_CALLBACK (gtk_tree_view_search_button_press_event),
10953                     tree_view);
10954   g_signal_connect (tree_view->priv->search_window, "scroll-event",
10955                     G_CALLBACK (gtk_tree_view_search_scroll_event),
10956                     tree_view);
10957
10958   frame = gtk_frame_new (NULL);
10959   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
10960   gtk_widget_show (frame);
10961   gtk_container_add (GTK_CONTAINER (tree_view->priv->search_window), frame);
10962
10963   vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
10964   gtk_widget_show (vbox);
10965   gtk_container_add (GTK_CONTAINER (frame), vbox);
10966   gtk_container_set_border_width (GTK_CONTAINER (vbox), 3);
10967
10968   /* add entry */
10969   tree_view->priv->search_entry = gtk_entry_new ();
10970   gtk_widget_show (tree_view->priv->search_entry);
10971   g_signal_connect (tree_view->priv->search_entry, "populate-popup",
10972                     G_CALLBACK (gtk_tree_view_search_disable_popdown),
10973                     tree_view);
10974   g_signal_connect (tree_view->priv->search_entry,
10975                     "activate", G_CALLBACK (gtk_tree_view_search_activate),
10976                     tree_view);
10977
10978   g_signal_connect (_gtk_entry_get_im_context (GTK_ENTRY (tree_view->priv->search_entry)),
10979                     "preedit-changed",
10980                     G_CALLBACK (gtk_tree_view_search_preedit_changed),
10981                     tree_view);
10982
10983   gtk_container_add (GTK_CONTAINER (vbox),
10984                      tree_view->priv->search_entry);
10985
10986   gtk_widget_realize (tree_view->priv->search_entry);
10987 }
10988
10989 /* Pops up the interactive search entry.  If keybinding is TRUE then the user
10990  * started this by typing the start_interactive_search keybinding.  Otherwise, it came from 
10991  */
10992 static gboolean
10993 gtk_tree_view_real_start_interactive_search (GtkTreeView *tree_view,
10994                                              GdkDevice   *device,
10995                                              gboolean     keybinding)
10996 {
10997   /* We only start interactive search if we have focus or the columns
10998    * have focus.  If one of our children have focus, we don't want to
10999    * start the search.
11000    */
11001   GList *list;
11002   gboolean found_focus = FALSE;
11003   GtkWidgetClass *entry_parent_class;
11004   
11005   if (!tree_view->priv->enable_search && !keybinding)
11006     return FALSE;
11007
11008   if (tree_view->priv->search_custom_entry_set)
11009     return FALSE;
11010
11011   if (tree_view->priv->search_window != NULL &&
11012       gtk_widget_get_visible (tree_view->priv->search_window))
11013     return TRUE;
11014
11015   for (list = tree_view->priv->columns; list; list = list->next)
11016     {
11017       GtkTreeViewColumn *column;
11018       GtkWidget         *button;
11019
11020       column = list->data;
11021       if (!gtk_tree_view_column_get_visible (column))
11022         continue;
11023
11024       button = gtk_tree_view_column_get_button (column);
11025       if (gtk_widget_has_focus (button))
11026         {
11027           found_focus = TRUE;
11028           break;
11029         }
11030     }
11031   
11032   if (gtk_widget_has_focus (GTK_WIDGET (tree_view)))
11033     found_focus = TRUE;
11034
11035   if (!found_focus)
11036     return FALSE;
11037
11038   if (tree_view->priv->search_column < 0)
11039     return FALSE;
11040
11041   gtk_tree_view_ensure_interactive_directory (tree_view);
11042
11043   if (keybinding)
11044     gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
11045
11046   /* done, show it */
11047   tree_view->priv->search_position_func (tree_view, tree_view->priv->search_window, tree_view->priv->search_position_user_data);
11048   gtk_widget_show (tree_view->priv->search_window);
11049   if (tree_view->priv->search_entry_changed_id == 0)
11050     {
11051       tree_view->priv->search_entry_changed_id =
11052         g_signal_connect (tree_view->priv->search_entry, "changed",
11053                           G_CALLBACK (gtk_tree_view_search_init),
11054                           tree_view);
11055     }
11056
11057   tree_view->priv->typeselect_flush_timeout =
11058     gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
11059                    (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
11060                    tree_view);
11061
11062   /* Grab focus will select all the text.  We don't want that to happen, so we
11063    * call the parent instance and bypass the selection change.  This is probably
11064    * really non-kosher. */
11065   entry_parent_class = g_type_class_peek_parent (GTK_ENTRY_GET_CLASS (tree_view->priv->search_entry));
11066   (entry_parent_class->grab_focus) (tree_view->priv->search_entry);
11067
11068   /* send focus-in event */
11069   send_focus_change (tree_view->priv->search_entry, device, TRUE);
11070
11071   /* search first matching iter */
11072   gtk_tree_view_search_init (tree_view->priv->search_entry, tree_view);
11073
11074   return TRUE;
11075 }
11076
11077 static gboolean
11078 gtk_tree_view_start_interactive_search (GtkTreeView *tree_view)
11079 {
11080   return gtk_tree_view_real_start_interactive_search (tree_view,
11081                                                       gtk_get_current_event_device (),
11082                                                       TRUE);
11083 }
11084
11085 /* this function returns the new width of the column being resized given
11086  * the column and x position of the cursor; the x cursor position is passed
11087  * in as a pointer and automagicly corrected if it's beyond min/max limits
11088  */
11089 static gint
11090 gtk_tree_view_new_column_width (GtkTreeView *tree_view,
11091                                 gint       i,
11092                                 gint      *x)
11093 {
11094   GtkAllocation allocation;
11095   GtkTreeViewColumn *column;
11096   GtkRequisition button_req;
11097   gint max_width, min_width;
11098   gint width;
11099   gboolean rtl;
11100
11101   /* first translate the x position from widget->window
11102    * to clist->clist_window
11103    */
11104   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
11105   column = g_list_nth (tree_view->priv->columns, i)->data;
11106   gtk_widget_get_allocation (gtk_tree_view_column_get_button (column), &allocation);
11107   width = rtl ? (allocation.x + allocation.width - *x) : (*x - allocation.x);
11108
11109   /* Clamp down the value */
11110   min_width = gtk_tree_view_column_get_min_width (column);
11111   if (min_width == -1)
11112     {
11113       gtk_widget_get_preferred_size (gtk_tree_view_column_get_button (column), &button_req, NULL);
11114       width = MAX (button_req.width, width);
11115     }
11116   else
11117     width = MAX (min_width, width);
11118
11119   max_width = gtk_tree_view_column_get_max_width (column);
11120   if (max_width != -1)
11121     width = MIN (width, max_width);
11122
11123   *x = rtl ? (allocation.x + allocation.width - width) : (allocation.x + width);
11124
11125   return width;
11126 }
11127
11128
11129 /* FIXME this adjust_allocation is a big cut-and-paste from
11130  * GtkCList, needs to be some "official" way to do this
11131  * factored out.
11132  */
11133 typedef struct
11134 {
11135   GdkWindow *window;
11136   int dx;
11137   int dy;
11138 } ScrollData;
11139
11140 /* The window to which widget->window is relative */
11141 #define ALLOCATION_WINDOW(widget)               \
11142    (!gtk_widget_get_has_window (widget) ?                   \
11143     gtk_widget_get_window (widget) :                        \
11144     gdk_window_get_parent (gtk_widget_get_window (widget)))
11145
11146 static void
11147 adjust_allocation_recurse (GtkWidget *widget,
11148                            gpointer   data)
11149 {
11150   GtkAllocation allocation;
11151   ScrollData *scroll_data = data;
11152
11153   /* Need to really size allocate instead of just poking
11154    * into widget->allocation if the widget is not realized.
11155    * FIXME someone figure out why this was.
11156    */
11157   gtk_widget_get_allocation (widget, &allocation);
11158   if (!gtk_widget_get_realized (widget))
11159     {
11160       if (gtk_widget_get_visible (widget))
11161         {
11162           GdkRectangle tmp_rectangle = allocation;
11163           tmp_rectangle.x += scroll_data->dx;
11164           tmp_rectangle.y += scroll_data->dy;
11165           
11166           gtk_widget_size_allocate (widget, &tmp_rectangle);
11167         }
11168     }
11169   else
11170     {
11171       if (ALLOCATION_WINDOW (widget) == scroll_data->window)
11172         {
11173           allocation.x += scroll_data->dx;
11174           allocation.y += scroll_data->dy;
11175           gtk_widget_set_allocation (widget, &allocation);
11176
11177           if (GTK_IS_CONTAINER (widget))
11178             gtk_container_forall (GTK_CONTAINER (widget),
11179                                   adjust_allocation_recurse,
11180                                   data);
11181         }
11182     }
11183 }
11184
11185 static void
11186 adjust_allocation (GtkWidget *widget,
11187                    int        dx,
11188                    int        dy)
11189 {
11190   ScrollData scroll_data;
11191
11192   if (gtk_widget_get_realized (widget))
11193     scroll_data.window = ALLOCATION_WINDOW (widget);
11194   else
11195     scroll_data.window = NULL;
11196     
11197   scroll_data.dx = dx;
11198   scroll_data.dy = dy;
11199   
11200   adjust_allocation_recurse (widget, &scroll_data);
11201 }
11202
11203 /* Callbacks */
11204 static void
11205 gtk_tree_view_adjustment_changed (GtkAdjustment *adjustment,
11206                                   GtkTreeView   *tree_view)
11207 {
11208   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11209     {
11210       GtkStyleContext *context;
11211       gint dy;
11212         
11213       gdk_window_move (tree_view->priv->bin_window,
11214                        - gtk_adjustment_get_value (tree_view->priv->hadjustment),
11215                        gtk_tree_view_get_effective_header_height (tree_view));
11216       gdk_window_move (tree_view->priv->header_window,
11217                        - gtk_adjustment_get_value (tree_view->priv->hadjustment),
11218                        0);
11219       dy = tree_view->priv->dy - (int) gtk_adjustment_get_value (tree_view->priv->vadjustment);
11220       if (dy)
11221         {
11222           update_prelight (tree_view,
11223                            tree_view->priv->event_last_x,
11224                            tree_view->priv->event_last_y - dy);
11225
11226           if (tree_view->priv->edited_column)
11227             {
11228               GList *list;
11229               GtkTreeViewChild *child = NULL;
11230               GtkCellEditable *edit_widget;
11231               GtkCellArea *area;
11232
11233               area        = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (tree_view->priv->edited_column));
11234               edit_widget = gtk_cell_area_get_edit_widget (area);
11235               if (GTK_IS_WIDGET (edit_widget))
11236                 {
11237                   adjust_allocation (GTK_WIDGET (edit_widget), 0, dy);
11238
11239                   for (list = tree_view->priv->children; list; list = list->next)
11240                     {
11241                       child = (GtkTreeViewChild *)list->data;
11242                       if (child->widget == GTK_WIDGET (edit_widget))
11243                         {
11244                           child->y += dy;
11245                           break;
11246                         }
11247                     }
11248                 }
11249             }
11250         }
11251       gdk_window_scroll (tree_view->priv->bin_window, 0, dy);
11252
11253       context = gtk_widget_get_style_context (GTK_WIDGET (tree_view));
11254       gtk_style_context_scroll_animations (context, tree_view->priv->bin_window, 0, dy);
11255
11256       if (tree_view->priv->dy != (int) gtk_adjustment_get_value (tree_view->priv->vadjustment))
11257         {
11258           /* update our dy and top_row */
11259           tree_view->priv->dy = (int) gtk_adjustment_get_value (tree_view->priv->vadjustment);
11260
11261           if (!tree_view->priv->in_top_row_to_dy)
11262             gtk_tree_view_dy_to_top_row (tree_view);
11263         }
11264
11265       gdk_window_process_updates (tree_view->priv->header_window, TRUE);
11266       gtk_tree_view_bin_process_updates (tree_view);
11267     }
11268 }
11269
11270 \f
11271
11272 /* Public methods
11273  */
11274
11275 /**
11276  * gtk_tree_view_new:
11277  *
11278  * Creates a new #GtkTreeView widget.
11279  *
11280  * Return value: A newly created #GtkTreeView widget.
11281  **/
11282 GtkWidget *
11283 gtk_tree_view_new (void)
11284 {
11285   return g_object_new (GTK_TYPE_TREE_VIEW, NULL);
11286 }
11287
11288 /**
11289  * gtk_tree_view_new_with_model:
11290  * @model: the model.
11291  *
11292  * Creates a new #GtkTreeView widget with the model initialized to @model.
11293  *
11294  * Return value: A newly created #GtkTreeView widget.
11295  **/
11296 GtkWidget *
11297 gtk_tree_view_new_with_model (GtkTreeModel *model)
11298 {
11299   return g_object_new (GTK_TYPE_TREE_VIEW, "model", model, NULL);
11300 }
11301
11302 /* Public Accessors
11303  */
11304
11305 /**
11306  * gtk_tree_view_get_model:
11307  * @tree_view: a #GtkTreeView
11308  *
11309  * Returns the model the #GtkTreeView is based on.  Returns %NULL if the
11310  * model is unset.
11311  *
11312  * Return value: (transfer none): A #GtkTreeModel, or %NULL if none is currently being used.
11313  **/
11314 GtkTreeModel *
11315 gtk_tree_view_get_model (GtkTreeView *tree_view)
11316 {
11317   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11318
11319   return tree_view->priv->model;
11320 }
11321
11322 /**
11323  * gtk_tree_view_set_model:
11324  * @tree_view: A #GtkTreeNode.
11325  * @model: (allow-none): The model.
11326  *
11327  * Sets the model for a #GtkTreeView.  If the @tree_view already has a model
11328  * set, it will remove it before setting the new model.  If @model is %NULL,
11329  * then it will unset the old model.
11330  **/
11331 void
11332 gtk_tree_view_set_model (GtkTreeView  *tree_view,
11333                          GtkTreeModel *model)
11334 {
11335   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11336   g_return_if_fail (model == NULL || GTK_IS_TREE_MODEL (model));
11337
11338   if (model == tree_view->priv->model)
11339     return;
11340
11341   if (tree_view->priv->scroll_to_path)
11342     {
11343       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
11344       tree_view->priv->scroll_to_path = NULL;
11345     }
11346
11347   if (tree_view->priv->model)
11348     {
11349       GList *tmplist = tree_view->priv->columns;
11350       GtkStyleContext *context;
11351
11352       gtk_tree_view_unref_and_check_selection_tree (tree_view, tree_view->priv->tree);
11353       gtk_tree_view_stop_editing (tree_view, TRUE);
11354
11355       context = gtk_widget_get_style_context (GTK_WIDGET (tree_view));
11356       gtk_style_context_cancel_animations (context, NULL);
11357
11358       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
11359                                             gtk_tree_view_row_changed,
11360                                             tree_view);
11361       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
11362                                             gtk_tree_view_row_inserted,
11363                                             tree_view);
11364       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
11365                                             gtk_tree_view_row_has_child_toggled,
11366                                             tree_view);
11367       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
11368                                             gtk_tree_view_row_deleted,
11369                                             tree_view);
11370       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
11371                                             gtk_tree_view_rows_reordered,
11372                                             tree_view);
11373
11374       for (; tmplist; tmplist = tmplist->next)
11375         _gtk_tree_view_column_unset_model (tmplist->data,
11376                                            tree_view->priv->model);
11377
11378       if (tree_view->priv->tree)
11379         gtk_tree_view_free_rbtree (tree_view);
11380
11381       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
11382       tree_view->priv->drag_dest_row = NULL;
11383       gtk_tree_row_reference_free (tree_view->priv->cursor);
11384       tree_view->priv->cursor = NULL;
11385       gtk_tree_row_reference_free (tree_view->priv->anchor);
11386       tree_view->priv->anchor = NULL;
11387       gtk_tree_row_reference_free (tree_view->priv->top_row);
11388       tree_view->priv->top_row = NULL;
11389       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
11390       tree_view->priv->scroll_to_path = NULL;
11391
11392       tree_view->priv->scroll_to_column = NULL;
11393
11394       g_object_unref (tree_view->priv->model);
11395
11396       tree_view->priv->search_column = -1;
11397       tree_view->priv->fixed_height_check = 0;
11398       tree_view->priv->fixed_height = -1;
11399       tree_view->priv->dy = tree_view->priv->top_row_dy = 0;
11400       tree_view->priv->last_button_x = -1;
11401       tree_view->priv->last_button_y = -1;
11402     }
11403
11404   tree_view->priv->model = model;
11405
11406   if (tree_view->priv->model)
11407     {
11408       gint i;
11409       GtkTreePath *path;
11410       GtkTreeIter iter;
11411       GtkTreeModelFlags flags;
11412
11413       if (tree_view->priv->search_column == -1)
11414         {
11415           for (i = 0; i < gtk_tree_model_get_n_columns (model); i++)
11416             {
11417               GType type = gtk_tree_model_get_column_type (model, i);
11418
11419               if (g_value_type_transformable (type, G_TYPE_STRING))
11420                 {
11421                   tree_view->priv->search_column = i;
11422                   break;
11423                 }
11424             }
11425         }
11426
11427       g_object_ref (tree_view->priv->model);
11428       g_signal_connect (tree_view->priv->model,
11429                         "row-changed",
11430                         G_CALLBACK (gtk_tree_view_row_changed),
11431                         tree_view);
11432       g_signal_connect (tree_view->priv->model,
11433                         "row-inserted",
11434                         G_CALLBACK (gtk_tree_view_row_inserted),
11435                         tree_view);
11436       g_signal_connect (tree_view->priv->model,
11437                         "row-has-child-toggled",
11438                         G_CALLBACK (gtk_tree_view_row_has_child_toggled),
11439                         tree_view);
11440       g_signal_connect (tree_view->priv->model,
11441                         "row-deleted",
11442                         G_CALLBACK (gtk_tree_view_row_deleted),
11443                         tree_view);
11444       g_signal_connect (tree_view->priv->model,
11445                         "rows-reordered",
11446                         G_CALLBACK (gtk_tree_view_rows_reordered),
11447                         tree_view);
11448
11449       flags = gtk_tree_model_get_flags (tree_view->priv->model);
11450       if ((flags & GTK_TREE_MODEL_LIST_ONLY) == GTK_TREE_MODEL_LIST_ONLY)
11451         tree_view->priv->is_list = TRUE;
11452       else
11453         tree_view->priv->is_list = FALSE;
11454
11455       path = gtk_tree_path_new_first ();
11456       if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, path))
11457         {
11458           tree_view->priv->tree = _gtk_rbtree_new ();
11459           gtk_tree_view_build_tree (tree_view, tree_view->priv->tree, &iter, 1, FALSE);
11460         }
11461       gtk_tree_path_free (path);
11462
11463       /*  FIXME: do I need to do this? gtk_tree_view_create_buttons (tree_view); */
11464       install_presize_handler (tree_view);
11465     }
11466
11467   g_object_notify (G_OBJECT (tree_view), "model");
11468
11469   if (tree_view->priv->selection)
11470   _gtk_tree_selection_emit_changed (tree_view->priv->selection);
11471
11472   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11473     gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11474 }
11475
11476 /**
11477  * gtk_tree_view_get_selection:
11478  * @tree_view: A #GtkTreeView.
11479  *
11480  * Gets the #GtkTreeSelection associated with @tree_view.
11481  *
11482  * Return value: (transfer none): A #GtkTreeSelection object.
11483  **/
11484 GtkTreeSelection *
11485 gtk_tree_view_get_selection (GtkTreeView *tree_view)
11486 {
11487   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11488
11489   return tree_view->priv->selection;
11490 }
11491
11492 /**
11493  * gtk_tree_view_get_hadjustment:
11494  * @tree_view: A #GtkTreeView
11495  *
11496  * Gets the #GtkAdjustment currently being used for the horizontal aspect.
11497  *
11498  * Return value: (transfer none): A #GtkAdjustment object, or %NULL
11499  *     if none is currently being used.
11500  *
11501  * Deprecated: 3.0: Use gtk_scrollable_get_hadjustment()
11502  **/
11503 GtkAdjustment *
11504 gtk_tree_view_get_hadjustment (GtkTreeView *tree_view)
11505 {
11506   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11507
11508   return tree_view->priv->hadjustment;
11509 }
11510
11511 /**
11512  * gtk_tree_view_set_hadjustment:
11513  * @tree_view: A #GtkTreeView
11514  * @adjustment: (allow-none): The #GtkAdjustment to set, or %NULL
11515  *
11516  * Sets the #GtkAdjustment for the current horizontal aspect.
11517  *
11518  * Deprecated: 3.0: Use gtk_scrollable_set_hadjustment()
11519  **/
11520 void
11521 gtk_tree_view_set_hadjustment (GtkTreeView   *tree_view,
11522                                GtkAdjustment *adjustment)
11523 {
11524   GtkTreeViewPrivate *priv = tree_view->priv;
11525
11526   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11527   g_return_if_fail (adjustment == NULL || GTK_IS_ADJUSTMENT (adjustment));
11528
11529   if (adjustment && priv->hadjustment == adjustment)
11530     return;
11531
11532   if (priv->hadjustment != NULL)
11533     {
11534       g_signal_handlers_disconnect_by_func (priv->hadjustment,
11535                                             gtk_tree_view_adjustment_changed,
11536                                             tree_view);
11537       g_object_unref (priv->hadjustment);
11538     }
11539
11540   if (adjustment == NULL)
11541     adjustment = gtk_adjustment_new (0.0, 0.0, 0.0,
11542                                      0.0, 0.0, 0.0);
11543
11544   g_signal_connect (adjustment, "value-changed",
11545                     G_CALLBACK (gtk_tree_view_adjustment_changed), tree_view);
11546   priv->hadjustment = g_object_ref_sink (adjustment);
11547   /* FIXME: Adjustment should probably be populated here with fresh values, but
11548    * internal details are too complicated for me to decipher right now.
11549    */
11550   gtk_tree_view_adjustment_changed (NULL, tree_view);
11551
11552   g_object_notify (G_OBJECT (tree_view), "hadjustment");
11553 }
11554
11555 /**
11556  * gtk_tree_view_get_vadjustment:
11557  * @tree_view: A #GtkTreeView
11558  *
11559  * Gets the #GtkAdjustment currently being used for the vertical aspect.
11560  *
11561  * Return value: (transfer none): A #GtkAdjustment object, or %NULL
11562  *     if none is currently being used.
11563  *
11564  * Deprecated: 3.0: Use gtk_scrollable_get_vadjustment()
11565  **/
11566 GtkAdjustment *
11567 gtk_tree_view_get_vadjustment (GtkTreeView *tree_view)
11568 {
11569   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11570
11571   return tree_view->priv->vadjustment;
11572 }
11573
11574 /**
11575  * gtk_tree_view_set_vadjustment:
11576  * @tree_view: A #GtkTreeView
11577  * @adjustment: (allow-none): The #GtkAdjustment to set, or %NULL
11578  *
11579  * Sets the #GtkAdjustment for the current vertical aspect.
11580  *
11581  * Deprecated: 3.0: Use gtk_scrollable_set_vadjustment()
11582  **/
11583 void
11584 gtk_tree_view_set_vadjustment (GtkTreeView   *tree_view,
11585                                GtkAdjustment *adjustment)
11586 {
11587   GtkTreeViewPrivate *priv = tree_view->priv;
11588
11589   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11590   g_return_if_fail (adjustment == NULL || GTK_IS_ADJUSTMENT (adjustment));
11591
11592   if (adjustment && priv->vadjustment == adjustment)
11593     return;
11594
11595   if (priv->vadjustment != NULL)
11596     {
11597       g_signal_handlers_disconnect_by_func (priv->vadjustment,
11598                                             gtk_tree_view_adjustment_changed,
11599                                             tree_view);
11600       g_object_unref (priv->vadjustment);
11601     }
11602
11603   if (adjustment == NULL)
11604     adjustment = gtk_adjustment_new (0.0, 0.0, 0.0,
11605                                      0.0, 0.0, 0.0);
11606
11607   g_signal_connect (adjustment, "value-changed",
11608                     G_CALLBACK (gtk_tree_view_adjustment_changed), tree_view);
11609   priv->vadjustment = g_object_ref_sink (adjustment);
11610   /* FIXME: Adjustment should probably be populated here with fresh values, but
11611    * internal details are too complicated for me to decipher right now.
11612    */
11613   gtk_tree_view_adjustment_changed (NULL, tree_view);
11614   g_object_notify (G_OBJECT (tree_view), "vadjustment");
11615 }
11616
11617 /* Column and header operations */
11618
11619 /**
11620  * gtk_tree_view_get_headers_visible:
11621  * @tree_view: A #GtkTreeView.
11622  *
11623  * Returns %TRUE if the headers on the @tree_view are visible.
11624  *
11625  * Return value: Whether the headers are visible or not.
11626  **/
11627 gboolean
11628 gtk_tree_view_get_headers_visible (GtkTreeView *tree_view)
11629 {
11630   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
11631
11632   return tree_view->priv->headers_visible;
11633 }
11634
11635 /**
11636  * gtk_tree_view_set_headers_visible:
11637  * @tree_view: A #GtkTreeView.
11638  * @headers_visible: %TRUE if the headers are visible
11639  *
11640  * Sets the visibility state of the headers.
11641  **/
11642 void
11643 gtk_tree_view_set_headers_visible (GtkTreeView *tree_view,
11644                                    gboolean     headers_visible)
11645 {
11646   gint x, y;
11647   GList *list;
11648   GtkTreeViewColumn *column;
11649   GtkAllocation allocation;
11650   GtkWidget *button;
11651
11652   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11653
11654   headers_visible = !! headers_visible;
11655
11656   if (tree_view->priv->headers_visible == headers_visible)
11657     return;
11658
11659   tree_view->priv->headers_visible = headers_visible == TRUE;
11660
11661   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11662     {
11663       gdk_window_get_position (tree_view->priv->bin_window, &x, &y);
11664       if (headers_visible)
11665         {
11666           gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
11667           gdk_window_move_resize (tree_view->priv->bin_window,
11668                                   x, y  + gtk_tree_view_get_effective_header_height (tree_view),
11669                                   tree_view->priv->width, allocation.height -  + gtk_tree_view_get_effective_header_height (tree_view));
11670
11671           if (gtk_widget_get_mapped (GTK_WIDGET (tree_view)))
11672             gtk_tree_view_map_buttons (tree_view);
11673         }
11674       else
11675         {
11676           gdk_window_move_resize (tree_view->priv->bin_window, x, y, tree_view->priv->width, tree_view->priv->height);
11677
11678           for (list = tree_view->priv->columns; list; list = list->next)
11679             {
11680               column = list->data;
11681               button = gtk_tree_view_column_get_button (column);
11682
11683               gtk_widget_hide (button);
11684               gtk_widget_unmap (button);
11685             }
11686           gdk_window_hide (tree_view->priv->header_window);
11687         }
11688     }
11689
11690   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
11691   gtk_adjustment_configure (tree_view->priv->vadjustment,
11692                             gtk_adjustment_get_value (tree_view->priv->vadjustment),
11693                             0,
11694                             tree_view->priv->height,
11695                             gtk_adjustment_get_step_increment (tree_view->priv->vadjustment),
11696                             (allocation.height - gtk_tree_view_get_effective_header_height (tree_view)) / 2,
11697                             allocation.height - gtk_tree_view_get_effective_header_height (tree_view));
11698
11699   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11700
11701   g_object_notify (G_OBJECT (tree_view), "headers-visible");
11702 }
11703
11704 /**
11705  * gtk_tree_view_columns_autosize:
11706  * @tree_view: A #GtkTreeView.
11707  *
11708  * Resizes all columns to their optimal width. Only works after the
11709  * treeview has been realized.
11710  **/
11711 void
11712 gtk_tree_view_columns_autosize (GtkTreeView *tree_view)
11713 {
11714   gboolean dirty = FALSE;
11715   GList *list;
11716   GtkTreeViewColumn *column;
11717
11718   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11719
11720   for (list = tree_view->priv->columns; list; list = list->next)
11721     {
11722       column = list->data;
11723       if (gtk_tree_view_column_get_sizing (column) == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
11724         continue;
11725       _gtk_tree_view_column_cell_set_dirty (column, TRUE);
11726       dirty = TRUE;
11727     }
11728
11729   if (dirty)
11730     gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11731 }
11732
11733 /**
11734  * gtk_tree_view_set_headers_clickable:
11735  * @tree_view: A #GtkTreeView.
11736  * @setting: %TRUE if the columns are clickable.
11737  *
11738  * Allow the column title buttons to be clicked.
11739  **/
11740 void
11741 gtk_tree_view_set_headers_clickable (GtkTreeView *tree_view,
11742                                      gboolean   setting)
11743 {
11744   GList *list;
11745
11746   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11747
11748   for (list = tree_view->priv->columns; list; list = list->next)
11749     gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (list->data), setting);
11750
11751   g_object_notify (G_OBJECT (tree_view), "headers-clickable");
11752 }
11753
11754
11755 /**
11756  * gtk_tree_view_get_headers_clickable:
11757  * @tree_view: A #GtkTreeView.
11758  *
11759  * Returns whether all header columns are clickable.
11760  *
11761  * Return value: %TRUE if all header columns are clickable, otherwise %FALSE
11762  *
11763  * Since: 2.10
11764  **/
11765 gboolean 
11766 gtk_tree_view_get_headers_clickable (GtkTreeView *tree_view)
11767 {
11768   GList *list;
11769   
11770   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
11771
11772   for (list = tree_view->priv->columns; list; list = list->next)
11773     if (!gtk_tree_view_column_get_clickable (GTK_TREE_VIEW_COLUMN (list->data)))
11774       return FALSE;
11775
11776   return TRUE;
11777 }
11778
11779 /**
11780  * gtk_tree_view_set_rules_hint
11781  * @tree_view: a #GtkTreeView
11782  * @setting: %TRUE if the tree requires reading across rows
11783  *
11784  * This function tells GTK+ that the user interface for your
11785  * application requires users to read across tree rows and associate
11786  * cells with one another. By default, GTK+ will then render the tree
11787  * with alternating row colors. Do <emphasis>not</emphasis> use it
11788  * just because you prefer the appearance of the ruled tree; that's a
11789  * question for the theme. Some themes will draw tree rows in
11790  * alternating colors even when rules are turned off, and users who
11791  * prefer that appearance all the time can choose those themes. You
11792  * should call this function only as a <emphasis>semantic</emphasis>
11793  * hint to the theme engine that your tree makes alternating colors
11794  * useful from a functional standpoint (since it has lots of columns,
11795  * generally).
11796  *
11797  **/
11798 void
11799 gtk_tree_view_set_rules_hint (GtkTreeView  *tree_view,
11800                               gboolean      setting)
11801 {
11802   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11803
11804   setting = setting != FALSE;
11805
11806   if (tree_view->priv->has_rules != setting)
11807     {
11808       tree_view->priv->has_rules = setting;
11809       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
11810     }
11811
11812   g_object_notify (G_OBJECT (tree_view), "rules-hint");
11813 }
11814
11815 /**
11816  * gtk_tree_view_get_rules_hint
11817  * @tree_view: a #GtkTreeView
11818  *
11819  * Gets the setting set by gtk_tree_view_set_rules_hint().
11820  *
11821  * Return value: %TRUE if rules are useful for the user of this tree
11822  **/
11823 gboolean
11824 gtk_tree_view_get_rules_hint (GtkTreeView  *tree_view)
11825 {
11826   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
11827
11828   return tree_view->priv->has_rules;
11829 }
11830
11831 /* Public Column functions
11832  */
11833
11834 /**
11835  * gtk_tree_view_append_column:
11836  * @tree_view: A #GtkTreeView.
11837  * @column: The #GtkTreeViewColumn to add.
11838  *
11839  * Appends @column to the list of columns. If @tree_view has "fixed_height"
11840  * mode enabled, then @column must have its "sizing" property set to be
11841  * GTK_TREE_VIEW_COLUMN_FIXED.
11842  *
11843  * Return value: The number of columns in @tree_view after appending.
11844  **/
11845 gint
11846 gtk_tree_view_append_column (GtkTreeView       *tree_view,
11847                              GtkTreeViewColumn *column)
11848 {
11849   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11850   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
11851   g_return_val_if_fail (gtk_tree_view_column_get_tree_view (column) == NULL, -1);
11852
11853   return gtk_tree_view_insert_column (tree_view, column, -1);
11854 }
11855
11856 void
11857 _gtk_tree_view_reset_header_styles (GtkTreeView *tree_view)
11858 {
11859   GList *columns;
11860
11861   for (columns = tree_view->priv->columns; columns; columns = columns->next)
11862     {
11863       GtkTreeViewColumn *column = columns->data;
11864       GtkWidget *header_widget;
11865
11866       if (gtk_tree_view_column_get_visible (column))
11867         continue;
11868
11869       header_widget = gtk_tree_view_column_get_widget (column);
11870
11871       if (!header_widget)
11872         header_widget = gtk_tree_view_column_get_button (column);
11873
11874       gtk_widget_reset_style (header_widget);
11875     }
11876 }
11877
11878
11879 /**
11880  * gtk_tree_view_remove_column:
11881  * @tree_view: A #GtkTreeView.
11882  * @column: The #GtkTreeViewColumn to remove.
11883  *
11884  * Removes @column from @tree_view.
11885  *
11886  * Return value: The number of columns in @tree_view after removing.
11887  **/
11888 gint
11889 gtk_tree_view_remove_column (GtkTreeView       *tree_view,
11890                              GtkTreeViewColumn *column)
11891 {
11892   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11893   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
11894   g_return_val_if_fail (gtk_tree_view_column_get_tree_view (column) == GTK_WIDGET (tree_view), -1);
11895
11896   if (tree_view->priv->focus_column == column)
11897     tree_view->priv->focus_column = NULL;
11898
11899   if (tree_view->priv->edited_column == column)
11900     {
11901       gtk_tree_view_stop_editing (tree_view, TRUE);
11902
11903       /* no need to, but just to be sure ... */
11904       tree_view->priv->edited_column = NULL;
11905     }
11906
11907   if (tree_view->priv->expander_column == column)
11908     tree_view->priv->expander_column = NULL;
11909
11910   g_signal_handlers_disconnect_by_func (column,
11911                                         G_CALLBACK (column_sizing_notify),
11912                                         tree_view);
11913
11914   _gtk_tree_view_column_unset_tree_view (column);
11915
11916   tree_view->priv->columns = g_list_remove (tree_view->priv->columns, column);
11917   tree_view->priv->n_columns--;
11918
11919   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11920     {
11921       GList *list;
11922
11923       _gtk_tree_view_column_unrealize_button (column);
11924       for (list = tree_view->priv->columns; list; list = list->next)
11925         {
11926           GtkTreeViewColumn *tmp_column;
11927
11928           tmp_column = GTK_TREE_VIEW_COLUMN (list->data);
11929           if (gtk_tree_view_column_get_visible (tmp_column))
11930             _gtk_tree_view_column_cell_set_dirty (tmp_column, TRUE);
11931         }
11932
11933       if (tree_view->priv->n_columns == 0 &&
11934           gtk_tree_view_get_headers_visible (tree_view))
11935         gdk_window_hide (tree_view->priv->header_window);
11936
11937       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11938     }
11939
11940   _gtk_tree_view_reset_header_styles (tree_view);
11941
11942   g_object_unref (column);
11943   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
11944
11945   return tree_view->priv->n_columns;
11946 }
11947
11948 /**
11949  * gtk_tree_view_insert_column:
11950  * @tree_view: A #GtkTreeView.
11951  * @column: The #GtkTreeViewColumn to be inserted.
11952  * @position: The position to insert @column in.
11953  *
11954  * This inserts the @column into the @tree_view at @position.  If @position is
11955  * -1, then the column is inserted at the end. If @tree_view has
11956  * "fixed_height" mode enabled, then @column must have its "sizing" property
11957  * set to be GTK_TREE_VIEW_COLUMN_FIXED.
11958  *
11959  * Return value: The number of columns in @tree_view after insertion.
11960  **/
11961 gint
11962 gtk_tree_view_insert_column (GtkTreeView       *tree_view,
11963                              GtkTreeViewColumn *column,
11964                              gint               position)
11965 {
11966   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11967   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
11968   g_return_val_if_fail (gtk_tree_view_column_get_tree_view (column) == NULL, -1);
11969
11970   if (tree_view->priv->fixed_height_mode)
11971     g_return_val_if_fail (gtk_tree_view_column_get_sizing (column)
11972                           == GTK_TREE_VIEW_COLUMN_FIXED, -1);
11973
11974   g_object_ref_sink (column);
11975
11976   if (tree_view->priv->n_columns == 0 &&
11977       gtk_widget_get_realized (GTK_WIDGET (tree_view)) &&
11978       gtk_tree_view_get_headers_visible (tree_view))
11979     {
11980       gdk_window_show (tree_view->priv->header_window);
11981     }
11982
11983   g_signal_connect (column, "notify::sizing",
11984                     G_CALLBACK (column_sizing_notify), tree_view);
11985
11986   tree_view->priv->columns = g_list_insert (tree_view->priv->columns,
11987                                             column, position);
11988   tree_view->priv->n_columns++;
11989
11990   _gtk_tree_view_column_set_tree_view (column, tree_view);
11991
11992   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11993     {
11994       GList *list;
11995
11996       _gtk_tree_view_column_realize_button (column);
11997
11998       for (list = tree_view->priv->columns; list; list = list->next)
11999         {
12000           column = GTK_TREE_VIEW_COLUMN (list->data);
12001           if (gtk_tree_view_column_get_visible (column))
12002             _gtk_tree_view_column_cell_set_dirty (column, TRUE);
12003         }
12004       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
12005     }
12006
12007   _gtk_tree_view_reset_header_styles (tree_view);
12008   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
12009
12010   return tree_view->priv->n_columns;
12011 }
12012
12013 /**
12014  * gtk_tree_view_insert_column_with_attributes:
12015  * @tree_view: A #GtkTreeView
12016  * @position: The position to insert the new column in
12017  * @title: The title to set the header to
12018  * @cell: The #GtkCellRenderer
12019  * @...: A %NULL-terminated list of attributes
12020  *
12021  * Creates a new #GtkTreeViewColumn and inserts it into the @tree_view at
12022  * @position.  If @position is -1, then the newly created column is inserted at
12023  * the end.  The column is initialized with the attributes given. If @tree_view
12024  * has "fixed_height" mode enabled, then the new column will have its sizing
12025  * property set to be GTK_TREE_VIEW_COLUMN_FIXED.
12026  *
12027  * Return value: The number of columns in @tree_view after insertion.
12028  **/
12029 gint
12030 gtk_tree_view_insert_column_with_attributes (GtkTreeView     *tree_view,
12031                                              gint             position,
12032                                              const gchar     *title,
12033                                              GtkCellRenderer *cell,
12034                                              ...)
12035 {
12036   GtkTreeViewColumn *column;
12037   gchar *attribute;
12038   va_list args;
12039   gint column_id;
12040
12041   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
12042
12043   column = gtk_tree_view_column_new ();
12044   if (tree_view->priv->fixed_height_mode)
12045     gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
12046
12047   gtk_tree_view_column_set_title (column, title);
12048   gtk_tree_view_column_pack_start (column, cell, TRUE);
12049
12050   va_start (args, cell);
12051
12052   attribute = va_arg (args, gchar *);
12053
12054   while (attribute != NULL)
12055     {
12056       column_id = va_arg (args, gint);
12057       gtk_tree_view_column_add_attribute (column, cell, attribute, column_id);
12058       attribute = va_arg (args, gchar *);
12059     }
12060
12061   va_end (args);
12062
12063   gtk_tree_view_insert_column (tree_view, column, position);
12064
12065   return tree_view->priv->n_columns;
12066 }
12067
12068 /**
12069  * gtk_tree_view_insert_column_with_data_func:
12070  * @tree_view: a #GtkTreeView
12071  * @position: Position to insert, -1 for append
12072  * @title: column title
12073  * @cell: cell renderer for column
12074  * @func: function to set attributes of cell renderer
12075  * @data: data for @func
12076  * @dnotify: destroy notifier for @data
12077  *
12078  * Convenience function that inserts a new column into the #GtkTreeView
12079  * with the given cell renderer and a #GtkCellDataFunc to set cell renderer
12080  * attributes (normally using data from the model). See also
12081  * gtk_tree_view_column_set_cell_data_func(), gtk_tree_view_column_pack_start().
12082  * If @tree_view has "fixed_height" mode enabled, then the new column will have its
12083  * "sizing" property set to be GTK_TREE_VIEW_COLUMN_FIXED.
12084  *
12085  * Return value: number of columns in the tree view post-insert
12086  **/
12087 gint
12088 gtk_tree_view_insert_column_with_data_func  (GtkTreeView               *tree_view,
12089                                              gint                       position,
12090                                              const gchar               *title,
12091                                              GtkCellRenderer           *cell,
12092                                              GtkTreeCellDataFunc        func,
12093                                              gpointer                   data,
12094                                              GDestroyNotify             dnotify)
12095 {
12096   GtkTreeViewColumn *column;
12097
12098   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
12099
12100   column = gtk_tree_view_column_new ();
12101   if (tree_view->priv->fixed_height_mode)
12102     gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
12103
12104   gtk_tree_view_column_set_title (column, title);
12105   gtk_tree_view_column_pack_start (column, cell, TRUE);
12106   gtk_tree_view_column_set_cell_data_func (column, cell, func, data, dnotify);
12107
12108   gtk_tree_view_insert_column (tree_view, column, position);
12109
12110   return tree_view->priv->n_columns;
12111 }
12112
12113 /**
12114  * gtk_tree_view_get_column:
12115  * @tree_view: A #GtkTreeView.
12116  * @n: The position of the column, counting from 0.
12117  *
12118  * Gets the #GtkTreeViewColumn at the given position in the #tree_view.
12119  *
12120  * Return value: (transfer none): The #GtkTreeViewColumn, or %NULL if the
12121  *     position is outside the range of columns.
12122  **/
12123 GtkTreeViewColumn *
12124 gtk_tree_view_get_column (GtkTreeView *tree_view,
12125                           gint         n)
12126 {
12127   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
12128
12129   if (n < 0 || n >= tree_view->priv->n_columns)
12130     return NULL;
12131
12132   if (tree_view->priv->columns == NULL)
12133     return NULL;
12134
12135   return GTK_TREE_VIEW_COLUMN (g_list_nth (tree_view->priv->columns, n)->data);
12136 }
12137
12138 /**
12139  * gtk_tree_view_get_columns:
12140  * @tree_view: A #GtkTreeView
12141  *
12142  * Returns a #GList of all the #GtkTreeViewColumn s currently in @tree_view.
12143  * The returned list must be freed with g_list_free ().
12144  *
12145  * Return value: (element-type GtkTreeViewColumn) (transfer container): A list of #GtkTreeViewColumn s
12146  **/
12147 GList *
12148 gtk_tree_view_get_columns (GtkTreeView *tree_view)
12149 {
12150   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
12151
12152   return g_list_copy (tree_view->priv->columns);
12153 }
12154
12155 /**
12156  * gtk_tree_view_move_column_after:
12157  * @tree_view: A #GtkTreeView
12158  * @column: The #GtkTreeViewColumn to be moved.
12159  * @base_column: (allow-none): The #GtkTreeViewColumn to be moved relative to, or %NULL.
12160  *
12161  * Moves @column to be after to @base_column.  If @base_column is %NULL, then
12162  * @column is placed in the first position.
12163  **/
12164 void
12165 gtk_tree_view_move_column_after (GtkTreeView       *tree_view,
12166                                  GtkTreeViewColumn *column,
12167                                  GtkTreeViewColumn *base_column)
12168 {
12169   GList *column_list_el, *base_el = NULL;
12170
12171   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12172
12173   column_list_el = g_list_find (tree_view->priv->columns, column);
12174   g_return_if_fail (column_list_el != NULL);
12175
12176   if (base_column)
12177     {
12178       base_el = g_list_find (tree_view->priv->columns, base_column);
12179       g_return_if_fail (base_el != NULL);
12180     }
12181
12182   if (column_list_el->prev == base_el)
12183     return;
12184
12185   tree_view->priv->columns = g_list_remove_link (tree_view->priv->columns, column_list_el);
12186   if (base_el == NULL)
12187     {
12188       column_list_el->prev = NULL;
12189       column_list_el->next = tree_view->priv->columns;
12190       if (column_list_el->next)
12191         column_list_el->next->prev = column_list_el;
12192       tree_view->priv->columns = column_list_el;
12193     }
12194   else
12195     {
12196       column_list_el->prev = base_el;
12197       column_list_el->next = base_el->next;
12198       if (column_list_el->next)
12199         column_list_el->next->prev = column_list_el;
12200       base_el->next = column_list_el;
12201     }
12202
12203   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
12204     {
12205       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
12206       gtk_tree_view_size_allocate_columns (GTK_WIDGET (tree_view), NULL);
12207     }
12208
12209   _gtk_tree_view_reset_header_styles (tree_view);
12210   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
12211 }
12212
12213 /**
12214  * gtk_tree_view_set_expander_column:
12215  * @tree_view: A #GtkTreeView
12216  * @column: %NULL, or the column to draw the expander arrow at.
12217  *
12218  * Sets the column to draw the expander arrow at. It must be in @tree_view.  
12219  * If @column is %NULL, then the expander arrow is always at the first 
12220  * visible column.
12221  *
12222  * If you do not want expander arrow to appear in your tree, set the 
12223  * expander column to a hidden column.
12224  **/
12225 void
12226 gtk_tree_view_set_expander_column (GtkTreeView       *tree_view,
12227                                    GtkTreeViewColumn *column)
12228 {
12229   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12230   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
12231
12232   if (tree_view->priv->expander_column != column)
12233     {
12234       GList *list;
12235
12236       if (column)
12237         {
12238           /* Confirm that column is in tree_view */
12239           for (list = tree_view->priv->columns; list; list = list->next)
12240             if (list->data == column)
12241               break;
12242           g_return_if_fail (list != NULL);
12243         }
12244
12245       tree_view->priv->expander_column = column;
12246       g_object_notify (G_OBJECT (tree_view), "expander-column");
12247     }
12248 }
12249
12250 /**
12251  * gtk_tree_view_get_expander_column:
12252  * @tree_view: A #GtkTreeView
12253  *
12254  * Returns the column that is the current expander column.
12255  * This column has the expander arrow drawn next to it.
12256  *
12257  * Return value: (transfer none): The expander column.
12258  **/
12259 GtkTreeViewColumn *
12260 gtk_tree_view_get_expander_column (GtkTreeView *tree_view)
12261 {
12262   GList *list;
12263
12264   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
12265
12266   for (list = tree_view->priv->columns; list; list = list->next)
12267     if (gtk_tree_view_is_expander_column (tree_view, GTK_TREE_VIEW_COLUMN (list->data)))
12268       return (GtkTreeViewColumn *) list->data;
12269   return NULL;
12270 }
12271
12272
12273 /**
12274  * gtk_tree_view_set_column_drag_function:
12275  * @tree_view: A #GtkTreeView.
12276  * @func: (allow-none): A function to determine which columns are reorderable, or %NULL.
12277  * @user_data: (allow-none): User data to be passed to @func, or %NULL
12278  * @destroy: (allow-none): Destroy notifier for @user_data, or %NULL
12279  *
12280  * Sets a user function for determining where a column may be dropped when
12281  * dragged.  This function is called on every column pair in turn at the
12282  * beginning of a column drag to determine where a drop can take place.  The
12283  * arguments passed to @func are: the @tree_view, the #GtkTreeViewColumn being
12284  * dragged, the two #GtkTreeViewColumn s determining the drop spot, and
12285  * @user_data.  If either of the #GtkTreeViewColumn arguments for the drop spot
12286  * are %NULL, then they indicate an edge.  If @func is set to be %NULL, then
12287  * @tree_view reverts to the default behavior of allowing all columns to be
12288  * dropped everywhere.
12289  **/
12290 void
12291 gtk_tree_view_set_column_drag_function (GtkTreeView               *tree_view,
12292                                         GtkTreeViewColumnDropFunc  func,
12293                                         gpointer                   user_data,
12294                                         GDestroyNotify             destroy)
12295 {
12296   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12297
12298   if (tree_view->priv->column_drop_func_data_destroy)
12299     tree_view->priv->column_drop_func_data_destroy (tree_view->priv->column_drop_func_data);
12300
12301   tree_view->priv->column_drop_func = func;
12302   tree_view->priv->column_drop_func_data = user_data;
12303   tree_view->priv->column_drop_func_data_destroy = destroy;
12304 }
12305
12306 /**
12307  * gtk_tree_view_scroll_to_point:
12308  * @tree_view: a #GtkTreeView
12309  * @tree_x: X coordinate of new top-left pixel of visible area, or -1
12310  * @tree_y: Y coordinate of new top-left pixel of visible area, or -1
12311  *
12312  * Scrolls the tree view such that the top-left corner of the visible
12313  * area is @tree_x, @tree_y, where @tree_x and @tree_y are specified
12314  * in tree coordinates.  The @tree_view must be realized before
12315  * this function is called.  If it isn't, you probably want to be
12316  * using gtk_tree_view_scroll_to_cell().
12317  *
12318  * If either @tree_x or @tree_y are -1, then that direction isn't scrolled.
12319  **/
12320 void
12321 gtk_tree_view_scroll_to_point (GtkTreeView *tree_view,
12322                                gint         tree_x,
12323                                gint         tree_y)
12324 {
12325   GtkAdjustment *hadj;
12326   GtkAdjustment *vadj;
12327
12328   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12329   g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (tree_view)));
12330
12331   hadj = tree_view->priv->hadjustment;
12332   vadj = tree_view->priv->vadjustment;
12333
12334   if (tree_x != -1)
12335     gtk_adjustment_set_value (hadj, tree_x);
12336   if (tree_y != -1)
12337     gtk_adjustment_set_value (vadj, tree_y);
12338 }
12339
12340 /**
12341  * gtk_tree_view_scroll_to_cell:
12342  * @tree_view: A #GtkTreeView.
12343  * @path: (allow-none): The path of the row to move to, or %NULL.
12344  * @column: (allow-none): The #GtkTreeViewColumn to move horizontally to, or %NULL.
12345  * @use_align: whether to use alignment arguments, or %FALSE.
12346  * @row_align: The vertical alignment of the row specified by @path.
12347  * @col_align: The horizontal alignment of the column specified by @column.
12348  *
12349  * Moves the alignments of @tree_view to the position specified by @column and
12350  * @path.  If @column is %NULL, then no horizontal scrolling occurs.  Likewise,
12351  * if @path is %NULL no vertical scrolling occurs.  At a minimum, one of @column
12352  * or @path need to be non-%NULL.  @row_align determines where the row is
12353  * placed, and @col_align determines where @column is placed.  Both are expected
12354  * to be between 0.0 and 1.0. 0.0 means left/top alignment, 1.0 means
12355  * right/bottom alignment, 0.5 means center.
12356  *
12357  * If @use_align is %FALSE, then the alignment arguments are ignored, and the
12358  * tree does the minimum amount of work to scroll the cell onto the screen.
12359  * This means that the cell will be scrolled to the edge closest to its current
12360  * position.  If the cell is currently visible on the screen, nothing is done.
12361  *
12362  * This function only works if the model is set, and @path is a valid row on the
12363  * model.  If the model changes before the @tree_view is realized, the centered
12364  * path will be modified to reflect this change.
12365  **/
12366 void
12367 gtk_tree_view_scroll_to_cell (GtkTreeView       *tree_view,
12368                               GtkTreePath       *path,
12369                               GtkTreeViewColumn *column,
12370                               gboolean           use_align,
12371                               gfloat             row_align,
12372                               gfloat             col_align)
12373 {
12374   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12375   g_return_if_fail (tree_view->priv->model != NULL);
12376   g_return_if_fail (tree_view->priv->tree != NULL);
12377   g_return_if_fail (row_align >= 0.0 && row_align <= 1.0);
12378   g_return_if_fail (col_align >= 0.0 && col_align <= 1.0);
12379   g_return_if_fail (path != NULL || column != NULL);
12380
12381 #if 0
12382   g_print ("gtk_tree_view_scroll_to_cell:\npath: %s\ncolumn: %s\nuse_align: %d\nrow_align: %f\ncol_align: %f\n",
12383            gtk_tree_path_to_string (path), column?"non-null":"null", use_align, row_align, col_align);
12384 #endif
12385   row_align = CLAMP (row_align, 0.0, 1.0);
12386   col_align = CLAMP (col_align, 0.0, 1.0);
12387
12388
12389   /* Note: Despite the benefits that come from having one code path for the
12390    * scrolling code, we short-circuit validate_visible_area's immplementation as
12391    * it is much slower than just going to the point.
12392    */
12393   if (!gtk_widget_get_visible (GTK_WIDGET (tree_view)) ||
12394       !gtk_widget_get_realized (GTK_WIDGET (tree_view)) ||
12395       _gtk_widget_get_alloc_needed (GTK_WIDGET (tree_view)) ||
12396       GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID))
12397     {
12398       if (tree_view->priv->scroll_to_path)
12399         gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
12400
12401       tree_view->priv->scroll_to_path = NULL;
12402       tree_view->priv->scroll_to_column = NULL;
12403
12404       if (path)
12405         tree_view->priv->scroll_to_path = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
12406       if (column)
12407         tree_view->priv->scroll_to_column = column;
12408       tree_view->priv->scroll_to_use_align = use_align;
12409       tree_view->priv->scroll_to_row_align = row_align;
12410       tree_view->priv->scroll_to_col_align = col_align;
12411
12412       install_presize_handler (tree_view);
12413     }
12414   else
12415     {
12416       GdkRectangle cell_rect;
12417       GdkRectangle vis_rect;
12418       gint dest_x, dest_y;
12419
12420       gtk_tree_view_get_background_area (tree_view, path, column, &cell_rect);
12421       gtk_tree_view_get_visible_rect (tree_view, &vis_rect);
12422
12423       cell_rect.y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, cell_rect.y);
12424
12425       dest_x = vis_rect.x;
12426       dest_y = vis_rect.y;
12427
12428       if (column)
12429         {
12430           if (use_align)
12431             {
12432               dest_x = cell_rect.x - ((vis_rect.width - cell_rect.width) * col_align);
12433             }
12434           else
12435             {
12436               if (cell_rect.x < vis_rect.x)
12437                 dest_x = cell_rect.x;
12438               if (cell_rect.x + cell_rect.width > vis_rect.x + vis_rect.width)
12439                 dest_x = cell_rect.x + cell_rect.width - vis_rect.width;
12440             }
12441         }
12442
12443       if (path)
12444         {
12445           if (use_align)
12446             {
12447               dest_y = cell_rect.y - ((vis_rect.height - cell_rect.height) * row_align);
12448               dest_y = MAX (dest_y, 0);
12449             }
12450           else
12451             {
12452               if (cell_rect.y < vis_rect.y)
12453                 dest_y = cell_rect.y;
12454               if (cell_rect.y + cell_rect.height > vis_rect.y + vis_rect.height)
12455                 dest_y = cell_rect.y + cell_rect.height - vis_rect.height;
12456             }
12457         }
12458
12459       gtk_tree_view_scroll_to_point (tree_view, dest_x, dest_y);
12460     }
12461 }
12462
12463 /**
12464  * gtk_tree_view_row_activated:
12465  * @tree_view: A #GtkTreeView
12466  * @path: The #GtkTreePath to be activated.
12467  * @column: The #GtkTreeViewColumn to be activated.
12468  *
12469  * Activates the cell determined by @path and @column.
12470  **/
12471 void
12472 gtk_tree_view_row_activated (GtkTreeView       *tree_view,
12473                              GtkTreePath       *path,
12474                              GtkTreeViewColumn *column)
12475 {
12476   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12477
12478   g_signal_emit (tree_view, tree_view_signals[ROW_ACTIVATED], 0, path, column);
12479 }
12480
12481
12482 static void
12483 gtk_tree_view_expand_all_emission_helper (GtkRBTree *tree,
12484                                           GtkRBNode *node,
12485                                           gpointer   data)
12486 {
12487   GtkTreeView *tree_view = data;
12488
12489   if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT &&
12490       node->children)
12491     {
12492       GtkTreePath *path;
12493       GtkTreeIter iter;
12494
12495       path = _gtk_tree_view_find_path (tree_view, tree, node);
12496       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
12497
12498       g_signal_emit (tree_view, tree_view_signals[ROW_EXPANDED], 0, &iter, path);
12499
12500       gtk_tree_path_free (path);
12501     }
12502
12503   if (node->children)
12504     _gtk_rbtree_traverse (node->children,
12505                           node->children->root,
12506                           G_PRE_ORDER,
12507                           gtk_tree_view_expand_all_emission_helper,
12508                           tree_view);
12509 }
12510
12511 /**
12512  * gtk_tree_view_expand_all:
12513  * @tree_view: A #GtkTreeView.
12514  *
12515  * Recursively expands all nodes in the @tree_view.
12516  **/
12517 void
12518 gtk_tree_view_expand_all (GtkTreeView *tree_view)
12519 {
12520   GtkTreePath *path;
12521   GtkRBTree *tree;
12522   GtkRBNode *node;
12523
12524   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12525
12526   if (tree_view->priv->tree == NULL)
12527     return;
12528
12529   path = gtk_tree_path_new_first ();
12530   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
12531
12532   while (node)
12533     {
12534       gtk_tree_view_real_expand_row (tree_view, path, tree, node, TRUE, FALSE);
12535       node = _gtk_rbtree_next (tree, node);
12536       gtk_tree_path_next (path);
12537   }
12538
12539   gtk_tree_path_free (path);
12540 }
12541
12542 /**
12543  * gtk_tree_view_collapse_all:
12544  * @tree_view: A #GtkTreeView.
12545  *
12546  * Recursively collapses all visible, expanded nodes in @tree_view.
12547  **/
12548 void
12549 gtk_tree_view_collapse_all (GtkTreeView *tree_view)
12550 {
12551   GtkRBTree *tree;
12552   GtkRBNode *node;
12553   GtkTreePath *path;
12554   gint *indices;
12555
12556   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12557
12558   if (tree_view->priv->tree == NULL)
12559     return;
12560
12561   path = gtk_tree_path_new ();
12562   gtk_tree_path_down (path);
12563   indices = gtk_tree_path_get_indices (path);
12564
12565   tree = tree_view->priv->tree;
12566   node = tree->root;
12567   while (node && node->left != tree->nil)
12568     node = node->left;
12569
12570   while (node)
12571     {
12572       if (node->children)
12573         gtk_tree_view_real_collapse_row (tree_view, path, tree, node, FALSE);
12574       indices[0]++;
12575       node = _gtk_rbtree_next (tree, node);
12576     }
12577
12578   gtk_tree_path_free (path);
12579 }
12580
12581 /**
12582  * gtk_tree_view_expand_to_path:
12583  * @tree_view: A #GtkTreeView.
12584  * @path: path to a row.
12585  *
12586  * Expands the row at @path. This will also expand all parent rows of
12587  * @path as necessary.
12588  *
12589  * Since: 2.2
12590  **/
12591 void
12592 gtk_tree_view_expand_to_path (GtkTreeView *tree_view,
12593                               GtkTreePath *path)
12594 {
12595   gint i, depth;
12596   gint *indices;
12597   GtkTreePath *tmp;
12598
12599   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12600   g_return_if_fail (path != NULL);
12601
12602   depth = gtk_tree_path_get_depth (path);
12603   indices = gtk_tree_path_get_indices (path);
12604
12605   tmp = gtk_tree_path_new ();
12606   g_return_if_fail (tmp != NULL);
12607
12608   for (i = 0; i < depth; i++)
12609     {
12610       gtk_tree_path_append_index (tmp, indices[i]);
12611       gtk_tree_view_expand_row (tree_view, tmp, FALSE);
12612     }
12613
12614   gtk_tree_path_free (tmp);
12615 }
12616
12617 /* FIXME the bool return values for expand_row and collapse_row are
12618  * not analagous; they should be TRUE if the row had children and
12619  * was not already in the requested state.
12620  */
12621
12622
12623 static gboolean
12624 gtk_tree_view_real_expand_row (GtkTreeView *tree_view,
12625                                GtkTreePath *path,
12626                                GtkRBTree   *tree,
12627                                GtkRBNode   *node,
12628                                gboolean     open_all,
12629                                gboolean     animate)
12630 {
12631   GtkTreeIter iter;
12632   GtkTreeIter temp;
12633   gboolean expand;
12634
12635   if (animate)
12636     g_object_get (gtk_widget_get_settings (GTK_WIDGET (tree_view)),
12637                   "gtk-enable-animations", &animate,
12638                   NULL);
12639
12640   remove_auto_expand_timeout (tree_view);
12641
12642   if (node->children && !open_all)
12643     return FALSE;
12644
12645   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
12646     return FALSE;
12647
12648   gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
12649   if (! gtk_tree_model_iter_has_child (tree_view->priv->model, &iter))
12650     return FALSE;
12651
12652
12653    if (node->children && open_all)
12654     {
12655       gboolean retval = FALSE;
12656       GtkTreePath *tmp_path = gtk_tree_path_copy (path);
12657
12658       gtk_tree_path_append_index (tmp_path, 0);
12659       tree = node->children;
12660       node = tree->root;
12661       while (node->left != tree->nil)
12662         node = node->left;
12663       /* try to expand the children */
12664       do
12665         {
12666          gboolean t;
12667          t = gtk_tree_view_real_expand_row (tree_view, tmp_path, tree, node,
12668                                             TRUE, animate);
12669          if (t)
12670            retval = TRUE;
12671
12672          gtk_tree_path_next (tmp_path);
12673          node = _gtk_rbtree_next (tree, node);
12674        }
12675       while (node != NULL);
12676
12677       gtk_tree_path_free (tmp_path);
12678
12679       return retval;
12680     }
12681
12682   g_signal_emit (tree_view, tree_view_signals[TEST_EXPAND_ROW], 0, &iter, path, &expand);
12683
12684   if (!gtk_tree_model_iter_has_child (tree_view->priv->model, &iter))
12685     return FALSE;
12686
12687   if (expand)
12688     return FALSE;
12689
12690   node->children = _gtk_rbtree_new ();
12691   node->children->parent_tree = tree;
12692   node->children->parent_node = node;
12693
12694   gtk_tree_model_iter_children (tree_view->priv->model, &temp, &iter);
12695
12696   gtk_tree_view_build_tree (tree_view,
12697                             node->children,
12698                             &temp,
12699                             gtk_tree_path_get_depth (path) + 1,
12700                             open_all);
12701
12702   if (animate)
12703     {
12704       GtkStyleContext *context;
12705
12706       context = gtk_widget_get_style_context (GTK_WIDGET (tree_view));
12707
12708       gtk_style_context_save (context);
12709       gtk_style_context_add_class (context, GTK_STYLE_CLASS_EXPANDER);
12710
12711       gtk_style_context_notify_state_change (context, tree_view->priv->bin_window,
12712                                              node, GTK_STATE_ACTIVE, TRUE);
12713
12714       _gtk_style_context_invalidate_animation_areas (context);
12715       gtk_style_context_restore (context);
12716     }
12717
12718   install_presize_handler (tree_view);
12719
12720   g_signal_emit (tree_view, tree_view_signals[ROW_EXPANDED], 0, &iter, path);
12721   if (open_all && node->children)
12722     {
12723       _gtk_rbtree_traverse (node->children,
12724                             node->children->root,
12725                             G_PRE_ORDER,
12726                             gtk_tree_view_expand_all_emission_helper,
12727                             tree_view);
12728     }
12729   return TRUE;
12730 }
12731
12732
12733 /**
12734  * gtk_tree_view_expand_row:
12735  * @tree_view: a #GtkTreeView
12736  * @path: path to a row
12737  * @open_all: whether to recursively expand, or just expand immediate children
12738  *
12739  * Opens the row so its children are visible.
12740  *
12741  * Return value: %TRUE if the row existed and had children
12742  **/
12743 gboolean
12744 gtk_tree_view_expand_row (GtkTreeView *tree_view,
12745                           GtkTreePath *path,
12746                           gboolean     open_all)
12747 {
12748   GtkRBTree *tree;
12749   GtkRBNode *node;
12750
12751   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12752   g_return_val_if_fail (tree_view->priv->model != NULL, FALSE);
12753   g_return_val_if_fail (path != NULL, FALSE);
12754
12755   if (_gtk_tree_view_find_node (tree_view,
12756                                 path,
12757                                 &tree,
12758                                 &node))
12759     return FALSE;
12760
12761   if (tree != NULL)
12762     return gtk_tree_view_real_expand_row (tree_view, path, tree, node, open_all, FALSE);
12763   else
12764     return FALSE;
12765 }
12766
12767 static gboolean
12768 gtk_tree_view_real_collapse_row (GtkTreeView *tree_view,
12769                                  GtkTreePath *path,
12770                                  GtkRBTree   *tree,
12771                                  GtkRBNode   *node,
12772                                  gboolean     animate)
12773 {
12774   GtkTreeIter iter;
12775   GtkTreeIter children;
12776   gboolean collapse;
12777   gint x, y;
12778   GList *list;
12779   GdkWindow *child, *parent;
12780
12781   if (animate)
12782     g_object_get (gtk_widget_get_settings (GTK_WIDGET (tree_view)),
12783                   "gtk-enable-animations", &animate,
12784                   NULL);
12785
12786   remove_auto_expand_timeout (tree_view);
12787
12788   if (node->children == NULL)
12789     return FALSE;
12790   gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
12791
12792   g_signal_emit (tree_view, tree_view_signals[TEST_COLLAPSE_ROW], 0, &iter, path, &collapse);
12793
12794   if (collapse)
12795     return FALSE;
12796
12797   /* if the prelighted node is a child of us, we want to unprelight it.  We have
12798    * a chance to prelight the correct node below */
12799
12800   if (tree_view->priv->prelight_tree)
12801     {
12802       GtkRBTree *parent_tree;
12803       GtkRBNode *parent_node;
12804
12805       parent_tree = tree_view->priv->prelight_tree->parent_tree;
12806       parent_node = tree_view->priv->prelight_tree->parent_node;
12807       while (parent_tree)
12808         {
12809           if (parent_tree == tree && parent_node == node)
12810             {
12811               ensure_unprelighted (tree_view);
12812               break;
12813             }
12814           parent_node = parent_tree->parent_node;
12815           parent_tree = parent_tree->parent_tree;
12816         }
12817     }
12818
12819   TREE_VIEW_INTERNAL_ASSERT (gtk_tree_model_iter_children (tree_view->priv->model, &children, &iter), FALSE);
12820
12821   for (list = tree_view->priv->columns; list; list = list->next)
12822     {
12823       GtkTreeViewColumn *column = list->data;
12824
12825       if (gtk_tree_view_column_get_visible (column) == FALSE)
12826         continue;
12827       if (gtk_tree_view_column_get_sizing (column) == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
12828         _gtk_tree_view_column_cell_set_dirty (column, TRUE);
12829     }
12830
12831   if (tree_view->priv->destroy_count_func)
12832     {
12833       GtkTreePath *child_path;
12834       gint child_count = 0;
12835       child_path = gtk_tree_path_copy (path);
12836       gtk_tree_path_down (child_path);
12837       if (node->children)
12838         _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, &child_count);
12839       tree_view->priv->destroy_count_func (tree_view, child_path, child_count, tree_view->priv->destroy_count_data);
12840       gtk_tree_path_free (child_path);
12841     }
12842
12843   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
12844     {
12845       GtkTreePath *cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
12846
12847       if (gtk_tree_path_is_ancestor (path, cursor_path))
12848         {
12849           gtk_tree_row_reference_free (tree_view->priv->cursor);
12850           tree_view->priv->cursor = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
12851                                                                       tree_view->priv->model,
12852                                                                       path);
12853         }
12854       gtk_tree_path_free (cursor_path);
12855     }
12856
12857   if (gtk_tree_row_reference_valid (tree_view->priv->anchor))
12858     {
12859       GtkTreePath *anchor_path = gtk_tree_row_reference_get_path (tree_view->priv->anchor);
12860       if (gtk_tree_path_is_ancestor (path, anchor_path))
12861         {
12862           gtk_tree_row_reference_free (tree_view->priv->anchor);
12863           tree_view->priv->anchor = NULL;
12864         }
12865       gtk_tree_path_free (anchor_path);
12866     }
12867
12868   /* Stop a pending double click */
12869   tree_view->priv->last_button_x = -1;
12870   tree_view->priv->last_button_y = -1;
12871
12872   if (gtk_tree_view_unref_and_check_selection_tree (tree_view, node->children))
12873     {
12874       _gtk_rbtree_remove (node->children);
12875       g_signal_emit_by_name (tree_view->priv->selection, "changed");
12876     }
12877   else
12878     _gtk_rbtree_remove (node->children);
12879
12880   if (animate)
12881     {
12882       GtkStyleContext *context;
12883
12884       context = gtk_widget_get_style_context (GTK_WIDGET (tree_view));
12885
12886       gtk_style_context_save (context);
12887       gtk_style_context_add_class (context, GTK_STYLE_CLASS_EXPANDER);
12888
12889       gtk_style_context_notify_state_change (context, tree_view->priv->bin_window,
12890                                              node, GTK_STATE_ACTIVE, FALSE);
12891
12892       _gtk_style_context_invalidate_animation_areas (context);
12893       gtk_style_context_restore (context);
12894     }
12895
12896   if (gtk_widget_get_mapped (GTK_WIDGET (tree_view)))
12897     {
12898       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
12899     }
12900
12901   g_signal_emit (tree_view, tree_view_signals[ROW_COLLAPSED], 0, &iter, path);
12902   
12903   if (gtk_widget_get_mapped (GTK_WIDGET (tree_view)))
12904     {
12905       /* now that we've collapsed all rows, we want to try to set the prelight
12906        * again. To do this, we fake a motion event and send it to ourselves. */
12907
12908       child = tree_view->priv->bin_window;
12909       parent = gdk_window_get_parent (child);
12910
12911       if (gdk_window_get_pointer (parent, &x, &y, NULL) == child)
12912         {
12913           GdkEventMotion event;
12914           gint child_x, child_y;
12915
12916           gdk_window_get_position (child, &child_x, &child_y);
12917
12918           event.window = tree_view->priv->bin_window;
12919           event.x = x - child_x;
12920           event.y = y - child_y;
12921
12922           /* despite the fact this isn't a real event, I'm almost positive it will
12923            * never trigger a drag event.  maybe_drag is the only function that uses
12924            * more than just event.x and event.y. */
12925           gtk_tree_view_motion_bin_window (GTK_WIDGET (tree_view), &event);
12926         }
12927     }
12928
12929   return TRUE;
12930 }
12931
12932 /**
12933  * gtk_tree_view_collapse_row:
12934  * @tree_view: a #GtkTreeView
12935  * @path: path to a row in the @tree_view
12936  *
12937  * Collapses a row (hides its child rows, if they exist).
12938  *
12939  * Return value: %TRUE if the row was collapsed.
12940  **/
12941 gboolean
12942 gtk_tree_view_collapse_row (GtkTreeView *tree_view,
12943                             GtkTreePath *path)
12944 {
12945   GtkRBTree *tree;
12946   GtkRBNode *node;
12947
12948   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12949   g_return_val_if_fail (tree_view->priv->tree != NULL, FALSE);
12950   g_return_val_if_fail (path != NULL, FALSE);
12951
12952   if (_gtk_tree_view_find_node (tree_view,
12953                                 path,
12954                                 &tree,
12955                                 &node))
12956     return FALSE;
12957
12958   if (tree == NULL || node->children == NULL)
12959     return FALSE;
12960
12961   return gtk_tree_view_real_collapse_row (tree_view, path, tree, node, FALSE);
12962 }
12963
12964 static void
12965 gtk_tree_view_map_expanded_rows_helper (GtkTreeView            *tree_view,
12966                                         GtkRBTree              *tree,
12967                                         GtkTreePath            *path,
12968                                         GtkTreeViewMappingFunc  func,
12969                                         gpointer                user_data)
12970 {
12971   GtkRBNode *node;
12972
12973   if (tree == NULL || tree->root == NULL)
12974     return;
12975
12976   node = tree->root;
12977
12978   while (node && node->left != tree->nil)
12979     node = node->left;
12980
12981   while (node)
12982     {
12983       if (node->children)
12984         {
12985           (* func) (tree_view, path, user_data);
12986           gtk_tree_path_down (path);
12987           gtk_tree_view_map_expanded_rows_helper (tree_view, node->children, path, func, user_data);
12988           gtk_tree_path_up (path);
12989         }
12990       gtk_tree_path_next (path);
12991       node = _gtk_rbtree_next (tree, node);
12992     }
12993 }
12994
12995 /**
12996  * gtk_tree_view_map_expanded_rows:
12997  * @tree_view: A #GtkTreeView
12998  * @func: (scope call): A function to be called
12999  * @data: User data to be passed to the function.
13000  *
13001  * Calls @func on all expanded rows.
13002  **/
13003 void
13004 gtk_tree_view_map_expanded_rows (GtkTreeView            *tree_view,
13005                                  GtkTreeViewMappingFunc  func,
13006                                  gpointer                user_data)
13007 {
13008   GtkTreePath *path;
13009
13010   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13011   g_return_if_fail (func != NULL);
13012
13013   path = gtk_tree_path_new_first ();
13014
13015   gtk_tree_view_map_expanded_rows_helper (tree_view,
13016                                           tree_view->priv->tree,
13017                                           path, func, user_data);
13018
13019   gtk_tree_path_free (path);
13020 }
13021
13022 /**
13023  * gtk_tree_view_row_expanded:
13024  * @tree_view: A #GtkTreeView.
13025  * @path: A #GtkTreePath to test expansion state.
13026  *
13027  * Returns %TRUE if the node pointed to by @path is expanded in @tree_view.
13028  *
13029  * Return value: %TRUE if #path is expanded.
13030  **/
13031 gboolean
13032 gtk_tree_view_row_expanded (GtkTreeView *tree_view,
13033                             GtkTreePath *path)
13034 {
13035   GtkRBTree *tree;
13036   GtkRBNode *node;
13037
13038   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
13039   g_return_val_if_fail (path != NULL, FALSE);
13040
13041   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
13042
13043   if (node == NULL)
13044     return FALSE;
13045
13046   return (node->children != NULL);
13047 }
13048
13049 /**
13050  * gtk_tree_view_get_reorderable:
13051  * @tree_view: a #GtkTreeView
13052  *
13053  * Retrieves whether the user can reorder the tree via drag-and-drop. See
13054  * gtk_tree_view_set_reorderable().
13055  *
13056  * Return value: %TRUE if the tree can be reordered.
13057  **/
13058 gboolean
13059 gtk_tree_view_get_reorderable (GtkTreeView *tree_view)
13060 {
13061   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
13062
13063   return tree_view->priv->reorderable;
13064 }
13065
13066 /**
13067  * gtk_tree_view_set_reorderable:
13068  * @tree_view: A #GtkTreeView.
13069  * @reorderable: %TRUE, if the tree can be reordered.
13070  *
13071  * This function is a convenience function to allow you to reorder
13072  * models that support the #GtkTreeDragSourceIface and the
13073  * #GtkTreeDragDestIface.  Both #GtkTreeStore and #GtkListStore support
13074  * these.  If @reorderable is %TRUE, then the user can reorder the
13075  * model by dragging and dropping rows. The developer can listen to
13076  * these changes by connecting to the model's row_inserted and
13077  * row_deleted signals. The reordering is implemented by setting up
13078  * the tree view as a drag source and destination. Therefore, drag and
13079  * drop can not be used in a reorderable view for any other purpose.
13080  *
13081  * This function does not give you any degree of control over the order -- any
13082  * reordering is allowed.  If more control is needed, you should probably
13083  * handle drag and drop manually.
13084  **/
13085 void
13086 gtk_tree_view_set_reorderable (GtkTreeView *tree_view,
13087                                gboolean     reorderable)
13088 {
13089   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13090
13091   reorderable = reorderable != FALSE;
13092
13093   if (tree_view->priv->reorderable == reorderable)
13094     return;
13095
13096   if (reorderable)
13097     {
13098       const GtkTargetEntry row_targets[] = {
13099         { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, 0 }
13100       };
13101
13102       gtk_tree_view_enable_model_drag_source (tree_view,
13103                                               GDK_BUTTON1_MASK,
13104                                               row_targets,
13105                                               G_N_ELEMENTS (row_targets),
13106                                               GDK_ACTION_MOVE);
13107       gtk_tree_view_enable_model_drag_dest (tree_view,
13108                                             row_targets,
13109                                             G_N_ELEMENTS (row_targets),
13110                                             GDK_ACTION_MOVE);
13111     }
13112   else
13113     {
13114       gtk_tree_view_unset_rows_drag_source (tree_view);
13115       gtk_tree_view_unset_rows_drag_dest (tree_view);
13116     }
13117
13118   tree_view->priv->reorderable = reorderable;
13119
13120   g_object_notify (G_OBJECT (tree_view), "reorderable");
13121 }
13122
13123 static void
13124 gtk_tree_view_real_set_cursor (GtkTreeView     *tree_view,
13125                                GtkTreePath     *path,
13126                                gboolean         clear_and_select,
13127                                gboolean         clamp_node)
13128 {
13129   GtkRBTree *tree = NULL;
13130   GtkRBNode *node = NULL;
13131
13132   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
13133     {
13134       GtkTreePath *cursor_path;
13135       cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
13136       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
13137       gtk_tree_path_free (cursor_path);
13138     }
13139
13140   gtk_tree_row_reference_free (tree_view->priv->cursor);
13141   tree_view->priv->cursor = NULL;
13142
13143   /* One cannot set the cursor on a separator.   Also, if
13144    * _gtk_tree_view_find_node returns TRUE, it ran out of tree
13145    * before finding the tree and node belonging to path.  The
13146    * path maps to a non-existing path and we will silently bail out.
13147    * We unset tree and node to avoid further processing.
13148    */
13149   if (!row_is_separator (tree_view, NULL, path)
13150       && _gtk_tree_view_find_node (tree_view, path, &tree, &node) == FALSE)
13151     {
13152       tree_view->priv->cursor =
13153           gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
13154                                             tree_view->priv->model,
13155                                             path);
13156     }
13157   else
13158     {
13159       tree = NULL;
13160       node = NULL;
13161     }
13162
13163   if (tree != NULL)
13164     {
13165       GtkRBTree *new_tree = NULL;
13166       GtkRBNode *new_node = NULL;
13167
13168       if (clear_and_select && !tree_view->priv->modify_selection_pressed)
13169         {
13170           GtkTreeSelectMode mode = 0;
13171
13172           if (tree_view->priv->extend_selection_pressed)
13173             mode |= GTK_TREE_SELECT_MODE_EXTEND;
13174
13175           _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
13176                                                     node, tree, path, mode,
13177                                                     FALSE);
13178         }
13179
13180       /* We have to re-find tree and node here again, somebody might have
13181        * cleared the node or the whole tree in the GtkTreeSelection::changed
13182        * callback. If the nodes differ we bail out here.
13183        */
13184       _gtk_tree_view_find_node (tree_view, path, &new_tree, &new_node);
13185
13186       if (tree != new_tree || node != new_node)
13187         return;
13188
13189       if (clamp_node)
13190         {
13191           gtk_tree_view_clamp_node_visible (tree_view, tree, node);
13192           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
13193         }
13194     }
13195
13196   g_signal_emit (tree_view, tree_view_signals[CURSOR_CHANGED], 0);
13197 }
13198
13199 /**
13200  * gtk_tree_view_get_cursor:
13201  * @tree_view: A #GtkTreeView
13202  * @path: (out) (transfer full) (allow-none): A pointer to be filled with the current cursor path, or %NULL
13203  * @focus_column: (out) (transfer none) (allow-none): A pointer to be filled with the current focus column, or %NULL
13204  *
13205  * Fills in @path and @focus_column with the current path and focus column.  If
13206  * the cursor isn't currently set, then *@path will be %NULL.  If no column
13207  * currently has focus, then *@focus_column will be %NULL.
13208  *
13209  * The returned #GtkTreePath must be freed with gtk_tree_path_free() when
13210  * you are done with it.
13211  **/
13212 void
13213 gtk_tree_view_get_cursor (GtkTreeView        *tree_view,
13214                           GtkTreePath       **path,
13215                           GtkTreeViewColumn **focus_column)
13216 {
13217   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13218
13219   if (path)
13220     {
13221       if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
13222         *path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
13223       else
13224         *path = NULL;
13225     }
13226
13227   if (focus_column)
13228     {
13229       *focus_column = tree_view->priv->focus_column;
13230     }
13231 }
13232
13233 /**
13234  * gtk_tree_view_set_cursor:
13235  * @tree_view: A #GtkTreeView
13236  * @path: A #GtkTreePath
13237  * @focus_column: (allow-none): A #GtkTreeViewColumn, or %NULL
13238  * @start_editing: %TRUE if the specified cell should start being edited.
13239  *
13240  * Sets the current keyboard focus to be at @path, and selects it.  This is
13241  * useful when you want to focus the user's attention on a particular row.  If
13242  * @focus_column is not %NULL, then focus is given to the column specified by 
13243  * it. Additionally, if @focus_column is specified, and @start_editing is 
13244  * %TRUE, then editing should be started in the specified cell.  
13245  * This function is often followed by @gtk_widget_grab_focus (@tree_view) 
13246  * in order to give keyboard focus to the widget.  Please note that editing 
13247  * can only happen when the widget is realized.
13248  *
13249  * If @path is invalid for @model, the current cursor (if any) will be unset
13250  * and the function will return without failing.
13251  **/
13252 void
13253 gtk_tree_view_set_cursor (GtkTreeView       *tree_view,
13254                           GtkTreePath       *path,
13255                           GtkTreeViewColumn *focus_column,
13256                           gboolean           start_editing)
13257 {
13258   gtk_tree_view_set_cursor_on_cell (tree_view, path, focus_column,
13259                                     NULL, start_editing);
13260 }
13261
13262 /**
13263  * gtk_tree_view_set_cursor_on_cell:
13264  * @tree_view: A #GtkTreeView
13265  * @path: A #GtkTreePath
13266  * @focus_column: (allow-none): A #GtkTreeViewColumn, or %NULL
13267  * @focus_cell: (allow-none): A #GtkCellRenderer, or %NULL
13268  * @start_editing: %TRUE if the specified cell should start being edited.
13269  *
13270  * Sets the current keyboard focus to be at @path, and selects it.  This is
13271  * useful when you want to focus the user's attention on a particular row.  If
13272  * @focus_column is not %NULL, then focus is given to the column specified by
13273  * it. If @focus_column and @focus_cell are not %NULL, and @focus_column
13274  * contains 2 or more editable or activatable cells, then focus is given to
13275  * the cell specified by @focus_cell. Additionally, if @focus_column is
13276  * specified, and @start_editing is %TRUE, then editing should be started in
13277  * the specified cell.  This function is often followed by
13278  * @gtk_widget_grab_focus (@tree_view) in order to give keyboard focus to the
13279  * widget.  Please note that editing can only happen when the widget is
13280  * realized.
13281  *
13282  * If @path is invalid for @model, the current cursor (if any) will be unset
13283  * and the function will return without failing.
13284  *
13285  * Since: 2.2
13286  **/
13287 void
13288 gtk_tree_view_set_cursor_on_cell (GtkTreeView       *tree_view,
13289                                   GtkTreePath       *path,
13290                                   GtkTreeViewColumn *focus_column,
13291                                   GtkCellRenderer   *focus_cell,
13292                                   gboolean           start_editing)
13293 {
13294   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13295   g_return_if_fail (path != NULL);
13296   g_return_if_fail (focus_column == NULL || GTK_IS_TREE_VIEW_COLUMN (focus_column));
13297
13298   if (!tree_view->priv->model)
13299     return;
13300
13301   if (focus_cell)
13302     {
13303       g_return_if_fail (focus_column);
13304       g_return_if_fail (GTK_IS_CELL_RENDERER (focus_cell));
13305     }
13306
13307   /* cancel the current editing, if it exists */
13308   if (tree_view->priv->edited_column &&
13309       gtk_cell_area_get_edit_widget
13310       (gtk_cell_layout_get_area (GTK_CELL_LAYOUT (tree_view->priv->edited_column))))
13311     gtk_tree_view_stop_editing (tree_view, TRUE);
13312
13313   gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
13314
13315   if (focus_column &&
13316       gtk_tree_view_column_get_visible (focus_column))
13317     {
13318       GList *list;
13319       gboolean column_in_tree = FALSE;
13320
13321       for (list = tree_view->priv->columns; list; list = list->next)
13322         if (list->data == focus_column)
13323           {
13324             column_in_tree = TRUE;
13325             break;
13326           }
13327       g_return_if_fail (column_in_tree);
13328       tree_view->priv->focus_column = focus_column;
13329       if (focus_cell)
13330         gtk_tree_view_column_focus_cell (focus_column, focus_cell);
13331       if (start_editing)
13332         gtk_tree_view_start_editing (tree_view, path, TRUE);
13333     }
13334 }
13335
13336 /**
13337  * gtk_tree_view_get_bin_window:
13338  * @tree_view: A #GtkTreeView
13339  *
13340  * Returns the window that @tree_view renders to.
13341  * This is used primarily to compare to <literal>event->window</literal>
13342  * to confirm that the event on @tree_view is on the right window.
13343  *
13344  * Return value: (transfer none): A #GdkWindow, or %NULL when @tree_view
13345  *     hasn't been realized yet
13346  **/
13347 GdkWindow *
13348 gtk_tree_view_get_bin_window (GtkTreeView *tree_view)
13349 {
13350   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
13351
13352   return tree_view->priv->bin_window;
13353 }
13354
13355 /**
13356  * gtk_tree_view_get_path_at_pos:
13357  * @tree_view: A #GtkTreeView.
13358  * @x: The x position to be identified (relative to bin_window).
13359  * @y: The y position to be identified (relative to bin_window).
13360  * @path: (out) (allow-none): A pointer to a #GtkTreePath pointer to be filled in, or %NULL
13361  * @column: (out) (transfer none) (allow-none): A pointer to a #GtkTreeViewColumn pointer to be filled in, or %NULL
13362  * @cell_x: (out) (allow-none): A pointer where the X coordinate relative to the cell can be placed, or %NULL
13363  * @cell_y: (out) (allow-none): A pointer where the Y coordinate relative to the cell can be placed, or %NULL
13364  *
13365  * Finds the path at the point (@x, @y), relative to bin_window coordinates
13366  * (please see gtk_tree_view_get_bin_window()).
13367  * That is, @x and @y are relative to an events coordinates. @x and @y must
13368  * come from an event on the @tree_view only where <literal>event->window ==
13369  * gtk_tree_view_get_bin_window (<!-- -->)</literal>. It is primarily for
13370  * things like popup menus. If @path is non-%NULL, then it will be filled
13371  * with the #GtkTreePath at that point.  This path should be freed with
13372  * gtk_tree_path_free().  If @column is non-%NULL, then it will be filled
13373  * with the column at that point.  @cell_x and @cell_y return the coordinates
13374  * relative to the cell background (i.e. the @background_area passed to
13375  * gtk_cell_renderer_render()).  This function is only meaningful if
13376  * @tree_view is realized.  Therefore this function will always return %FALSE
13377  * if @tree_view is not realized or does not have a model.
13378  *
13379  * For converting widget coordinates (eg. the ones you get from
13380  * GtkWidget::query-tooltip), please see
13381  * gtk_tree_view_convert_widget_to_bin_window_coords().
13382  *
13383  * Return value: %TRUE if a row exists at that coordinate.
13384  **/
13385 gboolean
13386 gtk_tree_view_get_path_at_pos (GtkTreeView        *tree_view,
13387                                gint                x,
13388                                gint                y,
13389                                GtkTreePath       **path,
13390                                GtkTreeViewColumn **column,
13391                                gint               *cell_x,
13392                                gint               *cell_y)
13393 {
13394   GtkRBTree *tree;
13395   GtkRBNode *node;
13396   gint y_offset;
13397
13398   g_return_val_if_fail (tree_view != NULL, FALSE);
13399
13400   if (path)
13401     *path = NULL;
13402   if (column)
13403     *column = NULL;
13404
13405   if (tree_view->priv->bin_window == NULL)
13406     return FALSE;
13407
13408   if (tree_view->priv->tree == NULL)
13409     return FALSE;
13410
13411   if (x > gtk_adjustment_get_upper (tree_view->priv->hadjustment))
13412     return FALSE;
13413
13414   if (x < 0 || y < 0)
13415     return FALSE;
13416
13417   if (column || cell_x)
13418     {
13419       GtkTreeViewColumn *tmp_column;
13420       GtkTreeViewColumn *last_column = NULL;
13421       GList *list;
13422       gint remaining_x = x;
13423       gboolean found = FALSE;
13424       gboolean rtl;
13425       gint width;
13426
13427       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
13428       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
13429            list;
13430            list = (rtl ? list->prev : list->next))
13431         {
13432           tmp_column = list->data;
13433
13434           if (gtk_tree_view_column_get_visible (tmp_column) == FALSE)
13435             continue;
13436
13437           last_column = tmp_column;
13438           width = gtk_tree_view_column_get_width (tmp_column);
13439           if (remaining_x <= width)
13440             {
13441               found = TRUE;
13442
13443               if (column)
13444                 *column = tmp_column;
13445
13446               if (cell_x)
13447                 *cell_x = remaining_x;
13448
13449               break;
13450             }
13451           remaining_x -= width;
13452         }
13453
13454       /* If found is FALSE and there is a last_column, then it the remainder
13455        * space is in that area
13456        */
13457       if (!found)
13458         {
13459           if (last_column)
13460             {
13461               if (column)
13462                 *column = last_column;
13463               
13464               if (cell_x)
13465                 *cell_x = gtk_tree_view_column_get_width (last_column) + remaining_x;
13466             }
13467           else
13468             {
13469               return FALSE;
13470             }
13471         }
13472     }
13473
13474   y_offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
13475                                       TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, y),
13476                                       &tree, &node);
13477
13478   if (tree == NULL)
13479     return FALSE;
13480
13481   if (cell_y)
13482     *cell_y = y_offset;
13483
13484   if (path)
13485     *path = _gtk_tree_view_find_path (tree_view, tree, node);
13486
13487   return TRUE;
13488 }
13489
13490
13491 static inline gint
13492 gtk_tree_view_get_cell_area_height (GtkTreeView *tree_view,
13493                                     GtkRBNode   *node,
13494                                     gint         vertical_separator)
13495 {
13496   int height;
13497
13498   /* The "cell" areas are the cell_area passed in to gtk_cell_renderer_render(),
13499    * i.e. just the cells, no spacing.
13500    *
13501    * The cell area height is at least expander_size - vertical_separator.
13502    * For regular nodes, the height is then at least expander_size. We should
13503    * be able to enforce the expander_size minimum here, because this
13504    * function will not be called for irregular (e.g. separator) rows.
13505    */
13506   height = gtk_tree_view_get_row_height (tree_view, node);
13507   if (height < tree_view->priv->expander_size)
13508     height = tree_view->priv->expander_size;
13509
13510   return height - vertical_separator;
13511 }
13512
13513 static inline gint
13514 gtk_tree_view_get_cell_area_y_offset (GtkTreeView *tree_view,
13515                                       GtkRBTree   *tree,
13516                                       GtkRBNode   *node,
13517                                       gint         vertical_separator)
13518 {
13519   int offset;
13520
13521   offset = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
13522   offset += vertical_separator / 2;
13523
13524   return offset;
13525 }
13526
13527 /**
13528  * gtk_tree_view_get_cell_area:
13529  * @tree_view: a #GtkTreeView
13530  * @path: (allow-none): a #GtkTreePath for the row, or %NULL to get only horizontal coordinates
13531  * @column: (allow-none): a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordinates
13532  * @rect: (out): rectangle to fill with cell rect
13533  *
13534  * Fills the bounding rectangle in bin_window coordinates for the cell at the
13535  * row specified by @path and the column specified by @column.  If @path is
13536  * %NULL, or points to a path not currently displayed, the @y and @height fields
13537  * of the rectangle will be filled with 0. If @column is %NULL, the @x and @width
13538  * fields will be filled with 0.  The sum of all cell rects does not cover the
13539  * entire tree; there are extra pixels in between rows, for example. The
13540  * returned rectangle is equivalent to the @cell_area passed to
13541  * gtk_cell_renderer_render().  This function is only valid if @tree_view is
13542  * realized.
13543  **/
13544 void
13545 gtk_tree_view_get_cell_area (GtkTreeView        *tree_view,
13546                              GtkTreePath        *path,
13547                              GtkTreeViewColumn  *column,
13548                              GdkRectangle       *rect)
13549 {
13550   GtkRBTree *tree = NULL;
13551   GtkRBNode *node = NULL;
13552   gint vertical_separator;
13553   gint horizontal_separator;
13554
13555   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13556   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
13557   g_return_if_fail (rect != NULL);
13558   g_return_if_fail (!column || gtk_tree_view_column_get_tree_view (column) == (GtkWidget *) tree_view);
13559   g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (tree_view)));
13560
13561   gtk_widget_style_get (GTK_WIDGET (tree_view),
13562                         "vertical-separator", &vertical_separator,
13563                         "horizontal-separator", &horizontal_separator,
13564                         NULL);
13565
13566   rect->x = 0;
13567   rect->y = 0;
13568   rect->width = 0;
13569   rect->height = 0;
13570
13571   if (column)
13572     {
13573       rect->x = gtk_tree_view_column_get_x_offset (column) + horizontal_separator/2;
13574       rect->width = gtk_tree_view_column_get_width (column) - horizontal_separator;
13575     }
13576
13577   if (path)
13578     {
13579       gboolean ret = _gtk_tree_view_find_node (tree_view, path, &tree, &node);
13580
13581       /* Get vertical coords */
13582       if ((!ret && tree == NULL) || ret)
13583         return;
13584
13585       if (row_is_separator (tree_view, NULL, path))
13586         {
13587           /* There isn't really a "cell area" for separator, so we
13588            * return the y, height values for background area instead.
13589            */
13590           rect->y = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
13591           rect->height = gtk_tree_view_get_row_height (tree_view, node);
13592         }
13593       else
13594         {
13595           rect->y = gtk_tree_view_get_cell_area_y_offset (tree_view, tree, node,
13596                                                           vertical_separator);
13597           rect->height = gtk_tree_view_get_cell_area_height (tree_view, node,
13598                                                              vertical_separator);
13599         }
13600
13601       if (column &&
13602           gtk_tree_view_is_expander_column (tree_view, column))
13603         {
13604           gint depth = gtk_tree_path_get_depth (path);
13605           gboolean rtl;
13606
13607           rtl = gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL;
13608
13609           if (!rtl)
13610             rect->x += (depth - 1) * tree_view->priv->level_indentation;
13611           rect->width -= (depth - 1) * tree_view->priv->level_indentation;
13612
13613           if (gtk_tree_view_draw_expanders (tree_view))
13614             {
13615               if (!rtl)
13616                 rect->x += depth * tree_view->priv->expander_size;
13617               rect->width -= depth * tree_view->priv->expander_size;
13618             }
13619
13620           rect->width = MAX (rect->width, 0);
13621         }
13622     }
13623 }
13624
13625 static inline gint
13626 gtk_tree_view_get_row_height (GtkTreeView *tree_view,
13627                               GtkRBNode   *node)
13628 {
13629   int height;
13630
13631   /* The "background" areas of all rows/cells add up to cover the entire tree.
13632    * The background includes all inter-row and inter-cell spacing.
13633    *
13634    * If the row pointed at by node does not have a height set, we default
13635    * to expander_size, which is the minimum height for regular nodes.
13636    * Non-regular nodes (e.g. separators) can have a height set smaller
13637    * than expander_size and should not be overruled here.
13638    */
13639   height = GTK_RBNODE_GET_HEIGHT (node);
13640   if (height <= 0)
13641     height = tree_view->priv->expander_size;
13642
13643   return height;
13644 }
13645
13646 static inline gint
13647 gtk_tree_view_get_row_y_offset (GtkTreeView *tree_view,
13648                                 GtkRBTree   *tree,
13649                                 GtkRBNode   *node)
13650 {
13651   int offset;
13652
13653   offset = _gtk_rbtree_node_find_offset (tree, node);
13654
13655   return RBTREE_Y_TO_TREE_WINDOW_Y (tree_view, offset);
13656 }
13657
13658 /**
13659  * gtk_tree_view_get_background_area:
13660  * @tree_view: a #GtkTreeView
13661  * @path: (allow-none): a #GtkTreePath for the row, or %NULL to get only horizontal coordinates
13662  * @column: (allow-none): a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordiantes
13663  * @rect: (out): rectangle to fill with cell background rect
13664  *
13665  * Fills the bounding rectangle in bin_window coordinates for the cell at the
13666  * row specified by @path and the column specified by @column.  If @path is
13667  * %NULL, or points to a node not found in the tree, the @y and @height fields of
13668  * the rectangle will be filled with 0. If @column is %NULL, the @x and @width
13669  * fields will be filled with 0.  The returned rectangle is equivalent to the
13670  * @background_area passed to gtk_cell_renderer_render().  These background
13671  * areas tile to cover the entire bin window.  Contrast with the @cell_area,
13672  * returned by gtk_tree_view_get_cell_area(), which returns only the cell
13673  * itself, excluding surrounding borders and the tree expander area.
13674  *
13675  **/
13676 void
13677 gtk_tree_view_get_background_area (GtkTreeView        *tree_view,
13678                                    GtkTreePath        *path,
13679                                    GtkTreeViewColumn  *column,
13680                                    GdkRectangle       *rect)
13681 {
13682   GtkRBTree *tree = NULL;
13683   GtkRBNode *node = NULL;
13684
13685   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13686   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
13687   g_return_if_fail (rect != NULL);
13688
13689   rect->x = 0;
13690   rect->y = 0;
13691   rect->width = 0;
13692   rect->height = 0;
13693
13694   if (path)
13695     {
13696       /* Get vertical coords */
13697
13698       if (!_gtk_tree_view_find_node (tree_view, path, &tree, &node) &&
13699           tree == NULL)
13700         return;
13701
13702       rect->y = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
13703       rect->height = gtk_tree_view_get_row_height (tree_view, node);
13704     }
13705
13706   if (column)
13707     {
13708       gint x2 = 0;
13709
13710       gtk_tree_view_get_background_xrange (tree_view, tree, column, &rect->x, &x2);
13711       rect->width = x2 - rect->x;
13712     }
13713 }
13714
13715 /**
13716  * gtk_tree_view_get_visible_rect:
13717  * @tree_view: a #GtkTreeView
13718  * @visible_rect: (out): rectangle to fill
13719  *
13720  * Fills @visible_rect with the currently-visible region of the
13721  * buffer, in tree coordinates. Convert to bin_window coordinates with
13722  * gtk_tree_view_convert_tree_to_bin_window_coords().
13723  * Tree coordinates start at 0,0 for row 0 of the tree, and cover the entire
13724  * scrollable area of the tree.
13725  **/
13726 void
13727 gtk_tree_view_get_visible_rect (GtkTreeView  *tree_view,
13728                                 GdkRectangle *visible_rect)
13729 {
13730   GtkAllocation allocation;
13731   GtkWidget *widget;
13732
13733   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13734
13735   widget = GTK_WIDGET (tree_view);
13736
13737   if (visible_rect)
13738     {
13739       gtk_widget_get_allocation (widget, &allocation);
13740       visible_rect->x = gtk_adjustment_get_value (tree_view->priv->hadjustment);
13741       visible_rect->y = gtk_adjustment_get_value (tree_view->priv->vadjustment);
13742       visible_rect->width = allocation.width;
13743       visible_rect->height = allocation.height - gtk_tree_view_get_effective_header_height (tree_view);
13744     }
13745 }
13746
13747 /**
13748  * gtk_tree_view_convert_widget_to_tree_coords:
13749  * @tree_view: a #GtkTreeView
13750  * @wx: X coordinate relative to the widget
13751  * @wy: Y coordinate relative to the widget
13752  * @tx: (out): return location for tree X coordinate
13753  * @ty: (out): return location for tree Y coordinate
13754  *
13755  * Converts widget coordinates to coordinates for the
13756  * tree (the full scrollable area of the tree).
13757  *
13758  * Since: 2.12
13759  **/
13760 void
13761 gtk_tree_view_convert_widget_to_tree_coords (GtkTreeView *tree_view,
13762                                              gint         wx,
13763                                              gint         wy,
13764                                              gint        *tx,
13765                                              gint        *ty)
13766 {
13767   gint x, y;
13768
13769   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13770
13771   gtk_tree_view_convert_widget_to_bin_window_coords (tree_view,
13772                                                      wx, wy,
13773                                                      &x, &y);
13774   gtk_tree_view_convert_bin_window_to_tree_coords (tree_view,
13775                                                    x, y,
13776                                                    tx, ty);
13777 }
13778
13779 /**
13780  * gtk_tree_view_convert_tree_to_widget_coords:
13781  * @tree_view: a #GtkTreeView
13782  * @tx: X coordinate relative to the tree
13783  * @ty: Y coordinate relative to the tree
13784  * @wx: (out): return location for widget X coordinate
13785  * @wy: (out): return location for widget Y coordinate
13786  *
13787  * Converts tree coordinates (coordinates in full scrollable area of the tree)
13788  * to widget coordinates.
13789  *
13790  * Since: 2.12
13791  **/
13792 void
13793 gtk_tree_view_convert_tree_to_widget_coords (GtkTreeView *tree_view,
13794                                              gint         tx,
13795                                              gint         ty,
13796                                              gint        *wx,
13797                                              gint        *wy)
13798 {
13799   gint x, y;
13800
13801   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13802
13803   gtk_tree_view_convert_tree_to_bin_window_coords (tree_view,
13804                                                    tx, ty,
13805                                                    &x, &y);
13806   gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
13807                                                      x, y,
13808                                                      wx, wy);
13809 }
13810
13811 /**
13812  * gtk_tree_view_convert_widget_to_bin_window_coords:
13813  * @tree_view: a #GtkTreeView
13814  * @wx: X coordinate relative to the widget
13815  * @wy: Y coordinate relative to the widget
13816  * @bx: (out): return location for bin_window X coordinate
13817  * @by: (out): return location for bin_window Y coordinate
13818  *
13819  * Converts widget coordinates to coordinates for the bin_window
13820  * (see gtk_tree_view_get_bin_window()).
13821  *
13822  * Since: 2.12
13823  **/
13824 void
13825 gtk_tree_view_convert_widget_to_bin_window_coords (GtkTreeView *tree_view,
13826                                                    gint         wx,
13827                                                    gint         wy,
13828                                                    gint        *bx,
13829                                                    gint        *by)
13830 {
13831   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13832
13833   if (bx)
13834     *bx = wx + gtk_adjustment_get_value (tree_view->priv->hadjustment);
13835   if (by)
13836     *by = wy - gtk_tree_view_get_effective_header_height (tree_view);
13837 }
13838
13839 /**
13840  * gtk_tree_view_convert_bin_window_to_widget_coords:
13841  * @tree_view: a #GtkTreeView
13842  * @bx: bin_window X coordinate
13843  * @by: bin_window Y coordinate
13844  * @wx: (out): return location for widget X coordinate
13845  * @wy: (out): return location for widget Y coordinate
13846  *
13847  * Converts bin_window coordinates (see gtk_tree_view_get_bin_window())
13848  * to widget relative coordinates.
13849  *
13850  * Since: 2.12
13851  **/
13852 void
13853 gtk_tree_view_convert_bin_window_to_widget_coords (GtkTreeView *tree_view,
13854                                                    gint         bx,
13855                                                    gint         by,
13856                                                    gint        *wx,
13857                                                    gint        *wy)
13858 {
13859   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13860
13861   if (wx)
13862     *wx = bx - gtk_adjustment_get_value (tree_view->priv->hadjustment);
13863   if (wy)
13864     *wy = by + gtk_tree_view_get_effective_header_height (tree_view);
13865 }
13866
13867 /**
13868  * gtk_tree_view_convert_tree_to_bin_window_coords:
13869  * @tree_view: a #GtkTreeView
13870  * @tx: tree X coordinate
13871  * @ty: tree Y coordinate
13872  * @bx: (out): return location for X coordinate relative to bin_window
13873  * @by: (out): return location for Y coordinate relative to bin_window
13874  *
13875  * Converts tree coordinates (coordinates in full scrollable area of the tree)
13876  * to bin_window coordinates.
13877  *
13878  * Since: 2.12
13879  **/
13880 void
13881 gtk_tree_view_convert_tree_to_bin_window_coords (GtkTreeView *tree_view,
13882                                                  gint         tx,
13883                                                  gint         ty,
13884                                                  gint        *bx,
13885                                                  gint        *by)
13886 {
13887   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13888
13889   if (bx)
13890     *bx = tx;
13891   if (by)
13892     *by = ty - tree_view->priv->dy;
13893 }
13894
13895 /**
13896  * gtk_tree_view_convert_bin_window_to_tree_coords:
13897  * @tree_view: a #GtkTreeView
13898  * @bx: X coordinate relative to bin_window
13899  * @by: Y coordinate relative to bin_window
13900  * @tx: (out): return location for tree X coordinate
13901  * @ty: (out): return location for tree Y coordinate
13902  *
13903  * Converts bin_window coordinates to coordinates for the
13904  * tree (the full scrollable area of the tree).
13905  *
13906  * Since: 2.12
13907  **/
13908 void
13909 gtk_tree_view_convert_bin_window_to_tree_coords (GtkTreeView *tree_view,
13910                                                  gint         bx,
13911                                                  gint         by,
13912                                                  gint        *tx,
13913                                                  gint        *ty)
13914 {
13915   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13916
13917   if (tx)
13918     *tx = bx;
13919   if (ty)
13920     *ty = by + tree_view->priv->dy;
13921 }
13922
13923
13924
13925 /**
13926  * gtk_tree_view_get_visible_range:
13927  * @tree_view: A #GtkTreeView
13928  * @start_path: (out) (allow-none): Return location for start of region,
13929  *              or %NULL.
13930  * @end_path: (out) (allow-none): Return location for end of region, or %NULL.
13931  *
13932  * Sets @start_path and @end_path to be the first and last visible path.
13933  * Note that there may be invisible paths in between.
13934  *
13935  * The paths should be freed with gtk_tree_path_free() after use.
13936  *
13937  * Returns: %TRUE, if valid paths were placed in @start_path and @end_path.
13938  *
13939  * Since: 2.8
13940  **/
13941 gboolean
13942 gtk_tree_view_get_visible_range (GtkTreeView  *tree_view,
13943                                  GtkTreePath **start_path,
13944                                  GtkTreePath **end_path)
13945 {
13946   GtkRBTree *tree;
13947   GtkRBNode *node;
13948   gboolean retval;
13949   
13950   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
13951
13952   if (!tree_view->priv->tree)
13953     return FALSE;
13954
13955   retval = TRUE;
13956
13957   if (start_path)
13958     {
13959       _gtk_rbtree_find_offset (tree_view->priv->tree,
13960                                TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, 0),
13961                                &tree, &node);
13962       if (node)
13963         *start_path = _gtk_tree_view_find_path (tree_view, tree, node);
13964       else
13965         retval = FALSE;
13966     }
13967
13968   if (end_path)
13969     {
13970       gint y;
13971
13972       if (tree_view->priv->height < gtk_adjustment_get_page_size (tree_view->priv->vadjustment))
13973         y = tree_view->priv->height - 1;
13974       else
13975         y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, gtk_adjustment_get_page_size (tree_view->priv->vadjustment)) - 1;
13976
13977       _gtk_rbtree_find_offset (tree_view->priv->tree, y, &tree, &node);
13978       if (node)
13979         *end_path = _gtk_tree_view_find_path (tree_view, tree, node);
13980       else
13981         retval = FALSE;
13982     }
13983
13984   return retval;
13985 }
13986
13987 /**
13988  * gtk_tree_view_is_blank_at_pos:
13989  * @tree_view: A #GtkTreeView
13990  * @x: The x position to be identified (relative to bin_window)
13991  * @y: The y position to be identified (relative to bin_window)
13992  * @path: (out) (allow-none): A pointer to a #GtkTreePath pointer to be filled in, or %NULL
13993  * @column: (out) (allow-none): A pointer to a #GtkTreeViewColumn pointer to be filled in, or %NULL
13994  * @cell_x: (out) (allow-none): A pointer where the X coordinate relative to the cell can be placed, or %NULL
13995  * @cell_y: (out) (allow-none): A pointer where the Y coordinate relative to the cell can be placed, or %NULL
13996  *
13997  * Determine whether the point (@x, @y) in @tree_view is blank, that is no
13998  * cell content nor an expander arrow is drawn at the location. If so, the
13999  * location can be considered as the background. You might wish to take
14000  * special action on clicks on the background, such as clearing a current
14001  * selection, having a custom context menu or starting rubber banding.
14002  *
14003  * The @x and @y coordinate that are provided must be relative to bin_window
14004  * coordinates.  That is, @x and @y must come from an event on @tree_view
14005  * where <literal>event->window == gtk_tree_view_get_bin_window (<!-- -->)</literal>.
14006  *
14007  * For converting widget coordinates (eg. the ones you get from
14008  * GtkWidget::query-tooltip), please see
14009  * gtk_tree_view_convert_widget_to_bin_window_coords().
14010  *
14011  * The @path, @column, @cell_x and @cell_y arguments will be filled in
14012  * likewise as for gtk_tree_view_get_path_at_pos().  Please see
14013  * gtk_tree_view_get_path_at_pos() for more information.
14014  *
14015  * Return value: %TRUE if the area at the given coordinates is blank,
14016  * %FALSE otherwise.
14017  *
14018  * Since: 3.0
14019  */
14020 gboolean
14021 gtk_tree_view_is_blank_at_pos (GtkTreeView       *tree_view,
14022                                gint                x,
14023                                gint                y,
14024                                GtkTreePath       **path,
14025                                GtkTreeViewColumn **column,
14026                                gint               *cell_x,
14027                                gint               *cell_y)
14028 {
14029   GtkRBTree *tree;
14030   GtkRBNode *node;
14031   GtkTreeIter iter;
14032   GtkTreePath *real_path;
14033   GtkTreeViewColumn *real_column;
14034   GdkRectangle cell_area, background_area;
14035
14036   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
14037
14038   if (!gtk_tree_view_get_path_at_pos (tree_view, x, y,
14039                                       &real_path, &real_column,
14040                                       cell_x, cell_y))
14041     /* If there's no path here, it is blank */
14042     return TRUE;
14043
14044   if (path)
14045     *path = real_path;
14046
14047   if (column)
14048     *column = real_column;
14049
14050   gtk_tree_model_get_iter (tree_view->priv->model, &iter, real_path);
14051   _gtk_tree_view_find_node (tree_view, real_path, &tree, &node);
14052
14053   /* Check if there's an expander arrow at (x, y) */
14054   if (real_column == tree_view->priv->expander_column
14055       && gtk_tree_view_draw_expanders (tree_view))
14056     {
14057       gboolean over_arrow;
14058
14059       over_arrow = coords_are_over_arrow (tree_view, tree, node, x, y);
14060
14061       if (over_arrow)
14062         {
14063           if (!path)
14064             gtk_tree_path_free (real_path);
14065           return FALSE;
14066         }
14067     }
14068
14069   /* Otherwise, have the column see if there's a cell at (x, y) */
14070   gtk_tree_view_column_cell_set_cell_data (real_column,
14071                                            tree_view->priv->model,
14072                                            &iter,
14073                                            GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
14074                                            node->children ? TRUE : FALSE);
14075
14076   gtk_tree_view_get_background_area (tree_view, real_path, real_column,
14077                                      &background_area);
14078   gtk_tree_view_get_cell_area (tree_view, real_path, real_column,
14079                                &cell_area);
14080
14081   if (!path)
14082     gtk_tree_path_free (real_path);
14083
14084   return _gtk_tree_view_column_is_blank_at_pos (real_column,
14085                                                 &cell_area,
14086                                                 &background_area,
14087                                                 x, y);
14088 }
14089
14090 static void
14091 unset_reorderable (GtkTreeView *tree_view)
14092 {
14093   if (tree_view->priv->reorderable)
14094     {
14095       tree_view->priv->reorderable = FALSE;
14096       g_object_notify (G_OBJECT (tree_view), "reorderable");
14097     }
14098 }
14099
14100 /**
14101  * gtk_tree_view_enable_model_drag_source:
14102  * @tree_view: a #GtkTreeView
14103  * @start_button_mask: Mask of allowed buttons to start drag
14104  * @targets: (array length=n_targets): the table of targets that the drag will support
14105  * @n_targets: the number of items in @targets
14106  * @actions: the bitmask of possible actions for a drag from this
14107  *    widget
14108  *
14109  * Turns @tree_view into a drag source for automatic DND. Calling this
14110  * method sets #GtkTreeView:reorderable to %FALSE.
14111  **/
14112 void
14113 gtk_tree_view_enable_model_drag_source (GtkTreeView              *tree_view,
14114                                         GdkModifierType           start_button_mask,
14115                                         const GtkTargetEntry     *targets,
14116                                         gint                      n_targets,
14117                                         GdkDragAction             actions)
14118 {
14119   TreeViewDragInfo *di;
14120
14121   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14122
14123   gtk_drag_source_set (GTK_WIDGET (tree_view),
14124                        0,
14125                        targets,
14126                        n_targets,
14127                        actions);
14128
14129   di = ensure_info (tree_view);
14130
14131   di->start_button_mask = start_button_mask;
14132   di->source_actions = actions;
14133   di->source_set = TRUE;
14134
14135   unset_reorderable (tree_view);
14136 }
14137
14138 /**
14139  * gtk_tree_view_enable_model_drag_dest:
14140  * @tree_view: a #GtkTreeView
14141  * @targets: (array length=n_targets): the table of targets that
14142  *           the drag will support
14143  * @n_targets: the number of items in @targets
14144  * @actions: the bitmask of possible actions for a drag from this
14145  *    widget
14146  * 
14147  * Turns @tree_view into a drop destination for automatic DND. Calling
14148  * this method sets #GtkTreeView:reorderable to %FALSE.
14149  **/
14150 void
14151 gtk_tree_view_enable_model_drag_dest (GtkTreeView              *tree_view,
14152                                       const GtkTargetEntry     *targets,
14153                                       gint                      n_targets,
14154                                       GdkDragAction             actions)
14155 {
14156   TreeViewDragInfo *di;
14157
14158   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14159
14160   gtk_drag_dest_set (GTK_WIDGET (tree_view),
14161                      0,
14162                      targets,
14163                      n_targets,
14164                      actions);
14165
14166   di = ensure_info (tree_view);
14167   di->dest_set = TRUE;
14168
14169   unset_reorderable (tree_view);
14170 }
14171
14172 /**
14173  * gtk_tree_view_unset_rows_drag_source:
14174  * @tree_view: a #GtkTreeView
14175  *
14176  * Undoes the effect of
14177  * gtk_tree_view_enable_model_drag_source(). Calling this method sets
14178  * #GtkTreeView:reorderable to %FALSE.
14179  **/
14180 void
14181 gtk_tree_view_unset_rows_drag_source (GtkTreeView *tree_view)
14182 {
14183   TreeViewDragInfo *di;
14184
14185   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14186
14187   di = get_info (tree_view);
14188
14189   if (di)
14190     {
14191       if (di->source_set)
14192         {
14193           gtk_drag_source_unset (GTK_WIDGET (tree_view));
14194           di->source_set = FALSE;
14195         }
14196
14197       if (!di->dest_set && !di->source_set)
14198         remove_info (tree_view);
14199     }
14200   
14201   unset_reorderable (tree_view);
14202 }
14203
14204 /**
14205  * gtk_tree_view_unset_rows_drag_dest:
14206  * @tree_view: a #GtkTreeView
14207  *
14208  * Undoes the effect of
14209  * gtk_tree_view_enable_model_drag_dest(). Calling this method sets
14210  * #GtkTreeView:reorderable to %FALSE.
14211  **/
14212 void
14213 gtk_tree_view_unset_rows_drag_dest (GtkTreeView *tree_view)
14214 {
14215   TreeViewDragInfo *di;
14216
14217   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14218
14219   di = get_info (tree_view);
14220
14221   if (di)
14222     {
14223       if (di->dest_set)
14224         {
14225           gtk_drag_dest_unset (GTK_WIDGET (tree_view));
14226           di->dest_set = FALSE;
14227         }
14228
14229       if (!di->dest_set && !di->source_set)
14230         remove_info (tree_view);
14231     }
14232
14233   unset_reorderable (tree_view);
14234 }
14235
14236 /**
14237  * gtk_tree_view_set_drag_dest_row:
14238  * @tree_view: a #GtkTreeView
14239  * @path: (allow-none): The path of the row to highlight, or %NULL
14240  * @pos: Specifies whether to drop before, after or into the row
14241  *
14242  * Sets the row that is highlighted for feedback.
14243  * If @path is %NULL, an existing highlight is removed.
14244  */
14245 void
14246 gtk_tree_view_set_drag_dest_row (GtkTreeView            *tree_view,
14247                                  GtkTreePath            *path,
14248                                  GtkTreeViewDropPosition pos)
14249 {
14250   GtkTreePath *current_dest;
14251
14252   /* Note; this function is exported to allow a custom DND
14253    * implementation, so it can't touch TreeViewDragInfo
14254    */
14255
14256   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14257
14258   current_dest = NULL;
14259
14260   if (tree_view->priv->drag_dest_row)
14261     {
14262       current_dest = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
14263       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
14264     }
14265
14266   /* special case a drop on an empty model */
14267   tree_view->priv->empty_view_drop = 0;
14268
14269   if (pos == GTK_TREE_VIEW_DROP_BEFORE && path
14270       && gtk_tree_path_get_depth (path) == 1
14271       && gtk_tree_path_get_indices (path)[0] == 0)
14272     {
14273       gint n_children;
14274
14275       n_children = gtk_tree_model_iter_n_children (tree_view->priv->model,
14276                                                    NULL);
14277
14278       if (!n_children)
14279         tree_view->priv->empty_view_drop = 1;
14280     }
14281
14282   tree_view->priv->drag_dest_pos = pos;
14283
14284   if (path)
14285     {
14286       tree_view->priv->drag_dest_row =
14287         gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
14288       gtk_tree_view_queue_draw_path (tree_view, path, NULL);
14289     }
14290   else
14291     tree_view->priv->drag_dest_row = NULL;
14292
14293   if (current_dest)
14294     {
14295       GtkRBTree *tree, *new_tree;
14296       GtkRBNode *node, *new_node;
14297
14298       _gtk_tree_view_find_node (tree_view, current_dest, &tree, &node);
14299       _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
14300
14301       if (tree && node)
14302         {
14303           _gtk_rbtree_next_full (tree, node, &new_tree, &new_node);
14304           if (new_tree && new_node)
14305             _gtk_tree_view_queue_draw_node (tree_view, new_tree, new_node, NULL);
14306
14307           _gtk_rbtree_prev_full (tree, node, &new_tree, &new_node);
14308           if (new_tree && new_node)
14309             _gtk_tree_view_queue_draw_node (tree_view, new_tree, new_node, NULL);
14310         }
14311       gtk_tree_path_free (current_dest);
14312     }
14313 }
14314
14315 /**
14316  * gtk_tree_view_get_drag_dest_row:
14317  * @tree_view: a #GtkTreeView
14318  * @path: (out) (allow-none): Return location for the path of the highlighted row, or %NULL.
14319  * @pos: (out) (allow-none): Return location for the drop position, or %NULL
14320  * 
14321  * Gets information about the row that is highlighted for feedback.
14322  **/
14323 void
14324 gtk_tree_view_get_drag_dest_row (GtkTreeView              *tree_view,
14325                                  GtkTreePath             **path,
14326                                  GtkTreeViewDropPosition  *pos)
14327 {
14328   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14329
14330   if (path)
14331     {
14332       if (tree_view->priv->drag_dest_row)
14333         *path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
14334       else
14335         {
14336           if (tree_view->priv->empty_view_drop)
14337             *path = gtk_tree_path_new_from_indices (0, -1);
14338           else
14339             *path = NULL;
14340         }
14341     }
14342
14343   if (pos)
14344     *pos = tree_view->priv->drag_dest_pos;
14345 }
14346
14347 /**
14348  * gtk_tree_view_get_dest_row_at_pos:
14349  * @tree_view: a #GtkTreeView
14350  * @drag_x: the position to determine the destination row for
14351  * @drag_y: the position to determine the destination row for
14352  * @path: (out) (allow-none): Return location for the path of the highlighted row, or %NULL.
14353  * @pos: (out) (allow-none): Return location for the drop position, or %NULL
14354  * 
14355  * Determines the destination row for a given position.  @drag_x and
14356  * @drag_y are expected to be in widget coordinates.  This function is only
14357  * meaningful if @tree_view is realized.  Therefore this function will always
14358  * return %FALSE if @tree_view is not realized or does not have a model.
14359  * 
14360  * Return value: whether there is a row at the given position, %TRUE if this
14361  * is indeed the case.
14362  **/
14363 gboolean
14364 gtk_tree_view_get_dest_row_at_pos (GtkTreeView             *tree_view,
14365                                    gint                     drag_x,
14366                                    gint                     drag_y,
14367                                    GtkTreePath            **path,
14368                                    GtkTreeViewDropPosition *pos)
14369 {
14370   gint cell_y;
14371   gint bin_x, bin_y;
14372   gdouble offset_into_row;
14373   gdouble third;
14374   GdkRectangle cell;
14375   GtkTreeViewColumn *column = NULL;
14376   GtkTreePath *tmp_path = NULL;
14377
14378   /* Note; this function is exported to allow a custom DND
14379    * implementation, so it can't touch TreeViewDragInfo
14380    */
14381
14382   g_return_val_if_fail (tree_view != NULL, FALSE);
14383   g_return_val_if_fail (drag_x >= 0, FALSE);
14384   g_return_val_if_fail (drag_y >= 0, FALSE);
14385
14386   if (path)
14387     *path = NULL;
14388
14389   if (tree_view->priv->bin_window == NULL)
14390     return FALSE;
14391
14392   if (tree_view->priv->tree == NULL)
14393     return FALSE;
14394
14395   /* If in the top third of a row, we drop before that row; if
14396    * in the bottom third, drop after that row; if in the middle,
14397    * and the row has children, drop into the row.
14398    */
14399   gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, drag_x, drag_y,
14400                                                      &bin_x, &bin_y);
14401
14402   if (!gtk_tree_view_get_path_at_pos (tree_view,
14403                                       bin_x,
14404                                       bin_y,
14405                                       &tmp_path,
14406                                       &column,
14407                                       NULL,
14408                                       &cell_y))
14409     return FALSE;
14410
14411   gtk_tree_view_get_background_area (tree_view, tmp_path, column,
14412                                      &cell);
14413
14414   offset_into_row = cell_y;
14415
14416   if (path)
14417     *path = tmp_path;
14418   else
14419     gtk_tree_path_free (tmp_path);
14420
14421   tmp_path = NULL;
14422
14423   third = cell.height / 3.0;
14424
14425   if (pos)
14426     {
14427       if (offset_into_row < third)
14428         {
14429           *pos = GTK_TREE_VIEW_DROP_BEFORE;
14430         }
14431       else if (offset_into_row < (cell.height / 2.0))
14432         {
14433           *pos = GTK_TREE_VIEW_DROP_INTO_OR_BEFORE;
14434         }
14435       else if (offset_into_row < third * 2.0)
14436         {
14437           *pos = GTK_TREE_VIEW_DROP_INTO_OR_AFTER;
14438         }
14439       else
14440         {
14441           *pos = GTK_TREE_VIEW_DROP_AFTER;
14442         }
14443     }
14444
14445   return TRUE;
14446 }
14447
14448
14449
14450 /* KEEP IN SYNC WITH GTK_TREE_VIEW_BIN_EXPOSE */
14451 /**
14452  * gtk_tree_view_create_row_drag_icon:
14453  * @tree_view: a #GtkTreeView
14454  * @path: a #GtkTreePath in @tree_view
14455  *
14456  * Creates a #cairo_surface_t representation of the row at @path.  
14457  * This image is used for a drag icon.
14458  *
14459  * Return value: (transfer full): a newly-allocated surface of the drag icon.
14460  **/
14461 cairo_surface_t *
14462 gtk_tree_view_create_row_drag_icon (GtkTreeView  *tree_view,
14463                                     GtkTreePath  *path)
14464 {
14465   GtkTreeIter   iter;
14466   GtkRBTree    *tree;
14467   GtkRBNode    *node;
14468   GtkStyleContext *context;
14469   GtkStateFlags state;
14470   gint cell_offset;
14471   GList *list;
14472   GdkRectangle background_area;
14473   GtkWidget *widget;
14474   gint depth;
14475   /* start drawing inside the black outline */
14476   gint x = 1, y = 1;
14477   cairo_surface_t *surface;
14478   gint bin_window_width;
14479   gboolean is_separator = FALSE;
14480   gboolean rtl, allow_rules;
14481   cairo_t *cr;
14482
14483   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14484   g_return_val_if_fail (path != NULL, NULL);
14485
14486   widget = GTK_WIDGET (tree_view);
14487
14488   if (!gtk_widget_get_realized (widget))
14489     return NULL;
14490
14491   depth = gtk_tree_path_get_depth (path);
14492
14493   _gtk_tree_view_find_node (tree_view,
14494                             path,
14495                             &tree,
14496                             &node);
14497
14498   if (tree == NULL)
14499     return NULL;
14500
14501   if (!gtk_tree_model_get_iter (tree_view->priv->model,
14502                                 &iter,
14503                                 path))
14504     return NULL;
14505
14506   context = gtk_widget_get_style_context (widget);
14507
14508   gtk_style_context_save (context);
14509
14510   state = gtk_widget_get_state_flags (widget);
14511   gtk_style_context_set_state (context, state);
14512
14513   gtk_style_context_add_class (context, GTK_STYLE_CLASS_VIEW);
14514   gtk_style_context_add_region (context, GTK_STYLE_REGION_COLUMN, 0);
14515
14516   gtk_widget_style_get (widget,
14517                         "allow-rules", &allow_rules,
14518                         NULL);
14519
14520   if (allow_rules && tree_view->priv->has_rules)
14521     {
14522       GtkRegionFlags row_flags;
14523
14524       if (_gtk_rbtree_node_find_parity (tree, node))
14525         row_flags = GTK_REGION_ODD;
14526       else
14527         row_flags = GTK_REGION_EVEN;
14528
14529       gtk_style_context_add_region (context, GTK_STYLE_REGION_ROW, row_flags);
14530     }
14531
14532   is_separator = row_is_separator (tree_view, &iter, NULL);
14533
14534   cell_offset = x;
14535
14536   background_area.y = y;
14537   background_area.height = gtk_tree_view_get_row_height (tree_view, node);
14538
14539   bin_window_width = gdk_window_get_width (tree_view->priv->bin_window);
14540
14541   surface = gdk_window_create_similar_surface (tree_view->priv->bin_window,
14542                                                CAIRO_CONTENT_COLOR,
14543                                                bin_window_width + 2,
14544                                                background_area.height + 2);
14545
14546   cr = cairo_create (surface);
14547
14548   gtk_render_background (context, cr, 0, 0,
14549                          bin_window_width + 2,
14550                          background_area.height + 2);
14551
14552   rtl = gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL;
14553
14554   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
14555       list;
14556       list = (rtl ? list->prev : list->next))
14557     {
14558       GtkTreeViewColumn *column = list->data;
14559       GdkRectangle cell_area;
14560       gint vertical_separator;
14561
14562       if (!gtk_tree_view_column_get_visible (column))
14563         continue;
14564
14565       gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, &iter,
14566                                                GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
14567                                                node->children?TRUE:FALSE);
14568
14569       background_area.x = cell_offset;
14570       background_area.width = gtk_tree_view_column_get_width (column);
14571
14572       gtk_widget_style_get (widget,
14573                             "vertical-separator", &vertical_separator,
14574                             NULL);
14575
14576       cell_area = background_area;
14577
14578       cell_area.y += vertical_separator / 2;
14579       cell_area.height -= vertical_separator;
14580
14581       if (gtk_tree_view_is_expander_column (tree_view, column))
14582         {
14583           if (!rtl)
14584             cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
14585           cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
14586
14587           if (gtk_tree_view_draw_expanders (tree_view))
14588             {
14589               if (!rtl)
14590                 cell_area.x += depth * tree_view->priv->expander_size;
14591               cell_area.width -= depth * tree_view->priv->expander_size;
14592             }
14593         }
14594
14595       if (gtk_tree_view_column_cell_is_visible (column))
14596         {
14597           if (is_separator)
14598             {
14599               gtk_style_context_save (context);
14600               gtk_style_context_add_class (context, GTK_STYLE_CLASS_SEPARATOR);
14601
14602               gtk_render_line (context, cr,
14603                                cell_area.x,
14604                                cell_area.y + cell_area.height / 2,
14605                                cell_area.x + cell_area.width,
14606                                cell_area.y + cell_area.height / 2);
14607
14608               gtk_style_context_restore (context);
14609             }
14610           else
14611             {
14612               _gtk_tree_view_column_cell_render (column,
14613                                                  cr,
14614                                                  &background_area,
14615                                                  &cell_area,
14616                                                  0, FALSE);
14617             }
14618         }
14619       cell_offset += gtk_tree_view_column_get_width (column);
14620     }
14621
14622   cairo_set_source_rgb (cr, 0, 0, 0);
14623   cairo_rectangle (cr, 
14624                    0.5, 0.5, 
14625                    bin_window_width + 1,
14626                    background_area.height + 1);
14627   cairo_set_line_width (cr, 1.0);
14628   cairo_stroke (cr);
14629
14630   cairo_destroy (cr);
14631
14632   cairo_surface_set_device_offset (surface, 2, 2);
14633
14634   gtk_style_context_restore (context);
14635
14636   return surface;
14637 }
14638
14639
14640 /**
14641  * gtk_tree_view_set_destroy_count_func:
14642  * @tree_view: A #GtkTreeView
14643  * @func: (allow-none): Function to be called when a view row is destroyed, or %NULL
14644  * @data: (allow-none): User data to be passed to @func, or %NULL
14645  * @destroy: (allow-none): Destroy notifier for @data, or %NULL
14646  *
14647  * This function should almost never be used.  It is meant for private use by
14648  * ATK for determining the number of visible children that are removed when the
14649  * user collapses a row, or a row is deleted.
14650  **/
14651 void
14652 gtk_tree_view_set_destroy_count_func (GtkTreeView             *tree_view,
14653                                       GtkTreeDestroyCountFunc  func,
14654                                       gpointer                 data,
14655                                       GDestroyNotify           destroy)
14656 {
14657   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14658
14659   if (tree_view->priv->destroy_count_destroy)
14660     tree_view->priv->destroy_count_destroy (tree_view->priv->destroy_count_data);
14661
14662   tree_view->priv->destroy_count_func = func;
14663   tree_view->priv->destroy_count_data = data;
14664   tree_view->priv->destroy_count_destroy = destroy;
14665 }
14666
14667
14668 /*
14669  * Interactive search
14670  */
14671
14672 /**
14673  * gtk_tree_view_set_enable_search:
14674  * @tree_view: A #GtkTreeView
14675  * @enable_search: %TRUE, if the user can search interactively
14676  *
14677  * If @enable_search is set, then the user can type in text to search through
14678  * the tree interactively (this is sometimes called "typeahead find").
14679  * 
14680  * Note that even if this is %FALSE, the user can still initiate a search 
14681  * using the "start-interactive-search" key binding.
14682  */
14683 void
14684 gtk_tree_view_set_enable_search (GtkTreeView *tree_view,
14685                                  gboolean     enable_search)
14686 {
14687   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14688
14689   enable_search = !!enable_search;
14690   
14691   if (tree_view->priv->enable_search != enable_search)
14692     {
14693        tree_view->priv->enable_search = enable_search;
14694        g_object_notify (G_OBJECT (tree_view), "enable-search");
14695     }
14696 }
14697
14698 /**
14699  * gtk_tree_view_get_enable_search:
14700  * @tree_view: A #GtkTreeView
14701  *
14702  * Returns whether or not the tree allows to start interactive searching 
14703  * by typing in text.
14704  *
14705  * Return value: whether or not to let the user search interactively
14706  */
14707 gboolean
14708 gtk_tree_view_get_enable_search (GtkTreeView *tree_view)
14709 {
14710   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
14711
14712   return tree_view->priv->enable_search;
14713 }
14714
14715
14716 /**
14717  * gtk_tree_view_get_search_column:
14718  * @tree_view: A #GtkTreeView
14719  *
14720  * Gets the column searched on by the interactive search code.
14721  *
14722  * Return value: the column the interactive search code searches in.
14723  */
14724 gint
14725 gtk_tree_view_get_search_column (GtkTreeView *tree_view)
14726 {
14727   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
14728
14729   return (tree_view->priv->search_column);
14730 }
14731
14732 /**
14733  * gtk_tree_view_set_search_column:
14734  * @tree_view: A #GtkTreeView
14735  * @column: the column of the model to search in, or -1 to disable searching
14736  *
14737  * Sets @column as the column where the interactive search code should
14738  * search in for the current model. 
14739  * 
14740  * If the search column is set, users can use the "start-interactive-search"
14741  * key binding to bring up search popup. The enable-search property controls
14742  * whether simply typing text will also start an interactive search.
14743  *
14744  * Note that @column refers to a column of the current model. The search 
14745  * column is reset to -1 when the model is changed.
14746  */
14747 void
14748 gtk_tree_view_set_search_column (GtkTreeView *tree_view,
14749                                  gint         column)
14750 {
14751   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14752   g_return_if_fail (column >= -1);
14753
14754   if (tree_view->priv->search_column == column)
14755     return;
14756
14757   tree_view->priv->search_column = column;
14758   g_object_notify (G_OBJECT (tree_view), "search-column");
14759 }
14760
14761 /**
14762  * gtk_tree_view_get_search_equal_func: (skip)
14763  * @tree_view: A #GtkTreeView
14764  *
14765  * Returns the compare function currently in use.
14766  *
14767  * Return value: the currently used compare function for the search code.
14768  */
14769
14770 GtkTreeViewSearchEqualFunc
14771 gtk_tree_view_get_search_equal_func (GtkTreeView *tree_view)
14772 {
14773   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14774
14775   return tree_view->priv->search_equal_func;
14776 }
14777
14778 /**
14779  * gtk_tree_view_set_search_equal_func:
14780  * @tree_view: A #GtkTreeView
14781  * @search_equal_func: the compare function to use during the search
14782  * @search_user_data: (allow-none): user data to pass to @search_equal_func, or %NULL
14783  * @search_destroy: (allow-none): Destroy notifier for @search_user_data, or %NULL
14784  *
14785  * Sets the compare function for the interactive search capabilities; note
14786  * that somewhat like strcmp() returning 0 for equality
14787  * #GtkTreeViewSearchEqualFunc returns %FALSE on matches.
14788  **/
14789 void
14790 gtk_tree_view_set_search_equal_func (GtkTreeView                *tree_view,
14791                                      GtkTreeViewSearchEqualFunc  search_equal_func,
14792                                      gpointer                    search_user_data,
14793                                      GDestroyNotify              search_destroy)
14794 {
14795   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14796   g_return_if_fail (search_equal_func != NULL);
14797
14798   if (tree_view->priv->search_destroy)
14799     tree_view->priv->search_destroy (tree_view->priv->search_user_data);
14800
14801   tree_view->priv->search_equal_func = search_equal_func;
14802   tree_view->priv->search_user_data = search_user_data;
14803   tree_view->priv->search_destroy = search_destroy;
14804   if (tree_view->priv->search_equal_func == NULL)
14805     tree_view->priv->search_equal_func = gtk_tree_view_search_equal_func;
14806 }
14807
14808 /**
14809  * gtk_tree_view_get_search_entry:
14810  * @tree_view: A #GtkTreeView
14811  *
14812  * Returns the #GtkEntry which is currently in use as interactive search
14813  * entry for @tree_view.  In case the built-in entry is being used, %NULL
14814  * will be returned.
14815  *
14816  * Return value: (transfer none): the entry currently in use as search entry.
14817  *
14818  * Since: 2.10
14819  */
14820 GtkEntry *
14821 gtk_tree_view_get_search_entry (GtkTreeView *tree_view)
14822 {
14823   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14824
14825   if (tree_view->priv->search_custom_entry_set)
14826     return GTK_ENTRY (tree_view->priv->search_entry);
14827
14828   return NULL;
14829 }
14830
14831 /**
14832  * gtk_tree_view_set_search_entry:
14833  * @tree_view: A #GtkTreeView
14834  * @entry: (allow-none): the entry the interactive search code of @tree_view should use or %NULL
14835  *
14836  * Sets the entry which the interactive search code will use for this
14837  * @tree_view.  This is useful when you want to provide a search entry
14838  * in our interface at all time at a fixed position.  Passing %NULL for
14839  * @entry will make the interactive search code use the built-in popup
14840  * entry again.
14841  *
14842  * Since: 2.10
14843  */
14844 void
14845 gtk_tree_view_set_search_entry (GtkTreeView *tree_view,
14846                                 GtkEntry    *entry)
14847 {
14848   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14849   g_return_if_fail (entry == NULL || GTK_IS_ENTRY (entry));
14850
14851   if (tree_view->priv->search_custom_entry_set)
14852     {
14853       if (tree_view->priv->search_entry_changed_id)
14854         {
14855           g_signal_handler_disconnect (tree_view->priv->search_entry,
14856                                        tree_view->priv->search_entry_changed_id);
14857           tree_view->priv->search_entry_changed_id = 0;
14858         }
14859       g_signal_handlers_disconnect_by_func (tree_view->priv->search_entry,
14860                                             G_CALLBACK (gtk_tree_view_search_key_press_event),
14861                                             tree_view);
14862
14863       g_object_unref (tree_view->priv->search_entry);
14864     }
14865   else if (tree_view->priv->search_window)
14866     {
14867       gtk_widget_destroy (tree_view->priv->search_window);
14868
14869       tree_view->priv->search_window = NULL;
14870     }
14871
14872   if (entry)
14873     {
14874       tree_view->priv->search_entry = g_object_ref (entry);
14875       tree_view->priv->search_custom_entry_set = TRUE;
14876
14877       if (tree_view->priv->search_entry_changed_id == 0)
14878         {
14879           tree_view->priv->search_entry_changed_id =
14880             g_signal_connect (tree_view->priv->search_entry, "changed",
14881                               G_CALLBACK (gtk_tree_view_search_init),
14882                               tree_view);
14883         }
14884       
14885         g_signal_connect (tree_view->priv->search_entry, "key-press-event",
14886                           G_CALLBACK (gtk_tree_view_search_key_press_event),
14887                           tree_view);
14888
14889         gtk_tree_view_search_init (tree_view->priv->search_entry, tree_view);
14890     }
14891   else
14892     {
14893       tree_view->priv->search_entry = NULL;
14894       tree_view->priv->search_custom_entry_set = FALSE;
14895     }
14896 }
14897
14898 /**
14899  * gtk_tree_view_set_search_position_func:
14900  * @tree_view: A #GtkTreeView
14901  * @func: (allow-none): the function to use to position the search dialog, or %NULL
14902  *    to use the default search position function
14903  * @data: (allow-none): user data to pass to @func, or %NULL
14904  * @destroy: (allow-none): Destroy notifier for @data, or %NULL
14905  *
14906  * Sets the function to use when positioning the search dialog.
14907  *
14908  * Since: 2.10
14909  **/
14910 void
14911 gtk_tree_view_set_search_position_func (GtkTreeView                   *tree_view,
14912                                         GtkTreeViewSearchPositionFunc  func,
14913                                         gpointer                       user_data,
14914                                         GDestroyNotify                 destroy)
14915 {
14916   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14917
14918   if (tree_view->priv->search_position_destroy)
14919     tree_view->priv->search_position_destroy (tree_view->priv->search_position_user_data);
14920
14921   tree_view->priv->search_position_func = func;
14922   tree_view->priv->search_position_user_data = user_data;
14923   tree_view->priv->search_position_destroy = destroy;
14924   if (tree_view->priv->search_position_func == NULL)
14925     tree_view->priv->search_position_func = gtk_tree_view_search_position_func;
14926 }
14927
14928 /**
14929  * gtk_tree_view_get_search_position_func: (skip)
14930  * @tree_view: A #GtkTreeView
14931  *
14932  * Returns the positioning function currently in use.
14933  *
14934  * Return value: the currently used function for positioning the search dialog.
14935  *
14936  * Since: 2.10
14937  */
14938 GtkTreeViewSearchPositionFunc
14939 gtk_tree_view_get_search_position_func (GtkTreeView *tree_view)
14940 {
14941   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14942
14943   return tree_view->priv->search_position_func;
14944 }
14945
14946
14947 static void
14948 gtk_tree_view_search_dialog_hide (GtkWidget   *search_dialog,
14949                                   GtkTreeView *tree_view,
14950                                   GdkDevice   *device)
14951 {
14952   if (tree_view->priv->disable_popdown)
14953     return;
14954
14955   if (tree_view->priv->search_entry_changed_id)
14956     {
14957       g_signal_handler_disconnect (tree_view->priv->search_entry,
14958                                    tree_view->priv->search_entry_changed_id);
14959       tree_view->priv->search_entry_changed_id = 0;
14960     }
14961   if (tree_view->priv->typeselect_flush_timeout)
14962     {
14963       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14964       tree_view->priv->typeselect_flush_timeout = 0;
14965     }
14966         
14967   if (gtk_widget_get_visible (search_dialog))
14968     {
14969       /* send focus-in event */
14970       send_focus_change (GTK_WIDGET (tree_view->priv->search_entry), device, FALSE);
14971       gtk_widget_hide (search_dialog);
14972       gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
14973       send_focus_change (GTK_WIDGET (tree_view), device, TRUE);
14974     }
14975 }
14976
14977 static void
14978 gtk_tree_view_search_position_func (GtkTreeView *tree_view,
14979                                     GtkWidget   *search_dialog,
14980                                     gpointer     user_data)
14981 {
14982   gint x, y;
14983   gint tree_x, tree_y;
14984   gint tree_width, tree_height;
14985   GdkWindow *tree_window = gtk_widget_get_window (GTK_WIDGET (tree_view));
14986   GdkScreen *screen = gdk_window_get_screen (tree_window);
14987   GtkRequisition requisition;
14988   gint monitor_num;
14989   GdkRectangle monitor;
14990
14991   monitor_num = gdk_screen_get_monitor_at_window (screen, tree_window);
14992   gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
14993
14994   gtk_widget_realize (search_dialog);
14995
14996   gdk_window_get_origin (tree_window, &tree_x, &tree_y);
14997   tree_width = gdk_window_get_width (tree_window);
14998   tree_height = gdk_window_get_height (tree_window);
14999   gtk_widget_get_preferred_size (search_dialog, &requisition, NULL);
15000
15001   if (tree_x + tree_width > gdk_screen_get_width (screen))
15002     x = gdk_screen_get_width (screen) - requisition.width;
15003   else if (tree_x + tree_width - requisition.width < 0)
15004     x = 0;
15005   else
15006     x = tree_x + tree_width - requisition.width;
15007
15008   if (tree_y + tree_height + requisition.height > gdk_screen_get_height (screen))
15009     y = gdk_screen_get_height (screen) - requisition.height;
15010   else if (tree_y + tree_height < 0) /* isn't really possible ... */
15011     y = 0;
15012   else
15013     y = tree_y + tree_height;
15014
15015   gtk_window_move (GTK_WINDOW (search_dialog), x, y);
15016 }
15017
15018 static void
15019 gtk_tree_view_search_disable_popdown (GtkEntry *entry,
15020                                       GtkMenu  *menu,
15021                                       gpointer  data)
15022 {
15023   GtkTreeView *tree_view = (GtkTreeView *)data;
15024
15025   tree_view->priv->disable_popdown = 1;
15026   g_signal_connect (menu, "hide",
15027                     G_CALLBACK (gtk_tree_view_search_enable_popdown), data);
15028 }
15029
15030 /* Because we're visible but offscreen, we just set a flag in the preedit
15031  * callback.
15032  */
15033 static void
15034 gtk_tree_view_search_preedit_changed (GtkIMContext *im_context,
15035                                       GtkTreeView  *tree_view)
15036 {
15037   tree_view->priv->imcontext_changed = 1;
15038   if (tree_view->priv->typeselect_flush_timeout)
15039     {
15040       g_source_remove (tree_view->priv->typeselect_flush_timeout);
15041       tree_view->priv->typeselect_flush_timeout =
15042         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
15043                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
15044                        tree_view);
15045     }
15046
15047 }
15048
15049 static void
15050 gtk_tree_view_search_activate (GtkEntry    *entry,
15051                                GtkTreeView *tree_view)
15052 {
15053   GtkTreePath *path;
15054   GtkRBNode *node;
15055   GtkRBTree *tree;
15056
15057   gtk_tree_view_search_dialog_hide (tree_view->priv->search_window,
15058                                     tree_view,
15059                                     gtk_get_current_event_device ());
15060
15061   /* If we have a row selected and it's the cursor row, we activate
15062    * the row XXX */
15063   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
15064     {
15065       path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
15066       
15067       _gtk_tree_view_find_node (tree_view, path, &tree, &node);
15068       
15069       if (node && GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
15070         gtk_tree_view_row_activated (tree_view, path, tree_view->priv->focus_column);
15071       
15072       gtk_tree_path_free (path);
15073     }
15074 }
15075
15076 static gboolean
15077 gtk_tree_view_real_search_enable_popdown (gpointer data)
15078 {
15079   GtkTreeView *tree_view = (GtkTreeView *)data;
15080
15081   tree_view->priv->disable_popdown = 0;
15082
15083   return FALSE;
15084 }
15085
15086 static void
15087 gtk_tree_view_search_enable_popdown (GtkWidget *widget,
15088                                      gpointer   data)
15089 {
15090   gdk_threads_add_timeout_full (G_PRIORITY_HIGH, 200, gtk_tree_view_real_search_enable_popdown, g_object_ref (data), g_object_unref);
15091 }
15092
15093 static gboolean
15094 gtk_tree_view_search_delete_event (GtkWidget *widget,
15095                                    GdkEventAny *event,
15096                                    GtkTreeView *tree_view)
15097 {
15098   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
15099
15100   gtk_tree_view_search_dialog_hide (widget, tree_view, NULL);
15101
15102   return TRUE;
15103 }
15104
15105 static gboolean
15106 gtk_tree_view_search_button_press_event (GtkWidget *widget,
15107                                          GdkEventButton *event,
15108                                          GtkTreeView *tree_view)
15109 {
15110   GdkDevice *keyb_device;
15111
15112   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
15113
15114   keyb_device = gdk_device_get_associated_device (event->device);
15115   gtk_tree_view_search_dialog_hide (widget, tree_view, keyb_device);
15116
15117   if (event->window == tree_view->priv->bin_window)
15118     gtk_tree_view_button_press (GTK_WIDGET (tree_view), event);
15119
15120   return TRUE;
15121 }
15122
15123 static gboolean
15124 gtk_tree_view_search_scroll_event (GtkWidget *widget,
15125                                    GdkEventScroll *event,
15126                                    GtkTreeView *tree_view)
15127 {
15128   gboolean retval = FALSE;
15129
15130   if (event->direction == GDK_SCROLL_UP)
15131     {
15132       gtk_tree_view_search_move (widget, tree_view, TRUE);
15133       retval = TRUE;
15134     }
15135   else if (event->direction == GDK_SCROLL_DOWN)
15136     {
15137       gtk_tree_view_search_move (widget, tree_view, FALSE);
15138       retval = TRUE;
15139     }
15140
15141   /* renew the flush timeout */
15142   if (retval && tree_view->priv->typeselect_flush_timeout
15143       && !tree_view->priv->search_custom_entry_set)
15144     {
15145       g_source_remove (tree_view->priv->typeselect_flush_timeout);
15146       tree_view->priv->typeselect_flush_timeout =
15147         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
15148                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
15149                        tree_view);
15150     }
15151
15152   return retval;
15153 }
15154
15155 static gboolean
15156 gtk_tree_view_search_key_press_event (GtkWidget *widget,
15157                                       GdkEventKey *event,
15158                                       GtkTreeView *tree_view)
15159 {
15160   gboolean retval = FALSE;
15161
15162   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
15163   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15164
15165   /* close window and cancel the search */
15166   if (!tree_view->priv->search_custom_entry_set
15167       && (event->keyval == GDK_KEY_Escape ||
15168           event->keyval == GDK_KEY_Tab ||
15169             event->keyval == GDK_KEY_KP_Tab ||
15170             event->keyval == GDK_KEY_ISO_Left_Tab))
15171     {
15172       gtk_tree_view_search_dialog_hide (widget, tree_view,
15173                                         gdk_event_get_device ((GdkEvent *) event));
15174       return TRUE;
15175     }
15176
15177   /* select previous matching iter */
15178   if (event->keyval == GDK_KEY_Up || event->keyval == GDK_KEY_KP_Up)
15179     {
15180       if (!gtk_tree_view_search_move (widget, tree_view, TRUE))
15181         gtk_widget_error_bell (widget);
15182
15183       retval = TRUE;
15184     }
15185
15186   if (((event->state & (GTK_DEFAULT_ACCEL_MOD_MASK | GDK_SHIFT_MASK)) == (GTK_DEFAULT_ACCEL_MOD_MASK | GDK_SHIFT_MASK))
15187       && (event->keyval == GDK_KEY_g || event->keyval == GDK_KEY_G))
15188     {
15189       if (!gtk_tree_view_search_move (widget, tree_view, TRUE))
15190         gtk_widget_error_bell (widget);
15191
15192       retval = TRUE;
15193     }
15194
15195   /* select next matching iter */
15196   if (event->keyval == GDK_KEY_Down || event->keyval == GDK_KEY_KP_Down)
15197     {
15198       if (!gtk_tree_view_search_move (widget, tree_view, FALSE))
15199         gtk_widget_error_bell (widget);
15200
15201       retval = TRUE;
15202     }
15203
15204   if (((event->state & (GTK_DEFAULT_ACCEL_MOD_MASK | GDK_SHIFT_MASK)) == GTK_DEFAULT_ACCEL_MOD_MASK)
15205       && (event->keyval == GDK_KEY_g || event->keyval == GDK_KEY_G))
15206     {
15207       if (!gtk_tree_view_search_move (widget, tree_view, FALSE))
15208         gtk_widget_error_bell (widget);
15209
15210       retval = TRUE;
15211     }
15212
15213   /* renew the flush timeout */
15214   if (retval && tree_view->priv->typeselect_flush_timeout
15215       && !tree_view->priv->search_custom_entry_set)
15216     {
15217       g_source_remove (tree_view->priv->typeselect_flush_timeout);
15218       tree_view->priv->typeselect_flush_timeout =
15219         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
15220                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
15221                        tree_view);
15222     }
15223
15224   return retval;
15225 }
15226
15227 /*  this function returns FALSE if there is a search string but
15228  *  nothing was found, and TRUE otherwise.
15229  */
15230 static gboolean
15231 gtk_tree_view_search_move (GtkWidget   *window,
15232                            GtkTreeView *tree_view,
15233                            gboolean     up)
15234 {
15235   gboolean ret;
15236   gint len;
15237   gint count = 0;
15238   const gchar *text;
15239   GtkTreeIter iter;
15240   GtkTreeModel *model;
15241   GtkTreeSelection *selection;
15242
15243   text = gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry));
15244
15245   g_return_val_if_fail (text != NULL, FALSE);
15246
15247   len = strlen (text);
15248
15249   if (up && tree_view->priv->selected_iter == 1)
15250     return strlen (text) < 1;
15251
15252   len = strlen (text);
15253
15254   if (len < 1)
15255     return TRUE;
15256
15257   model = gtk_tree_view_get_model (tree_view);
15258   selection = gtk_tree_view_get_selection (tree_view);
15259
15260   /* search */
15261   gtk_tree_selection_unselect_all (selection);
15262   if (!gtk_tree_model_get_iter_first (model, &iter))
15263     return TRUE;
15264
15265   ret = gtk_tree_view_search_iter (model, selection, &iter, text,
15266                                    &count, up?((tree_view->priv->selected_iter) - 1):((tree_view->priv->selected_iter + 1)));
15267
15268   if (ret)
15269     {
15270       /* found */
15271       tree_view->priv->selected_iter += up?(-1):(1);
15272       return TRUE;
15273     }
15274   else
15275     {
15276       /* return to old iter */
15277       count = 0;
15278       gtk_tree_model_get_iter_first (model, &iter);
15279       gtk_tree_view_search_iter (model, selection,
15280                                  &iter, text,
15281                                  &count, tree_view->priv->selected_iter);
15282       return FALSE;
15283     }
15284 }
15285
15286 static gboolean
15287 gtk_tree_view_search_equal_func (GtkTreeModel *model,
15288                                  gint          column,
15289                                  const gchar  *key,
15290                                  GtkTreeIter  *iter,
15291                                  gpointer      search_data)
15292 {
15293   gboolean retval = TRUE;
15294   const gchar *str;
15295   gchar *normalized_string;
15296   gchar *normalized_key;
15297   gchar *case_normalized_string = NULL;
15298   gchar *case_normalized_key = NULL;
15299   GValue value = {0,};
15300   GValue transformed = {0,};
15301
15302   gtk_tree_model_get_value (model, iter, column, &value);
15303
15304   g_value_init (&transformed, G_TYPE_STRING);
15305
15306   if (!g_value_transform (&value, &transformed))
15307     {
15308       g_value_unset (&value);
15309       return TRUE;
15310     }
15311
15312   g_value_unset (&value);
15313
15314   str = g_value_get_string (&transformed);
15315   if (!str)
15316     {
15317       g_value_unset (&transformed);
15318       return TRUE;
15319     }
15320
15321   normalized_string = g_utf8_normalize (str, -1, G_NORMALIZE_ALL);
15322   normalized_key = g_utf8_normalize (key, -1, G_NORMALIZE_ALL);
15323
15324   if (normalized_string && normalized_key)
15325     {
15326       case_normalized_string = g_utf8_casefold (normalized_string, -1);
15327       case_normalized_key = g_utf8_casefold (normalized_key, -1);
15328
15329       if (strncmp (case_normalized_key, case_normalized_string, strlen (case_normalized_key)) == 0)
15330         retval = FALSE;
15331     }
15332
15333   g_value_unset (&transformed);
15334   g_free (normalized_key);
15335   g_free (normalized_string);
15336   g_free (case_normalized_key);
15337   g_free (case_normalized_string);
15338
15339   return retval;
15340 }
15341
15342 static gboolean
15343 gtk_tree_view_search_iter (GtkTreeModel     *model,
15344                            GtkTreeSelection *selection,
15345                            GtkTreeIter      *iter,
15346                            const gchar      *text,
15347                            gint             *count,
15348                            gint              n)
15349 {
15350   GtkRBTree *tree = NULL;
15351   GtkRBNode *node = NULL;
15352   GtkTreePath *path;
15353
15354   GtkTreeView *tree_view = gtk_tree_selection_get_tree_view (selection);
15355
15356   path = gtk_tree_model_get_path (model, iter);
15357   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
15358
15359   do
15360     {
15361       if (! tree_view->priv->search_equal_func (model, tree_view->priv->search_column, text, iter, tree_view->priv->search_user_data))
15362         {
15363           (*count)++;
15364           if (*count == n)
15365             {
15366               gtk_tree_view_scroll_to_cell (tree_view, path, NULL,
15367                                             TRUE, 0.5, 0.0);
15368               gtk_tree_selection_select_iter (selection, iter);
15369               gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
15370
15371               if (path)
15372                 gtk_tree_path_free (path);
15373
15374               return TRUE;
15375             }
15376         }
15377
15378       if (node->children)
15379         {
15380           gboolean has_child;
15381           GtkTreeIter tmp;
15382
15383           tree = node->children;
15384           node = tree->root;
15385
15386           while (node->left != tree->nil)
15387             node = node->left;
15388
15389           tmp = *iter;
15390           has_child = gtk_tree_model_iter_children (model, iter, &tmp);
15391           gtk_tree_path_down (path);
15392
15393           /* sanity check */
15394           TREE_VIEW_INTERNAL_ASSERT (has_child, FALSE);
15395         }
15396       else
15397         {
15398           gboolean done = FALSE;
15399
15400           do
15401             {
15402               node = _gtk_rbtree_next (tree, node);
15403
15404               if (node)
15405                 {
15406                   gboolean has_next;
15407
15408                   has_next = gtk_tree_model_iter_next (model, iter);
15409
15410                   done = TRUE;
15411                   gtk_tree_path_next (path);
15412
15413                   /* sanity check */
15414                   TREE_VIEW_INTERNAL_ASSERT (has_next, FALSE);
15415                 }
15416               else
15417                 {
15418                   gboolean has_parent;
15419                   GtkTreeIter tmp_iter = *iter;
15420
15421                   node = tree->parent_node;
15422                   tree = tree->parent_tree;
15423
15424                   if (!tree)
15425                     {
15426                       if (path)
15427                         gtk_tree_path_free (path);
15428
15429                       /* we've run out of tree, done with this func */
15430                       return FALSE;
15431                     }
15432
15433                   has_parent = gtk_tree_model_iter_parent (model,
15434                                                            iter,
15435                                                            &tmp_iter);
15436                   gtk_tree_path_up (path);
15437
15438                   /* sanity check */
15439                   TREE_VIEW_INTERNAL_ASSERT (has_parent, FALSE);
15440                 }
15441             }
15442           while (!done);
15443         }
15444     }
15445   while (1);
15446
15447   return FALSE;
15448 }
15449
15450 static void
15451 gtk_tree_view_search_init (GtkWidget   *entry,
15452                            GtkTreeView *tree_view)
15453 {
15454   gint ret;
15455   gint count = 0;
15456   const gchar *text;
15457   GtkTreeIter iter;
15458   GtkTreeModel *model;
15459   GtkTreeSelection *selection;
15460
15461   g_return_if_fail (GTK_IS_ENTRY (entry));
15462   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15463
15464   text = gtk_entry_get_text (GTK_ENTRY (entry));
15465
15466   model = gtk_tree_view_get_model (tree_view);
15467   selection = gtk_tree_view_get_selection (tree_view);
15468
15469   /* search */
15470   gtk_tree_selection_unselect_all (selection);
15471   if (tree_view->priv->typeselect_flush_timeout
15472       && !tree_view->priv->search_custom_entry_set)
15473     {
15474       g_source_remove (tree_view->priv->typeselect_flush_timeout);
15475       tree_view->priv->typeselect_flush_timeout =
15476         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
15477                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
15478                        tree_view);
15479     }
15480
15481   if (*text == '\0')
15482     return;
15483
15484   if (!gtk_tree_model_get_iter_first (model, &iter))
15485     return;
15486
15487   ret = gtk_tree_view_search_iter (model, selection,
15488                                    &iter, text,
15489                                    &count, 1);
15490
15491   if (ret)
15492     tree_view->priv->selected_iter = 1;
15493 }
15494
15495 void
15496 _gtk_tree_view_remove_editable (GtkTreeView       *tree_view,
15497                                 GtkTreeViewColumn *column,
15498                                 GtkCellEditable   *cell_editable)
15499 {
15500   if (tree_view->priv->edited_column == NULL)
15501     return;
15502
15503   g_return_if_fail (column == tree_view->priv->edited_column);
15504
15505   tree_view->priv->edited_column = NULL;
15506
15507   if (gtk_widget_has_focus (GTK_WIDGET (cell_editable)))
15508     gtk_widget_grab_focus (GTK_WIDGET (tree_view));
15509
15510   gtk_container_remove (GTK_CONTAINER (tree_view),
15511                         GTK_WIDGET (cell_editable));
15512
15513   /* FIXME should only redraw a single node */
15514   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15515 }
15516
15517 static gboolean
15518 gtk_tree_view_start_editing (GtkTreeView *tree_view,
15519                              GtkTreePath *cursor_path,
15520                              gboolean     edit_only)
15521 {
15522   GtkTreeIter iter;
15523   GdkRectangle cell_area;
15524   GtkTreeViewColumn *focus_column;
15525   guint flags = 0; /* can be 0, as the flags are primarily for rendering */
15526   gint retval = FALSE;
15527   GtkRBTree *cursor_tree;
15528   GtkRBNode *cursor_node;
15529
15530   g_assert (tree_view->priv->focus_column);
15531   focus_column = tree_view->priv->focus_column;
15532
15533   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
15534     return FALSE;
15535
15536   if (_gtk_tree_view_find_node (tree_view, cursor_path, &cursor_tree, &cursor_node) ||
15537       cursor_node == NULL)
15538     return FALSE;
15539
15540   gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path);
15541
15542   validate_row (tree_view, cursor_tree, cursor_node, &iter, cursor_path);
15543
15544   gtk_tree_view_column_cell_set_cell_data (focus_column,
15545                                            tree_view->priv->model,
15546                                            &iter,
15547                                            GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_PARENT),
15548                                            cursor_node->children ? TRUE : FALSE);
15549   gtk_tree_view_get_cell_area (tree_view,
15550                                cursor_path,
15551                                focus_column,
15552                                &cell_area);
15553
15554   if (gtk_cell_area_activate (gtk_cell_layout_get_area (GTK_CELL_LAYOUT (focus_column)),
15555                               _gtk_tree_view_column_get_context (focus_column),
15556                               GTK_WIDGET (tree_view),
15557                               &cell_area,
15558                               flags, edit_only))
15559     retval = TRUE;
15560
15561   return retval;
15562 }
15563
15564 void
15565 _gtk_tree_view_add_editable (GtkTreeView       *tree_view,
15566                              GtkTreeViewColumn *column,
15567                              GtkTreePath       *path,
15568                              GtkCellEditable   *cell_editable,
15569                              GdkRectangle      *cell_area)
15570 {
15571   gint pre_val = gtk_adjustment_get_value (tree_view->priv->vadjustment);
15572   GtkRequisition requisition;
15573
15574   tree_view->priv->edited_column = column;
15575
15576   gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
15577   cell_area->y += pre_val - (int)gtk_adjustment_get_value (tree_view->priv->vadjustment);
15578
15579   gtk_widget_get_preferred_size (GTK_WIDGET (cell_editable),
15580                                  &requisition, NULL);
15581
15582   tree_view->priv->draw_keyfocus = TRUE;
15583
15584   if (requisition.height < cell_area->height)
15585     {
15586       gint diff = cell_area->height - requisition.height;
15587       gtk_tree_view_put (tree_view,
15588                          GTK_WIDGET (cell_editable),
15589                          cell_area->x, cell_area->y + diff/2,
15590                          cell_area->width, requisition.height);
15591     }
15592   else
15593     {
15594       gtk_tree_view_put (tree_view,
15595                          GTK_WIDGET (cell_editable),
15596                          cell_area->x, cell_area->y,
15597                          cell_area->width, cell_area->height);
15598     }
15599 }
15600
15601 static void
15602 gtk_tree_view_stop_editing (GtkTreeView *tree_view,
15603                             gboolean     cancel_editing)
15604 {
15605   GtkTreeViewColumn *column;
15606
15607   if (tree_view->priv->edited_column == NULL)
15608     return;
15609
15610   /*
15611    * This is very evil. We need to do this, because
15612    * gtk_cell_editable_editing_done may trigger gtk_tree_view_row_changed
15613    * later on. If gtk_tree_view_row_changed notices
15614    * tree_view->priv->edited_column != NULL, it'll call
15615    * gtk_tree_view_stop_editing again. Bad things will happen then.
15616    *
15617    * Please read that again if you intend to modify anything here.
15618    */
15619
15620   column = tree_view->priv->edited_column;
15621   gtk_cell_area_stop_editing (gtk_cell_layout_get_area (GTK_CELL_LAYOUT (column)), cancel_editing);
15622   tree_view->priv->edited_column = NULL;
15623 }
15624
15625
15626 /**
15627  * gtk_tree_view_set_hover_selection:
15628  * @tree_view: a #GtkTreeView
15629  * @hover: %TRUE to enable hover selection mode
15630  *
15631  * Enables or disables the hover selection mode of @tree_view.
15632  * Hover selection makes the selected row follow the pointer.
15633  * Currently, this works only for the selection modes 
15634  * %GTK_SELECTION_SINGLE and %GTK_SELECTION_BROWSE.
15635  * 
15636  * Since: 2.6
15637  **/
15638 void     
15639 gtk_tree_view_set_hover_selection (GtkTreeView *tree_view,
15640                                    gboolean     hover)
15641 {
15642   hover = hover != FALSE;
15643
15644   if (hover != tree_view->priv->hover_selection)
15645     {
15646       tree_view->priv->hover_selection = hover;
15647
15648       g_object_notify (G_OBJECT (tree_view), "hover-selection");
15649     }
15650 }
15651
15652 /**
15653  * gtk_tree_view_get_hover_selection:
15654  * @tree_view: a #GtkTreeView
15655  * 
15656  * Returns whether hover selection mode is turned on for @tree_view.
15657  * 
15658  * Return value: %TRUE if @tree_view is in hover selection mode
15659  *
15660  * Since: 2.6 
15661  **/
15662 gboolean 
15663 gtk_tree_view_get_hover_selection (GtkTreeView *tree_view)
15664 {
15665   return tree_view->priv->hover_selection;
15666 }
15667
15668 /**
15669  * gtk_tree_view_set_hover_expand:
15670  * @tree_view: a #GtkTreeView
15671  * @expand: %TRUE to enable hover selection mode
15672  *
15673  * Enables of disables the hover expansion mode of @tree_view.
15674  * Hover expansion makes rows expand or collapse if the pointer 
15675  * moves over them.
15676  * 
15677  * Since: 2.6
15678  **/
15679 void     
15680 gtk_tree_view_set_hover_expand (GtkTreeView *tree_view,
15681                                 gboolean     expand)
15682 {
15683   expand = expand != FALSE;
15684
15685   if (expand != tree_view->priv->hover_expand)
15686     {
15687       tree_view->priv->hover_expand = expand;
15688
15689       g_object_notify (G_OBJECT (tree_view), "hover-expand");
15690     }
15691 }
15692
15693 /**
15694  * gtk_tree_view_get_hover_expand:
15695  * @tree_view: a #GtkTreeView
15696  * 
15697  * Returns whether hover expansion mode is turned on for @tree_view.
15698  * 
15699  * Return value: %TRUE if @tree_view is in hover expansion mode
15700  *
15701  * Since: 2.6 
15702  **/
15703 gboolean 
15704 gtk_tree_view_get_hover_expand (GtkTreeView *tree_view)
15705 {
15706   return tree_view->priv->hover_expand;
15707 }
15708
15709 /**
15710  * gtk_tree_view_set_rubber_banding:
15711  * @tree_view: a #GtkTreeView
15712  * @enable: %TRUE to enable rubber banding
15713  *
15714  * Enables or disables rubber banding in @tree_view.  If the selection mode
15715  * is #GTK_SELECTION_MULTIPLE, rubber banding will allow the user to select
15716  * multiple rows by dragging the mouse.
15717  * 
15718  * Since: 2.10
15719  **/
15720 void
15721 gtk_tree_view_set_rubber_banding (GtkTreeView *tree_view,
15722                                   gboolean     enable)
15723 {
15724   enable = enable != FALSE;
15725
15726   if (enable != tree_view->priv->rubber_banding_enable)
15727     {
15728       tree_view->priv->rubber_banding_enable = enable;
15729
15730       g_object_notify (G_OBJECT (tree_view), "rubber-banding");
15731     }
15732 }
15733
15734 /**
15735  * gtk_tree_view_get_rubber_banding:
15736  * @tree_view: a #GtkTreeView
15737  * 
15738  * Returns whether rubber banding is turned on for @tree_view.  If the
15739  * selection mode is #GTK_SELECTION_MULTIPLE, rubber banding will allow the
15740  * user to select multiple rows by dragging the mouse.
15741  * 
15742  * Return value: %TRUE if rubber banding in @tree_view is enabled.
15743  *
15744  * Since: 2.10
15745  **/
15746 gboolean
15747 gtk_tree_view_get_rubber_banding (GtkTreeView *tree_view)
15748 {
15749   return tree_view->priv->rubber_banding_enable;
15750 }
15751
15752 /**
15753  * gtk_tree_view_is_rubber_banding_active:
15754  * @tree_view: a #GtkTreeView
15755  * 
15756  * Returns whether a rubber banding operation is currently being done
15757  * in @tree_view.
15758  *
15759  * Return value: %TRUE if a rubber banding operation is currently being
15760  * done in @tree_view.
15761  *
15762  * Since: 2.12
15763  **/
15764 gboolean
15765 gtk_tree_view_is_rubber_banding_active (GtkTreeView *tree_view)
15766 {
15767   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15768
15769   if (tree_view->priv->rubber_banding_enable
15770       && tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
15771     return TRUE;
15772
15773   return FALSE;
15774 }
15775
15776 /**
15777  * gtk_tree_view_get_row_separator_func: (skip)
15778  * @tree_view: a #GtkTreeView
15779  * 
15780  * Returns the current row separator function.
15781  * 
15782  * Return value: the current row separator function.
15783  *
15784  * Since: 2.6
15785  **/
15786 GtkTreeViewRowSeparatorFunc 
15787 gtk_tree_view_get_row_separator_func (GtkTreeView *tree_view)
15788 {
15789   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
15790
15791   return tree_view->priv->row_separator_func;
15792 }
15793
15794 /**
15795  * gtk_tree_view_set_row_separator_func:
15796  * @tree_view: a #GtkTreeView
15797  * @func: (allow-none): a #GtkTreeViewRowSeparatorFunc
15798  * @data: (allow-none): user data to pass to @func, or %NULL
15799  * @destroy: (allow-none): destroy notifier for @data, or %NULL
15800  * 
15801  * Sets the row separator function, which is used to determine
15802  * whether a row should be drawn as a separator. If the row separator
15803  * function is %NULL, no separators are drawn. This is the default value.
15804  *
15805  * Since: 2.6
15806  **/
15807 void
15808 gtk_tree_view_set_row_separator_func (GtkTreeView                 *tree_view,
15809                                       GtkTreeViewRowSeparatorFunc  func,
15810                                       gpointer                     data,
15811                                       GDestroyNotify               destroy)
15812 {
15813   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15814
15815   if (tree_view->priv->row_separator_destroy)
15816     tree_view->priv->row_separator_destroy (tree_view->priv->row_separator_data);
15817
15818   tree_view->priv->row_separator_func = func;
15819   tree_view->priv->row_separator_data = data;
15820   tree_view->priv->row_separator_destroy = destroy;
15821
15822   /* Have the tree recalculate heights */
15823   _gtk_rbtree_mark_invalid (tree_view->priv->tree);
15824   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
15825 }
15826
15827   
15828 static void
15829 gtk_tree_view_grab_notify (GtkWidget *widget,
15830                            gboolean   was_grabbed)
15831 {
15832   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
15833
15834   tree_view->priv->in_grab = !was_grabbed;
15835
15836   if (!was_grabbed)
15837     {
15838       tree_view->priv->pressed_button = -1;
15839
15840       if (tree_view->priv->rubber_band_status)
15841         gtk_tree_view_stop_rubber_band (tree_view);
15842     }
15843 }
15844
15845 static void
15846 gtk_tree_view_state_flags_changed (GtkWidget     *widget,
15847                                    GtkStateFlags  previous_state)
15848 {
15849   if (gtk_widget_get_realized (widget))
15850     {
15851       GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
15852       GtkStyleContext *context;
15853
15854       context = gtk_widget_get_style_context (widget);
15855       gtk_style_context_set_background (context, tree_view->priv->bin_window);
15856     }
15857
15858   gtk_widget_queue_draw (widget);
15859 }
15860
15861 /**
15862  * gtk_tree_view_get_grid_lines:
15863  * @tree_view: a #GtkTreeView
15864  *
15865  * Returns which grid lines are enabled in @tree_view.
15866  *
15867  * Return value: a #GtkTreeViewGridLines value indicating which grid lines
15868  * are enabled.
15869  *
15870  * Since: 2.10
15871  */
15872 GtkTreeViewGridLines
15873 gtk_tree_view_get_grid_lines (GtkTreeView *tree_view)
15874 {
15875   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
15876
15877   return tree_view->priv->grid_lines;
15878 }
15879
15880 /**
15881  * gtk_tree_view_set_grid_lines:
15882  * @tree_view: a #GtkTreeView
15883  * @grid_lines: a #GtkTreeViewGridLines value indicating which grid lines to
15884  * enable.
15885  *
15886  * Sets which grid lines to draw in @tree_view.
15887  *
15888  * Since: 2.10
15889  */
15890 void
15891 gtk_tree_view_set_grid_lines (GtkTreeView           *tree_view,
15892                               GtkTreeViewGridLines   grid_lines)
15893 {
15894   GtkTreeViewPrivate *priv;
15895   GtkWidget *widget;
15896   GtkTreeViewGridLines old_grid_lines;
15897
15898   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15899
15900   priv = tree_view->priv;
15901   widget = GTK_WIDGET (tree_view);
15902
15903   old_grid_lines = priv->grid_lines;
15904   priv->grid_lines = grid_lines;
15905   
15906   if (gtk_widget_get_realized (widget))
15907     {
15908       if (grid_lines == GTK_TREE_VIEW_GRID_LINES_NONE &&
15909           priv->grid_line_width)
15910         {
15911           priv->grid_line_width = 0;
15912         }
15913       
15914       if (grid_lines != GTK_TREE_VIEW_GRID_LINES_NONE && 
15915           !priv->grid_line_width)
15916         {
15917           gint8 *dash_list;
15918
15919           gtk_widget_style_get (widget,
15920                                 "grid-line-width", &priv->grid_line_width,
15921                                 "grid-line-pattern", (gchar *)&dash_list,
15922                                 NULL);
15923       
15924           if (dash_list)
15925             {
15926               priv->grid_line_dashes[0] = dash_list[0];
15927               if (dash_list[0])
15928                 priv->grid_line_dashes[1] = dash_list[1];
15929               
15930               g_free (dash_list);
15931             }
15932           else
15933             {
15934               priv->grid_line_dashes[0] = 1;
15935               priv->grid_line_dashes[1] = 1;
15936             }
15937         }      
15938     }
15939
15940   if (old_grid_lines != grid_lines)
15941     {
15942       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15943       
15944       g_object_notify (G_OBJECT (tree_view), "enable-grid-lines");
15945     }
15946 }
15947
15948 /**
15949  * gtk_tree_view_get_enable_tree_lines:
15950  * @tree_view: a #GtkTreeView.
15951  *
15952  * Returns whether or not tree lines are drawn in @tree_view.
15953  *
15954  * Return value: %TRUE if tree lines are drawn in @tree_view, %FALSE
15955  * otherwise.
15956  *
15957  * Since: 2.10
15958  */
15959 gboolean
15960 gtk_tree_view_get_enable_tree_lines (GtkTreeView *tree_view)
15961 {
15962   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15963
15964   return tree_view->priv->tree_lines_enabled;
15965 }
15966
15967 /**
15968  * gtk_tree_view_set_enable_tree_lines:
15969  * @tree_view: a #GtkTreeView
15970  * @enabled: %TRUE to enable tree line drawing, %FALSE otherwise.
15971  *
15972  * Sets whether to draw lines interconnecting the expanders in @tree_view.
15973  * This does not have any visible effects for lists.
15974  *
15975  * Since: 2.10
15976  */
15977 void
15978 gtk_tree_view_set_enable_tree_lines (GtkTreeView *tree_view,
15979                                      gboolean     enabled)
15980 {
15981   GtkTreeViewPrivate *priv;
15982   GtkWidget *widget;
15983   gboolean was_enabled;
15984
15985   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15986
15987   enabled = enabled != FALSE;
15988
15989   priv = tree_view->priv;
15990   widget = GTK_WIDGET (tree_view);
15991
15992   was_enabled = priv->tree_lines_enabled;
15993
15994   priv->tree_lines_enabled = enabled;
15995
15996   if (gtk_widget_get_realized (widget))
15997     {
15998       if (!enabled && priv->tree_line_width)
15999         {
16000           priv->tree_line_width = 0;
16001         }
16002       
16003       if (enabled && !priv->tree_line_width)
16004         {
16005           gint8 *dash_list;
16006           gtk_widget_style_get (widget,
16007                                 "tree-line-width", &priv->tree_line_width,
16008                                 "tree-line-pattern", (gchar *)&dash_list,
16009                                 NULL);
16010           
16011           if (dash_list)
16012             {
16013               priv->tree_line_dashes[0] = dash_list[0];
16014               if (dash_list[0])
16015                 priv->tree_line_dashes[1] = dash_list[1];
16016               
16017               g_free (dash_list);
16018             }
16019           else
16020             {
16021               priv->tree_line_dashes[0] = 1;
16022               priv->tree_line_dashes[1] = 1;
16023             }
16024         }
16025     }
16026
16027   if (was_enabled != enabled)
16028     {
16029       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
16030
16031       g_object_notify (G_OBJECT (tree_view), "enable-tree-lines");
16032     }
16033 }
16034
16035
16036 /**
16037  * gtk_tree_view_set_show_expanders:
16038  * @tree_view: a #GtkTreeView
16039  * @enabled: %TRUE to enable expander drawing, %FALSE otherwise.
16040  *
16041  * Sets whether to draw and enable expanders and indent child rows in
16042  * @tree_view.  When disabled there will be no expanders visible in trees
16043  * and there will be no way to expand and collapse rows by default.  Also
16044  * note that hiding the expanders will disable the default indentation.  You
16045  * can set a custom indentation in this case using
16046  * gtk_tree_view_set_level_indentation().
16047  * This does not have any visible effects for lists.
16048  *
16049  * Since: 2.12
16050  */
16051 void
16052 gtk_tree_view_set_show_expanders (GtkTreeView *tree_view,
16053                                   gboolean     enabled)
16054 {
16055   gboolean was_enabled;
16056
16057   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
16058
16059   enabled = enabled != FALSE;
16060   was_enabled = tree_view->priv->show_expanders;
16061
16062   tree_view->priv->show_expanders = enabled == TRUE;
16063
16064   if (enabled != was_enabled)
16065     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
16066 }
16067
16068 /**
16069  * gtk_tree_view_get_show_expanders:
16070  * @tree_view: a #GtkTreeView.
16071  *
16072  * Returns whether or not expanders are drawn in @tree_view.
16073  *
16074  * Return value: %TRUE if expanders are drawn in @tree_view, %FALSE
16075  * otherwise.
16076  *
16077  * Since: 2.12
16078  */
16079 gboolean
16080 gtk_tree_view_get_show_expanders (GtkTreeView *tree_view)
16081 {
16082   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
16083
16084   return tree_view->priv->show_expanders;
16085 }
16086
16087 /**
16088  * gtk_tree_view_set_level_indentation:
16089  * @tree_view: a #GtkTreeView
16090  * @indentation: the amount, in pixels, of extra indentation in @tree_view.
16091  *
16092  * Sets the amount of extra indentation for child levels to use in @tree_view
16093  * in addition to the default indentation.  The value should be specified in
16094  * pixels, a value of 0 disables this feature and in this case only the default
16095  * indentation will be used.
16096  * This does not have any visible effects for lists.
16097  *
16098  * Since: 2.12
16099  */
16100 void
16101 gtk_tree_view_set_level_indentation (GtkTreeView *tree_view,
16102                                      gint         indentation)
16103 {
16104   tree_view->priv->level_indentation = indentation;
16105
16106   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
16107 }
16108
16109 /**
16110  * gtk_tree_view_get_level_indentation:
16111  * @tree_view: a #GtkTreeView.
16112  *
16113  * Returns the amount, in pixels, of extra indentation for child levels
16114  * in @tree_view.
16115  *
16116  * Return value: the amount of extra indentation for child levels in
16117  * @tree_view.  A return value of 0 means that this feature is disabled.
16118  *
16119  * Since: 2.12
16120  */
16121 gint
16122 gtk_tree_view_get_level_indentation (GtkTreeView *tree_view)
16123 {
16124   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
16125
16126   return tree_view->priv->level_indentation;
16127 }
16128
16129 /**
16130  * gtk_tree_view_set_tooltip_row:
16131  * @tree_view: a #GtkTreeView
16132  * @tooltip: a #GtkTooltip
16133  * @path: a #GtkTreePath
16134  *
16135  * Sets the tip area of @tooltip to be the area covered by the row at @path.
16136  * See also gtk_tree_view_set_tooltip_column() for a simpler alternative.
16137  * See also gtk_tooltip_set_tip_area().
16138  *
16139  * Since: 2.12
16140  */
16141 void
16142 gtk_tree_view_set_tooltip_row (GtkTreeView *tree_view,
16143                                GtkTooltip  *tooltip,
16144                                GtkTreePath *path)
16145 {
16146   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
16147   g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
16148
16149   gtk_tree_view_set_tooltip_cell (tree_view, tooltip, path, NULL, NULL);
16150 }
16151
16152 /**
16153  * gtk_tree_view_set_tooltip_cell:
16154  * @tree_view: a #GtkTreeView
16155  * @tooltip: a #GtkTooltip
16156  * @path: (allow-none): a #GtkTreePath or %NULL
16157  * @column: (allow-none): a #GtkTreeViewColumn or %NULL
16158  * @cell: (allow-none): a #GtkCellRenderer or %NULL
16159  *
16160  * Sets the tip area of @tooltip to the area @path, @column and @cell have
16161  * in common.  For example if @path is %NULL and @column is set, the tip
16162  * area will be set to the full area covered by @column.  See also
16163  * gtk_tooltip_set_tip_area().
16164  *
16165  * Note that if @path is not specified and @cell is set and part of a column
16166  * containing the expander, the tooltip might not show and hide at the correct
16167  * position.  In such cases @path must be set to the current node under the
16168  * mouse cursor for this function to operate correctly.
16169  *
16170  * See also gtk_tree_view_set_tooltip_column() for a simpler alternative.
16171  *
16172  * Since: 2.12
16173  */
16174 void
16175 gtk_tree_view_set_tooltip_cell (GtkTreeView       *tree_view,
16176                                 GtkTooltip        *tooltip,
16177                                 GtkTreePath       *path,
16178                                 GtkTreeViewColumn *column,
16179                                 GtkCellRenderer   *cell)
16180 {
16181   GtkAllocation allocation;
16182   GdkRectangle rect;
16183
16184   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
16185   g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
16186   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
16187   g_return_if_fail (cell == NULL || GTK_IS_CELL_RENDERER (cell));
16188
16189   /* Determine x values. */
16190   if (column && cell)
16191     {
16192       GdkRectangle tmp;
16193       gint start, width;
16194
16195       /* We always pass in path here, whether it is NULL or not.
16196        * For cells in expander columns path must be specified so that
16197        * we can correctly account for the indentation.  This also means
16198        * that the tooltip is constrained vertically by the "Determine y
16199        * values" code below; this is not a real problem since cells actually
16200        * don't stretch vertically in constrast to columns.
16201        */
16202       gtk_tree_view_get_cell_area (tree_view, path, column, &tmp);
16203       gtk_tree_view_column_cell_get_position (column, cell, &start, &width);
16204
16205       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
16206                                                          tmp.x + start, 0,
16207                                                          &rect.x, NULL);
16208       rect.width = width;
16209     }
16210   else if (column)
16211     {
16212       GdkRectangle tmp;
16213
16214       gtk_tree_view_get_background_area (tree_view, NULL, column, &tmp);
16215       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
16216                                                          tmp.x, 0,
16217                                                          &rect.x, NULL);
16218       rect.width = tmp.width;
16219     }
16220   else
16221     {
16222       gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
16223       rect.x = 0;
16224       rect.width = allocation.width;
16225     }
16226
16227   /* Determine y values. */
16228   if (path)
16229     {
16230       GdkRectangle tmp;
16231
16232       gtk_tree_view_get_background_area (tree_view, path, NULL, &tmp);
16233       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
16234                                                          0, tmp.y,
16235                                                          NULL, &rect.y);
16236       rect.height = tmp.height;
16237     }
16238   else
16239     {
16240       rect.y = 0;
16241       rect.height = gtk_adjustment_get_page_size (tree_view->priv->vadjustment);
16242     }
16243
16244   gtk_tooltip_set_tip_area (tooltip, &rect);
16245 }
16246
16247 /**
16248  * gtk_tree_view_get_tooltip_context:
16249  * @tree_view: a #GtkTreeView
16250  * @x: (inout): the x coordinate (relative to widget coordinates)
16251  * @y: (inout): the y coordinate (relative to widget coordinates)
16252  * @keyboard_tip: whether this is a keyboard tooltip or not
16253  * @model: (out) (allow-none): a pointer to receive a #GtkTreeModel or %NULL
16254  * @path: (out) (allow-none): a pointer to receive a #GtkTreePath or %NULL
16255  * @iter: (out) (allow-none): a pointer to receive a #GtkTreeIter or %NULL
16256  *
16257  * This function is supposed to be used in a #GtkWidget::query-tooltip
16258  * signal handler for #GtkTreeView.  The @x, @y and @keyboard_tip values
16259  * which are received in the signal handler, should be passed to this
16260  * function without modification.
16261  *
16262  * The return value indicates whether there is a tree view row at the given
16263  * coordinates (%TRUE) or not (%FALSE) for mouse tooltips.  For keyboard
16264  * tooltips the row returned will be the cursor row.  When %TRUE, then any of
16265  * @model, @path and @iter which have been provided will be set to point to
16266  * that row and the corresponding model.  @x and @y will always be converted
16267  * to be relative to @tree_view's bin_window if @keyboard_tooltip is %FALSE.
16268  *
16269  * Return value: whether or not the given tooltip context points to a row.
16270  *
16271  * Since: 2.12
16272  */
16273 gboolean
16274 gtk_tree_view_get_tooltip_context (GtkTreeView   *tree_view,
16275                                    gint          *x,
16276                                    gint          *y,
16277                                    gboolean       keyboard_tip,
16278                                    GtkTreeModel **model,
16279                                    GtkTreePath  **path,
16280                                    GtkTreeIter   *iter)
16281 {
16282   GtkTreePath *tmppath = NULL;
16283
16284   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
16285   g_return_val_if_fail (x != NULL, FALSE);
16286   g_return_val_if_fail (y != NULL, FALSE);
16287
16288   if (keyboard_tip)
16289     {
16290       gtk_tree_view_get_cursor (tree_view, &tmppath, NULL);
16291
16292       if (!tmppath)
16293         return FALSE;
16294     }
16295   else
16296     {
16297       gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, *x, *y,
16298                                                          x, y);
16299
16300       if (!gtk_tree_view_get_path_at_pos (tree_view, *x, *y,
16301                                           &tmppath, NULL, NULL, NULL))
16302         return FALSE;
16303     }
16304
16305   if (model)
16306     *model = gtk_tree_view_get_model (tree_view);
16307
16308   if (iter)
16309     gtk_tree_model_get_iter (gtk_tree_view_get_model (tree_view),
16310                              iter, tmppath);
16311
16312   if (path)
16313     *path = tmppath;
16314   else
16315     gtk_tree_path_free (tmppath);
16316
16317   return TRUE;
16318 }
16319
16320 static gboolean
16321 gtk_tree_view_set_tooltip_query_cb (GtkWidget  *widget,
16322                                     gint        x,
16323                                     gint        y,
16324                                     gboolean    keyboard_tip,
16325                                     GtkTooltip *tooltip,
16326                                     gpointer    data)
16327 {
16328   GValue value = { 0, };
16329   GValue transformed = { 0, };
16330   GtkTreeIter iter;
16331   GtkTreePath *path;
16332   GtkTreeModel *model;
16333   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
16334
16335   if (!gtk_tree_view_get_tooltip_context (GTK_TREE_VIEW (widget),
16336                                           &x, &y,
16337                                           keyboard_tip,
16338                                           &model, &path, &iter))
16339     return FALSE;
16340
16341   gtk_tree_model_get_value (model, &iter,
16342                             tree_view->priv->tooltip_column, &value);
16343
16344   g_value_init (&transformed, G_TYPE_STRING);
16345
16346   if (!g_value_transform (&value, &transformed))
16347     {
16348       g_value_unset (&value);
16349       gtk_tree_path_free (path);
16350
16351       return FALSE;
16352     }
16353
16354   g_value_unset (&value);
16355
16356   if (!g_value_get_string (&transformed))
16357     {
16358       g_value_unset (&transformed);
16359       gtk_tree_path_free (path);
16360
16361       return FALSE;
16362     }
16363
16364   gtk_tooltip_set_markup (tooltip, g_value_get_string (&transformed));
16365   gtk_tree_view_set_tooltip_row (tree_view, tooltip, path);
16366
16367   gtk_tree_path_free (path);
16368   g_value_unset (&transformed);
16369
16370   return TRUE;
16371 }
16372
16373 /**
16374  * gtk_tree_view_set_tooltip_column:
16375  * @tree_view: a #GtkTreeView
16376  * @column: an integer, which is a valid column number for @tree_view's model
16377  *
16378  * If you only plan to have simple (text-only) tooltips on full rows, you
16379  * can use this function to have #GtkTreeView handle these automatically
16380  * for you. @column should be set to the column in @tree_view's model
16381  * containing the tooltip texts, or -1 to disable this feature.
16382  *
16383  * When enabled, #GtkWidget::has-tooltip will be set to %TRUE and
16384  * @tree_view will connect a #GtkWidget::query-tooltip signal handler.
16385  *
16386  * Note that the signal handler sets the text with gtk_tooltip_set_markup(),
16387  * so &amp;, &lt;, etc have to be escaped in the text.
16388  *
16389  * Since: 2.12
16390  */
16391 void
16392 gtk_tree_view_set_tooltip_column (GtkTreeView *tree_view,
16393                                   gint         column)
16394 {
16395   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
16396
16397   if (column == tree_view->priv->tooltip_column)
16398     return;
16399
16400   if (column == -1)
16401     {
16402       g_signal_handlers_disconnect_by_func (tree_view,
16403                                             gtk_tree_view_set_tooltip_query_cb,
16404                                             NULL);
16405       gtk_widget_set_has_tooltip (GTK_WIDGET (tree_view), FALSE);
16406     }
16407   else
16408     {
16409       if (tree_view->priv->tooltip_column == -1)
16410         {
16411           g_signal_connect (tree_view, "query-tooltip",
16412                             G_CALLBACK (gtk_tree_view_set_tooltip_query_cb), NULL);
16413           gtk_widget_set_has_tooltip (GTK_WIDGET (tree_view), TRUE);
16414         }
16415     }
16416
16417   tree_view->priv->tooltip_column = column;
16418   g_object_notify (G_OBJECT (tree_view), "tooltip-column");
16419 }
16420
16421 /**
16422  * gtk_tree_view_get_tooltip_column:
16423  * @tree_view: a #GtkTreeView
16424  *
16425  * Returns the column of @tree_view's model which is being used for
16426  * displaying tooltips on @tree_view's rows.
16427  *
16428  * Return value: the index of the tooltip column that is currently being
16429  * used, or -1 if this is disabled.
16430  *
16431  * Since: 2.12
16432  */
16433 gint
16434 gtk_tree_view_get_tooltip_column (GtkTreeView *tree_view)
16435 {
16436   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
16437
16438   return tree_view->priv->tooltip_column;
16439 }