]> Pileus Git - ~andy/gtk/blob - gtk/gtktreeview.c
tree-view: add back gtk_style_context_set_background()
[~andy/gtk] / gtk / gtktreeview.c
1 /* gtktreeview.c
2  * Copyright (C) 2000  Red Hat, Inc.,  Jonathan Blandford <jrb@redhat.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
16  */
17
18
19 #include "config.h"
20
21 #include <math.h>
22 #include <string.h>
23
24 #include "gtktreeview.h"
25
26 #include "gtkadjustment.h"
27 #include "gtkrbtree.h"
28 #include "gtktreednd.h"
29 #include "gtktreeprivate.h"
30 #include "gtkcellrenderer.h"
31 #include "gtkmarshalers.h"
32 #include "gtkbuildable.h"
33 #include "gtkbutton.h"
34 #include "gtklabel.h"
35 #include "gtkbox.h"
36 #include "gtkarrow.h"
37 #include "gtkintl.h"
38 #include "gtkbindings.h"
39 #include "gtkcontainer.h"
40 #include "gtkentry.h"
41 #include "gtkframe.h"
42 #include "gtkmain.h"
43 #include "gtktreemodelsort.h"
44 #include "gtktooltip.h"
45 #include "gtkscrollable.h"
46 #include "gtkcelllayout.h"
47 #include "gtkprivate.h"
48 #include "gtkwidgetprivate.h"
49 #include "gtkentryprivate.h"
50 #include "gtkstylecontextprivate.h"
51 #include "gtkcssstylepropertyprivate.h"
52 #include "gtktypebuiltins.h"
53 #include "gtkmain.h"
54 #include "gtksettings.h"
55 #include "gtkwidgetpath.h"
56 #include "a11y/gtktreeviewaccessibleprivate.h"
57
58
59 /**
60  * SECTION:gtktreeview
61  * @Short_description: A widget for displaying both trees and lists
62  * @Title: GtkTreeView
63  * @See_also: #GtkTreeViewColumn, #GtkTreeSelection, #GtkTreeDnd, #GtkTreeMode,
64  *   #GtkTreeSortable, #GtkTreeModelSort, #GtkListStore, #GtkTreeStore,
65  *   #GtkCellRenderer, #GtkCellEditable, #GtkCellRendererPixbuf,
66  *   #GtkCellRendererText, #GtkCellRendererToggle
67  *
68  * Widget that displays any object that implements the #GtkTreeModel interface.
69  *
70  * Please refer to the <link linkend="TreeWidget">tree widget conceptual
71  * overview</link> for an overview of all the objects and data types related
72  * to the tree widget and how they work together.
73  *
74  * Several different coordinate systems are exposed in the GtkTreeView API.
75  * These are:
76  *
77  * <inlinegraphic fileref="tree-view-coordinates.png" format="PNG"></inlinegraphic>
78  * <variablelist><title>Coordinate systems in GtkTreeView API</title>
79  * <varlistentry><term>Widget coordinates</term>
80  * <listitem>
81  * <para>
82  * Coordinates relative to the widget (usually <literal>widget->window</literal>).
83  * </para>
84  * </listitem>
85  * </varlistentry>
86  * <varlistentry><term>Bin window coordinates</term>
87  * <listitem>
88  * <para>
89  * Coordinates relative to the window that GtkTreeView renders to.
90  * </para>
91  * </listitem>
92  * </varlistentry>
93  * <varlistentry><term>Tree coordinates</term>
94  * <listitem>
95  * <para>
96  * Coordinates relative to the entire scrollable area of GtkTreeView. These
97  * coordinates start at (0, 0) for row 0 of the tree.
98  * </para>
99  * </listitem>
100  * </varlistentry>
101  * </variablelist>
102  *
103  * Several functions are available for converting between the different
104  * coordinate systems.  The most common translations are between widget and bin
105  * window coordinates and between bin window and tree coordinates. For the
106  * former you can use gtk_tree_view_convert_widget_to_bin_window_coords()
107  * (and vice versa), for the latter gtk_tree_view_convert_bin_window_to_tree_coords()
108  * (and vice versa).
109  *
110  * <refsect2 id="GtkTreeView-BUILDER-UI">
111  * <title>GtkTreeView as GtkBuildable</title>
112  * The GtkTreeView implementation of the GtkBuildable interface accepts
113  * #GtkTreeViewColumn objects as &lt;child&gt; elements and exposes the
114  * internal #GtkTreeSelection in UI definitions.
115  * <example>
116  * <title>A UI definition fragment with GtkTreeView</title>
117  * <programlisting><![CDATA[
118  * <object class="GtkTreeView" id="treeview">
119  *   <property name="model">liststore1</property>
120  *   <child>
121  *     <object class="GtkTreeViewColumn" id="test-column">
122  *       <property name="title">Test</property>
123  *       <child>
124  *         <object class="GtkCellRendererText" id="test-renderer"/>
125  *         <attributes>
126  *           <attribute name="text">1</attribute>
127  *         </attributes>
128  *       </child>
129  *     </object>
130  *   </child>
131  *   <child internal-child="selection">
132  *     <object class="GtkTreeSelection" id="selection">
133  *       <signal name="changed" handler="on_treeview_selection_changed"/>
134  *     </object>
135  *   </child>
136  * </object>
137  * ]]></programlisting>
138  * </example>
139  * </refsect2>
140  */
141
142 enum
143 {
144   DRAG_COLUMN_WINDOW_STATE_UNSET = 0,
145   DRAG_COLUMN_WINDOW_STATE_ORIGINAL = 1,
146   DRAG_COLUMN_WINDOW_STATE_ARROW = 2,
147   DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT = 3,
148   DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT = 4
149 };
150
151 enum
152 {
153   RUBBER_BAND_OFF = 0,
154   RUBBER_BAND_MAYBE_START = 1,
155   RUBBER_BAND_ACTIVE = 2
156 };
157
158 typedef enum {
159   CLEAR_AND_SELECT = (1 << 0),
160   CLAMP_NODE       = (1 << 1),
161   CURSOR_INVALID   = (1 << 2)
162 } SetCursorFlags;
163
164  /* This lovely little value is used to determine how far away from the title bar
165   * you can move the mouse and still have a column drag work.
166   */
167 #define TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER(tree_view) (10*gtk_tree_view_get_effective_header_height(tree_view))
168
169 #ifdef __GNUC__
170
171 #define TREE_VIEW_INTERNAL_ASSERT(expr, ret)     G_STMT_START{          \
172      if (!(expr))                                                       \
173        {                                                                \
174          g_log (G_LOG_DOMAIN,                                           \
175                 G_LOG_LEVEL_CRITICAL,                                   \
176                 "%s (%s): assertion `%s' failed.\n"                     \
177                 "There is a disparity between the internal view of the GtkTreeView,\n"    \
178                 "and the GtkTreeModel.  This generally means that the model has changed\n"\
179                 "without letting the view know.  Any display from now on is likely to\n"  \
180                 "be incorrect.\n",                                                        \
181                 G_STRLOC,                                               \
182                 G_STRFUNC,                                              \
183                 #expr);                                                 \
184          return ret;                                                    \
185        };                               }G_STMT_END
186
187 #define TREE_VIEW_INTERNAL_ASSERT_VOID(expr)     G_STMT_START{          \
188      if (!(expr))                                                       \
189        {                                                                \
190          g_log (G_LOG_DOMAIN,                                           \
191                 G_LOG_LEVEL_CRITICAL,                                   \
192                 "%s (%s): assertion `%s' failed.\n"                     \
193                 "There is a disparity between the internal view of the GtkTreeView,\n"    \
194                 "and the GtkTreeModel.  This generally means that the model has changed\n"\
195                 "without letting the view know.  Any display from now on is likely to\n"  \
196                 "be incorrect.\n",                                                        \
197                 G_STRLOC,                                               \
198                 G_STRFUNC,                                              \
199                 #expr);                                                 \
200          return;                                                        \
201        };                               }G_STMT_END
202
203 #else
204
205 #define TREE_VIEW_INTERNAL_ASSERT(expr, ret)     G_STMT_START{          \
206      if (!(expr))                                                       \
207        {                                                                \
208          g_log (G_LOG_DOMAIN,                                           \
209                 G_LOG_LEVEL_CRITICAL,                                   \
210                 "file %s: line %d: assertion `%s' failed.\n"       \
211                 "There is a disparity between the internal view of the GtkTreeView,\n"    \
212                 "and the GtkTreeModel.  This generally means that the model has changed\n"\
213                 "without letting the view know.  Any display from now on is likely to\n"  \
214                 "be incorrect.\n",                                                        \
215                 __FILE__,                                               \
216                 __LINE__,                                               \
217                 #expr);                                                 \
218          return ret;                                                    \
219        };                               }G_STMT_END
220
221 #define TREE_VIEW_INTERNAL_ASSERT_VOID(expr)     G_STMT_START{          \
222      if (!(expr))                                                       \
223        {                                                                \
224          g_log (G_LOG_DOMAIN,                                           \
225                 G_LOG_LEVEL_CRITICAL,                                   \
226                 "file %s: line %d: assertion '%s' failed.\n"            \
227                 "There is a disparity between the internal view of the GtkTreeView,\n"    \
228                 "and the GtkTreeModel.  This generally means that the model has changed\n"\
229                 "without letting the view know.  Any display from now on is likely to\n"  \
230                 "be incorrect.\n",                                                        \
231                 __FILE__,                                               \
232                 __LINE__,                                               \
233                 #expr);                                                 \
234          return;                                                        \
235        };                               }G_STMT_END
236 #endif
237
238 #define GTK_TREE_VIEW_PRIORITY_VALIDATE (GDK_PRIORITY_REDRAW + 5)
239 #define GTK_TREE_VIEW_PRIORITY_SCROLL_SYNC (GTK_TREE_VIEW_PRIORITY_VALIDATE + 2)
240 #define GTK_TREE_VIEW_TIME_MS_PER_IDLE 30
241 #define SCROLL_EDGE_SIZE 15
242 #define EXPANDER_EXTRA_PADDING 4
243 #define GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT 5000
244 #define AUTO_EXPAND_TIMEOUT 500
245
246 /* Translate from bin_window coordinates to rbtree (tree coordinates) and
247  * vice versa.
248  */
249 #define TREE_WINDOW_Y_TO_RBTREE_Y(tree_view,y) ((y) + tree_view->priv->dy)
250 #define RBTREE_Y_TO_TREE_WINDOW_Y(tree_view,y) ((y) - tree_view->priv->dy)
251
252 typedef struct _GtkTreeViewColumnReorder GtkTreeViewColumnReorder;
253 struct _GtkTreeViewColumnReorder
254 {
255   gint left_align;
256   gint right_align;
257   GtkTreeViewColumn *left_column;
258   GtkTreeViewColumn *right_column;
259 };
260
261 typedef struct _GtkTreeViewChild GtkTreeViewChild;
262 struct _GtkTreeViewChild
263 {
264   GtkWidget *widget;
265   gint x;
266   gint y;
267   gint width;
268   gint height;
269 };
270
271
272 typedef struct _TreeViewDragInfo TreeViewDragInfo;
273 struct _TreeViewDragInfo
274 {
275   GdkModifierType start_button_mask;
276   GtkTargetList *_unused_source_target_list;
277   GdkDragAction source_actions;
278
279   GtkTargetList *_unused_dest_target_list;
280
281   guint source_set : 1;
282   guint dest_set : 1;
283 };
284
285
286 struct _GtkTreeViewPrivate
287 {
288   GtkTreeModel *model;
289
290   /* tree information */
291   GtkRBTree *tree;
292
293   /* Container info */
294   GList *children;
295   gint width;
296   gint height;
297
298   /* Adjustments */
299   GtkAdjustment *hadjustment;
300   GtkAdjustment *vadjustment;
301   gint           min_display_width;
302   gint           min_display_height;
303
304   /* Sub windows */
305   GdkWindow *bin_window;
306   GdkWindow *header_window;
307
308   /* Scroll position state keeping */
309   GtkTreeRowReference *top_row;
310   gint top_row_dy;
311   /* dy == y pos of top_row + top_row_dy */
312   /* we cache it for simplicity of the code */
313   gint dy;
314
315   guint presize_handler_timer;
316   guint validate_rows_timer;
317   guint scroll_sync_timer;
318
319   /* Indentation and expander layout */
320   GtkTreeViewColumn *expander_column;
321
322   gint level_indentation;
323
324   /* Key navigation (focus), selection */
325   gint cursor_offset;
326
327   GtkTreeRowReference *anchor;
328   GtkRBNode *cursor_node;
329   GtkRBTree *cursor_tree;
330
331   GtkTreeViewColumn *focus_column;
332
333   /* Current pressed node, previously pressed, prelight */
334   GtkRBNode *button_pressed_node;
335   GtkRBTree *button_pressed_tree;
336
337   gint pressed_button;
338   gint press_start_x;
339   gint press_start_y;
340
341   gint event_last_x;
342   gint event_last_y;
343
344   guint last_button_time;
345   gint last_button_x;
346   gint last_button_y;
347
348   GtkRBNode *prelight_node;
349   GtkRBTree *prelight_tree;
350
351   /* Cell Editing */
352   GtkTreeViewColumn *edited_column;
353
354   /* The node that's currently being collapsed or expanded */
355   GtkRBNode *expanded_collapsed_node;
356   GtkRBTree *expanded_collapsed_tree;
357   guint expand_collapse_timeout;
358
359   /* Auto expand/collapse timeout in hover mode */
360   guint auto_expand_timeout;
361
362   /* Selection information */
363   GtkTreeSelection *selection;
364
365   /* Header information */
366   gint n_columns;
367   GList *columns;
368   gint header_height;
369
370   GtkTreeViewColumnDropFunc column_drop_func;
371   gpointer column_drop_func_data;
372   GDestroyNotify column_drop_func_data_destroy;
373   GList *column_drag_info;
374   GtkTreeViewColumnReorder *cur_reorder;
375
376   gint prev_width_before_expander;
377
378   /* Interactive Header reordering */
379   GdkWindow *drag_window;
380   GdkWindow *drag_highlight_window;
381   GtkTreeViewColumn *drag_column;
382   gint drag_column_x;
383
384   /* Interactive Header Resizing */
385   gint drag_pos;
386   gint x_drag;
387
388   /* Column width allocation */
389   gint minimum_width;
390   gint natural_width;
391   gint n_expand_columns;
392
393   /* ATK Hack */
394   GtkTreeDestroyCountFunc destroy_count_func;
395   gpointer destroy_count_data;
396   GDestroyNotify destroy_count_destroy;
397
398   /* Scroll timeout (e.g. during dnd, rubber banding) */
399   guint scroll_timeout;
400
401   /* Row drag-and-drop */
402   GtkTreeRowReference *drag_dest_row;
403   GtkTreeViewDropPosition drag_dest_pos;
404   guint open_dest_timeout;
405
406   /* Rubber banding */
407   gint rubber_band_status;
408   gint rubber_band_x;
409   gint rubber_band_y;
410   gint rubber_band_extend;
411   gint rubber_band_modify;
412
413   GtkRBNode *rubber_band_start_node;
414   GtkRBTree *rubber_band_start_tree;
415
416   GtkRBNode *rubber_band_end_node;
417   GtkRBTree *rubber_band_end_tree;
418
419   /* fixed height */
420   gint fixed_height;
421
422   /* Scroll-to functionality when unrealized */
423   GtkTreeRowReference *scroll_to_path;
424   GtkTreeViewColumn *scroll_to_column;
425   gfloat scroll_to_row_align;
426   gfloat scroll_to_col_align;
427
428   /* Interactive search */
429   gint selected_iter;
430   gint search_column;
431   GtkTreeViewSearchPositionFunc search_position_func;
432   GtkTreeViewSearchEqualFunc search_equal_func;
433   gpointer search_user_data;
434   GDestroyNotify search_destroy;
435   gpointer search_position_user_data;
436   GDestroyNotify search_position_destroy;
437   GtkWidget *search_window;
438   GtkWidget *search_entry;
439   gulong search_entry_changed_id;
440   guint typeselect_flush_timeout;
441
442   /* Grid and tree lines */
443   GtkTreeViewGridLines grid_lines;
444   double grid_line_dashes[2];
445   int grid_line_width;
446
447   gboolean tree_lines_enabled;
448   double tree_line_dashes[2];
449   int tree_line_width;
450
451   /* Row separators */
452   GtkTreeViewRowSeparatorFunc row_separator_func;
453   gpointer row_separator_data;
454   GDestroyNotify row_separator_destroy;
455
456   /* Tooltip support */
457   gint tooltip_column;
458
459   /* Here comes the bitfield */
460   guint scroll_to_use_align : 1;
461
462   guint fixed_height_mode : 1;
463   guint fixed_height_check : 1;
464
465   guint activate_on_single_click : 1;
466   guint reorderable : 1;
467   guint header_has_focus : 1;
468   guint drag_column_window_state : 3;
469   /* hint to display rows in alternating colors */
470   guint has_rules : 1;
471   guint mark_rows_col_dirty : 1;
472
473   /* for DnD */
474   guint empty_view_drop : 1;
475
476   guint modify_selection_pressed : 1;
477   guint extend_selection_pressed : 1;
478
479   guint init_hadjust_value : 1;
480
481   guint in_top_row_to_dy : 1;
482
483   /* interactive search */
484   guint enable_search : 1;
485   guint disable_popdown : 1;
486   guint search_custom_entry_set : 1;
487   
488   guint hover_selection : 1;
489   guint hover_expand : 1;
490   guint imcontext_changed : 1;
491
492   guint rubber_banding_enable : 1;
493
494   guint in_grab : 1;
495
496   /* Whether our key press handler is to avoid sending an unhandled binding to the search entry */
497   guint search_entry_avoid_unhandled_binding : 1;
498
499   /* GtkScrollablePolicy needs to be checked when
500    * driving the scrollable adjustment values */
501   guint hscroll_policy : 1;
502   guint vscroll_policy : 1;
503
504   /* GtkTreeView flags */
505   guint is_list : 1;
506   guint show_expanders : 1;
507   guint in_column_resize : 1;
508   guint arrow_prelit : 1;
509   guint headers_visible : 1;
510   guint draw_keyfocus : 1;
511   guint model_setup : 1;
512   guint in_column_drag : 1;
513 };
514
515
516 /* Signals */
517 enum
518 {
519   ROW_ACTIVATED,
520   TEST_EXPAND_ROW,
521   TEST_COLLAPSE_ROW,
522   ROW_EXPANDED,
523   ROW_COLLAPSED,
524   COLUMNS_CHANGED,
525   CURSOR_CHANGED,
526   MOVE_CURSOR,
527   SELECT_ALL,
528   UNSELECT_ALL,
529   SELECT_CURSOR_ROW,
530   TOGGLE_CURSOR_ROW,
531   EXPAND_COLLAPSE_CURSOR_ROW,
532   SELECT_CURSOR_PARENT,
533   START_INTERACTIVE_SEARCH,
534   LAST_SIGNAL
535 };
536
537 /* Properties */
538 enum {
539   PROP_0,
540   PROP_MODEL,
541   PROP_HADJUSTMENT,
542   PROP_VADJUSTMENT,
543   PROP_HSCROLL_POLICY,
544   PROP_VSCROLL_POLICY,
545   PROP_HEADERS_VISIBLE,
546   PROP_HEADERS_CLICKABLE,
547   PROP_EXPANDER_COLUMN,
548   PROP_REORDERABLE,
549   PROP_RULES_HINT,
550   PROP_ENABLE_SEARCH,
551   PROP_SEARCH_COLUMN,
552   PROP_FIXED_HEIGHT_MODE,
553   PROP_HOVER_SELECTION,
554   PROP_HOVER_EXPAND,
555   PROP_SHOW_EXPANDERS,
556   PROP_LEVEL_INDENTATION,
557   PROP_RUBBER_BANDING,
558   PROP_ENABLE_GRID_LINES,
559   PROP_ENABLE_TREE_LINES,
560   PROP_TOOLTIP_COLUMN,
561   PROP_ACTIVATE_ON_SINGLE_CLICK
562 };
563
564 /* object signals */
565 static void     gtk_tree_view_finalize             (GObject          *object);
566 static void     gtk_tree_view_set_property         (GObject         *object,
567                                                     guint            prop_id,
568                                                     const GValue    *value,
569                                                     GParamSpec      *pspec);
570 static void     gtk_tree_view_get_property         (GObject         *object,
571                                                     guint            prop_id,
572                                                     GValue          *value,
573                                                     GParamSpec      *pspec);
574
575 /* gtkwidget signals */
576 static void     gtk_tree_view_destroy              (GtkWidget        *widget);
577 static void     gtk_tree_view_realize              (GtkWidget        *widget);
578 static void     gtk_tree_view_unrealize            (GtkWidget        *widget);
579 static void     gtk_tree_view_map                  (GtkWidget        *widget);
580 static void     gtk_tree_view_get_preferred_width  (GtkWidget        *widget,
581                                                     gint             *minimum,
582                                                     gint             *natural);
583 static void     gtk_tree_view_get_preferred_height (GtkWidget        *widget,
584                                                     gint             *minimum,
585                                                     gint             *natural);
586 static void     gtk_tree_view_size_allocate        (GtkWidget        *widget,
587                                                     GtkAllocation    *allocation);
588 static gboolean gtk_tree_view_draw                 (GtkWidget        *widget,
589                                                     cairo_t          *cr);
590 static gboolean gtk_tree_view_key_press            (GtkWidget        *widget,
591                                                     GdkEventKey      *event);
592 static gboolean gtk_tree_view_key_release          (GtkWidget        *widget,
593                                                     GdkEventKey      *event);
594 static gboolean gtk_tree_view_motion               (GtkWidget        *widget,
595                                                     GdkEventMotion   *event);
596 static gboolean gtk_tree_view_enter_notify         (GtkWidget        *widget,
597                                                     GdkEventCrossing *event);
598 static gboolean gtk_tree_view_leave_notify         (GtkWidget        *widget,
599                                                     GdkEventCrossing *event);
600 static gboolean gtk_tree_view_button_press         (GtkWidget        *widget,
601                                                     GdkEventButton   *event);
602 static gboolean gtk_tree_view_button_release       (GtkWidget        *widget,
603                                                     GdkEventButton   *event);
604 static gboolean gtk_tree_view_grab_broken          (GtkWidget          *widget,
605                                                     GdkEventGrabBroken *event);
606 #if 0
607 static gboolean gtk_tree_view_configure            (GtkWidget         *widget,
608                                                     GdkEventConfigure *event);
609 #endif
610
611 static GtkWidgetPath * gtk_tree_view_get_path_for_child (GtkContainer *container,
612                                                          GtkWidget    *child);
613
614 static void     gtk_tree_view_set_focus_child      (GtkContainer     *container,
615                                                     GtkWidget        *child);
616 static gint     gtk_tree_view_focus_out            (GtkWidget        *widget,
617                                                     GdkEventFocus    *event);
618 static gint     gtk_tree_view_focus                (GtkWidget        *widget,
619                                                     GtkDirectionType  direction);
620 static void     gtk_tree_view_grab_focus           (GtkWidget        *widget);
621 static void     gtk_tree_view_style_updated        (GtkWidget        *widget);
622 static void     gtk_tree_view_grab_notify          (GtkWidget        *widget,
623                                                     gboolean          was_grabbed);
624 static void     gtk_tree_view_state_flags_changed  (GtkWidget        *widget,
625                                                     GtkStateFlags     previous_state);
626
627 /* container signals */
628 static void     gtk_tree_view_remove               (GtkContainer     *container,
629                                                     GtkWidget        *widget);
630 static void     gtk_tree_view_forall               (GtkContainer     *container,
631                                                     gboolean          include_internals,
632                                                     GtkCallback       callback,
633                                                     gpointer          callback_data);
634
635 /* Source side drag signals */
636 static void gtk_tree_view_drag_begin       (GtkWidget        *widget,
637                                             GdkDragContext   *context);
638 static void gtk_tree_view_drag_end         (GtkWidget        *widget,
639                                             GdkDragContext   *context);
640 static void gtk_tree_view_drag_data_get    (GtkWidget        *widget,
641                                             GdkDragContext   *context,
642                                             GtkSelectionData *selection_data,
643                                             guint             info,
644                                             guint             time);
645 static void gtk_tree_view_drag_data_delete (GtkWidget        *widget,
646                                             GdkDragContext   *context);
647
648 /* Target side drag signals */
649 static void     gtk_tree_view_drag_leave         (GtkWidget        *widget,
650                                                   GdkDragContext   *context,
651                                                   guint             time);
652 static gboolean gtk_tree_view_drag_motion        (GtkWidget        *widget,
653                                                   GdkDragContext   *context,
654                                                   gint              x,
655                                                   gint              y,
656                                                   guint             time);
657 static gboolean gtk_tree_view_drag_drop          (GtkWidget        *widget,
658                                                   GdkDragContext   *context,
659                                                   gint              x,
660                                                   gint              y,
661                                                   guint             time);
662 static void     gtk_tree_view_drag_data_received (GtkWidget        *widget,
663                                                   GdkDragContext   *context,
664                                                   gint              x,
665                                                   gint              y,
666                                                   GtkSelectionData *selection_data,
667                                                   guint             info,
668                                                   guint             time);
669
670 /* tree_model signals */
671 static gboolean gtk_tree_view_real_move_cursor            (GtkTreeView     *tree_view,
672                                                            GtkMovementStep  step,
673                                                            gint             count);
674 static gboolean gtk_tree_view_real_select_all             (GtkTreeView     *tree_view);
675 static gboolean gtk_tree_view_real_unselect_all           (GtkTreeView     *tree_view);
676 static gboolean gtk_tree_view_real_select_cursor_row      (GtkTreeView     *tree_view,
677                                                            gboolean         start_editing);
678 static gboolean gtk_tree_view_real_toggle_cursor_row      (GtkTreeView     *tree_view);
679 static gboolean gtk_tree_view_real_expand_collapse_cursor_row (GtkTreeView     *tree_view,
680                                                                gboolean         logical,
681                                                                gboolean         expand,
682                                                                gboolean         open_all);
683 static gboolean gtk_tree_view_real_select_cursor_parent   (GtkTreeView     *tree_view);
684 static void gtk_tree_view_row_changed                     (GtkTreeModel    *model,
685                                                            GtkTreePath     *path,
686                                                            GtkTreeIter     *iter,
687                                                            gpointer         data);
688 static void gtk_tree_view_row_inserted                    (GtkTreeModel    *model,
689                                                            GtkTreePath     *path,
690                                                            GtkTreeIter     *iter,
691                                                            gpointer         data);
692 static void gtk_tree_view_row_has_child_toggled           (GtkTreeModel    *model,
693                                                            GtkTreePath     *path,
694                                                            GtkTreeIter     *iter,
695                                                            gpointer         data);
696 static void gtk_tree_view_row_deleted                     (GtkTreeModel    *model,
697                                                            GtkTreePath     *path,
698                                                            gpointer         data);
699 static void gtk_tree_view_rows_reordered                  (GtkTreeModel    *model,
700                                                            GtkTreePath     *parent,
701                                                            GtkTreeIter     *iter,
702                                                            gint            *new_order,
703                                                            gpointer         data);
704
705 /* Incremental reflow */
706 static gboolean validate_row             (GtkTreeView *tree_view,
707                                           GtkRBTree   *tree,
708                                           GtkRBNode   *node,
709                                           GtkTreeIter *iter,
710                                           GtkTreePath *path);
711 static void     validate_visible_area    (GtkTreeView *tree_view);
712 static gboolean validate_rows_handler    (GtkTreeView *tree_view);
713 static gboolean do_validate_rows         (GtkTreeView *tree_view,
714                                           gboolean     queue_resize);
715 static gboolean validate_rows            (GtkTreeView *tree_view);
716 static gboolean presize_handler_callback (gpointer     data);
717 static void     install_presize_handler  (GtkTreeView *tree_view);
718 static void     install_scroll_sync_handler (GtkTreeView *tree_view);
719 static void     gtk_tree_view_set_top_row   (GtkTreeView *tree_view,
720                                              GtkTreePath *path,
721                                              gint         offset);
722 static void     gtk_tree_view_dy_to_top_row (GtkTreeView *tree_view);
723 static void     gtk_tree_view_top_row_to_dy (GtkTreeView *tree_view);
724 static void     invalidate_empty_focus      (GtkTreeView *tree_view);
725
726 /* Internal functions */
727 static gboolean gtk_tree_view_is_expander_column             (GtkTreeView        *tree_view,
728                                                               GtkTreeViewColumn  *column);
729 static inline gboolean gtk_tree_view_draw_expanders          (GtkTreeView        *tree_view);
730 static void     gtk_tree_view_add_move_binding               (GtkBindingSet      *binding_set,
731                                                               guint               keyval,
732                                                               guint               modmask,
733                                                               gboolean            add_shifted_binding,
734                                                               GtkMovementStep     step,
735                                                               gint                count);
736 static gint     gtk_tree_view_unref_and_check_selection_tree (GtkTreeView        *tree_view,
737                                                               GtkRBTree          *tree);
738 static void     gtk_tree_view_queue_draw_path                (GtkTreeView        *tree_view,
739                                                               GtkTreePath        *path,
740                                                               const GdkRectangle *clip_rect);
741 static void     gtk_tree_view_queue_draw_arrow               (GtkTreeView        *tree_view,
742                                                               GtkRBTree          *tree,
743                                                               GtkRBNode          *node);
744 static void     gtk_tree_view_draw_arrow                     (GtkTreeView        *tree_view,
745                                                               cairo_t            *cr,
746                                                               GtkRBTree          *tree,
747                                                               GtkRBNode          *node);
748 static void     gtk_tree_view_get_arrow_xrange               (GtkTreeView        *tree_view,
749                                                               GtkRBTree          *tree,
750                                                               gint               *x1,
751                                                               gint               *x2);
752 static void     gtk_tree_view_adjustment_changed             (GtkAdjustment      *adjustment,
753                                                               GtkTreeView        *tree_view);
754 static void     gtk_tree_view_build_tree                     (GtkTreeView        *tree_view,
755                                                               GtkRBTree          *tree,
756                                                               GtkTreeIter        *iter,
757                                                               gint                depth,
758                                                               gboolean            recurse);
759 static void     gtk_tree_view_clamp_node_visible             (GtkTreeView        *tree_view,
760                                                               GtkRBTree          *tree,
761                                                               GtkRBNode          *node);
762 static void     gtk_tree_view_clamp_column_visible           (GtkTreeView        *tree_view,
763                                                               GtkTreeViewColumn  *column,
764                                                               gboolean            focus_to_cell);
765 static gboolean gtk_tree_view_maybe_begin_dragging_row       (GtkTreeView        *tree_view,
766                                                               GdkEventMotion     *event);
767 static void     gtk_tree_view_focus_to_cursor                (GtkTreeView        *tree_view);
768 static void     gtk_tree_view_move_cursor_up_down            (GtkTreeView        *tree_view,
769                                                               gint                count);
770 static void     gtk_tree_view_move_cursor_page_up_down       (GtkTreeView        *tree_view,
771                                                               gint                count);
772 static void     gtk_tree_view_move_cursor_left_right         (GtkTreeView        *tree_view,
773                                                               gint                count);
774 static void     gtk_tree_view_move_cursor_start_end          (GtkTreeView        *tree_view,
775                                                               gint                count);
776 static gboolean gtk_tree_view_real_collapse_row              (GtkTreeView        *tree_view,
777                                                               GtkTreePath        *path,
778                                                               GtkRBTree          *tree,
779                                                               GtkRBNode          *node,
780                                                               gboolean            animate);
781 static gboolean gtk_tree_view_real_expand_row                (GtkTreeView        *tree_view,
782                                                               GtkTreePath        *path,
783                                                               GtkRBTree          *tree,
784                                                               GtkRBNode          *node,
785                                                               gboolean            open_all,
786                                                               gboolean            animate);
787 static void     gtk_tree_view_real_set_cursor                (GtkTreeView        *tree_view,
788                                                               GtkTreePath        *path,
789                                                               SetCursorFlags      flags);
790 static gboolean gtk_tree_view_has_can_focus_cell             (GtkTreeView        *tree_view);
791 static void     column_sizing_notify                         (GObject            *object,
792                                                               GParamSpec         *pspec,
793                                                               gpointer            data);
794 static void     gtk_tree_view_stop_rubber_band               (GtkTreeView        *tree_view);
795 static void     update_prelight                              (GtkTreeView        *tree_view,
796                                                               int                 x,
797                                                               int                 y);
798
799 static inline gint gtk_tree_view_get_effective_header_height (GtkTreeView *tree_view);
800
801 static inline gint gtk_tree_view_get_cell_area_y_offset      (GtkTreeView *tree_view,
802                                                               GtkRBTree   *tree,
803                                                               GtkRBNode   *node,
804                                                               gint         vertical_separator);
805 static inline gint gtk_tree_view_get_cell_area_height        (GtkTreeView *tree_view,
806                                                               GtkRBNode   *node,
807                                                               gint         vertical_separator);
808
809 static inline gint gtk_tree_view_get_row_y_offset            (GtkTreeView *tree_view,
810                                                               GtkRBTree   *tree,
811                                                               GtkRBNode   *node);
812 static inline gint gtk_tree_view_get_row_height              (GtkTreeView *tree_view,
813                                                               GtkRBNode   *node);
814
815 /* interactive search */
816 static void     gtk_tree_view_ensure_interactive_directory (GtkTreeView *tree_view);
817 static void     gtk_tree_view_search_dialog_hide        (GtkWidget        *search_dialog,
818                                                          GtkTreeView      *tree_view,
819                                                          GdkDevice        *device);
820 static void     gtk_tree_view_search_position_func      (GtkTreeView      *tree_view,
821                                                          GtkWidget        *search_dialog,
822                                                          gpointer          user_data);
823 static void     gtk_tree_view_search_disable_popdown    (GtkEntry         *entry,
824                                                          GtkMenu          *menu,
825                                                          gpointer          data);
826 static void     gtk_tree_view_search_preedit_changed    (GtkIMContext     *im_context,
827                                                          GtkTreeView      *tree_view);
828 static void     gtk_tree_view_search_activate           (GtkEntry         *entry,
829                                                          GtkTreeView      *tree_view);
830 static gboolean gtk_tree_view_real_search_enable_popdown(gpointer          data);
831 static void     gtk_tree_view_search_enable_popdown     (GtkWidget        *widget,
832                                                          gpointer          data);
833 static gboolean gtk_tree_view_search_delete_event       (GtkWidget        *widget,
834                                                          GdkEventAny      *event,
835                                                          GtkTreeView      *tree_view);
836 static gboolean gtk_tree_view_search_button_press_event (GtkWidget        *widget,
837                                                          GdkEventButton   *event,
838                                                          GtkTreeView      *tree_view);
839 static gboolean gtk_tree_view_search_scroll_event       (GtkWidget        *entry,
840                                                          GdkEventScroll   *event,
841                                                          GtkTreeView      *tree_view);
842 static gboolean gtk_tree_view_search_key_press_event    (GtkWidget        *entry,
843                                                          GdkEventKey      *event,
844                                                          GtkTreeView      *tree_view);
845 static gboolean gtk_tree_view_search_move               (GtkWidget        *window,
846                                                          GtkTreeView      *tree_view,
847                                                          gboolean          up);
848 static gboolean gtk_tree_view_search_equal_func         (GtkTreeModel     *model,
849                                                          gint              column,
850                                                          const gchar      *key,
851                                                          GtkTreeIter      *iter,
852                                                          gpointer          search_data);
853 static gboolean gtk_tree_view_search_iter               (GtkTreeModel     *model,
854                                                          GtkTreeSelection *selection,
855                                                          GtkTreeIter      *iter,
856                                                          const gchar      *text,
857                                                          gint             *count,
858                                                          gint              n);
859 static void     gtk_tree_view_search_init               (GtkWidget        *entry,
860                                                          GtkTreeView      *tree_view);
861 static void     gtk_tree_view_put                       (GtkTreeView      *tree_view,
862                                                          GtkWidget        *child_widget,
863                                                          gint              x,
864                                                          gint              y,
865                                                          gint              width,
866                                                          gint              height);
867 static gboolean gtk_tree_view_start_editing             (GtkTreeView      *tree_view,
868                                                          GtkTreePath      *cursor_path,
869                                                          gboolean          edit_only);
870 static void gtk_tree_view_stop_editing                  (GtkTreeView *tree_view,
871                                                          gboolean     cancel_editing);
872 static gboolean gtk_tree_view_real_start_interactive_search (GtkTreeView *tree_view,
873                                                              GdkDevice   *device,
874                                                              gboolean     keybinding);
875 static gboolean gtk_tree_view_start_interactive_search      (GtkTreeView *tree_view);
876 static GtkTreeViewColumn *gtk_tree_view_get_drop_column (GtkTreeView       *tree_view,
877                                                          GtkTreeViewColumn *column,
878                                                          gint               drop_position);
879
880 /* GtkBuildable */
881 static void     gtk_tree_view_buildable_add_child          (GtkBuildable      *tree_view,
882                                                             GtkBuilder        *builder,
883                                                             GObject           *child,
884                                                             const gchar       *type);
885 static GObject *gtk_tree_view_buildable_get_internal_child (GtkBuildable      *buildable,
886                                                             GtkBuilder        *builder,
887                                                             const gchar       *childname);
888 static void     gtk_tree_view_buildable_init               (GtkBuildableIface *iface);
889
890 static GtkAdjustment *gtk_tree_view_do_get_hadjustment (GtkTreeView   *tree_view);
891 static void           gtk_tree_view_do_set_hadjustment (GtkTreeView   *tree_view,
892                                                         GtkAdjustment *adjustment);
893 static GtkAdjustment *gtk_tree_view_do_get_vadjustment (GtkTreeView   *tree_view);
894 static void           gtk_tree_view_do_set_vadjustment (GtkTreeView   *tree_view,
895                                                         GtkAdjustment *adjustment);
896
897 static gboolean scroll_row_timeout                   (gpointer     data);
898 static void     add_scroll_timeout                   (GtkTreeView *tree_view);
899 static void     remove_scroll_timeout                (GtkTreeView *tree_view);
900
901 static guint tree_view_signals [LAST_SIGNAL] = { 0 };
902
903 \f
904
905 /* GType Methods
906  */
907
908 G_DEFINE_TYPE_WITH_CODE (GtkTreeView, gtk_tree_view, GTK_TYPE_CONTAINER,
909                          G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
910                                                 gtk_tree_view_buildable_init)
911                          G_IMPLEMENT_INTERFACE (GTK_TYPE_SCROLLABLE, NULL))
912
913 static void
914 gtk_tree_view_class_init (GtkTreeViewClass *class)
915 {
916   GObjectClass *o_class;
917   GtkWidgetClass *widget_class;
918   GtkContainerClass *container_class;
919   GtkBindingSet *binding_set;
920
921   binding_set = gtk_binding_set_by_class (class);
922
923   o_class = (GObjectClass *) class;
924   widget_class = (GtkWidgetClass *) class;
925   container_class = (GtkContainerClass *) class;
926
927   /* GObject signals */
928   o_class->set_property = gtk_tree_view_set_property;
929   o_class->get_property = gtk_tree_view_get_property;
930   o_class->finalize = gtk_tree_view_finalize;
931
932   /* GtkWidget signals */
933   widget_class->destroy = gtk_tree_view_destroy;
934   widget_class->map = gtk_tree_view_map;
935   widget_class->realize = gtk_tree_view_realize;
936   widget_class->unrealize = gtk_tree_view_unrealize;
937   widget_class->get_preferred_width = gtk_tree_view_get_preferred_width;
938   widget_class->get_preferred_height = gtk_tree_view_get_preferred_height;
939   widget_class->size_allocate = gtk_tree_view_size_allocate;
940   widget_class->button_press_event = gtk_tree_view_button_press;
941   widget_class->button_release_event = gtk_tree_view_button_release;
942   widget_class->grab_broken_event = gtk_tree_view_grab_broken;
943   /*widget_class->configure_event = gtk_tree_view_configure;*/
944   widget_class->motion_notify_event = gtk_tree_view_motion;
945   widget_class->draw = gtk_tree_view_draw;
946   widget_class->key_press_event = gtk_tree_view_key_press;
947   widget_class->key_release_event = gtk_tree_view_key_release;
948   widget_class->enter_notify_event = gtk_tree_view_enter_notify;
949   widget_class->leave_notify_event = gtk_tree_view_leave_notify;
950   widget_class->focus_out_event = gtk_tree_view_focus_out;
951   widget_class->drag_begin = gtk_tree_view_drag_begin;
952   widget_class->drag_end = gtk_tree_view_drag_end;
953   widget_class->drag_data_get = gtk_tree_view_drag_data_get;
954   widget_class->drag_data_delete = gtk_tree_view_drag_data_delete;
955   widget_class->drag_leave = gtk_tree_view_drag_leave;
956   widget_class->drag_motion = gtk_tree_view_drag_motion;
957   widget_class->drag_drop = gtk_tree_view_drag_drop;
958   widget_class->drag_data_received = gtk_tree_view_drag_data_received;
959   widget_class->focus = gtk_tree_view_focus;
960   widget_class->grab_focus = gtk_tree_view_grab_focus;
961   widget_class->style_updated = gtk_tree_view_style_updated;
962   widget_class->grab_notify = gtk_tree_view_grab_notify;
963   widget_class->state_flags_changed = gtk_tree_view_state_flags_changed;
964
965   /* GtkContainer signals */
966   container_class->remove = gtk_tree_view_remove;
967   container_class->forall = gtk_tree_view_forall;
968   container_class->set_focus_child = gtk_tree_view_set_focus_child;
969   container_class->get_path_for_child = gtk_tree_view_get_path_for_child;
970
971   class->move_cursor = gtk_tree_view_real_move_cursor;
972   class->select_all = gtk_tree_view_real_select_all;
973   class->unselect_all = gtk_tree_view_real_unselect_all;
974   class->select_cursor_row = gtk_tree_view_real_select_cursor_row;
975   class->toggle_cursor_row = gtk_tree_view_real_toggle_cursor_row;
976   class->expand_collapse_cursor_row = gtk_tree_view_real_expand_collapse_cursor_row;
977   class->select_cursor_parent = gtk_tree_view_real_select_cursor_parent;
978   class->start_interactive_search = gtk_tree_view_start_interactive_search;
979
980   /* Properties */
981
982   g_object_class_install_property (o_class,
983                                    PROP_MODEL,
984                                    g_param_spec_object ("model",
985                                                         P_("TreeView Model"),
986                                                         P_("The model for the tree view"),
987                                                         GTK_TYPE_TREE_MODEL,
988                                                         GTK_PARAM_READWRITE));
989
990   g_object_class_override_property (o_class, PROP_HADJUSTMENT,    "hadjustment");
991   g_object_class_override_property (o_class, PROP_VADJUSTMENT,    "vadjustment");
992   g_object_class_override_property (o_class, PROP_HSCROLL_POLICY, "hscroll-policy");
993   g_object_class_override_property (o_class, PROP_VSCROLL_POLICY, "vscroll-policy");
994
995   g_object_class_install_property (o_class,
996                                    PROP_HEADERS_VISIBLE,
997                                    g_param_spec_boolean ("headers-visible",
998                                                          P_("Headers Visible"),
999                                                          P_("Show the column header buttons"),
1000                                                          TRUE,
1001                                                          GTK_PARAM_READWRITE));
1002
1003   g_object_class_install_property (o_class,
1004                                    PROP_HEADERS_CLICKABLE,
1005                                    g_param_spec_boolean ("headers-clickable",
1006                                                          P_("Headers Clickable"),
1007                                                          P_("Column headers respond to click events"),
1008                                                          TRUE,
1009                                                          GTK_PARAM_READWRITE));
1010
1011   g_object_class_install_property (o_class,
1012                                    PROP_EXPANDER_COLUMN,
1013                                    g_param_spec_object ("expander-column",
1014                                                         P_("Expander Column"),
1015                                                         P_("Set the column for the expander column"),
1016                                                         GTK_TYPE_TREE_VIEW_COLUMN,
1017                                                         GTK_PARAM_READWRITE));
1018
1019   g_object_class_install_property (o_class,
1020                                    PROP_REORDERABLE,
1021                                    g_param_spec_boolean ("reorderable",
1022                                                          P_("Reorderable"),
1023                                                          P_("View is reorderable"),
1024                                                          FALSE,
1025                                                          GTK_PARAM_READWRITE));
1026
1027   g_object_class_install_property (o_class,
1028                                    PROP_RULES_HINT,
1029                                    g_param_spec_boolean ("rules-hint",
1030                                                          P_("Rules Hint"),
1031                                                          P_("Set a hint to the theme engine to draw rows in alternating colors"),
1032                                                          FALSE,
1033                                                          GTK_PARAM_READWRITE));
1034
1035     g_object_class_install_property (o_class,
1036                                      PROP_ENABLE_SEARCH,
1037                                      g_param_spec_boolean ("enable-search",
1038                                                            P_("Enable Search"),
1039                                                            P_("View allows user to search through columns interactively"),
1040                                                            TRUE,
1041                                                            GTK_PARAM_READWRITE));
1042
1043     g_object_class_install_property (o_class,
1044                                      PROP_SEARCH_COLUMN,
1045                                      g_param_spec_int ("search-column",
1046                                                        P_("Search Column"),
1047                                                        P_("Model column to search through during interactive search"),
1048                                                        -1,
1049                                                        G_MAXINT,
1050                                                        -1,
1051                                                        GTK_PARAM_READWRITE));
1052
1053     /**
1054      * GtkTreeView:fixed-height-mode:
1055      *
1056      * Setting the ::fixed-height-mode property to %TRUE speeds up 
1057      * #GtkTreeView by assuming that all rows have the same height. 
1058      * Only enable this option if all rows are the same height.  
1059      * Please see gtk_tree_view_set_fixed_height_mode() for more 
1060      * information on this option.
1061      *
1062      * Since: 2.4
1063      **/
1064     g_object_class_install_property (o_class,
1065                                      PROP_FIXED_HEIGHT_MODE,
1066                                      g_param_spec_boolean ("fixed-height-mode",
1067                                                            P_("Fixed Height Mode"),
1068                                                            P_("Speeds up GtkTreeView by assuming that all rows have the same height"),
1069                                                            FALSE,
1070                                                            GTK_PARAM_READWRITE));
1071     
1072     /**
1073      * GtkTreeView:hover-selection:
1074      * 
1075      * Enables or disables the hover selection mode of @tree_view.
1076      * Hover selection makes the selected row follow the pointer.
1077      * Currently, this works only for the selection modes 
1078      * %GTK_SELECTION_SINGLE and %GTK_SELECTION_BROWSE.
1079      *
1080      * This mode is primarily intended for treeviews in popups, e.g.
1081      * in #GtkComboBox or #GtkEntryCompletion.
1082      *
1083      * Since: 2.6
1084      */
1085     g_object_class_install_property (o_class,
1086                                      PROP_HOVER_SELECTION,
1087                                      g_param_spec_boolean ("hover-selection",
1088                                                            P_("Hover Selection"),
1089                                                            P_("Whether the selection should follow the pointer"),
1090                                                            FALSE,
1091                                                            GTK_PARAM_READWRITE));
1092
1093     /**
1094      * GtkTreeView:hover-expand:
1095      * 
1096      * Enables or disables the hover expansion mode of @tree_view.
1097      * Hover expansion makes rows expand or collapse if the pointer moves 
1098      * over them.
1099      *
1100      * This mode is primarily intended for treeviews in popups, e.g.
1101      * in #GtkComboBox or #GtkEntryCompletion.
1102      *
1103      * Since: 2.6
1104      */
1105     g_object_class_install_property (o_class,
1106                                      PROP_HOVER_EXPAND,
1107                                      g_param_spec_boolean ("hover-expand",
1108                                                            P_("Hover Expand"),
1109                                                            P_("Whether rows should be expanded/collapsed when the pointer moves over them"),
1110                                                            FALSE,
1111                                                            GTK_PARAM_READWRITE));
1112
1113     /**
1114      * GtkTreeView:show-expanders:
1115      *
1116      * %TRUE if the view has expanders.
1117      *
1118      * Since: 2.12
1119      */
1120     g_object_class_install_property (o_class,
1121                                      PROP_SHOW_EXPANDERS,
1122                                      g_param_spec_boolean ("show-expanders",
1123                                                            P_("Show Expanders"),
1124                                                            P_("View has expanders"),
1125                                                            TRUE,
1126                                                            GTK_PARAM_READWRITE));
1127
1128     /**
1129      * GtkTreeView:level-indentation:
1130      *
1131      * Extra indentation for each level.
1132      *
1133      * Since: 2.12
1134      */
1135     g_object_class_install_property (o_class,
1136                                      PROP_LEVEL_INDENTATION,
1137                                      g_param_spec_int ("level-indentation",
1138                                                        P_("Level Indentation"),
1139                                                        P_("Extra indentation for each level"),
1140                                                        0,
1141                                                        G_MAXINT,
1142                                                        0,
1143                                                        GTK_PARAM_READWRITE));
1144
1145     g_object_class_install_property (o_class,
1146                                      PROP_RUBBER_BANDING,
1147                                      g_param_spec_boolean ("rubber-banding",
1148                                                            P_("Rubber Banding"),
1149                                                            P_("Whether to enable selection of multiple items by dragging the mouse pointer"),
1150                                                            FALSE,
1151                                                            GTK_PARAM_READWRITE));
1152
1153     g_object_class_install_property (o_class,
1154                                      PROP_ENABLE_GRID_LINES,
1155                                      g_param_spec_enum ("enable-grid-lines",
1156                                                         P_("Enable Grid Lines"),
1157                                                         P_("Whether grid lines should be drawn in the tree view"),
1158                                                         GTK_TYPE_TREE_VIEW_GRID_LINES,
1159                                                         GTK_TREE_VIEW_GRID_LINES_NONE,
1160                                                         GTK_PARAM_READWRITE));
1161
1162     g_object_class_install_property (o_class,
1163                                      PROP_ENABLE_TREE_LINES,
1164                                      g_param_spec_boolean ("enable-tree-lines",
1165                                                            P_("Enable Tree Lines"),
1166                                                            P_("Whether tree lines should be drawn in the tree view"),
1167                                                            FALSE,
1168                                                            GTK_PARAM_READWRITE));
1169
1170     g_object_class_install_property (o_class,
1171                                      PROP_TOOLTIP_COLUMN,
1172                                      g_param_spec_int ("tooltip-column",
1173                                                        P_("Tooltip Column"),
1174                                                        P_("The column in the model containing the tooltip texts for the rows"),
1175                                                        -1,
1176                                                        G_MAXINT,
1177                                                        -1,
1178                                                        GTK_PARAM_READWRITE));
1179
1180   /**
1181    * GtkTreeView:activate-on-single-click:
1182    *
1183    * The activate-on-single-click property specifies whether the "row-activated" signal
1184    * will be emitted after a single click.
1185    *
1186    * Since: 3.8
1187    */
1188   g_object_class_install_property (o_class,
1189                                    PROP_ACTIVATE_ON_SINGLE_CLICK,
1190                                    g_param_spec_boolean ("activate-on-single-click",
1191                                                          P_("Activate on Single Click"),
1192                                                          P_("Activate row on a single click"),
1193                                                          FALSE,
1194                                                          GTK_PARAM_READWRITE));
1195
1196   /* Style properties */
1197 #define _TREE_VIEW_EXPANDER_SIZE 14
1198 #define _TREE_VIEW_VERTICAL_SEPARATOR 2
1199 #define _TREE_VIEW_HORIZONTAL_SEPARATOR 2
1200
1201   gtk_widget_class_install_style_property (widget_class,
1202                                            g_param_spec_int ("expander-size",
1203                                                              P_("Expander Size"),
1204                                                              P_("Size of the expander arrow"),
1205                                                              0,
1206                                                              G_MAXINT,
1207                                                              _TREE_VIEW_EXPANDER_SIZE,
1208                                                              GTK_PARAM_READABLE));
1209
1210   gtk_widget_class_install_style_property (widget_class,
1211                                            g_param_spec_int ("vertical-separator",
1212                                                              P_("Vertical Separator Width"),
1213                                                              P_("Vertical space between cells.  Must be an even number"),
1214                                                              0,
1215                                                              G_MAXINT,
1216                                                              _TREE_VIEW_VERTICAL_SEPARATOR,
1217                                                              GTK_PARAM_READABLE));
1218
1219   gtk_widget_class_install_style_property (widget_class,
1220                                            g_param_spec_int ("horizontal-separator",
1221                                                              P_("Horizontal Separator Width"),
1222                                                              P_("Horizontal space between cells.  Must be an even number"),
1223                                                              0,
1224                                                              G_MAXINT,
1225                                                              _TREE_VIEW_HORIZONTAL_SEPARATOR,
1226                                                              GTK_PARAM_READABLE));
1227
1228   gtk_widget_class_install_style_property (widget_class,
1229                                            g_param_spec_boolean ("allow-rules",
1230                                                                  P_("Allow Rules"),
1231                                                                  P_("Allow drawing of alternating color rows"),
1232                                                                  TRUE,
1233                                                                  GTK_PARAM_READABLE));
1234
1235   gtk_widget_class_install_style_property (widget_class,
1236                                            g_param_spec_boolean ("indent-expanders",
1237                                                                  P_("Indent Expanders"),
1238                                                                  P_("Make the expanders indented"),
1239                                                                  TRUE,
1240                                                                  GTK_PARAM_READABLE));
1241
1242   gtk_widget_class_install_style_property (widget_class,
1243                                            g_param_spec_boxed ("even-row-color",
1244                                                                P_("Even Row Color"),
1245                                                                P_("Color to use for even rows"),
1246                                                                GDK_TYPE_COLOR,
1247                                                                GTK_PARAM_READABLE));
1248
1249   gtk_widget_class_install_style_property (widget_class,
1250                                            g_param_spec_boxed ("odd-row-color",
1251                                                                P_("Odd Row Color"),
1252                                                                P_("Color to use for odd rows"),
1253                                                                GDK_TYPE_COLOR,
1254                                                                GTK_PARAM_READABLE));
1255
1256   gtk_widget_class_install_style_property (widget_class,
1257                                            g_param_spec_int ("grid-line-width",
1258                                                              P_("Grid line width"),
1259                                                              P_("Width, in pixels, of the tree view grid lines"),
1260                                                              0, G_MAXINT, 1,
1261                                                              GTK_PARAM_READABLE));
1262
1263   gtk_widget_class_install_style_property (widget_class,
1264                                            g_param_spec_int ("tree-line-width",
1265                                                              P_("Tree line width"),
1266                                                              P_("Width, in pixels, of the tree view lines"),
1267                                                              0, G_MAXINT, 1,
1268                                                              GTK_PARAM_READABLE));
1269
1270   gtk_widget_class_install_style_property (widget_class,
1271                                            g_param_spec_string ("grid-line-pattern",
1272                                                                 P_("Grid line pattern"),
1273                                                                 P_("Dash pattern used to draw the tree view grid lines"),
1274                                                                 "\1\1",
1275                                                                 GTK_PARAM_READABLE));
1276
1277   gtk_widget_class_install_style_property (widget_class,
1278                                            g_param_spec_string ("tree-line-pattern",
1279                                                                 P_("Tree line pattern"),
1280                                                                 P_("Dash pattern used to draw the tree view lines"),
1281                                                                 "\1\1",
1282                                                                 GTK_PARAM_READABLE));
1283
1284   /* Signals */
1285   /**
1286    * GtkTreeView::row-activated:
1287    * @tree_view: the object on which the signal is emitted
1288    * @path: the #GtkTreePath for the activated row
1289    * @column: the #GtkTreeViewColumn in which the activation occurred
1290    *
1291    * The "row-activated" signal is emitted when the method
1292    * gtk_tree_view_row_activated() is called, when the user double
1293    * clicks a treeview row with the "activate-on-single-click"
1294    * property set to %FALSE, or when the user single clicks a row when
1295    * the "activate-on-single-click" property set to %TRUE. It is also
1296    * emitted when a non-editable row is selected and one of the keys:
1297    * Space, Shift+Space, Return or Enter is pressed.
1298    * 
1299    * For selection handling refer to the <link linkend="TreeWidget">tree 
1300    * widget conceptual overview</link> as well as #GtkTreeSelection.
1301    */
1302   tree_view_signals[ROW_ACTIVATED] =
1303     g_signal_new (I_("row-activated"),
1304                   G_TYPE_FROM_CLASS (o_class),
1305                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1306                   G_STRUCT_OFFSET (GtkTreeViewClass, row_activated),
1307                   NULL, NULL,
1308                   _gtk_marshal_VOID__BOXED_OBJECT,
1309                   G_TYPE_NONE, 2,
1310                   GTK_TYPE_TREE_PATH,
1311                   GTK_TYPE_TREE_VIEW_COLUMN);
1312
1313   /**
1314    * GtkTreeView::test-expand-row:
1315    * @tree_view: the object on which the signal is emitted
1316    * @iter: the tree iter of the row to expand
1317    * @path: a tree path that points to the row 
1318    * 
1319    * The given row is about to be expanded (show its children nodes). Use this
1320    * signal if you need to control the expandability of individual rows.
1321    *
1322    * Returns: %FALSE to allow expansion, %TRUE to reject
1323    */
1324   tree_view_signals[TEST_EXPAND_ROW] =
1325     g_signal_new (I_("test-expand-row"),
1326                   G_TYPE_FROM_CLASS (o_class),
1327                   G_SIGNAL_RUN_LAST,
1328                   G_STRUCT_OFFSET (GtkTreeViewClass, test_expand_row),
1329                   _gtk_boolean_handled_accumulator, NULL,
1330                   _gtk_marshal_BOOLEAN__BOXED_BOXED,
1331                   G_TYPE_BOOLEAN, 2,
1332                   GTK_TYPE_TREE_ITER,
1333                   GTK_TYPE_TREE_PATH);
1334
1335   /**
1336    * GtkTreeView::test-collapse-row:
1337    * @tree_view: the object on which the signal is emitted
1338    * @iter: the tree iter of the row to collapse
1339    * @path: a tree path that points to the row 
1340    * 
1341    * The given row is about to be collapsed (hide its children nodes). Use this
1342    * signal if you need to control the collapsibility of individual rows.
1343    *
1344    * Returns: %FALSE to allow collapsing, %TRUE to reject
1345    */
1346   tree_view_signals[TEST_COLLAPSE_ROW] =
1347     g_signal_new (I_("test-collapse-row"),
1348                   G_TYPE_FROM_CLASS (o_class),
1349                   G_SIGNAL_RUN_LAST,
1350                   G_STRUCT_OFFSET (GtkTreeViewClass, test_collapse_row),
1351                   _gtk_boolean_handled_accumulator, NULL,
1352                   _gtk_marshal_BOOLEAN__BOXED_BOXED,
1353                   G_TYPE_BOOLEAN, 2,
1354                   GTK_TYPE_TREE_ITER,
1355                   GTK_TYPE_TREE_PATH);
1356
1357   /**
1358    * GtkTreeView::row-expanded:
1359    * @tree_view: the object on which the signal is emitted
1360    * @iter: the tree iter of the expanded row
1361    * @path: a tree path that points to the row 
1362    * 
1363    * The given row has been expanded (child nodes are shown).
1364    */
1365   tree_view_signals[ROW_EXPANDED] =
1366     g_signal_new (I_("row-expanded"),
1367                   G_TYPE_FROM_CLASS (o_class),
1368                   G_SIGNAL_RUN_LAST,
1369                   G_STRUCT_OFFSET (GtkTreeViewClass, row_expanded),
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::row-collapsed:
1378    * @tree_view: the object on which the signal is emitted
1379    * @iter: the tree iter of the collapsed row
1380    * @path: a tree path that points to the row 
1381    * 
1382    * The given row has been collapsed (child nodes are hidden).
1383    */
1384   tree_view_signals[ROW_COLLAPSED] =
1385     g_signal_new (I_("row-collapsed"),
1386                   G_TYPE_FROM_CLASS (o_class),
1387                   G_SIGNAL_RUN_LAST,
1388                   G_STRUCT_OFFSET (GtkTreeViewClass, row_collapsed),
1389                   NULL, NULL,
1390                   _gtk_marshal_VOID__BOXED_BOXED,
1391                   G_TYPE_NONE, 2,
1392                   GTK_TYPE_TREE_ITER,
1393                   GTK_TYPE_TREE_PATH);
1394
1395   /**
1396    * GtkTreeView::columns-changed:
1397    * @tree_view: the object on which the signal is emitted 
1398    * 
1399    * The number of columns of the treeview has changed.
1400    */
1401   tree_view_signals[COLUMNS_CHANGED] =
1402     g_signal_new (I_("columns-changed"),
1403                   G_TYPE_FROM_CLASS (o_class),
1404                   G_SIGNAL_RUN_LAST,
1405                   G_STRUCT_OFFSET (GtkTreeViewClass, columns_changed),
1406                   NULL, NULL,
1407                   _gtk_marshal_VOID__VOID,
1408                   G_TYPE_NONE, 0);
1409
1410   /**
1411    * GtkTreeView::cursor-changed:
1412    * @tree_view: the object on which the signal is emitted
1413    * 
1414    * The position of the cursor (focused cell) has changed.
1415    */
1416   tree_view_signals[CURSOR_CHANGED] =
1417     g_signal_new (I_("cursor-changed"),
1418                   G_TYPE_FROM_CLASS (o_class),
1419                   G_SIGNAL_RUN_LAST,
1420                   G_STRUCT_OFFSET (GtkTreeViewClass, cursor_changed),
1421                   NULL, NULL,
1422                   _gtk_marshal_VOID__VOID,
1423                   G_TYPE_NONE, 0);
1424
1425   tree_view_signals[MOVE_CURSOR] =
1426     g_signal_new (I_("move-cursor"),
1427                   G_TYPE_FROM_CLASS (o_class),
1428                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1429                   G_STRUCT_OFFSET (GtkTreeViewClass, move_cursor),
1430                   NULL, NULL,
1431                   _gtk_marshal_BOOLEAN__ENUM_INT,
1432                   G_TYPE_BOOLEAN, 2,
1433                   GTK_TYPE_MOVEMENT_STEP,
1434                   G_TYPE_INT);
1435
1436   tree_view_signals[SELECT_ALL] =
1437     g_signal_new (I_("select-all"),
1438                   G_TYPE_FROM_CLASS (o_class),
1439                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1440                   G_STRUCT_OFFSET (GtkTreeViewClass, select_all),
1441                   NULL, NULL,
1442                   _gtk_marshal_BOOLEAN__VOID,
1443                   G_TYPE_BOOLEAN, 0);
1444
1445   tree_view_signals[UNSELECT_ALL] =
1446     g_signal_new (I_("unselect-all"),
1447                   G_TYPE_FROM_CLASS (o_class),
1448                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1449                   G_STRUCT_OFFSET (GtkTreeViewClass, unselect_all),
1450                   NULL, NULL,
1451                   _gtk_marshal_BOOLEAN__VOID,
1452                   G_TYPE_BOOLEAN, 0);
1453
1454   tree_view_signals[SELECT_CURSOR_ROW] =
1455     g_signal_new (I_("select-cursor-row"),
1456                   G_TYPE_FROM_CLASS (o_class),
1457                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1458                   G_STRUCT_OFFSET (GtkTreeViewClass, select_cursor_row),
1459                   NULL, NULL,
1460                   _gtk_marshal_BOOLEAN__BOOLEAN,
1461                   G_TYPE_BOOLEAN, 1,
1462                   G_TYPE_BOOLEAN);
1463
1464   tree_view_signals[TOGGLE_CURSOR_ROW] =
1465     g_signal_new (I_("toggle-cursor-row"),
1466                   G_TYPE_FROM_CLASS (o_class),
1467                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1468                   G_STRUCT_OFFSET (GtkTreeViewClass, toggle_cursor_row),
1469                   NULL, NULL,
1470                   _gtk_marshal_BOOLEAN__VOID,
1471                   G_TYPE_BOOLEAN, 0);
1472
1473   tree_view_signals[EXPAND_COLLAPSE_CURSOR_ROW] =
1474     g_signal_new (I_("expand-collapse-cursor-row"),
1475                   G_TYPE_FROM_CLASS (o_class),
1476                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1477                   G_STRUCT_OFFSET (GtkTreeViewClass, expand_collapse_cursor_row),
1478                   NULL, NULL,
1479                   _gtk_marshal_BOOLEAN__BOOLEAN_BOOLEAN_BOOLEAN,
1480                   G_TYPE_BOOLEAN, 3,
1481                   G_TYPE_BOOLEAN,
1482                   G_TYPE_BOOLEAN,
1483                   G_TYPE_BOOLEAN);
1484
1485   tree_view_signals[SELECT_CURSOR_PARENT] =
1486     g_signal_new (I_("select-cursor-parent"),
1487                   G_TYPE_FROM_CLASS (o_class),
1488                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1489                   G_STRUCT_OFFSET (GtkTreeViewClass, select_cursor_parent),
1490                   NULL, NULL,
1491                   _gtk_marshal_BOOLEAN__VOID,
1492                   G_TYPE_BOOLEAN, 0);
1493
1494   tree_view_signals[START_INTERACTIVE_SEARCH] =
1495     g_signal_new (I_("start-interactive-search"),
1496                   G_TYPE_FROM_CLASS (o_class),
1497                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1498                   G_STRUCT_OFFSET (GtkTreeViewClass, start_interactive_search),
1499                   NULL, NULL,
1500                   _gtk_marshal_BOOLEAN__VOID,
1501                   G_TYPE_BOOLEAN, 0);
1502
1503   /* Key bindings */
1504   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Up, 0, TRUE,
1505                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
1506   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Up, 0, TRUE,
1507                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
1508
1509   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Down, 0, TRUE,
1510                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
1511   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Down, 0, TRUE,
1512                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
1513
1514   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_p, GDK_CONTROL_MASK, FALSE,
1515                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
1516
1517   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_n, GDK_CONTROL_MASK, FALSE,
1518                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
1519
1520   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Home, 0, TRUE,
1521                                   GTK_MOVEMENT_BUFFER_ENDS, -1);
1522   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Home, 0, TRUE,
1523                                   GTK_MOVEMENT_BUFFER_ENDS, -1);
1524
1525   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_End, 0, TRUE,
1526                                   GTK_MOVEMENT_BUFFER_ENDS, 1);
1527   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_End, 0, TRUE,
1528                                   GTK_MOVEMENT_BUFFER_ENDS, 1);
1529
1530   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Page_Up, 0, TRUE,
1531                                   GTK_MOVEMENT_PAGES, -1);
1532   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Page_Up, 0, TRUE,
1533                                   GTK_MOVEMENT_PAGES, -1);
1534
1535   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Page_Down, 0, TRUE,
1536                                   GTK_MOVEMENT_PAGES, 1);
1537   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Page_Down, 0, TRUE,
1538                                   GTK_MOVEMENT_PAGES, 1);
1539
1540
1541   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Right, 0, "move-cursor", 2,
1542                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1543                                 G_TYPE_INT, 1);
1544
1545   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Left, 0, "move-cursor", 2,
1546                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1547                                 G_TYPE_INT, -1);
1548
1549   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Right, 0, "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, 0, "move-cursor", 2,
1554                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1555                                 G_TYPE_INT, -1);
1556
1557   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Right, GDK_CONTROL_MASK,
1558                                 "move-cursor", 2,
1559                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1560                                 G_TYPE_INT, 1);
1561
1562   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Left, GDK_CONTROL_MASK,
1563                                 "move-cursor", 2,
1564                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1565                                 G_TYPE_INT, -1);
1566
1567   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Right, GDK_CONTROL_MASK,
1568                                 "move-cursor", 2,
1569                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1570                                 G_TYPE_INT, 1);
1571
1572   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Left, GDK_CONTROL_MASK,
1573                                 "move-cursor", 2,
1574                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1575                                 G_TYPE_INT, -1);
1576
1577   gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, GDK_CONTROL_MASK, "toggle-cursor-row", 0);
1578   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Space, GDK_CONTROL_MASK, "toggle-cursor-row", 0);
1579
1580   gtk_binding_entry_add_signal (binding_set, GDK_KEY_a, GDK_CONTROL_MASK, "select-all", 0);
1581   gtk_binding_entry_add_signal (binding_set, GDK_KEY_slash, GDK_CONTROL_MASK, "select-all", 0);
1582
1583   gtk_binding_entry_add_signal (binding_set, GDK_KEY_A, GDK_CONTROL_MASK | GDK_SHIFT_MASK, "unselect-all", 0);
1584   gtk_binding_entry_add_signal (binding_set, GDK_KEY_backslash, GDK_CONTROL_MASK, "unselect-all", 0);
1585
1586   gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, GDK_SHIFT_MASK, "select-cursor-row", 1,
1587                                 G_TYPE_BOOLEAN, TRUE);
1588   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Space, GDK_SHIFT_MASK, "select-cursor-row", 1,
1589                                 G_TYPE_BOOLEAN, TRUE);
1590
1591   gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, 0, "select-cursor-row", 1,
1592                                 G_TYPE_BOOLEAN, TRUE);
1593   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Space, 0, "select-cursor-row", 1,
1594                                 G_TYPE_BOOLEAN, TRUE);
1595   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Return, 0, "select-cursor-row", 1,
1596                                 G_TYPE_BOOLEAN, TRUE);
1597   gtk_binding_entry_add_signal (binding_set, GDK_KEY_ISO_Enter, 0, "select-cursor-row", 1,
1598                                 G_TYPE_BOOLEAN, TRUE);
1599   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Enter, 0, "select-cursor-row", 1,
1600                                 G_TYPE_BOOLEAN, TRUE);
1601
1602   /* expand and collapse rows */
1603   gtk_binding_entry_add_signal (binding_set, GDK_KEY_plus, 0, "expand-collapse-cursor-row", 3,
1604                                 G_TYPE_BOOLEAN, TRUE,
1605                                 G_TYPE_BOOLEAN, TRUE,
1606                                 G_TYPE_BOOLEAN, FALSE);
1607
1608   gtk_binding_entry_add_signal (binding_set, GDK_KEY_asterisk, 0,
1609                                 "expand-collapse-cursor-row", 3,
1610                                 G_TYPE_BOOLEAN, TRUE,
1611                                 G_TYPE_BOOLEAN, TRUE,
1612                                 G_TYPE_BOOLEAN, TRUE);
1613   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Multiply, 0,
1614                                 "expand-collapse-cursor-row", 3,
1615                                 G_TYPE_BOOLEAN, TRUE,
1616                                 G_TYPE_BOOLEAN, TRUE,
1617                                 G_TYPE_BOOLEAN, TRUE);
1618
1619   gtk_binding_entry_add_signal (binding_set, GDK_KEY_slash, 0,
1620                                 "expand-collapse-cursor-row", 3,
1621                                 G_TYPE_BOOLEAN, TRUE,
1622                                 G_TYPE_BOOLEAN, FALSE,
1623                                 G_TYPE_BOOLEAN, FALSE);
1624   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Divide, 0,
1625                                 "expand-collapse-cursor-row", 3,
1626                                 G_TYPE_BOOLEAN, TRUE,
1627                                 G_TYPE_BOOLEAN, FALSE,
1628                                 G_TYPE_BOOLEAN, FALSE);
1629
1630   /* Not doable on US keyboards */
1631   gtk_binding_entry_add_signal (binding_set, GDK_KEY_plus, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1632                                 G_TYPE_BOOLEAN, TRUE,
1633                                 G_TYPE_BOOLEAN, TRUE,
1634                                 G_TYPE_BOOLEAN, TRUE);
1635   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Add, 0, "expand-collapse-cursor-row", 3,
1636                                 G_TYPE_BOOLEAN, TRUE,
1637                                 G_TYPE_BOOLEAN, TRUE,
1638                                 G_TYPE_BOOLEAN, FALSE);
1639   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Add, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1640                                 G_TYPE_BOOLEAN, TRUE,
1641                                 G_TYPE_BOOLEAN, TRUE,
1642                                 G_TYPE_BOOLEAN, TRUE);
1643   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Add, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1644                                 G_TYPE_BOOLEAN, TRUE,
1645                                 G_TYPE_BOOLEAN, TRUE,
1646                                 G_TYPE_BOOLEAN, TRUE);
1647   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Right, GDK_SHIFT_MASK,
1648                                 "expand-collapse-cursor-row", 3,
1649                                 G_TYPE_BOOLEAN, FALSE,
1650                                 G_TYPE_BOOLEAN, TRUE,
1651                                 G_TYPE_BOOLEAN, TRUE);
1652   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Right, GDK_SHIFT_MASK,
1653                                 "expand-collapse-cursor-row", 3,
1654                                 G_TYPE_BOOLEAN, FALSE,
1655                                 G_TYPE_BOOLEAN, TRUE,
1656                                 G_TYPE_BOOLEAN, TRUE);
1657   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Right,
1658                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1659                                 "expand-collapse-cursor-row", 3,
1660                                 G_TYPE_BOOLEAN, FALSE,
1661                                 G_TYPE_BOOLEAN, TRUE,
1662                                 G_TYPE_BOOLEAN, TRUE);
1663   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Right,
1664                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1665                                 "expand-collapse-cursor-row", 3,
1666                                 G_TYPE_BOOLEAN, FALSE,
1667                                 G_TYPE_BOOLEAN, TRUE,
1668                                 G_TYPE_BOOLEAN, TRUE);
1669
1670   gtk_binding_entry_add_signal (binding_set, GDK_KEY_minus, 0, "expand-collapse-cursor-row", 3,
1671                                 G_TYPE_BOOLEAN, TRUE,
1672                                 G_TYPE_BOOLEAN, FALSE,
1673                                 G_TYPE_BOOLEAN, FALSE);
1674   gtk_binding_entry_add_signal (binding_set, GDK_KEY_minus, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1675                                 G_TYPE_BOOLEAN, TRUE,
1676                                 G_TYPE_BOOLEAN, FALSE,
1677                                 G_TYPE_BOOLEAN, TRUE);
1678   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Subtract, 0, "expand-collapse-cursor-row", 3,
1679                                 G_TYPE_BOOLEAN, TRUE,
1680                                 G_TYPE_BOOLEAN, FALSE,
1681                                 G_TYPE_BOOLEAN, FALSE);
1682   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Subtract, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1683                                 G_TYPE_BOOLEAN, TRUE,
1684                                 G_TYPE_BOOLEAN, FALSE,
1685                                 G_TYPE_BOOLEAN, TRUE);
1686   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Left, GDK_SHIFT_MASK,
1687                                 "expand-collapse-cursor-row", 3,
1688                                 G_TYPE_BOOLEAN, FALSE,
1689                                 G_TYPE_BOOLEAN, FALSE,
1690                                 G_TYPE_BOOLEAN, TRUE);
1691   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Left, GDK_SHIFT_MASK,
1692                                 "expand-collapse-cursor-row", 3,
1693                                 G_TYPE_BOOLEAN, FALSE,
1694                                 G_TYPE_BOOLEAN, FALSE,
1695                                 G_TYPE_BOOLEAN, TRUE);
1696   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Left,
1697                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1698                                 "expand-collapse-cursor-row", 3,
1699                                 G_TYPE_BOOLEAN, FALSE,
1700                                 G_TYPE_BOOLEAN, FALSE,
1701                                 G_TYPE_BOOLEAN, TRUE);
1702   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Left,
1703                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1704                                 "expand-collapse-cursor-row", 3,
1705                                 G_TYPE_BOOLEAN, FALSE,
1706                                 G_TYPE_BOOLEAN, FALSE,
1707                                 G_TYPE_BOOLEAN, TRUE);
1708
1709   gtk_binding_entry_add_signal (binding_set, GDK_KEY_BackSpace, 0, "select-cursor-parent", 0);
1710   gtk_binding_entry_add_signal (binding_set, GDK_KEY_BackSpace, GDK_CONTROL_MASK, "select-cursor-parent", 0);
1711
1712   gtk_binding_entry_add_signal (binding_set, GDK_KEY_f, GDK_CONTROL_MASK, "start-interactive-search", 0);
1713
1714   gtk_binding_entry_add_signal (binding_set, GDK_KEY_F, GDK_CONTROL_MASK, "start-interactive-search", 0);
1715
1716   g_type_class_add_private (o_class, sizeof (GtkTreeViewPrivate));
1717
1718   gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_TREE_VIEW_ACCESSIBLE);
1719 }
1720
1721 static void
1722 gtk_tree_view_init (GtkTreeView *tree_view)
1723 {
1724   tree_view->priv = G_TYPE_INSTANCE_GET_PRIVATE (tree_view, GTK_TYPE_TREE_VIEW, GtkTreeViewPrivate);
1725
1726   gtk_widget_set_can_focus (GTK_WIDGET (tree_view), TRUE);
1727   gtk_widget_set_redraw_on_allocate (GTK_WIDGET (tree_view), FALSE);
1728
1729   tree_view->priv->show_expanders = TRUE;
1730   tree_view->priv->draw_keyfocus = TRUE;
1731   tree_view->priv->headers_visible = TRUE;
1732   tree_view->priv->activate_on_single_click = FALSE;
1733
1734   /* We need some padding */
1735   tree_view->priv->dy = 0;
1736   tree_view->priv->cursor_offset = 0;
1737   tree_view->priv->n_columns = 0;
1738   tree_view->priv->header_height = 1;
1739   tree_view->priv->x_drag = 0;
1740   tree_view->priv->drag_pos = -1;
1741   tree_view->priv->minimum_width = 0;
1742   tree_view->priv->natural_width = 0;
1743   tree_view->priv->n_expand_columns = 0;
1744   tree_view->priv->header_has_focus = FALSE;
1745   tree_view->priv->pressed_button = -1;
1746   tree_view->priv->press_start_x = -1;
1747   tree_view->priv->press_start_y = -1;
1748   tree_view->priv->reorderable = FALSE;
1749   tree_view->priv->presize_handler_timer = 0;
1750   tree_view->priv->scroll_sync_timer = 0;
1751   tree_view->priv->fixed_height = -1;
1752   tree_view->priv->fixed_height_mode = FALSE;
1753   tree_view->priv->fixed_height_check = 0;
1754   tree_view->priv->selection = _gtk_tree_selection_new_with_tree_view (tree_view);
1755   tree_view->priv->enable_search = TRUE;
1756   tree_view->priv->search_column = -1;
1757   tree_view->priv->search_position_func = gtk_tree_view_search_position_func;
1758   tree_view->priv->search_equal_func = gtk_tree_view_search_equal_func;
1759   tree_view->priv->search_custom_entry_set = FALSE;
1760   tree_view->priv->typeselect_flush_timeout = 0;
1761   tree_view->priv->init_hadjust_value = TRUE;    
1762   tree_view->priv->width = 0;
1763           
1764   tree_view->priv->hover_selection = FALSE;
1765   tree_view->priv->hover_expand = FALSE;
1766
1767   tree_view->priv->level_indentation = 0;
1768
1769   tree_view->priv->rubber_banding_enable = FALSE;
1770
1771   tree_view->priv->grid_lines = GTK_TREE_VIEW_GRID_LINES_NONE;
1772   tree_view->priv->tree_lines_enabled = FALSE;
1773
1774   tree_view->priv->tooltip_column = -1;
1775
1776   tree_view->priv->last_button_x = -1;
1777   tree_view->priv->last_button_y = -1;
1778
1779   tree_view->priv->event_last_x = -10000;
1780   tree_view->priv->event_last_y = -10000;
1781
1782   gtk_tree_view_do_set_vadjustment (tree_view, NULL);
1783   gtk_tree_view_do_set_hadjustment (tree_view, NULL);
1784
1785   gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (tree_view)),
1786                                GTK_STYLE_CLASS_VIEW);
1787 }
1788
1789 \f
1790
1791 /* GObject Methods
1792  */
1793
1794 static void
1795 gtk_tree_view_set_property (GObject         *object,
1796                             guint            prop_id,
1797                             const GValue    *value,
1798                             GParamSpec      *pspec)
1799 {
1800   GtkTreeView *tree_view;
1801
1802   tree_view = GTK_TREE_VIEW (object);
1803
1804   switch (prop_id)
1805     {
1806     case PROP_MODEL:
1807       gtk_tree_view_set_model (tree_view, g_value_get_object (value));
1808       break;
1809     case PROP_HADJUSTMENT:
1810       gtk_tree_view_do_set_hadjustment (tree_view, g_value_get_object (value));
1811       break;
1812     case PROP_VADJUSTMENT:
1813       gtk_tree_view_do_set_vadjustment (tree_view, g_value_get_object (value));
1814       break;
1815     case PROP_HSCROLL_POLICY:
1816       tree_view->priv->hscroll_policy = g_value_get_enum (value);
1817       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
1818       break;
1819     case PROP_VSCROLL_POLICY:
1820       tree_view->priv->vscroll_policy = g_value_get_enum (value);
1821       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
1822       break;
1823     case PROP_HEADERS_VISIBLE:
1824       gtk_tree_view_set_headers_visible (tree_view, g_value_get_boolean (value));
1825       break;
1826     case PROP_HEADERS_CLICKABLE:
1827       gtk_tree_view_set_headers_clickable (tree_view, g_value_get_boolean (value));
1828       break;
1829     case PROP_EXPANDER_COLUMN:
1830       gtk_tree_view_set_expander_column (tree_view, g_value_get_object (value));
1831       break;
1832     case PROP_REORDERABLE:
1833       gtk_tree_view_set_reorderable (tree_view, g_value_get_boolean (value));
1834       break;
1835     case PROP_RULES_HINT:
1836       gtk_tree_view_set_rules_hint (tree_view, g_value_get_boolean (value));
1837       break;
1838     case PROP_ENABLE_SEARCH:
1839       gtk_tree_view_set_enable_search (tree_view, g_value_get_boolean (value));
1840       break;
1841     case PROP_SEARCH_COLUMN:
1842       gtk_tree_view_set_search_column (tree_view, g_value_get_int (value));
1843       break;
1844     case PROP_FIXED_HEIGHT_MODE:
1845       gtk_tree_view_set_fixed_height_mode (tree_view, g_value_get_boolean (value));
1846       break;
1847     case PROP_HOVER_SELECTION:
1848       tree_view->priv->hover_selection = g_value_get_boolean (value);
1849       break;
1850     case PROP_HOVER_EXPAND:
1851       tree_view->priv->hover_expand = g_value_get_boolean (value);
1852       break;
1853     case PROP_SHOW_EXPANDERS:
1854       gtk_tree_view_set_show_expanders (tree_view, g_value_get_boolean (value));
1855       break;
1856     case PROP_LEVEL_INDENTATION:
1857       tree_view->priv->level_indentation = g_value_get_int (value);
1858       break;
1859     case PROP_RUBBER_BANDING:
1860       tree_view->priv->rubber_banding_enable = g_value_get_boolean (value);
1861       break;
1862     case PROP_ENABLE_GRID_LINES:
1863       gtk_tree_view_set_grid_lines (tree_view, g_value_get_enum (value));
1864       break;
1865     case PROP_ENABLE_TREE_LINES:
1866       gtk_tree_view_set_enable_tree_lines (tree_view, g_value_get_boolean (value));
1867       break;
1868     case PROP_TOOLTIP_COLUMN:
1869       gtk_tree_view_set_tooltip_column (tree_view, g_value_get_int (value));
1870       break;
1871     case PROP_ACTIVATE_ON_SINGLE_CLICK:
1872       gtk_tree_view_set_activate_on_single_click (tree_view, g_value_get_boolean (value));
1873       break;
1874     default:
1875       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1876       break;
1877     }
1878 }
1879
1880 static void
1881 gtk_tree_view_get_property (GObject    *object,
1882                             guint       prop_id,
1883                             GValue     *value,
1884                             GParamSpec *pspec)
1885 {
1886   GtkTreeView *tree_view;
1887
1888   tree_view = GTK_TREE_VIEW (object);
1889
1890   switch (prop_id)
1891     {
1892     case PROP_MODEL:
1893       g_value_set_object (value, tree_view->priv->model);
1894       break;
1895     case PROP_HADJUSTMENT:
1896       g_value_set_object (value, tree_view->priv->hadjustment);
1897       break;
1898     case PROP_VADJUSTMENT:
1899       g_value_set_object (value, tree_view->priv->vadjustment);
1900       break;
1901     case PROP_HSCROLL_POLICY:
1902       g_value_set_enum (value, tree_view->priv->hscroll_policy);
1903       break;
1904     case PROP_VSCROLL_POLICY:
1905       g_value_set_enum (value, tree_view->priv->vscroll_policy);
1906       break;
1907     case PROP_HEADERS_VISIBLE:
1908       g_value_set_boolean (value, gtk_tree_view_get_headers_visible (tree_view));
1909       break;
1910     case PROP_HEADERS_CLICKABLE:
1911       g_value_set_boolean (value, gtk_tree_view_get_headers_clickable (tree_view));
1912       break;
1913     case PROP_EXPANDER_COLUMN:
1914       g_value_set_object (value, tree_view->priv->expander_column);
1915       break;
1916     case PROP_REORDERABLE:
1917       g_value_set_boolean (value, tree_view->priv->reorderable);
1918       break;
1919     case PROP_RULES_HINT:
1920       g_value_set_boolean (value, tree_view->priv->has_rules);
1921       break;
1922     case PROP_ENABLE_SEARCH:
1923       g_value_set_boolean (value, tree_view->priv->enable_search);
1924       break;
1925     case PROP_SEARCH_COLUMN:
1926       g_value_set_int (value, tree_view->priv->search_column);
1927       break;
1928     case PROP_FIXED_HEIGHT_MODE:
1929       g_value_set_boolean (value, tree_view->priv->fixed_height_mode);
1930       break;
1931     case PROP_HOVER_SELECTION:
1932       g_value_set_boolean (value, tree_view->priv->hover_selection);
1933       break;
1934     case PROP_HOVER_EXPAND:
1935       g_value_set_boolean (value, tree_view->priv->hover_expand);
1936       break;
1937     case PROP_SHOW_EXPANDERS:
1938       g_value_set_boolean (value, tree_view->priv->show_expanders);
1939       break;
1940     case PROP_LEVEL_INDENTATION:
1941       g_value_set_int (value, tree_view->priv->level_indentation);
1942       break;
1943     case PROP_RUBBER_BANDING:
1944       g_value_set_boolean (value, tree_view->priv->rubber_banding_enable);
1945       break;
1946     case PROP_ENABLE_GRID_LINES:
1947       g_value_set_enum (value, tree_view->priv->grid_lines);
1948       break;
1949     case PROP_ENABLE_TREE_LINES:
1950       g_value_set_boolean (value, tree_view->priv->tree_lines_enabled);
1951       break;
1952     case PROP_TOOLTIP_COLUMN:
1953       g_value_set_int (value, tree_view->priv->tooltip_column);
1954       break;
1955     case PROP_ACTIVATE_ON_SINGLE_CLICK:
1956       g_value_set_boolean (value, tree_view->priv->activate_on_single_click);
1957       break;
1958     default:
1959       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1960       break;
1961     }
1962 }
1963
1964 static void
1965 gtk_tree_view_finalize (GObject *object)
1966 {
1967   G_OBJECT_CLASS (gtk_tree_view_parent_class)->finalize (object);
1968 }
1969
1970
1971 static GtkBuildableIface *parent_buildable_iface;
1972
1973 static void
1974 gtk_tree_view_buildable_init (GtkBuildableIface *iface)
1975 {
1976   parent_buildable_iface = g_type_interface_peek_parent (iface);
1977   iface->add_child = gtk_tree_view_buildable_add_child;
1978   iface->get_internal_child = gtk_tree_view_buildable_get_internal_child;
1979 }
1980
1981 static void
1982 gtk_tree_view_buildable_add_child (GtkBuildable *tree_view,
1983                                    GtkBuilder  *builder,
1984                                    GObject     *child,
1985                                    const gchar *type)
1986 {
1987   gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), GTK_TREE_VIEW_COLUMN (child));
1988 }
1989
1990 static GObject *
1991 gtk_tree_view_buildable_get_internal_child (GtkBuildable      *buildable,
1992                                             GtkBuilder        *builder,
1993                                             const gchar       *childname)
1994 {
1995     if (strcmp (childname, "selection") == 0)
1996       return G_OBJECT (GTK_TREE_VIEW (buildable)->priv->selection);
1997     
1998     return parent_buildable_iface->get_internal_child (buildable,
1999                                                        builder,
2000                                                        childname);
2001 }
2002
2003 /* GtkWidget Methods
2004  */
2005
2006 static void
2007 gtk_tree_view_free_rbtree (GtkTreeView *tree_view)
2008 {
2009   _gtk_rbtree_free (tree_view->priv->tree);
2010   
2011   tree_view->priv->tree = NULL;
2012   tree_view->priv->button_pressed_node = NULL;
2013   tree_view->priv->button_pressed_tree = NULL;
2014   tree_view->priv->prelight_tree = NULL;
2015   tree_view->priv->prelight_node = NULL;
2016   tree_view->priv->expanded_collapsed_node = NULL;
2017   tree_view->priv->expanded_collapsed_tree = NULL;
2018 }
2019
2020 static void
2021 gtk_tree_view_destroy (GtkWidget *widget)
2022 {
2023   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2024   GList *list;
2025
2026   gtk_tree_view_stop_editing (tree_view, TRUE);
2027
2028   if (tree_view->priv->columns != NULL)
2029     {
2030       list = tree_view->priv->columns;
2031       while (list)
2032         {
2033           GtkTreeViewColumn *column;
2034           column = GTK_TREE_VIEW_COLUMN (list->data);
2035           list = list->next;
2036           gtk_tree_view_remove_column (tree_view, column);
2037         }
2038       tree_view->priv->columns = NULL;
2039     }
2040
2041   if (tree_view->priv->tree != NULL)
2042     {
2043       gtk_tree_view_unref_and_check_selection_tree (tree_view, tree_view->priv->tree);
2044
2045       gtk_tree_view_free_rbtree (tree_view);
2046     }
2047
2048   if (tree_view->priv->selection != NULL)
2049     {
2050       _gtk_tree_selection_set_tree_view (tree_view->priv->selection, NULL);
2051       g_object_unref (tree_view->priv->selection);
2052       tree_view->priv->selection = NULL;
2053     }
2054
2055   if (tree_view->priv->scroll_to_path != NULL)
2056     {
2057       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
2058       tree_view->priv->scroll_to_path = NULL;
2059     }
2060
2061   if (tree_view->priv->drag_dest_row != NULL)
2062     {
2063       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
2064       tree_view->priv->drag_dest_row = NULL;
2065     }
2066
2067   if (tree_view->priv->top_row != NULL)
2068     {
2069       gtk_tree_row_reference_free (tree_view->priv->top_row);
2070       tree_view->priv->top_row = NULL;
2071     }
2072
2073   if (tree_view->priv->column_drop_func_data &&
2074       tree_view->priv->column_drop_func_data_destroy)
2075     {
2076       tree_view->priv->column_drop_func_data_destroy (tree_view->priv->column_drop_func_data);
2077       tree_view->priv->column_drop_func_data = NULL;
2078     }
2079
2080   if (tree_view->priv->destroy_count_destroy &&
2081       tree_view->priv->destroy_count_data)
2082     {
2083       tree_view->priv->destroy_count_destroy (tree_view->priv->destroy_count_data);
2084       tree_view->priv->destroy_count_data = NULL;
2085     }
2086
2087   gtk_tree_row_reference_free (tree_view->priv->anchor);
2088   tree_view->priv->anchor = NULL;
2089
2090   /* destroy interactive search dialog */
2091   if (tree_view->priv->search_window)
2092     {
2093       gtk_widget_destroy (tree_view->priv->search_window);
2094       tree_view->priv->search_window = NULL;
2095       tree_view->priv->search_entry = NULL;
2096       if (tree_view->priv->typeselect_flush_timeout)
2097         {
2098           g_source_remove (tree_view->priv->typeselect_flush_timeout);
2099           tree_view->priv->typeselect_flush_timeout = 0;
2100         }
2101     }
2102
2103   if (tree_view->priv->search_destroy && tree_view->priv->search_user_data)
2104     {
2105       tree_view->priv->search_destroy (tree_view->priv->search_user_data);
2106       tree_view->priv->search_user_data = NULL;
2107     }
2108
2109   if (tree_view->priv->search_position_destroy && tree_view->priv->search_position_user_data)
2110     {
2111       tree_view->priv->search_position_destroy (tree_view->priv->search_position_user_data);
2112       tree_view->priv->search_position_user_data = NULL;
2113     }
2114
2115   if (tree_view->priv->row_separator_destroy && tree_view->priv->row_separator_data)
2116     {
2117       tree_view->priv->row_separator_destroy (tree_view->priv->row_separator_data);
2118       tree_view->priv->row_separator_data = NULL;
2119     }
2120   
2121   gtk_tree_view_set_model (tree_view, NULL);
2122
2123   if (tree_view->priv->hadjustment)
2124     {
2125       g_object_unref (tree_view->priv->hadjustment);
2126       tree_view->priv->hadjustment = NULL;
2127     }
2128   if (tree_view->priv->vadjustment)
2129     {
2130       g_object_unref (tree_view->priv->vadjustment);
2131       tree_view->priv->vadjustment = NULL;
2132     }
2133
2134   GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->destroy (widget);
2135 }
2136
2137 /* GtkWidget::map helper */
2138 static void
2139 gtk_tree_view_map_buttons (GtkTreeView *tree_view)
2140 {
2141   GList *list;
2142
2143   g_return_if_fail (gtk_widget_get_mapped (GTK_WIDGET (tree_view)));
2144
2145   if (tree_view->priv->headers_visible)
2146     {
2147       GtkTreeViewColumn *column;
2148       GtkWidget         *button;
2149       GdkWindow         *window;
2150
2151       for (list = tree_view->priv->columns; list; list = list->next)
2152         {
2153           column = list->data;
2154           button = gtk_tree_view_column_get_button (column);
2155
2156           if (gtk_tree_view_column_get_visible (column) && button)
2157             gtk_widget_show_now (button);
2158
2159           if (gtk_widget_get_visible (button) &&
2160               !gtk_widget_get_mapped (button))
2161             gtk_widget_map (button);
2162         }
2163       for (list = tree_view->priv->columns; list; list = list->next)
2164         {
2165           column = list->data;
2166           if (gtk_tree_view_column_get_visible (column) == FALSE)
2167             continue;
2168
2169           window = _gtk_tree_view_column_get_window (column);
2170           if (gtk_tree_view_column_get_resizable (column))
2171             {
2172               gdk_window_raise (window);
2173               gdk_window_show (window);
2174             }
2175           else
2176             gdk_window_hide (window);
2177         }
2178       gdk_window_show (tree_view->priv->header_window);
2179     }
2180 }
2181
2182 static void
2183 gtk_tree_view_map (GtkWidget *widget)
2184 {
2185   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2186   GList *tmp_list;
2187
2188   gtk_widget_set_mapped (widget, TRUE);
2189
2190   tmp_list = tree_view->priv->children;
2191   while (tmp_list)
2192     {
2193       GtkTreeViewChild *child = tmp_list->data;
2194       tmp_list = tmp_list->next;
2195
2196       if (gtk_widget_get_visible (child->widget))
2197         {
2198           if (!gtk_widget_get_mapped (child->widget))
2199             gtk_widget_map (child->widget);
2200         }
2201     }
2202   gdk_window_show (tree_view->priv->bin_window);
2203
2204   gtk_tree_view_map_buttons (tree_view);
2205
2206   gdk_window_show (gtk_widget_get_window (widget));
2207 }
2208
2209 static void
2210 gtk_tree_view_ensure_background (GtkTreeView *tree_view)
2211 {
2212   GtkStyleContext *context;
2213
2214   context = gtk_widget_get_style_context (GTK_WIDGET (tree_view));
2215
2216   gtk_style_context_set_background (context, tree_view->priv->bin_window);
2217   gtk_style_context_set_background (context, gtk_widget_get_window (GTK_WIDGET (tree_view)));
2218   gtk_style_context_set_background (context, tree_view->priv->header_window);
2219 }
2220
2221 static void
2222 gtk_tree_view_realize (GtkWidget *widget)
2223 {
2224   GtkAllocation allocation;
2225   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2226   GdkWindow *window;
2227   GdkWindowAttr attributes;
2228   GList *tmp_list;
2229   gint attributes_mask;
2230
2231   gtk_widget_set_realized (widget, TRUE);
2232
2233   gtk_widget_get_allocation (widget, &allocation);
2234
2235   /* Make the main, clipping window */
2236   attributes.window_type = GDK_WINDOW_CHILD;
2237   attributes.x = allocation.x;
2238   attributes.y = allocation.y;
2239   attributes.width = allocation.width;
2240   attributes.height = allocation.height;
2241   attributes.wclass = GDK_INPUT_OUTPUT;
2242   attributes.visual = gtk_widget_get_visual (widget);
2243   attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK;
2244
2245   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
2246
2247   window = gdk_window_new (gtk_widget_get_parent_window (widget),
2248                            &attributes, attributes_mask);
2249   gtk_widget_set_window (widget, window);
2250   gdk_window_set_user_data (window, widget);
2251
2252   gtk_widget_get_allocation (widget, &allocation);
2253
2254   /* Make the window for the tree */
2255   attributes.x = 0;
2256   attributes.y = gtk_tree_view_get_effective_header_height (tree_view);
2257   attributes.width = MAX (tree_view->priv->width, allocation.width);
2258   attributes.height = allocation.height;
2259   attributes.event_mask = (GDK_EXPOSURE_MASK |
2260                            GDK_SCROLL_MASK |
2261                            GDK_SMOOTH_SCROLL_MASK |
2262                            GDK_POINTER_MOTION_MASK |
2263                            GDK_ENTER_NOTIFY_MASK |
2264                            GDK_LEAVE_NOTIFY_MASK |
2265                            GDK_BUTTON_PRESS_MASK |
2266                            GDK_BUTTON_RELEASE_MASK |
2267                            gtk_widget_get_events (widget));
2268
2269   tree_view->priv->bin_window = gdk_window_new (window,
2270                                                 &attributes, attributes_mask);
2271   gdk_window_set_user_data (tree_view->priv->bin_window, widget);
2272
2273   gtk_widget_get_allocation (widget, &allocation);
2274
2275   /* Make the column header window */
2276   attributes.x = 0;
2277   attributes.y = 0;
2278   attributes.width = MAX (tree_view->priv->width, allocation.width);
2279   attributes.height = tree_view->priv->header_height;
2280   attributes.event_mask = (GDK_EXPOSURE_MASK |
2281                            GDK_SCROLL_MASK |
2282                            GDK_ENTER_NOTIFY_MASK |
2283                            GDK_LEAVE_NOTIFY_MASK |
2284                            GDK_BUTTON_PRESS_MASK |
2285                            GDK_BUTTON_RELEASE_MASK |
2286                            GDK_KEY_PRESS_MASK |
2287                            GDK_KEY_RELEASE_MASK |
2288                            gtk_widget_get_events (widget));
2289
2290   tree_view->priv->header_window = gdk_window_new (window,
2291                                                    &attributes, attributes_mask);
2292   gdk_window_set_user_data (tree_view->priv->header_window, widget);
2293
2294   gtk_tree_view_ensure_background (tree_view);
2295
2296   tmp_list = tree_view->priv->children;
2297   while (tmp_list)
2298     {
2299       GtkTreeViewChild *child = tmp_list->data;
2300       tmp_list = tmp_list->next;
2301
2302       gtk_widget_set_parent_window (child->widget, tree_view->priv->bin_window);
2303     }
2304
2305   for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
2306     _gtk_tree_view_column_realize_button (GTK_TREE_VIEW_COLUMN (tmp_list->data));
2307
2308   /* Need to call those here, since they create GCs */
2309   gtk_tree_view_set_grid_lines (tree_view, tree_view->priv->grid_lines);
2310   gtk_tree_view_set_enable_tree_lines (tree_view, tree_view->priv->tree_lines_enabled);
2311
2312   install_presize_handler (tree_view); 
2313 }
2314
2315 static void
2316 gtk_tree_view_unrealize (GtkWidget *widget)
2317 {
2318   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2319   GtkTreeViewPrivate *priv = tree_view->priv;
2320   GList *list;
2321
2322   if (priv->scroll_timeout != 0)
2323     {
2324       g_source_remove (priv->scroll_timeout);
2325       priv->scroll_timeout = 0;
2326     }
2327
2328   if (priv->auto_expand_timeout != 0)
2329     {
2330       g_source_remove (priv->auto_expand_timeout);
2331       priv->auto_expand_timeout = 0;
2332     }
2333
2334   if (priv->open_dest_timeout != 0)
2335     {
2336       g_source_remove (priv->open_dest_timeout);
2337       priv->open_dest_timeout = 0;
2338     }
2339
2340   if (priv->presize_handler_timer != 0)
2341     {
2342       g_source_remove (priv->presize_handler_timer);
2343       priv->presize_handler_timer = 0;
2344     }
2345
2346   if (priv->validate_rows_timer != 0)
2347     {
2348       g_source_remove (priv->validate_rows_timer);
2349       priv->validate_rows_timer = 0;
2350     }
2351
2352   if (priv->scroll_sync_timer != 0)
2353     {
2354       g_source_remove (priv->scroll_sync_timer);
2355       priv->scroll_sync_timer = 0;
2356     }
2357
2358   if (priv->typeselect_flush_timeout)
2359     {
2360       g_source_remove (priv->typeselect_flush_timeout);
2361       priv->typeselect_flush_timeout = 0;
2362     }
2363   
2364   for (list = priv->columns; list; list = list->next)
2365     _gtk_tree_view_column_unrealize_button (GTK_TREE_VIEW_COLUMN (list->data));
2366
2367   gdk_window_set_user_data (priv->bin_window, NULL);
2368   gdk_window_destroy (priv->bin_window);
2369   priv->bin_window = NULL;
2370
2371   gdk_window_set_user_data (priv->header_window, NULL);
2372   gdk_window_destroy (priv->header_window);
2373   priv->header_window = NULL;
2374
2375   if (priv->drag_window)
2376     {
2377       gdk_window_set_user_data (priv->drag_window, NULL);
2378       gdk_window_destroy (priv->drag_window);
2379       priv->drag_window = NULL;
2380     }
2381
2382   if (priv->drag_highlight_window)
2383     {
2384       gdk_window_set_user_data (priv->drag_highlight_window, NULL);
2385       gdk_window_destroy (priv->drag_highlight_window);
2386       priv->drag_highlight_window = NULL;
2387     }
2388
2389   GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->unrealize (widget);
2390 }
2391
2392 /* GtkWidget::get_preferred_height helper */
2393 static void
2394 gtk_tree_view_update_height (GtkTreeView *tree_view)
2395 {
2396   GList *list;
2397
2398   tree_view->priv->header_height = 0;
2399
2400   for (list = tree_view->priv->columns; list; list = list->next)
2401     {
2402       GtkRequisition     requisition;
2403       GtkTreeViewColumn *column = list->data;
2404       GtkWidget         *button = gtk_tree_view_column_get_button (column);
2405
2406       if (button == NULL)
2407         continue;
2408
2409       gtk_widget_get_preferred_size (button, &requisition, NULL);
2410       tree_view->priv->header_height = MAX (tree_view->priv->header_height, requisition.height);
2411     }
2412
2413   if (tree_view->priv->tree == NULL)
2414     tree_view->priv->height = 0;
2415   else
2416     tree_view->priv->height = tree_view->priv->tree->root->offset;
2417 }
2418
2419 static void
2420 gtk_tree_view_get_preferred_width (GtkWidget *widget,
2421                                    gint      *minimum,
2422                                    gint      *natural)
2423 {
2424   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2425   GList *list;
2426   GtkTreeViewColumn *column;
2427   gint column_minimum, column_natural;
2428
2429   /* we validate some rows initially just to make sure we have some size.
2430    * In practice, with a lot of static lists, this should get a good width.
2431    */
2432   do_validate_rows (tree_view, FALSE);
2433   
2434   tree_view->priv->minimum_width = 0;
2435   tree_view->priv->natural_width = 0;
2436   tree_view->priv->n_expand_columns = 0;
2437
2438   /* keep this in sync with size_allocate below */
2439   for (list = tree_view->priv->columns; list; list = list->next)
2440     {
2441       column = list->data;
2442       if (!gtk_tree_view_column_get_visible (column) || column == tree_view->priv->drag_column)
2443         continue;
2444
2445       _gtk_tree_view_column_request_width (column, &column_minimum, &column_natural);
2446       tree_view->priv->minimum_width += column_minimum;
2447       tree_view->priv->natural_width += column_natural;
2448
2449       if (gtk_tree_view_column_get_expand (column))
2450         tree_view->priv->n_expand_columns++;
2451     }
2452
2453   if (minimum != NULL)
2454     *minimum = tree_view->priv->minimum_width;
2455   if (natural != NULL)
2456     *natural = tree_view->priv->natural_width;
2457 }
2458
2459 static void
2460 gtk_tree_view_get_preferred_height (GtkWidget *widget,
2461                                     gint      *minimum,
2462                                     gint      *natural)
2463 {
2464   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2465   gint height;
2466
2467   gtk_tree_view_update_height (tree_view);
2468
2469   height = tree_view->priv->height + gtk_tree_view_get_effective_header_height (tree_view);
2470
2471   if (minimum != NULL)
2472     *minimum = height;
2473   if (natural != NULL)
2474     *natural = height;
2475 }
2476
2477 static void
2478 gtk_tree_view_modify_column_width (GtkTreeView       *tree_view,
2479                                    GtkTreeViewColumn *column,
2480                                    gint               width)
2481 {
2482   gboolean is_expand;
2483   gint n_expand_others;
2484   gint minimum, natural, natural_others;
2485   gint expand;
2486
2487   is_expand = gtk_tree_view_column_get_expand (column);
2488   n_expand_others = tree_view->priv->n_expand_columns - (is_expand ? 1 : 0);
2489
2490   _gtk_tree_view_column_request_width (column, &minimum, &natural);
2491   natural_others = tree_view->priv->natural_width - natural;
2492
2493   if (natural_others + width < tree_view->priv->width)
2494     {
2495       /* There is extra space that needs to be taken up by letting some other
2496        * column(s) expand: by default, the last column. */
2497       if (!n_expand_others)
2498         {
2499           GList *last = g_list_last (tree_view->priv->columns);
2500           while (!gtk_tree_view_column_get_visible (last->data))
2501             last = last->prev;
2502
2503           if (column == last->data)
2504             return;
2505
2506           gtk_tree_view_column_set_expand (last->data, TRUE);
2507           n_expand_others++;
2508         }
2509
2510       /* Now try to make this column expandable also.  Solving the following
2511        * equations reveals what the natural width should be to achieve the
2512        * desired width after expanding:
2513        *
2514        *   1. natural + expand = desired_width
2515        *   2. natural + natural_others + expand * (n_expand_others + 1) = total_width
2516        *
2517        * Solution:
2518        *   expand = (total_width - natural_others - desired_width) / n_expand_others
2519        *
2520        * It is possible for the solved natural width to be less than the
2521        * minimum; in that case, we cannot let the column expand.
2522        */
2523       expand = (tree_view->priv->width - natural_others - width) / n_expand_others;
2524
2525       if (minimum + expand > width)
2526         {
2527           if (is_expand)
2528             gtk_tree_view_column_set_expand (column, FALSE);
2529         }
2530       else
2531         {
2532           if (!is_expand)
2533             gtk_tree_view_column_set_expand (column, TRUE);
2534
2535           width -= expand;
2536         }
2537     }
2538
2539   gtk_tree_view_column_set_fixed_width (column, width);
2540 }
2541
2542 static int
2543 gtk_tree_view_calculate_width_before_expander (GtkTreeView *tree_view)
2544 {
2545   int width = 0;
2546   GList *list;
2547   gboolean rtl;
2548
2549   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2550   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
2551        list->data != tree_view->priv->expander_column;
2552        list = (rtl ? list->prev : list->next))
2553     {
2554       GtkTreeViewColumn *column = list->data;
2555
2556       width += gtk_tree_view_column_get_width (column);
2557     }
2558
2559   return width;
2560 }
2561
2562 /* GtkWidget::size_allocate helper */
2563 static void
2564 gtk_tree_view_size_allocate_columns (GtkWidget *widget,
2565                                      gboolean  *width_changed)
2566 {
2567   GtkTreeView *tree_view;
2568   GList *list, *first_column, *last_column;
2569   GtkTreeViewColumn *column;
2570   GtkAllocation widget_allocation;
2571   gint minimum_width, natural_width, n_expand_columns, width;
2572   gint column_minimum, column_natural, column_width;
2573   gboolean rtl;
2574   
2575   tree_view = GTK_TREE_VIEW (widget);
2576
2577   for (last_column = g_list_last (tree_view->priv->columns);
2578        last_column &&
2579        !(gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (last_column->data)));
2580        last_column = last_column->prev)
2581     ;
2582   if (last_column == NULL)
2583     return;
2584
2585   for (first_column = g_list_first (tree_view->priv->columns);
2586        first_column &&
2587        !(gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (first_column->data)));
2588        first_column = first_column->next)
2589     ;
2590
2591   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
2592
2593   gtk_widget_get_allocation (widget, &widget_allocation);
2594
2595   minimum_width = tree_view->priv->minimum_width;
2596   natural_width = tree_view->priv->natural_width;
2597   n_expand_columns = tree_view->priv->n_expand_columns;
2598
2599   width = MAX (widget_allocation.width, minimum_width);
2600
2601   /* We change the width here.  The user might have been resizing columns,
2602    * which changes the total width of the tree view.  This is of
2603    * importance for getting the horizontal scroll bar right.
2604    */
2605   if (tree_view->priv->width != width)
2606     {
2607       tree_view->priv->width = width;
2608       if (width_changed)
2609         *width_changed = TRUE;
2610     }
2611
2612   /* iterate through columns in reverse order */
2613   for (list = (rtl ? first_column : last_column); 
2614        list != (rtl ? last_column->next : first_column->prev);
2615        list = (rtl ? list->next : list->prev)) 
2616     {
2617       column = list->data;
2618
2619       if (!gtk_tree_view_column_get_visible (column) || column == tree_view->priv->drag_column)
2620         continue;
2621
2622       _gtk_tree_view_column_request_width (column, &column_minimum, &column_natural);
2623       
2624       column_width = column_natural;
2625
2626       if (width > natural_width)
2627         {
2628           /* We need to expand some columns.  If there are none marked to
2629            * expand, give all the extra space to the last column. */
2630           if (n_expand_columns == 0)
2631             {
2632               column_width = column_natural + (width - natural_width);
2633             }
2634           else if (gtk_tree_view_column_get_expand (column))
2635             {
2636               column_width = column_natural + (width - natural_width) / n_expand_columns;
2637               n_expand_columns--;
2638             }
2639         }
2640       else if (width < natural_width)
2641         {
2642           /* We need to shrink some columns.  Starting with later columns,
2643            * shrink each one down to its minimum width as necessary. */
2644           column_width = MAX (column_natural + (width - natural_width), column_minimum);
2645         }
2646         
2647       _gtk_tree_view_column_allocate (column, width - column_width, column_width);
2648       
2649       minimum_width -= column_minimum;
2650       natural_width -= column_natural;
2651       width -= column_width;
2652     }
2653 }
2654
2655 /* GtkWidget::size_allocate helper */
2656 static void
2657 gtk_tree_view_size_allocate_drag_column (GtkWidget *widget)
2658 {
2659   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2660   GtkAllocation drag_allocation;
2661   GtkWidget *button;
2662
2663   if (tree_view->priv->drag_column == NULL)
2664     return;
2665
2666   button = gtk_tree_view_column_get_button (tree_view->priv->drag_column);
2667
2668   drag_allocation.x = 0;
2669   drag_allocation.y = 0;
2670   drag_allocation.width = gdk_window_get_width (tree_view->priv->drag_window);
2671   drag_allocation.height = gdk_window_get_height (tree_view->priv->drag_window);
2672   gtk_widget_size_allocate (button, &drag_allocation);
2673 }
2674
2675 static void
2676 gtk_tree_view_size_allocate (GtkWidget     *widget,
2677                              GtkAllocation *allocation)
2678 {
2679   GtkAllocation widget_allocation;
2680   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2681   GList *tmp_list;
2682   gboolean width_changed = FALSE;
2683   gint old_width;
2684
2685   gtk_widget_get_allocation (widget, &widget_allocation);
2686   old_width = widget_allocation.width;
2687   if (allocation->width != widget_allocation.width)
2688     width_changed = TRUE;
2689
2690   gtk_widget_set_allocation (widget, allocation);
2691
2692   tmp_list = tree_view->priv->children;
2693
2694   while (tmp_list)
2695     {
2696       GtkAllocation allocation;
2697
2698       GtkTreeViewChild *child = tmp_list->data;
2699       tmp_list = tmp_list->next;
2700
2701       /* totally ignore our child's requisition */
2702       allocation.x = child->x;
2703       allocation.y = child->y;
2704       allocation.width = child->width;
2705       allocation.height = child->height;
2706       gtk_widget_size_allocate (child->widget, &allocation);
2707     }
2708
2709   /* We size-allocate the columns first because the width of the
2710    * tree view (used in updating the adjustments below) might change.
2711    */
2712   gtk_tree_view_size_allocate_columns (widget, &width_changed);
2713   gtk_tree_view_size_allocate_drag_column (widget);
2714
2715   g_object_freeze_notify (G_OBJECT (tree_view->priv->hadjustment));
2716   gtk_adjustment_set_page_size (tree_view->priv->hadjustment,
2717                                 allocation->width);
2718   gtk_adjustment_set_page_increment (tree_view->priv->hadjustment,
2719                                      allocation->width * 0.9);
2720   gtk_adjustment_set_step_increment (tree_view->priv->hadjustment,
2721                                      allocation->width * 0.1);
2722   gtk_adjustment_set_lower (tree_view->priv->hadjustment, 0);
2723   gtk_adjustment_set_upper (tree_view->priv->hadjustment,
2724                             MAX (gtk_adjustment_get_page_size (tree_view->priv->hadjustment),
2725                                  tree_view->priv->width));
2726   g_object_thaw_notify (G_OBJECT (tree_view->priv->hadjustment));
2727
2728   if (gtk_widget_get_direction(widget) == GTK_TEXT_DIR_RTL)   
2729     {
2730       if (allocation->width < tree_view->priv->width)
2731         {
2732           if (tree_view->priv->init_hadjust_value)
2733             {
2734               gtk_adjustment_set_value (tree_view->priv->hadjustment,
2735                                         MAX (tree_view->priv->width -
2736                                              allocation->width, 0));
2737               tree_view->priv->init_hadjust_value = FALSE;
2738             }
2739           else if (allocation->width != old_width)
2740             {
2741               gtk_adjustment_set_value (tree_view->priv->hadjustment,
2742                                         CLAMP (gtk_adjustment_get_value (tree_view->priv->hadjustment) - allocation->width + old_width,
2743                                                0,
2744                                                tree_view->priv->width - allocation->width));
2745             }
2746         }
2747       else
2748         {
2749           gtk_adjustment_set_value (tree_view->priv->hadjustment, 0);
2750           tree_view->priv->init_hadjust_value = TRUE;
2751         }
2752     }
2753   else
2754     if (gtk_adjustment_get_value (tree_view->priv->hadjustment) + allocation->width > tree_view->priv->width)
2755       gtk_adjustment_set_value (tree_view->priv->hadjustment,
2756                                 MAX (tree_view->priv->width -
2757                                      allocation->width, 0));
2758
2759   g_object_freeze_notify (G_OBJECT (tree_view->priv->vadjustment));
2760   gtk_adjustment_set_page_size (tree_view->priv->vadjustment,
2761                                 allocation->height -
2762                                 gtk_tree_view_get_effective_header_height (tree_view));
2763   gtk_adjustment_set_step_increment (tree_view->priv->vadjustment,
2764                                      gtk_adjustment_get_page_size (tree_view->priv->vadjustment) * 0.1);
2765   gtk_adjustment_set_page_increment (tree_view->priv->vadjustment,
2766                                      gtk_adjustment_get_page_size (tree_view->priv->vadjustment) * 0.9);
2767   gtk_adjustment_set_lower (tree_view->priv->vadjustment, 0);
2768   gtk_adjustment_set_upper (tree_view->priv->vadjustment,
2769                             MAX (gtk_adjustment_get_page_size (tree_view->priv->vadjustment),
2770                                  tree_view->priv->height));
2771   g_object_thaw_notify (G_OBJECT (tree_view->priv->vadjustment));
2772
2773   /* now the adjustments and window sizes are in sync, we can sync toprow/dy again */
2774   if (tree_view->priv->height <= gtk_adjustment_get_page_size (tree_view->priv->vadjustment))
2775     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
2776   else if (gtk_adjustment_get_value (tree_view->priv->vadjustment) + gtk_adjustment_get_page_size (tree_view->priv->vadjustment) > tree_view->priv->height)
2777     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment),
2778                               tree_view->priv->height - gtk_adjustment_get_page_size (tree_view->priv->vadjustment));
2779   else if (gtk_tree_row_reference_valid (tree_view->priv->top_row))
2780     gtk_tree_view_top_row_to_dy (tree_view);
2781   else
2782     gtk_tree_view_dy_to_top_row (tree_view);
2783   
2784   if (gtk_widget_get_realized (widget))
2785     {
2786       gdk_window_move_resize (gtk_widget_get_window (widget),
2787                               allocation->x, allocation->y,
2788                               allocation->width, allocation->height);
2789       gdk_window_move_resize (tree_view->priv->header_window,
2790                               - (gint) gtk_adjustment_get_value (tree_view->priv->hadjustment),
2791                               0,
2792                               MAX (tree_view->priv->width, allocation->width),
2793                               tree_view->priv->header_height);
2794       gdk_window_move_resize (tree_view->priv->bin_window,
2795                               - (gint) gtk_adjustment_get_value (tree_view->priv->hadjustment),
2796                               gtk_tree_view_get_effective_header_height (tree_view),
2797                               MAX (tree_view->priv->width, allocation->width),
2798                               allocation->height - gtk_tree_view_get_effective_header_height (tree_view));
2799
2800       if (tree_view->priv->tree == NULL)
2801         invalidate_empty_focus (tree_view);
2802
2803       if (width_changed && tree_view->priv->expander_column)
2804         {
2805           /* Might seem awkward, but is the best heuristic I could come up
2806            * with.  Only if the width of the columns before the expander
2807            * changes, we will update the prelight status.  It is this
2808            * width that makes the expander move vertically.  Always updating
2809            * prelight status causes trouble with hover selections.
2810            */
2811           gint width_before_expander;
2812
2813           width_before_expander = gtk_tree_view_calculate_width_before_expander (tree_view);
2814
2815           if (tree_view->priv->prev_width_before_expander
2816               != width_before_expander)
2817               update_prelight (tree_view,
2818                                tree_view->priv->event_last_x,
2819                                tree_view->priv->event_last_y);
2820
2821           tree_view->priv->prev_width_before_expander = width_before_expander;
2822         }
2823     }
2824 }
2825
2826 /* Grabs the focus and unsets the GTK_TREE_VIEW_DRAW_KEYFOCUS flag */
2827 static void
2828 grab_focus_and_unset_draw_keyfocus (GtkTreeView *tree_view)
2829 {
2830   GtkWidget *widget = GTK_WIDGET (tree_view);
2831
2832   if (gtk_widget_get_can_focus (widget) && !gtk_widget_has_focus (widget))
2833     gtk_widget_grab_focus (widget);
2834   tree_view->priv->draw_keyfocus = 0;
2835 }
2836
2837 static inline gboolean
2838 row_is_separator (GtkTreeView *tree_view,
2839                   GtkTreeIter *iter,
2840                   GtkTreePath *path)
2841 {
2842   gboolean is_separator = FALSE;
2843
2844   if (tree_view->priv->row_separator_func)
2845     {
2846       GtkTreeIter tmpiter;
2847
2848       if (iter)
2849         tmpiter = *iter;
2850       else
2851         {
2852           if (!gtk_tree_model_get_iter (tree_view->priv->model, &tmpiter, path))
2853             return FALSE;
2854         }
2855
2856       is_separator = tree_view->priv->row_separator_func (tree_view->priv->model,
2857                                                           &tmpiter,
2858                                                           tree_view->priv->row_separator_data);
2859     }
2860
2861   return is_separator;
2862 }
2863
2864 static int
2865 gtk_tree_view_get_expander_size (GtkTreeView *tree_view)
2866 {
2867   gint expander_size;
2868
2869   gtk_widget_style_get (GTK_WIDGET (tree_view),
2870                         "expander-size", &expander_size,
2871                         NULL);
2872   expander_size += EXPANDER_EXTRA_PADDING;
2873
2874   return expander_size;
2875 }
2876
2877 static gboolean
2878 gtk_tree_view_button_press (GtkWidget      *widget,
2879                             GdkEventButton *event)
2880 {
2881   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2882   GList *list;
2883   GtkTreeViewColumn *column = NULL;
2884   gint i;
2885   GdkRectangle background_area;
2886   GdkRectangle cell_area;
2887   gint vertical_separator;
2888   gint horizontal_separator;
2889   gboolean path_is_selectable;
2890   gboolean rtl;
2891
2892   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
2893   gtk_tree_view_stop_editing (tree_view, FALSE);
2894   gtk_widget_style_get (widget,
2895                         "vertical-separator", &vertical_separator,
2896                         "horizontal-separator", &horizontal_separator,
2897                         NULL);
2898
2899   /* Don't handle extra mouse buttons events, let them bubble up */
2900   if (event->button > 5)
2901     return FALSE;
2902  
2903   /* Because grab_focus can cause reentrancy, we delay grab_focus until after
2904    * we're done handling the button press.
2905    */
2906
2907   if (event->window == tree_view->priv->bin_window)
2908     {
2909       GtkRBNode *node;
2910       GtkRBTree *tree;
2911       GtkTreePath *path;
2912       gint depth;
2913       gint new_y;
2914       gint y_offset;
2915       gint dval;
2916       gint pre_val, aft_val;
2917       GtkTreeViewColumn *column = NULL;
2918       gint column_handled_click = FALSE;
2919       gboolean row_double_click = FALSE;
2920       gboolean rtl;
2921       gboolean node_selected;
2922       GdkModifierType extend_mod_mask;
2923       GdkModifierType modify_mod_mask;
2924
2925       /* Empty tree? */
2926       if (tree_view->priv->tree == NULL)
2927         {
2928           grab_focus_and_unset_draw_keyfocus (tree_view);
2929           return TRUE;
2930         }
2931
2932       /* are we in an arrow? */
2933       if (tree_view->priv->prelight_node &&
2934           tree_view->priv->arrow_prelit &&
2935           gtk_tree_view_draw_expanders (tree_view))
2936         {
2937           if (event->button == GDK_BUTTON_PRIMARY)
2938             {
2939               gtk_grab_add (widget);
2940               tree_view->priv->button_pressed_node = tree_view->priv->prelight_node;
2941               tree_view->priv->button_pressed_tree = tree_view->priv->prelight_tree;
2942               gtk_tree_view_queue_draw_arrow (GTK_TREE_VIEW (widget),
2943                                               tree_view->priv->prelight_tree,
2944                                               tree_view->priv->prelight_node);
2945             }
2946
2947           grab_focus_and_unset_draw_keyfocus (tree_view);
2948           return TRUE;
2949         }
2950
2951       /* find the node that was clicked */
2952       new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
2953       if (new_y < 0)
2954         new_y = 0;
2955       y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
2956
2957       if (node == NULL)
2958         {
2959           /* We clicked in dead space */
2960           grab_focus_and_unset_draw_keyfocus (tree_view);
2961           return TRUE;
2962         }
2963
2964       /* Get the path and the node */
2965       path = _gtk_tree_path_new_from_rbtree (tree, node);
2966       path_is_selectable = !row_is_separator (tree_view, NULL, path);
2967
2968       if (!path_is_selectable)
2969         {
2970           gtk_tree_path_free (path);
2971           grab_focus_and_unset_draw_keyfocus (tree_view);
2972           return TRUE;
2973         }
2974
2975       depth = gtk_tree_path_get_depth (path);
2976       background_area.y = y_offset + event->y;
2977       background_area.height = gtk_tree_view_get_row_height (tree_view, node);
2978       background_area.x = 0;
2979
2980
2981       /* Let the column have a chance at selecting it. */
2982       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2983       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
2984            list; list = (rtl ? list->prev : list->next))
2985         {
2986           GtkTreeViewColumn *candidate = list->data;
2987
2988           if (!gtk_tree_view_column_get_visible (candidate))
2989             continue;
2990
2991           background_area.width = gtk_tree_view_column_get_width (candidate);
2992           if ((background_area.x > (gint) event->x) ||
2993               (background_area.x + background_area.width <= (gint) event->x))
2994             {
2995               background_area.x += background_area.width;
2996               continue;
2997             }
2998
2999           /* we found the focus column */
3000           column = candidate;
3001           cell_area = background_area;
3002           cell_area.width -= horizontal_separator;
3003           cell_area.height -= vertical_separator;
3004           cell_area.x += horizontal_separator/2;
3005           cell_area.y += vertical_separator/2;
3006           if (gtk_tree_view_is_expander_column (tree_view, column))
3007             {
3008               if (!rtl)
3009                 cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
3010               cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
3011
3012               if (gtk_tree_view_draw_expanders (tree_view))
3013                 {
3014                   gint expander_size = gtk_tree_view_get_expander_size (tree_view);
3015                   if (!rtl)
3016                     cell_area.x += depth * expander_size;
3017                   cell_area.width -= depth * expander_size;
3018                 }
3019             }
3020           break;
3021         }
3022
3023       if (column == NULL)
3024         {
3025           gtk_tree_path_free (path);
3026           grab_focus_and_unset_draw_keyfocus (tree_view);
3027           return FALSE;
3028         }
3029
3030       _gtk_tree_view_set_focus_column (tree_view, column);
3031
3032       /* decide if we edit */
3033       if (event->type == GDK_BUTTON_PRESS && event->button == GDK_BUTTON_PRIMARY &&
3034           !(event->state & gtk_accelerator_get_default_mod_mask ()))
3035         {
3036           GtkTreePath *anchor;
3037           GtkTreeIter iter;
3038
3039           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
3040           gtk_tree_view_column_cell_set_cell_data (column,
3041                                                    tree_view->priv->model,
3042                                                    &iter,
3043                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
3044                                                    node->children?TRUE:FALSE);
3045
3046           if (tree_view->priv->anchor)
3047             anchor = gtk_tree_row_reference_get_path (tree_view->priv->anchor);
3048           else
3049             anchor = NULL;
3050
3051           if ((anchor && !gtk_tree_path_compare (anchor, path))
3052               || !_gtk_tree_view_column_has_editable_cell (column))
3053             {
3054               GtkCellEditable *cell_editable = NULL;
3055
3056               /* FIXME: get the right flags */
3057               guint flags = 0;
3058
3059               if (_gtk_tree_view_column_cell_event (column,
3060                                                     (GdkEvent *)event,
3061                                                     &cell_area, flags))
3062                 {
3063                   GtkCellArea *area = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (column));
3064                   cell_editable = gtk_cell_area_get_edit_widget (area);
3065
3066                   if (cell_editable != NULL)
3067                     {
3068                       gtk_tree_path_free (path);
3069                       gtk_tree_path_free (anchor);
3070                       return TRUE;
3071                     }
3072                   column_handled_click = TRUE;
3073                 }
3074             }
3075           if (anchor)
3076             gtk_tree_path_free (anchor);
3077         }
3078
3079       extend_mod_mask =
3080         gtk_widget_get_modifier_mask (widget, GDK_MODIFIER_INTENT_EXTEND_SELECTION);
3081
3082       modify_mod_mask =
3083         gtk_widget_get_modifier_mask (widget, GDK_MODIFIER_INTENT_MODIFY_SELECTION);
3084
3085       /* select */
3086       node_selected = GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED);
3087       pre_val = gtk_adjustment_get_value (tree_view->priv->vadjustment);
3088
3089       /* we only handle selection modifications on the first button press
3090        */
3091       if (event->type == GDK_BUTTON_PRESS)
3092         {
3093           GtkCellRenderer *focus_cell;
3094
3095           if ((event->state & modify_mod_mask) == modify_mod_mask)
3096             tree_view->priv->modify_selection_pressed = TRUE;
3097           if ((event->state & extend_mod_mask) == extend_mod_mask)
3098             tree_view->priv->extend_selection_pressed = TRUE;
3099
3100           /* We update the focus cell here, this is also needed if the
3101            * column does not contain an editable cell.  In this case,
3102            * GtkCellArea did not receive the event for processing (and
3103            * could not update the focus cell).
3104            */
3105           focus_cell = _gtk_tree_view_column_get_cell_at_pos (column,
3106                                                               &cell_area,
3107                                                               &background_area,
3108                                                               event->x,
3109                                                               event->y);
3110
3111           if (focus_cell)
3112             gtk_tree_view_column_focus_cell (column, focus_cell);
3113
3114           if (event->state & modify_mod_mask)
3115             {
3116               gtk_tree_view_real_set_cursor (tree_view, path, CLAMP_NODE);
3117               gtk_tree_view_real_toggle_cursor_row (tree_view);
3118             }
3119           else if (event->state & extend_mod_mask)
3120             {
3121               gtk_tree_view_real_set_cursor (tree_view, path, CLAMP_NODE);
3122               gtk_tree_view_real_select_cursor_row (tree_view, FALSE);
3123             }
3124           else
3125             {
3126               gtk_tree_view_real_set_cursor (tree_view, path, CLEAR_AND_SELECT | CLAMP_NODE);
3127             }
3128
3129           tree_view->priv->modify_selection_pressed = FALSE;
3130           tree_view->priv->extend_selection_pressed = FALSE;
3131         }
3132
3133       /* the treeview may have been scrolled because of _set_cursor,
3134        * correct here
3135        */
3136
3137       aft_val = gtk_adjustment_get_value (tree_view->priv->vadjustment);
3138       dval = pre_val - aft_val;
3139
3140       cell_area.y += dval;
3141       background_area.y += dval;
3142
3143       /* Save press to possibly begin a drag
3144        */
3145       if (!column_handled_click &&
3146           !tree_view->priv->in_grab &&
3147           tree_view->priv->pressed_button < 0)
3148         {
3149           tree_view->priv->pressed_button = event->button;
3150           tree_view->priv->press_start_x = event->x;
3151           tree_view->priv->press_start_y = event->y;
3152
3153           if (tree_view->priv->rubber_banding_enable
3154               && !node_selected
3155               && gtk_tree_selection_get_mode (tree_view->priv->selection) == GTK_SELECTION_MULTIPLE)
3156             {
3157               tree_view->priv->press_start_y += tree_view->priv->dy;
3158               tree_view->priv->rubber_band_x = event->x;
3159               tree_view->priv->rubber_band_y = event->y + tree_view->priv->dy;
3160               tree_view->priv->rubber_band_status = RUBBER_BAND_MAYBE_START;
3161
3162               if ((event->state & modify_mod_mask) == modify_mod_mask)
3163                 tree_view->priv->rubber_band_modify = TRUE;
3164               if ((event->state & extend_mod_mask) == extend_mod_mask)
3165                 tree_view->priv->rubber_band_extend = TRUE;
3166             }
3167         }
3168
3169       if (event->button == GDK_BUTTON_PRIMARY && event->type == GDK_BUTTON_PRESS)
3170         {
3171
3172           /* Test if a double click happened on the same row. */
3173           if (!tree_view->priv->activate_on_single_click)
3174             {
3175               int double_click_time, double_click_distance;
3176
3177               g_object_get (gtk_settings_get_default (),
3178                             "gtk-double-click-time", &double_click_time,
3179                             "gtk-double-click-distance", &double_click_distance,
3180                             NULL);
3181
3182               /* Same conditions as _gdk_event_button_generate */
3183               if (tree_view->priv->last_button_x != -1 &&
3184                   (event->time < tree_view->priv->last_button_time + double_click_time) &&
3185                   (ABS (event->x - tree_view->priv->last_button_x) <= double_click_distance) &&
3186                   (ABS (event->y - tree_view->priv->last_button_y) <= double_click_distance))
3187                 {
3188                   /* We do no longer compare paths of this row and the
3189                    * row clicked previously.  We use the double click
3190                    * distance to decide whether this is a valid click,
3191                    * allowing the mouse to slightly move over another row.
3192                    */
3193                   row_double_click = TRUE;
3194
3195                   tree_view->priv->last_button_time = 0;
3196                   tree_view->priv->last_button_x = -1;
3197                   tree_view->priv->last_button_y = -1;
3198                 }
3199               else
3200                 {
3201                   tree_view->priv->last_button_time = event->time;
3202                   tree_view->priv->last_button_x = event->x;
3203                   tree_view->priv->last_button_y = event->y;
3204                 }
3205             }
3206           else
3207             {
3208               tree_view->priv->button_pressed_node = tree_view->priv->prelight_node;
3209               tree_view->priv->button_pressed_tree = tree_view->priv->prelight_tree;
3210             }
3211         }
3212
3213       if (row_double_click)
3214         {
3215           gtk_grab_remove (widget);
3216           gtk_tree_view_row_activated (tree_view, path, column);
3217
3218           if (tree_view->priv->pressed_button == event->button)
3219             tree_view->priv->pressed_button = -1;
3220         }
3221
3222       gtk_tree_path_free (path);
3223
3224       /* If we activated the row through a double click we don't want to grab
3225        * focus back, as moving focus to another widget is pretty common.
3226        */
3227       if (!row_double_click)
3228         grab_focus_and_unset_draw_keyfocus (tree_view);
3229
3230       return TRUE;
3231     }
3232
3233   /* We didn't click in the window.  Let's check to see if we clicked on a column resize window.
3234    */
3235   for (i = 0, list = tree_view->priv->columns; list; list = list->next, i++)
3236     {
3237       column = list->data;
3238       if (event->window == _gtk_tree_view_column_get_window (column) &&
3239           gtk_tree_view_column_get_resizable (column) &&
3240           _gtk_tree_view_column_get_window (column))
3241         {
3242           gpointer drag_data;
3243           gint column_width, x;
3244
3245           if (event->type == GDK_2BUTTON_PRESS &&
3246               gtk_tree_view_column_get_sizing (column) != GTK_TREE_VIEW_COLUMN_AUTOSIZE)
3247             {
3248               gtk_tree_view_column_set_fixed_width (column, -1);
3249               gtk_tree_view_column_set_expand (column, FALSE);
3250               _gtk_tree_view_column_autosize (tree_view, column);
3251               return TRUE;
3252             }
3253
3254           if (gdk_device_grab (gdk_event_get_device ((GdkEvent*)event),
3255                                _gtk_tree_view_column_get_window (column),
3256                                GDK_OWNERSHIP_NONE,
3257                                FALSE,
3258                                GDK_POINTER_MOTION_HINT_MASK
3259                                 | GDK_BUTTON1_MOTION_MASK
3260                                 | GDK_BUTTON_RELEASE_MASK,
3261                                NULL,
3262                                event->time) != GDK_GRAB_SUCCESS)
3263             return FALSE;
3264
3265           gtk_grab_add (widget);
3266           tree_view->priv->in_column_resize = TRUE;
3267
3268           /* block attached dnd signal handler */
3269           drag_data = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
3270           if (drag_data)
3271             g_signal_handlers_block_matched (widget,
3272                                              G_SIGNAL_MATCH_DATA,
3273                                              0, 0, NULL, NULL,
3274                                              drag_data);
3275
3276           column_width = gtk_tree_view_column_get_width (column);
3277           gdk_window_get_device_position (tree_view->priv->bin_window,
3278                                           gdk_event_get_device ((GdkEvent *) event),
3279                                           &x, NULL, NULL);
3280
3281           tree_view->priv->drag_pos = i;
3282           tree_view->priv->x_drag = x + (rtl ? column_width : -column_width);
3283
3284           if (!gtk_widget_has_focus (widget))
3285             gtk_widget_grab_focus (widget);
3286
3287           return TRUE;
3288         }
3289     }
3290   return FALSE;
3291 }
3292
3293 /* GtkWidget::button_release_event helper */
3294 static gboolean
3295 gtk_tree_view_button_release_drag_column (GtkWidget      *widget,
3296                                           GdkEventButton *event)
3297 {
3298   GtkTreeView *tree_view;
3299   GtkWidget *button;
3300   GList *l;
3301   gboolean rtl;
3302   GdkDevice *device, *other;
3303   GtkStyleContext *context;
3304
3305   tree_view = GTK_TREE_VIEW (widget);
3306
3307   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
3308   device = gdk_event_get_device ((GdkEvent*)event);
3309   other = gdk_device_get_associated_device (device);
3310   gdk_device_ungrab (device, event->time);
3311   gdk_device_ungrab (other, event->time);
3312
3313   /* Move the button back */
3314   button = gtk_tree_view_column_get_button (tree_view->priv->drag_column);
3315
3316   context = gtk_widget_get_style_context (button);
3317   gtk_style_context_remove_class (context, GTK_STYLE_CLASS_DND);
3318
3319   g_object_ref (button);
3320   gtk_container_remove (GTK_CONTAINER (tree_view), button);
3321   gtk_widget_set_parent_window (button, tree_view->priv->header_window);
3322   gtk_widget_set_parent (button, GTK_WIDGET (tree_view));
3323   g_object_unref (button);
3324   gtk_widget_queue_resize (widget);
3325   if (gtk_tree_view_column_get_resizable (tree_view->priv->drag_column))
3326     {
3327       gdk_window_raise (_gtk_tree_view_column_get_window (tree_view->priv->drag_column));
3328       gdk_window_show (_gtk_tree_view_column_get_window (tree_view->priv->drag_column));
3329     }
3330   else
3331     gdk_window_hide (_gtk_tree_view_column_get_window (tree_view->priv->drag_column));
3332
3333   gtk_widget_grab_focus (button);
3334
3335   if (rtl)
3336     {
3337       if (tree_view->priv->cur_reorder &&
3338           tree_view->priv->cur_reorder->right_column != tree_view->priv->drag_column)
3339         gtk_tree_view_move_column_after (tree_view, tree_view->priv->drag_column,
3340                                          tree_view->priv->cur_reorder->right_column);
3341     }
3342   else
3343     {
3344       if (tree_view->priv->cur_reorder &&
3345           tree_view->priv->cur_reorder->left_column != tree_view->priv->drag_column)
3346         gtk_tree_view_move_column_after (tree_view, tree_view->priv->drag_column,
3347                                          tree_view->priv->cur_reorder->left_column);
3348     }
3349   tree_view->priv->drag_column = NULL;
3350   gdk_window_destroy (tree_view->priv->drag_window);
3351   tree_view->priv->drag_window = NULL;
3352
3353   for (l = tree_view->priv->column_drag_info; l != NULL; l = l->next)
3354     g_slice_free (GtkTreeViewColumnReorder, l->data);
3355   g_list_free (tree_view->priv->column_drag_info);
3356   tree_view->priv->column_drag_info = NULL;
3357   tree_view->priv->cur_reorder = NULL;
3358
3359   if (tree_view->priv->drag_highlight_window)
3360     gdk_window_hide (tree_view->priv->drag_highlight_window);
3361
3362   /* Reset our flags */
3363   tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_UNSET;
3364   tree_view->priv->in_column_drag = FALSE;
3365
3366   return TRUE;
3367 }
3368
3369 /* GtkWidget::button_release_event helper */
3370 static gboolean
3371 gtk_tree_view_button_release_column_resize (GtkWidget      *widget,
3372                                             GdkEventButton *event)
3373 {
3374   GtkTreeView *tree_view;
3375   gpointer drag_data;
3376
3377   tree_view = GTK_TREE_VIEW (widget);
3378
3379   tree_view->priv->drag_pos = -1;
3380
3381   /* unblock attached dnd signal handler */
3382   drag_data = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
3383   if (drag_data)
3384     g_signal_handlers_unblock_matched (widget,
3385                                        G_SIGNAL_MATCH_DATA,
3386                                        0, 0, NULL, NULL,
3387                                        drag_data);
3388
3389   tree_view->priv->in_column_resize = FALSE;
3390   gtk_grab_remove (widget);
3391   gdk_device_ungrab (gdk_event_get_device ((GdkEvent*)event), event->time);
3392   return TRUE;
3393 }
3394
3395 static gboolean
3396 button_event_modifies_selection (GdkEventButton *event)
3397 {
3398         return (event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)) != 0;
3399 }
3400
3401 static gboolean
3402 gtk_tree_view_button_release (GtkWidget      *widget,
3403                               GdkEventButton *event)
3404 {
3405   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
3406
3407   if (tree_view->priv->in_column_drag)
3408     return gtk_tree_view_button_release_drag_column (widget, event);
3409
3410   if (tree_view->priv->rubber_band_status)
3411     gtk_tree_view_stop_rubber_band (tree_view);
3412
3413   if (tree_view->priv->pressed_button == event->button)
3414     tree_view->priv->pressed_button = -1;
3415
3416   if (tree_view->priv->in_column_resize)
3417     return gtk_tree_view_button_release_column_resize (widget, event);
3418
3419   if (tree_view->priv->button_pressed_node == NULL)
3420     return FALSE;
3421
3422   if (event->button == GDK_BUTTON_PRIMARY
3423       && tree_view->priv->button_pressed_node == tree_view->priv->prelight_node)
3424     {
3425       if (tree_view->priv->arrow_prelit)
3426         {
3427           GtkTreePath *path = NULL;
3428
3429           path = _gtk_tree_path_new_from_rbtree (tree_view->priv->button_pressed_tree,
3430                                                  tree_view->priv->button_pressed_node);
3431           /* Actually activate the node */
3432           if (tree_view->priv->button_pressed_node->children == NULL)
3433             gtk_tree_view_real_expand_row (tree_view, path,
3434                                            tree_view->priv->button_pressed_tree,
3435                                            tree_view->priv->button_pressed_node,
3436                                            FALSE, TRUE);
3437           else
3438             gtk_tree_view_real_collapse_row (GTK_TREE_VIEW (widget), path,
3439                                              tree_view->priv->button_pressed_tree,
3440                                              tree_view->priv->button_pressed_node, TRUE);
3441           gtk_tree_path_free (path);
3442         }
3443       else if (tree_view->priv->activate_on_single_click
3444                && !button_event_modifies_selection (event))
3445         {
3446           GtkTreePath *path = NULL;
3447
3448           path = _gtk_tree_path_new_from_rbtree (tree_view->priv->button_pressed_tree,
3449                                                  tree_view->priv->button_pressed_node);
3450           gtk_tree_view_row_activated (tree_view, path, tree_view->priv->focus_column);
3451           gtk_tree_path_free (path);
3452         }
3453
3454       gtk_grab_remove (widget);
3455       tree_view->priv->button_pressed_tree = NULL;
3456       tree_view->priv->button_pressed_node = NULL;
3457     }
3458
3459   return TRUE;
3460 }
3461
3462 static gboolean
3463 gtk_tree_view_grab_broken (GtkWidget          *widget,
3464                            GdkEventGrabBroken *event)
3465 {
3466   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
3467
3468   if (tree_view->priv->in_column_drag)
3469     gtk_tree_view_button_release_drag_column (widget, (GdkEventButton *)event);
3470
3471   if (tree_view->priv->in_column_resize)
3472     gtk_tree_view_button_release_column_resize (widget, (GdkEventButton *)event);
3473
3474   return TRUE;
3475 }
3476
3477 #if 0
3478 static gboolean
3479 gtk_tree_view_configure (GtkWidget *widget,
3480                          GdkEventConfigure *event)
3481 {
3482   GtkTreeView *tree_view;
3483
3484   tree_view = GTK_TREE_VIEW (widget);
3485   tree_view->priv->search_position_func (tree_view, tree_view->priv->search_window);
3486
3487   return FALSE;
3488 }
3489 #endif
3490
3491 /* GtkWidget::motion_event function set.
3492  */
3493
3494 static gboolean
3495 coords_are_over_arrow (GtkTreeView *tree_view,
3496                        GtkRBTree   *tree,
3497                        GtkRBNode   *node,
3498                        /* these are in bin window coords */
3499                        gint         x,
3500                        gint         y)
3501 {
3502   GdkRectangle arrow;
3503   gint x2;
3504
3505   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
3506     return FALSE;
3507
3508   if ((node->flags & GTK_RBNODE_IS_PARENT) == 0)
3509     return FALSE;
3510
3511   arrow.y = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
3512   arrow.height = gtk_tree_view_get_row_height (tree_view, node);
3513
3514   gtk_tree_view_get_arrow_xrange (tree_view, tree, &arrow.x, &x2);
3515
3516   arrow.width = x2 - arrow.x;
3517
3518   return (x >= arrow.x &&
3519           x < (arrow.x + arrow.width) &&
3520           y >= arrow.y &&
3521           y < (arrow.y + arrow.height));
3522 }
3523
3524 static gboolean
3525 auto_expand_timeout (gpointer data)
3526 {
3527   GtkTreeView *tree_view = GTK_TREE_VIEW (data);
3528   GtkTreePath *path;
3529
3530   if (tree_view->priv->prelight_node)
3531     {
3532       path = _gtk_tree_path_new_from_rbtree (tree_view->priv->prelight_tree,
3533                                              tree_view->priv->prelight_node);
3534
3535       if (tree_view->priv->prelight_node->children)
3536         gtk_tree_view_collapse_row (tree_view, path);
3537       else
3538         gtk_tree_view_expand_row (tree_view, path, FALSE);
3539
3540       gtk_tree_path_free (path);
3541     }
3542
3543   tree_view->priv->auto_expand_timeout = 0;
3544
3545   return FALSE;
3546 }
3547
3548 static void
3549 remove_auto_expand_timeout (GtkTreeView *tree_view)
3550 {
3551   if (tree_view->priv->auto_expand_timeout != 0)
3552     {
3553       g_source_remove (tree_view->priv->auto_expand_timeout);
3554       tree_view->priv->auto_expand_timeout = 0;
3555     }
3556 }
3557
3558 static void
3559 do_prelight (GtkTreeView *tree_view,
3560              GtkRBTree   *tree,
3561              GtkRBNode   *node,
3562              /* these are in bin_window coords */
3563              gint         x,
3564              gint         y)
3565 {
3566   if (tree_view->priv->prelight_tree == tree &&
3567       tree_view->priv->prelight_node == node)
3568     {
3569       /*  We are still on the same node,
3570           but we might need to take care of the arrow  */
3571
3572       if (tree && node && gtk_tree_view_draw_expanders (tree_view))
3573         {
3574           gboolean over_arrow;
3575
3576           over_arrow = coords_are_over_arrow (tree_view, tree, node, x, y);
3577
3578           if (over_arrow != tree_view->priv->arrow_prelit)
3579             {
3580               if (over_arrow)
3581                 tree_view->priv->arrow_prelit = TRUE;
3582               else
3583                 tree_view->priv->arrow_prelit = FALSE;
3584
3585               gtk_tree_view_queue_draw_arrow (tree_view, tree, node);
3586             }
3587         }
3588
3589       return;
3590     }
3591
3592   if (tree_view->priv->prelight_tree && tree_view->priv->prelight_node)
3593     {
3594       /*  Unprelight the old node and arrow  */
3595
3596       GTK_RBNODE_UNSET_FLAG (tree_view->priv->prelight_node,
3597                              GTK_RBNODE_IS_PRELIT);
3598
3599       if (tree_view->priv->arrow_prelit
3600           && gtk_tree_view_draw_expanders (tree_view))
3601         {
3602           tree_view->priv->arrow_prelit = FALSE;
3603           
3604           gtk_tree_view_queue_draw_arrow (tree_view,
3605                                           tree_view->priv->prelight_tree,
3606                                           tree_view->priv->prelight_node);
3607         }
3608
3609       _gtk_tree_view_queue_draw_node (tree_view,
3610                                       tree_view->priv->prelight_tree,
3611                                       tree_view->priv->prelight_node,
3612                                       NULL);
3613     }
3614
3615
3616   if (tree_view->priv->hover_expand)
3617     remove_auto_expand_timeout (tree_view);
3618
3619   /*  Set the new prelight values  */
3620   tree_view->priv->prelight_node = node;
3621   tree_view->priv->prelight_tree = tree;
3622
3623   if (!node || !tree)
3624     return;
3625
3626   /*  Prelight the new node and arrow  */
3627
3628   if (gtk_tree_view_draw_expanders (tree_view)
3629       && coords_are_over_arrow (tree_view, tree, node, x, y))
3630     {
3631       tree_view->priv->arrow_prelit = TRUE;
3632
3633       gtk_tree_view_queue_draw_arrow (tree_view, tree, node);
3634     }
3635
3636   GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_PRELIT);
3637
3638   _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
3639
3640   if (tree_view->priv->hover_expand)
3641     {
3642       tree_view->priv->auto_expand_timeout = 
3643         gdk_threads_add_timeout (AUTO_EXPAND_TIMEOUT, auto_expand_timeout, tree_view);
3644     }
3645 }
3646
3647 static void
3648 prelight_or_select (GtkTreeView *tree_view,
3649                     GtkRBTree   *tree,
3650                     GtkRBNode   *node,
3651                     /* these are in bin_window coords */
3652                     gint         x,
3653                     gint         y)
3654 {
3655   GtkSelectionMode mode = gtk_tree_selection_get_mode (tree_view->priv->selection);
3656   
3657   if (tree_view->priv->hover_selection &&
3658       (mode == GTK_SELECTION_SINGLE || mode == GTK_SELECTION_BROWSE) &&
3659       !(tree_view->priv->edited_column &&
3660         gtk_cell_area_get_edit_widget 
3661         (gtk_cell_layout_get_area (GTK_CELL_LAYOUT (tree_view->priv->edited_column)))))
3662     {
3663       if (node)
3664         {
3665           if (!GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
3666             {
3667               GtkTreePath *path;
3668               
3669               path = _gtk_tree_path_new_from_rbtree (tree, node);
3670               gtk_tree_selection_select_path (tree_view->priv->selection, path);
3671               if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
3672                 {
3673                   tree_view->priv->draw_keyfocus = FALSE;
3674                   gtk_tree_view_real_set_cursor (tree_view, path, 0);
3675                 }
3676               gtk_tree_path_free (path);
3677             }
3678         }
3679
3680       else if (mode == GTK_SELECTION_SINGLE)
3681         gtk_tree_selection_unselect_all (tree_view->priv->selection);
3682     }
3683
3684     do_prelight (tree_view, tree, node, x, y);
3685 }
3686
3687 static void
3688 ensure_unprelighted (GtkTreeView *tree_view)
3689 {
3690   do_prelight (tree_view,
3691                NULL, NULL,
3692                -1000, -1000); /* coords not possibly over an arrow */
3693
3694   g_assert (tree_view->priv->prelight_node == NULL);
3695 }
3696
3697 static void
3698 update_prelight (GtkTreeView *tree_view,
3699                  gint         x,
3700                  gint         y)
3701 {
3702   int new_y;
3703   GtkRBTree *tree;
3704   GtkRBNode *node;
3705
3706   if (tree_view->priv->tree == NULL)
3707     return;
3708
3709   if (x == -10000)
3710     {
3711       ensure_unprelighted (tree_view);
3712       return;
3713     }
3714
3715   new_y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, y);
3716   if (new_y < 0)
3717     new_y = 0;
3718
3719   _gtk_rbtree_find_offset (tree_view->priv->tree,
3720                            new_y, &tree, &node);
3721
3722   if (node)
3723     prelight_or_select (tree_view, tree, node, x, y);
3724 }
3725
3726
3727
3728
3729 /* Our motion arrow is either a box (in the case of the original spot)
3730  * or an arrow.  It is expander_size wide.
3731  */
3732 /*
3733  * 11111111111111
3734  * 01111111111110
3735  * 00111111111100
3736  * 00011111111000
3737  * 00001111110000
3738  * 00000111100000
3739  * 00000111100000
3740  * 00000111100000
3741  * ~ ~ ~ ~ ~ ~ ~
3742  * 00000111100000
3743  * 00000111100000
3744  * 00000111100000
3745  * 00001111110000
3746  * 00011111111000
3747  * 00111111111100
3748  * 01111111111110
3749  * 11111111111111
3750  */
3751
3752 static void
3753 gtk_tree_view_motion_draw_column_motion_arrow (GtkTreeView *tree_view)
3754 {
3755   GtkTreeViewColumnReorder *reorder = tree_view->priv->cur_reorder;
3756   GtkWidget *widget = GTK_WIDGET (tree_view);
3757   cairo_surface_t *mask_image;
3758   cairo_region_t *mask_region;
3759   gint x;
3760   gint y;
3761   gint width;
3762   gint height;
3763   gint arrow_type = DRAG_COLUMN_WINDOW_STATE_UNSET;
3764   GdkWindowAttr attributes;
3765   guint attributes_mask;
3766   cairo_t *cr;
3767
3768   if (!reorder ||
3769       reorder->left_column == tree_view->priv->drag_column ||
3770       reorder->right_column == tree_view->priv->drag_column)
3771     arrow_type = DRAG_COLUMN_WINDOW_STATE_ORIGINAL;
3772   else if (reorder->left_column || reorder->right_column)
3773     {
3774       GtkAllocation left_allocation, right_allocation;
3775       GdkRectangle visible_rect;
3776       GtkWidget *button;
3777
3778       gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
3779       if (reorder->left_column)
3780         {
3781           button = gtk_tree_view_column_get_button (reorder->left_column);
3782           gtk_widget_get_allocation (button, &left_allocation);
3783           x = left_allocation.x + left_allocation.width;
3784         }
3785       else
3786         {
3787           button = gtk_tree_view_column_get_button (reorder->right_column);
3788           gtk_widget_get_allocation (button, &right_allocation);
3789           x = right_allocation.x;
3790         }
3791
3792       if (x < visible_rect.x)
3793         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT;
3794       else if (x > visible_rect.x + visible_rect.width)
3795         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT;
3796       else
3797         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW;
3798     }
3799
3800   /* We want to draw the rectangle over the initial location. */
3801   if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ORIGINAL)
3802     {
3803       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ORIGINAL)
3804         {
3805           GtkAllocation drag_allocation;
3806           GtkWidget    *button;
3807
3808           if (tree_view->priv->drag_highlight_window)
3809             {
3810               gdk_window_set_user_data (tree_view->priv->drag_highlight_window,
3811                                         NULL);
3812               gdk_window_destroy (tree_view->priv->drag_highlight_window);
3813             }
3814
3815           button = gtk_tree_view_column_get_button (tree_view->priv->drag_column);
3816           attributes.window_type = GDK_WINDOW_CHILD;
3817           attributes.wclass = GDK_INPUT_OUTPUT;
3818           attributes.x = tree_view->priv->drag_column_x;
3819           attributes.y = 0;
3820           gtk_widget_get_allocation (button, &drag_allocation);
3821           width = attributes.width = drag_allocation.width;
3822           height = attributes.height = drag_allocation.height;
3823           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
3824           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3825           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
3826           tree_view->priv->drag_highlight_window = gdk_window_new (tree_view->priv->header_window, &attributes, attributes_mask);
3827           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
3828
3829           mask_image = cairo_image_surface_create (CAIRO_FORMAT_A1, width, height);
3830           cr = cairo_create (mask_image);
3831
3832           cairo_rectangle (cr, 1, 1, width - 2, height - 2);
3833           cairo_stroke (cr);
3834           cairo_destroy (cr);
3835
3836           mask_region = gdk_cairo_region_create_from_surface (mask_image);
3837           gdk_window_shape_combine_region (tree_view->priv->drag_highlight_window,
3838                                            mask_region, 0, 0);
3839
3840           cairo_region_destroy (mask_region);
3841           cairo_surface_destroy (mask_image);
3842
3843           tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_ORIGINAL;
3844         }
3845     }
3846   else if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW)
3847     {
3848       GtkAllocation button_allocation;
3849       GtkWidget    *button;
3850
3851       width = gtk_tree_view_get_expander_size (tree_view);
3852
3853       /* Get x, y, width, height of arrow */
3854       gdk_window_get_origin (tree_view->priv->header_window, &x, &y);
3855       if (reorder->left_column)
3856         {
3857           button = gtk_tree_view_column_get_button (reorder->left_column);
3858           gtk_widget_get_allocation (button, &button_allocation);
3859           x += button_allocation.x + button_allocation.width - width/2;
3860           height = button_allocation.height;
3861         }
3862       else
3863         {
3864           button = gtk_tree_view_column_get_button (reorder->right_column);
3865           gtk_widget_get_allocation (button, &button_allocation);
3866           x += button_allocation.x - width/2;
3867           height = button_allocation.height;
3868         }
3869       y -= width/2; /* The arrow takes up only half the space */
3870       height += width;
3871
3872       /* Create the new window */
3873       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW)
3874         {
3875           if (tree_view->priv->drag_highlight_window)
3876             {
3877               gdk_window_set_user_data (tree_view->priv->drag_highlight_window,
3878                                         NULL);
3879               gdk_window_destroy (tree_view->priv->drag_highlight_window);
3880             }
3881
3882           attributes.window_type = GDK_WINDOW_TEMP;
3883           attributes.wclass = GDK_INPUT_OUTPUT;
3884           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
3885           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3886           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
3887           attributes.x = x;
3888           attributes.y = y;
3889           attributes.width = width;
3890           attributes.height = height;
3891           tree_view->priv->drag_highlight_window = gdk_window_new (gtk_widget_get_root_window (widget),
3892                                                                    &attributes, attributes_mask);
3893           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
3894
3895           mask_image = cairo_image_surface_create (CAIRO_FORMAT_A1, width, height);
3896
3897           cr = cairo_create (mask_image);
3898           cairo_move_to (cr, 0, 0);
3899           cairo_line_to (cr, width, 0);
3900           cairo_line_to (cr, width / 2., width / 2);
3901           cairo_move_to (cr, 0, height);
3902           cairo_line_to (cr, width, height);
3903           cairo_line_to (cr, width / 2., height - width / 2.);
3904           cairo_fill (cr);
3905           cairo_destroy (cr);
3906
3907           mask_region = gdk_cairo_region_create_from_surface (mask_image);
3908           gdk_window_shape_combine_region (tree_view->priv->drag_highlight_window,
3909                                            mask_region, 0, 0);
3910
3911           cairo_region_destroy (mask_region);
3912           cairo_surface_destroy (mask_image);
3913         }
3914
3915       tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_ARROW;
3916       gdk_window_move (tree_view->priv->drag_highlight_window, x, y);
3917     }
3918   else if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT ||
3919            arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
3920     {
3921       GtkAllocation allocation;
3922       GtkWidget    *button;
3923       gint          expander_size;
3924
3925       expander_size = gtk_tree_view_get_expander_size (tree_view);
3926
3927       /* Get x, y, width, height of arrow */
3928       width = expander_size/2; /* remember, the arrow only takes half the available width */
3929       gdk_window_get_origin (gtk_widget_get_window (widget),
3930                              &x, &y);
3931       if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
3932         {
3933           gtk_widget_get_allocation (widget, &allocation);
3934           x += allocation.width - width;
3935         }
3936
3937       if (reorder->left_column)
3938         {
3939           button = gtk_tree_view_column_get_button (reorder->left_column);
3940           gtk_widget_get_allocation (button, &allocation);
3941           height = allocation.height;
3942         }
3943       else
3944         {
3945           button = gtk_tree_view_column_get_button (reorder->right_column);
3946           gtk_widget_get_allocation (button, &allocation);
3947           height = allocation.height;
3948         }
3949
3950       y -= expander_size;
3951       height += 2 * expander_size;
3952
3953       /* Create the new window */
3954       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT &&
3955           tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
3956         {
3957           if (tree_view->priv->drag_highlight_window)
3958             {
3959               gdk_window_set_user_data (tree_view->priv->drag_highlight_window,
3960                                         NULL);
3961               gdk_window_destroy (tree_view->priv->drag_highlight_window);
3962             }
3963
3964           attributes.window_type = GDK_WINDOW_TEMP;
3965           attributes.wclass = GDK_INPUT_OUTPUT;
3966           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
3967           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3968           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
3969           attributes.x = x;
3970           attributes.y = y;
3971           attributes.width = width;
3972           attributes.height = height;
3973           tree_view->priv->drag_highlight_window = gdk_window_new (gtk_widget_get_root_window (widget), &attributes, attributes_mask);
3974           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
3975
3976           mask_image = cairo_image_surface_create (CAIRO_FORMAT_A1, width, height);
3977
3978           cr = cairo_create (mask_image);
3979           /* mirror if we're on the left */
3980           if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT)
3981             {
3982               cairo_translate (cr, width, 0);
3983               cairo_scale (cr, -1, 1);
3984             }
3985           cairo_move_to (cr, 0, 0);
3986           cairo_line_to (cr, width, width);
3987           cairo_line_to (cr, 0, expander_size);
3988           cairo_move_to (cr, 0, height);
3989           cairo_line_to (cr, width, height - width);
3990           cairo_line_to (cr, 0, height - expander_size);
3991           cairo_fill (cr);
3992           cairo_destroy (cr);
3993
3994           mask_region = gdk_cairo_region_create_from_surface (mask_image);
3995           gdk_window_shape_combine_region (tree_view->priv->drag_highlight_window,
3996                                            mask_region, 0, 0);
3997
3998           cairo_region_destroy (mask_region);
3999           cairo_surface_destroy (mask_image);
4000         }
4001
4002       tree_view->priv->drag_column_window_state = arrow_type;
4003       gdk_window_move (tree_view->priv->drag_highlight_window, x, y);
4004    }
4005   else
4006     {
4007       g_warning (G_STRLOC"Invalid GtkTreeViewColumnReorder struct");
4008       gdk_window_hide (tree_view->priv->drag_highlight_window);
4009       return;
4010     }
4011
4012   gdk_window_show (tree_view->priv->drag_highlight_window);
4013   gdk_window_raise (tree_view->priv->drag_highlight_window);
4014 }
4015
4016 static gboolean
4017 gtk_tree_view_motion_resize_column (GtkWidget      *widget,
4018                                     GdkEventMotion *event)
4019 {
4020   gint x;
4021   gint new_width;
4022   GtkTreeViewColumn *column;
4023   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
4024
4025   column = gtk_tree_view_get_column (tree_view, tree_view->priv->drag_pos);
4026
4027   gdk_window_get_device_position (tree_view->priv->bin_window,
4028                                   gdk_event_get_device ((GdkEvent *) event),
4029                                   &x, NULL, NULL);
4030
4031   if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
4032     new_width = MAX (tree_view->priv->x_drag - x, 0);
4033   else
4034     new_width = MAX (x - tree_view->priv->x_drag, 0);
4035
4036   if (new_width != gtk_tree_view_column_get_width (column))
4037     gtk_tree_view_modify_column_width (tree_view, column, new_width);
4038
4039   return FALSE;
4040 }
4041
4042
4043 static void
4044 gtk_tree_view_update_current_reorder (GtkTreeView *tree_view,
4045                                       GdkEvent    *event)
4046 {
4047   GtkTreeViewColumnReorder *reorder = NULL;
4048   GList *list;
4049   gint mouse_x;
4050
4051   gdk_window_get_device_position (tree_view->priv->header_window,
4052                                   gdk_event_get_device (event),
4053                                   &mouse_x, NULL, NULL);
4054   for (list = tree_view->priv->column_drag_info; list; list = list->next)
4055     {
4056       reorder = (GtkTreeViewColumnReorder *) list->data;
4057       if (mouse_x >= reorder->left_align && mouse_x < reorder->right_align)
4058         break;
4059       reorder = NULL;
4060     }
4061
4062   /*  if (reorder && reorder == tree_view->priv->cur_reorder)
4063       return;*/
4064
4065   tree_view->priv->cur_reorder = reorder;
4066   gtk_tree_view_motion_draw_column_motion_arrow (tree_view);
4067 }
4068
4069 static void
4070 gtk_tree_view_vertical_autoscroll (GtkTreeView *tree_view)
4071 {
4072   GdkRectangle visible_rect;
4073   gint y;
4074   gint offset;
4075
4076   gdk_window_get_device_position (tree_view->priv->bin_window,
4077                                   gdk_device_manager_get_client_pointer (
4078                                     gdk_display_get_device_manager (
4079                                       gtk_widget_get_display (GTK_WIDGET (tree_view)))),
4080                                   NULL, &y, NULL);
4081   y += tree_view->priv->dy;
4082
4083   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
4084
4085   /* see if we are near the edge. */
4086   offset = y - (visible_rect.y + 2 * SCROLL_EDGE_SIZE);
4087   if (offset > 0)
4088     {
4089       offset = y - (visible_rect.y + visible_rect.height - 2 * SCROLL_EDGE_SIZE);
4090       if (offset < 0)
4091         return;
4092     }
4093
4094   gtk_adjustment_set_value (tree_view->priv->vadjustment,
4095                             MAX (gtk_adjustment_get_value (tree_view->priv->vadjustment) + offset, 0.0));
4096 }
4097
4098 static gboolean
4099 gtk_tree_view_horizontal_autoscroll (GtkTreeView *tree_view,
4100                                      GdkEvent    *event)
4101 {
4102   GdkRectangle visible_rect;
4103   gint x;
4104   gint offset;
4105
4106   gdk_window_get_device_position (tree_view->priv->bin_window,
4107                                   gdk_event_get_device (event),
4108                                   &x, NULL, NULL);
4109
4110   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
4111
4112   /* See if we are near the edge. */
4113   offset = x - (visible_rect.x + SCROLL_EDGE_SIZE);
4114   if (offset > 0)
4115     {
4116       offset = x - (visible_rect.x + visible_rect.width - SCROLL_EDGE_SIZE);
4117       if (offset < 0)
4118         return TRUE;
4119     }
4120   offset = offset/3;
4121
4122   gtk_adjustment_set_value (tree_view->priv->hadjustment,
4123                             MAX (gtk_adjustment_get_value (tree_view->priv->hadjustment) + offset, 0.0));
4124
4125   return TRUE;
4126
4127 }
4128
4129 static gboolean
4130 gtk_tree_view_motion_drag_column (GtkWidget      *widget,
4131                                   GdkEventMotion *event)
4132 {
4133   GtkAllocation allocation, button_allocation;
4134   GtkTreeView *tree_view = (GtkTreeView *) widget;
4135   GtkTreeViewColumn *column = tree_view->priv->drag_column;
4136   GtkWidget *button;
4137   gint x, y;
4138
4139   /* Sanity Check */
4140   if ((column == NULL) ||
4141       (event->window != tree_view->priv->drag_window))
4142     return FALSE;
4143
4144   button = gtk_tree_view_column_get_button (column);
4145
4146   /* Handle moving the header */
4147   gdk_window_get_position (tree_view->priv->drag_window, &x, &y);
4148   gtk_widget_get_allocation (widget, &allocation);
4149   gtk_widget_get_allocation (button, &button_allocation);
4150   x = CLAMP (x + (gint)event->x - _gtk_tree_view_column_get_drag_x (column), 0,
4151              MAX (tree_view->priv->width, allocation.width) - button_allocation.width);
4152   gdk_window_move (tree_view->priv->drag_window, x, y);
4153   
4154   /* autoscroll, if needed */
4155   gtk_tree_view_horizontal_autoscroll (tree_view, (GdkEvent *) event);
4156   /* Update the current reorder position and arrow; */
4157   gtk_tree_view_update_current_reorder (tree_view, (GdkEvent *) event);
4158
4159   return TRUE;
4160 }
4161
4162 static void
4163 gtk_tree_view_stop_rubber_band (GtkTreeView *tree_view)
4164 {
4165   remove_scroll_timeout (tree_view);
4166   gtk_grab_remove (GTK_WIDGET (tree_view));
4167
4168   if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
4169     {
4170       GtkTreePath *tmp_path;
4171
4172       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
4173
4174       /* The anchor path should be set to the start path */
4175       tmp_path = _gtk_tree_path_new_from_rbtree (tree_view->priv->rubber_band_start_tree,
4176                                                  tree_view->priv->rubber_band_start_node);
4177
4178       if (tree_view->priv->anchor)
4179         gtk_tree_row_reference_free (tree_view->priv->anchor);
4180
4181       tree_view->priv->anchor =
4182         gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
4183                                           tree_view->priv->model,
4184                                           tmp_path);
4185
4186       gtk_tree_path_free (tmp_path);
4187
4188       /* ... and the cursor to the end path */
4189       tmp_path = _gtk_tree_path_new_from_rbtree (tree_view->priv->rubber_band_end_tree,
4190                                                  tree_view->priv->rubber_band_end_node);
4191       gtk_tree_view_real_set_cursor (GTK_TREE_VIEW (tree_view), tmp_path, 0);
4192       gtk_tree_path_free (tmp_path);
4193
4194       _gtk_tree_selection_emit_changed (tree_view->priv->selection);
4195     }
4196
4197   /* Clear status variables */
4198   tree_view->priv->rubber_band_status = RUBBER_BAND_OFF;
4199   tree_view->priv->rubber_band_extend = FALSE;
4200   tree_view->priv->rubber_band_modify = FALSE;
4201
4202   tree_view->priv->rubber_band_start_node = NULL;
4203   tree_view->priv->rubber_band_start_tree = NULL;
4204   tree_view->priv->rubber_band_end_node = NULL;
4205   tree_view->priv->rubber_band_end_tree = NULL;
4206 }
4207
4208 static void
4209 gtk_tree_view_update_rubber_band_selection_range (GtkTreeView *tree_view,
4210                                                  GtkRBTree   *start_tree,
4211                                                  GtkRBNode   *start_node,
4212                                                  GtkRBTree   *end_tree,
4213                                                  GtkRBNode   *end_node,
4214                                                  gboolean     select,
4215                                                  gboolean     skip_start,
4216                                                  gboolean     skip_end)
4217 {
4218   if (start_node == end_node)
4219     return;
4220
4221   /* We skip the first node and jump inside the loop */
4222   if (skip_start)
4223     goto skip_first;
4224
4225   do
4226     {
4227       /* Small optimization by assuming insensitive nodes are never
4228        * selected.
4229        */
4230       if (!GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
4231         {
4232           GtkTreePath *path;
4233           gboolean selectable;
4234
4235           path = _gtk_tree_path_new_from_rbtree (start_tree, start_node);
4236           selectable = _gtk_tree_selection_row_is_selectable (tree_view->priv->selection, start_node, path);
4237           gtk_tree_path_free (path);
4238
4239           if (!selectable)
4240             goto node_not_selectable;
4241         }
4242
4243       if (select)
4244         {
4245           if (tree_view->priv->rubber_band_extend)
4246             GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4247           else if (tree_view->priv->rubber_band_modify)
4248             {
4249               /* Toggle the selection state */
4250               if (GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
4251                 GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4252               else
4253                 GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4254             }
4255           else
4256             GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4257         }
4258       else
4259         {
4260           /* Mirror the above */
4261           if (tree_view->priv->rubber_band_extend)
4262             GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4263           else if (tree_view->priv->rubber_band_modify)
4264             {
4265               /* Toggle the selection state */
4266               if (GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
4267                 GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4268               else
4269                 GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4270             }
4271           else
4272             GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4273         }
4274
4275       _gtk_tree_view_queue_draw_node (tree_view, start_tree, start_node, NULL);
4276
4277 node_not_selectable:
4278       if (start_node == end_node)
4279         break;
4280
4281 skip_first:
4282
4283       if (start_node->children)
4284         {
4285           start_tree = start_node->children;
4286           start_node = _gtk_rbtree_first (start_tree);
4287         }
4288       else
4289         {
4290           _gtk_rbtree_next_full (start_tree, start_node, &start_tree, &start_node);
4291
4292           if (!start_tree)
4293             /* Ran out of tree */
4294             break;
4295         }
4296
4297       if (skip_end && start_node == end_node)
4298         break;
4299     }
4300   while (TRUE);
4301 }
4302
4303 static void
4304 gtk_tree_view_update_rubber_band_selection (GtkTreeView *tree_view)
4305 {
4306   GtkRBTree *start_tree, *end_tree;
4307   GtkRBNode *start_node, *end_node;
4308
4309   _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);
4310   _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);
4311
4312   /* Handle the start area first */
4313   if (!tree_view->priv->rubber_band_start_node)
4314     {
4315       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4316                                                        start_tree,
4317                                                        start_node,
4318                                                        end_tree,
4319                                                        end_node,
4320                                                        TRUE,
4321                                                        FALSE,
4322                                                        FALSE);
4323     }
4324   else if (_gtk_rbtree_node_find_offset (start_tree, start_node) <
4325            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_start_tree, tree_view->priv->rubber_band_start_node))
4326     {
4327       /* New node is above the old one; selection became bigger */
4328       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4329                                                        start_tree,
4330                                                        start_node,
4331                                                        tree_view->priv->rubber_band_start_tree,
4332                                                        tree_view->priv->rubber_band_start_node,
4333                                                        TRUE,
4334                                                        FALSE,
4335                                                        TRUE);
4336     }
4337   else if (_gtk_rbtree_node_find_offset (start_tree, start_node) >
4338            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_start_tree, tree_view->priv->rubber_band_start_node))
4339     {
4340       /* New node is below the old one; selection became smaller */
4341       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4342                                                        tree_view->priv->rubber_band_start_tree,
4343                                                        tree_view->priv->rubber_band_start_node,
4344                                                        start_tree,
4345                                                        start_node,
4346                                                        FALSE,
4347                                                        FALSE,
4348                                                        TRUE);
4349     }
4350
4351   tree_view->priv->rubber_band_start_tree = start_tree;
4352   tree_view->priv->rubber_band_start_node = start_node;
4353
4354   /* Next, handle the end area */
4355   if (!tree_view->priv->rubber_band_end_node)
4356     {
4357       /* In the event this happens, start_node was also NULL; this case is
4358        * handled above.
4359        */
4360     }
4361   else if (!end_node)
4362     {
4363       /* Find the last node in the tree */
4364       _gtk_rbtree_find_offset (tree_view->priv->tree, tree_view->priv->height - 1,
4365                                &end_tree, &end_node);
4366
4367       /* Selection reached end of the tree */
4368       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4369                                                        tree_view->priv->rubber_band_end_tree,
4370                                                        tree_view->priv->rubber_band_end_node,
4371                                                        end_tree,
4372                                                        end_node,
4373                                                        TRUE,
4374                                                        TRUE,
4375                                                        FALSE);
4376     }
4377   else if (_gtk_rbtree_node_find_offset (end_tree, end_node) >
4378            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_end_tree, tree_view->priv->rubber_band_end_node))
4379     {
4380       /* New node is below the old one; selection became bigger */
4381       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4382                                                        tree_view->priv->rubber_band_end_tree,
4383                                                        tree_view->priv->rubber_band_end_node,
4384                                                        end_tree,
4385                                                        end_node,
4386                                                        TRUE,
4387                                                        TRUE,
4388                                                        FALSE);
4389     }
4390   else if (_gtk_rbtree_node_find_offset (end_tree, end_node) <
4391            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_end_tree, tree_view->priv->rubber_band_end_node))
4392     {
4393       /* New node is above the old one; selection became smaller */
4394       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4395                                                        end_tree,
4396                                                        end_node,
4397                                                        tree_view->priv->rubber_band_end_tree,
4398                                                        tree_view->priv->rubber_band_end_node,
4399                                                        FALSE,
4400                                                        TRUE,
4401                                                        FALSE);
4402     }
4403
4404   tree_view->priv->rubber_band_end_tree = end_tree;
4405   tree_view->priv->rubber_band_end_node = end_node;
4406 }
4407
4408 static void
4409 gtk_tree_view_update_rubber_band (GtkTreeView *tree_view)
4410 {
4411   gint x, y;
4412   GdkRectangle old_area;
4413   GdkRectangle new_area;
4414   GdkRectangle common;
4415   cairo_region_t *invalid_region;
4416
4417   old_area.x = MIN (tree_view->priv->press_start_x, tree_view->priv->rubber_band_x);
4418   old_area.y = MIN (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y) - tree_view->priv->dy;
4419   old_area.width = ABS (tree_view->priv->rubber_band_x - tree_view->priv->press_start_x) + 1;
4420   old_area.height = ABS (tree_view->priv->rubber_band_y - tree_view->priv->press_start_y) + 1;
4421
4422   gdk_window_get_device_position (tree_view->priv->bin_window,
4423                                   gdk_device_manager_get_client_pointer (
4424                                     gdk_display_get_device_manager (
4425                                       gtk_widget_get_display (GTK_WIDGET (tree_view)))),
4426                                   &x, &y, NULL);
4427
4428   x = MAX (x, 0);
4429   y = MAX (y, 0) + tree_view->priv->dy;
4430
4431   new_area.x = MIN (tree_view->priv->press_start_x, x);
4432   new_area.y = MIN (tree_view->priv->press_start_y, y) - tree_view->priv->dy;
4433   new_area.width = ABS (x - tree_view->priv->press_start_x) + 1;
4434   new_area.height = ABS (y - tree_view->priv->press_start_y) + 1;
4435
4436   invalid_region = cairo_region_create_rectangle (&old_area);
4437   cairo_region_union_rectangle (invalid_region, &new_area);
4438
4439   gdk_rectangle_intersect (&old_area, &new_area, &common);
4440   if (common.width > 2 && common.height > 2)
4441     {
4442       cairo_region_t *common_region;
4443
4444       /* make sure the border is invalidated */
4445       common.x += 1;
4446       common.y += 1;
4447       common.width -= 2;
4448       common.height -= 2;
4449
4450       common_region = cairo_region_create_rectangle (&common);
4451
4452       cairo_region_subtract (invalid_region, common_region);
4453       cairo_region_destroy (common_region);
4454     }
4455
4456   gdk_window_invalidate_region (tree_view->priv->bin_window, invalid_region, TRUE);
4457
4458   cairo_region_destroy (invalid_region);
4459
4460   tree_view->priv->rubber_band_x = x;
4461   tree_view->priv->rubber_band_y = y;
4462
4463   gtk_tree_view_update_rubber_band_selection (tree_view);
4464 }
4465
4466 static void
4467 gtk_tree_view_paint_rubber_band (GtkTreeView  *tree_view,
4468                                  cairo_t      *cr)
4469 {
4470   GdkRectangle rect;
4471   GtkStyleContext *context;
4472
4473   cairo_save (cr);
4474
4475   context = gtk_widget_get_style_context (GTK_WIDGET (tree_view));
4476
4477   gtk_style_context_save (context);
4478   gtk_style_context_add_class (context, GTK_STYLE_CLASS_RUBBERBAND);
4479
4480   rect.x = MIN (tree_view->priv->press_start_x, tree_view->priv->rubber_band_x);
4481   rect.y = MIN (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y) - tree_view->priv->dy;
4482   rect.width = ABS (tree_view->priv->press_start_x - tree_view->priv->rubber_band_x) + 1;
4483   rect.height = ABS (tree_view->priv->press_start_y - tree_view->priv->rubber_band_y) + 1;
4484
4485   gdk_cairo_rectangle (cr, &rect);
4486   cairo_clip (cr);
4487
4488   gtk_render_background (context, cr,
4489                          rect.x, rect.y,
4490                          rect.width, rect.height);
4491   gtk_render_frame (context, cr,
4492                     rect.x, rect.y,
4493                     rect.width, rect.height);
4494
4495   gtk_style_context_restore (context);
4496   cairo_restore (cr);
4497 }
4498
4499 static gboolean
4500 gtk_tree_view_motion_bin_window (GtkWidget      *widget,
4501                                  GdkEventMotion *event)
4502 {
4503   GtkTreeView *tree_view;
4504   GtkRBTree *tree;
4505   GtkRBNode *node;
4506   gint new_y;
4507
4508   tree_view = (GtkTreeView *) widget;
4509
4510   if (tree_view->priv->tree == NULL)
4511     return FALSE;
4512
4513   if (tree_view->priv->rubber_band_status == RUBBER_BAND_MAYBE_START)
4514     {
4515       gtk_grab_add (GTK_WIDGET (tree_view));
4516       gtk_tree_view_update_rubber_band (tree_view);
4517
4518       tree_view->priv->rubber_band_status = RUBBER_BAND_ACTIVE;
4519     }
4520   else if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
4521     {
4522       gtk_tree_view_update_rubber_band (tree_view);
4523
4524       add_scroll_timeout (tree_view);
4525     }
4526
4527   /* only check for an initiated drag when a button is pressed */
4528   if (tree_view->priv->pressed_button >= 0
4529       && !tree_view->priv->rubber_band_status)
4530     gtk_tree_view_maybe_begin_dragging_row (tree_view, event);
4531
4532   new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
4533   if (new_y < 0)
4534     new_y = 0;
4535
4536   _gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
4537
4538   /* If we are currently pressing down a button, we don't want to prelight anything else. */
4539   if ((tree_view->priv->button_pressed_node != NULL) &&
4540       (tree_view->priv->button_pressed_node != node))
4541     node = NULL;
4542
4543   tree_view->priv->event_last_x = event->x;
4544   tree_view->priv->event_last_y = event->y;
4545
4546   prelight_or_select (tree_view, tree, node, event->x, event->y);
4547
4548   return TRUE;
4549 }
4550
4551 static gboolean
4552 gtk_tree_view_motion (GtkWidget      *widget,
4553                       GdkEventMotion *event)
4554 {
4555   GtkTreeView *tree_view;
4556
4557   tree_view = (GtkTreeView *) widget;
4558
4559   /* Resizing a column */
4560   if (tree_view->priv->in_column_resize)
4561     return gtk_tree_view_motion_resize_column (widget, event);
4562
4563   /* Drag column */
4564   if (tree_view->priv->in_column_drag)
4565     return gtk_tree_view_motion_drag_column (widget, event);
4566
4567   /* Sanity check it */
4568   if (event->window == tree_view->priv->bin_window)
4569     return gtk_tree_view_motion_bin_window (widget, event);
4570
4571   return FALSE;
4572 }
4573
4574 /* Invalidate the focus rectangle near the edge of the bin_window; used when
4575  * the tree is empty.
4576  */
4577 static void
4578 invalidate_empty_focus (GtkTreeView *tree_view)
4579 {
4580   GdkRectangle area;
4581
4582   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
4583     return;
4584
4585   area.x = 0;
4586   area.y = 0;
4587   area.width = gdk_window_get_width (tree_view->priv->bin_window);
4588   area.height = gdk_window_get_height (tree_view->priv->bin_window);
4589   gdk_window_invalidate_rect (tree_view->priv->bin_window, &area, FALSE);
4590 }
4591
4592 /* Draws a focus rectangle near the edge of the bin_window; used when the tree
4593  * is empty.
4594  */
4595 static void
4596 draw_empty_focus (GtkTreeView *tree_view, cairo_t *cr)
4597 {
4598   GtkWidget *widget = GTK_WIDGET (tree_view);
4599   gint w, h;
4600
4601   if (!gtk_widget_has_visible_focus (widget))
4602     return;
4603
4604   w = gdk_window_get_width (tree_view->priv->bin_window) - 2;
4605   h = gdk_window_get_height (tree_view->priv->bin_window) - 2;
4606
4607   if (w > 0 && h > 0)
4608     {
4609       GtkStyleContext *context;
4610
4611       context = gtk_widget_get_style_context (widget);
4612
4613       gtk_render_focus (context, cr, 1, 1, w, h);
4614     }
4615 }
4616
4617 typedef enum {
4618   GTK_TREE_VIEW_GRID_LINE,
4619   GTK_TREE_VIEW_TREE_LINE,
4620   GTK_TREE_VIEW_FOREGROUND_LINE
4621 } GtkTreeViewLineType;
4622
4623 static void
4624 gtk_tree_view_draw_line (GtkTreeView         *tree_view,
4625                          cairo_t             *cr,
4626                          GtkTreeViewLineType  type,
4627                          int                  x1,
4628                          int                  y1,
4629                          int                  x2,
4630                          int                  y2)
4631 {
4632   cairo_save (cr);
4633
4634   switch (type)
4635     {
4636     case GTK_TREE_VIEW_TREE_LINE:
4637       cairo_set_source_rgb (cr, 0, 0, 0);
4638       cairo_set_line_width (cr, tree_view->priv->tree_line_width);
4639       if (tree_view->priv->tree_line_dashes[0])
4640         cairo_set_dash (cr, 
4641                         tree_view->priv->tree_line_dashes,
4642                         2, 0.5);
4643       break;
4644     case GTK_TREE_VIEW_GRID_LINE:
4645       cairo_set_source_rgb (cr, 0, 0, 0);
4646       cairo_set_line_width (cr, tree_view->priv->grid_line_width);
4647       if (tree_view->priv->grid_line_dashes[0])
4648         cairo_set_dash (cr, 
4649                         tree_view->priv->grid_line_dashes,
4650                         2, 0.5);
4651       break;
4652     default:
4653       g_assert_not_reached ();
4654       /* fall through */
4655     case GTK_TREE_VIEW_FOREGROUND_LINE:
4656       {
4657         GtkStyleContext *context;
4658         GtkStateFlags state;
4659         GdkRGBA color;
4660
4661         context = gtk_widget_get_style_context (GTK_WIDGET (tree_view));
4662         state = gtk_widget_get_state_flags (GTK_WIDGET (tree_view));
4663
4664         cairo_set_line_width (cr, 1.0);
4665         gtk_style_context_get_color (context, state, &color);
4666         gdk_cairo_set_source_rgba (cr, &color);
4667       }
4668
4669       break;
4670     }
4671
4672   cairo_move_to (cr, x1 + 0.5, y1 + 0.5);
4673   cairo_line_to (cr, x2 + 0.5, y2 + 0.5);
4674   cairo_stroke (cr);
4675
4676   cairo_restore (cr);
4677 }
4678                          
4679 static void
4680 gtk_tree_view_draw_grid_lines (GtkTreeView    *tree_view,
4681                                cairo_t        *cr,
4682                                gint            n_visible_columns)
4683 {
4684   GList *list = tree_view->priv->columns;
4685   gint i = 0;
4686   gint current_x = 0;
4687
4688   if (tree_view->priv->grid_lines != GTK_TREE_VIEW_GRID_LINES_VERTICAL
4689       && tree_view->priv->grid_lines != GTK_TREE_VIEW_GRID_LINES_BOTH)
4690     return;
4691
4692   /* Only draw the lines for visible rows and columns */
4693   for (list = tree_view->priv->columns; list; list = list->next, i++)
4694     {
4695       GtkTreeViewColumn *column = list->data;
4696
4697       /* We don't want a line for the last column */
4698       if (i == n_visible_columns - 1)
4699         break;
4700
4701       if (!gtk_tree_view_column_get_visible (column))
4702         continue;
4703
4704       current_x += gtk_tree_view_column_get_width (column);
4705
4706       gtk_tree_view_draw_line (tree_view, cr,
4707                                GTK_TREE_VIEW_GRID_LINE,
4708                                current_x - 1, 0,
4709                                current_x - 1, tree_view->priv->height);
4710     }
4711 }
4712
4713 /* Warning: Very scary function.
4714  * Modify at your own risk
4715  *
4716  * KEEP IN SYNC WITH gtk_tree_view_create_row_drag_icon()!
4717  * FIXME: It's not...
4718  */
4719 static gboolean
4720 gtk_tree_view_bin_draw (GtkWidget      *widget,
4721                         cairo_t        *cr)
4722 {
4723   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
4724   GtkTreePath *path;
4725   GtkRBTree *tree;
4726   GList *list;
4727   GtkRBNode *node;
4728   GtkRBNode *drag_highlight = NULL;
4729   GtkRBTree *drag_highlight_tree = NULL;
4730   GtkTreeIter iter;
4731   gint new_y;
4732   gint y_offset, cell_offset;
4733   gint max_height;
4734   gint depth;
4735   GdkRectangle background_area;
4736   GdkRectangle cell_area;
4737   GdkRectangle clip;
4738   guint flags;
4739   gint highlight_x;
4740   gint expander_cell_width;
4741   gint bin_window_width;
4742   gint bin_window_height;
4743   GtkTreePath *drag_dest_path;
4744   GList *first_column, *last_column;
4745   gint vertical_separator;
4746   gint horizontal_separator;
4747   gboolean allow_rules;
4748   gboolean has_can_focus_cell;
4749   gboolean rtl;
4750   gint n_visible_columns;
4751   gint grid_line_width;
4752   gint expander_size;
4753   gboolean draw_vgrid_lines, draw_hgrid_lines;
4754   GtkStyleContext *context;
4755   gboolean parity;
4756
4757   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
4758   context = gtk_widget_get_style_context (widget);
4759
4760   gtk_widget_style_get (widget,
4761                         "horizontal-separator", &horizontal_separator,
4762                         "vertical-separator", &vertical_separator,
4763                         "allow-rules", &allow_rules,
4764                         NULL);
4765
4766   if (tree_view->priv->tree == NULL)
4767     {
4768       draw_empty_focus (tree_view, cr);
4769       return TRUE;
4770     }
4771
4772   bin_window_width = gdk_window_get_width (tree_view->priv->bin_window);
4773   bin_window_height = gdk_window_get_height (tree_view->priv->bin_window);
4774   cairo_rectangle (cr, 0, 0, bin_window_width, bin_window_height);
4775   cairo_clip (cr);
4776   if (!gdk_cairo_get_clip_rectangle (cr, &clip))
4777     return TRUE;
4778
4779   new_y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, clip.y);
4780
4781   if (new_y < 0)
4782     new_y = 0;
4783   y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
4784
4785   if (tree_view->priv->height < bin_window_height)
4786     {
4787       gtk_style_context_save (context);
4788       gtk_style_context_add_class (context, GTK_STYLE_CLASS_CELL);
4789
4790       gtk_render_background (context, cr,
4791                              0, tree_view->priv->height,
4792                              bin_window_width,
4793                              bin_window_height - tree_view->priv->height);
4794
4795       gtk_style_context_restore (context);
4796     }
4797
4798   if (node == NULL)
4799     return TRUE;
4800
4801   /* find the path for the node */
4802   path = _gtk_tree_path_new_from_rbtree (tree, node);
4803   gtk_tree_model_get_iter (tree_view->priv->model,
4804                            &iter,
4805                            path);
4806   depth = gtk_tree_path_get_depth (path);
4807   gtk_tree_path_free (path);
4808   
4809   drag_dest_path = NULL;
4810
4811   if (tree_view->priv->drag_dest_row)
4812     drag_dest_path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
4813
4814   if (drag_dest_path)
4815     _gtk_tree_view_find_node (tree_view, drag_dest_path,
4816                               &drag_highlight_tree, &drag_highlight);
4817
4818   draw_vgrid_lines =
4819     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_VERTICAL
4820     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
4821   draw_hgrid_lines =
4822     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_HORIZONTAL
4823     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
4824   expander_size = gtk_tree_view_get_expander_size (tree_view);
4825
4826   if (draw_vgrid_lines || draw_hgrid_lines)
4827     gtk_widget_style_get (widget, "grid-line-width", &grid_line_width, NULL);
4828   
4829   n_visible_columns = 0;
4830   for (list = tree_view->priv->columns; list; list = list->next)
4831     {
4832       if (!gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (list->data)))
4833         continue;
4834       n_visible_columns ++;
4835     }
4836
4837   /* Find the last column */
4838   for (last_column = g_list_last (tree_view->priv->columns);
4839        last_column &&
4840        !(gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (last_column->data)));
4841        last_column = last_column->prev)
4842     ;
4843
4844   /* and the first */
4845   for (first_column = g_list_first (tree_view->priv->columns);
4846        first_column &&
4847        !(gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (first_column->data)));
4848        first_column = first_column->next)
4849     ;
4850
4851   /* Actually process the expose event.  To do this, we want to
4852    * start at the first node of the event, and walk the tree in
4853    * order, drawing each successive node.
4854    */
4855   
4856   parity = !(_gtk_rbtree_node_get_index (tree, node) % 2);
4857
4858   do
4859     {
4860       gboolean is_separator = FALSE;
4861       gboolean is_first = FALSE;
4862       gboolean is_last = FALSE;
4863       gint n_col = 0;
4864
4865       parity = !parity;
4866       is_separator = row_is_separator (tree_view, &iter, NULL);
4867
4868       max_height = gtk_tree_view_get_row_height (tree_view, node);
4869
4870       cell_offset = 0;
4871       highlight_x = 0; /* should match x coord of first cell */
4872       expander_cell_width = 0;
4873
4874       background_area.y = y_offset + clip.y;
4875       background_area.height = max_height;
4876
4877       flags = 0;
4878
4879       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PRELIT))
4880         flags |= GTK_CELL_RENDERER_PRELIT;
4881
4882       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
4883         flags |= GTK_CELL_RENDERER_SELECTED;
4884
4885       /* we *need* to set cell data on all cells before the call
4886        * to _has_can_focus_cell, else _has_can_focus_cell() does not
4887        * return a correct value.
4888        */
4889       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
4890            list;
4891            list = (rtl ? list->prev : list->next))
4892         {
4893           GtkTreeViewColumn *column = list->data;
4894           gtk_tree_view_column_cell_set_cell_data (column,
4895                                                    tree_view->priv->model,
4896                                                    &iter,
4897                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
4898                                                    node->children?TRUE:FALSE);
4899         }
4900
4901       has_can_focus_cell = gtk_tree_view_has_can_focus_cell (tree_view);
4902
4903       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
4904            list;
4905            list = (rtl ? list->prev : list->next))
4906         {
4907           GtkTreeViewColumn *column = list->data;
4908           GtkRegionFlags row_flags = 0, column_flags = 0;
4909           GtkStateFlags state = 0;
4910           gint width;
4911           gboolean draw_focus;
4912
4913           if (!gtk_tree_view_column_get_visible (column))
4914             continue;
4915
4916           n_col++;
4917           width = gtk_tree_view_column_get_width (column);
4918
4919           if (cell_offset > clip.x + clip.width ||
4920               cell_offset + width < clip.x)
4921             {
4922               cell_offset += width;
4923               continue;
4924             }
4925
4926           if (gtk_tree_view_column_get_sort_indicator (column))
4927             flags |= GTK_CELL_RENDERER_SORTED;
4928           else
4929             flags &= ~GTK_CELL_RENDERER_SORTED;
4930
4931           if (tree_view->priv->cursor_node == node)
4932             flags |= GTK_CELL_RENDERER_FOCUSED;
4933           else
4934             flags &= ~GTK_CELL_RENDERER_FOCUSED;
4935
4936           if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
4937             flags |= GTK_CELL_RENDERER_EXPANDABLE;
4938           else
4939             flags &= ~GTK_CELL_RENDERER_EXPANDABLE;
4940
4941           if (node->children)
4942             flags |= GTK_CELL_RENDERER_EXPANDED;
4943           else
4944             flags &= ~GTK_CELL_RENDERER_EXPANDED;
4945
4946           background_area.x = cell_offset;
4947           background_area.width = width;
4948
4949           cell_area = background_area;
4950           cell_area.y += vertical_separator / 2;
4951           cell_area.x += horizontal_separator / 2;
4952           cell_area.height -= vertical_separator;
4953           cell_area.width -= horizontal_separator;
4954
4955           if (draw_vgrid_lines)
4956             {
4957               if (list == first_column)
4958                 {
4959                   cell_area.width -= grid_line_width / 2;
4960                 }
4961               else if (list == last_column)
4962                 {
4963                   cell_area.x += grid_line_width / 2;
4964                   cell_area.width -= grid_line_width / 2;
4965                 }
4966               else
4967                 {
4968                   cell_area.x += grid_line_width / 2;
4969                   cell_area.width -= grid_line_width;
4970                 }
4971             }
4972
4973           if (draw_hgrid_lines)
4974             {
4975               cell_area.y += grid_line_width / 2;
4976               cell_area.height -= grid_line_width;
4977             }
4978
4979           if (!gdk_rectangle_intersect (&clip, &background_area, NULL))
4980             {
4981               cell_offset += gtk_tree_view_column_get_width (column);
4982               continue;
4983             }
4984
4985           gtk_tree_view_column_cell_set_cell_data (column,
4986                                                    tree_view->priv->model,
4987                                                    &iter,
4988                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
4989                                                    node->children?TRUE:FALSE);
4990
4991           /* Select the detail for drawing the cell.  relevant
4992            * factors are parity, sortedness, and whether to
4993            * display rules.
4994            */
4995           if (allow_rules && tree_view->priv->has_rules)
4996             {
4997               if (parity)
4998                 row_flags |= GTK_REGION_ODD;
4999               else
5000                 row_flags |= GTK_REGION_EVEN;
5001             }
5002
5003           if ((flags & GTK_CELL_RENDERER_SORTED) &&
5004               n_visible_columns >= 3)
5005             column_flags |= GTK_REGION_SORTED;
5006
5007           is_first = (rtl ? !list->next : !list->prev);
5008           is_last = (rtl ? !list->prev : !list->next);
5009
5010           if (is_first)
5011             column_flags |= GTK_REGION_FIRST;
5012
5013           if (is_last)
5014             column_flags |= GTK_REGION_LAST;
5015
5016           if ((n_col % 2) == 0)
5017             column_flags |= GTK_REGION_EVEN;
5018           else
5019             column_flags |= GTK_REGION_ODD;
5020
5021           gtk_style_context_save (context);
5022
5023           state = gtk_cell_renderer_get_state (NULL, widget, flags);
5024           gtk_style_context_set_state (context, state);
5025
5026           gtk_style_context_add_class (context, GTK_STYLE_CLASS_CELL);
5027           gtk_style_context_add_region (context, GTK_STYLE_REGION_ROW, row_flags);
5028           gtk_style_context_add_region (context, GTK_STYLE_REGION_COLUMN, column_flags);
5029
5030           if (node == tree_view->priv->cursor_node && has_can_focus_cell
5031               && ((column == tree_view->priv->focus_column
5032                    && tree_view->priv->draw_keyfocus &&
5033                    gtk_widget_has_visible_focus (widget))
5034                   || (column == tree_view->priv->edited_column)))
5035             draw_focus = TRUE;
5036           else
5037             draw_focus = FALSE;
5038
5039           /* Draw background */
5040           gtk_render_background (context, cr,
5041                                  background_area.x,
5042                                  background_area.y,
5043                                  background_area.width,
5044                                  background_area.height);
5045
5046           /* Draw frame */
5047           gtk_render_frame (context, cr,
5048                             background_area.x,
5049                             background_area.y,
5050                             background_area.width,
5051                             background_area.height);
5052
5053           if (gtk_tree_view_is_expander_column (tree_view, column))
5054             {
5055               if (!rtl)
5056                 cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
5057               cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
5058
5059               if (gtk_tree_view_draw_expanders (tree_view))
5060                 {
5061                   int expander_size = gtk_tree_view_get_expander_size (tree_view);
5062                   if (!rtl)
5063                     cell_area.x += depth * expander_size;
5064                   cell_area.width -= depth * expander_size;
5065                 }
5066
5067               /* If we have an expander column, the highlight underline
5068                * starts with that column, so that it indicates which
5069                * level of the tree we're dropping at.
5070                */
5071               highlight_x = cell_area.x;
5072               expander_cell_width = cell_area.width;
5073
5074               if (is_separator)
5075                 {
5076                   gtk_style_context_save (context);
5077                   gtk_style_context_add_class (context, GTK_STYLE_CLASS_SEPARATOR);
5078
5079                   gtk_render_line (context, cr,
5080                                    cell_area.x,
5081                                    cell_area.y + cell_area.height / 2,
5082                                    cell_area.x + cell_area.width,
5083                                    cell_area.y + cell_area.height / 2);
5084
5085                   gtk_style_context_restore (context);
5086                 }
5087               else
5088                 {
5089                   _gtk_tree_view_column_cell_render (column,
5090                                                      cr,
5091                                                      &background_area,
5092                                                      &cell_area,
5093                                                      flags,
5094                                                      draw_focus);
5095                 }
5096
5097               if (gtk_tree_view_draw_expanders (tree_view)
5098                   && (node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT)
5099                 {
5100                   gtk_tree_view_draw_arrow (GTK_TREE_VIEW (widget),
5101                                             cr,
5102                                             tree,
5103                                             node);
5104                 }
5105             }
5106           else
5107             {
5108               if (is_separator)
5109                 {
5110                   gtk_style_context_save (context);
5111                   gtk_style_context_add_class (context, GTK_STYLE_CLASS_SEPARATOR);
5112
5113                   gtk_render_line (context, cr,
5114                                    cell_area.x,
5115                                    cell_area.y + cell_area.height / 2,
5116                                    cell_area.x + cell_area.width,
5117                                    cell_area.y + cell_area.height / 2);
5118
5119                   gtk_style_context_restore (context);
5120                 }
5121               else
5122                 _gtk_tree_view_column_cell_render (column,
5123                                                    cr,
5124                                                    &background_area,
5125                                                    &cell_area,
5126                                                    flags,
5127                                                    draw_focus);
5128             }
5129
5130           if (draw_hgrid_lines)
5131             {
5132               if (background_area.y > 0)
5133                 gtk_tree_view_draw_line (tree_view, cr,
5134                                          GTK_TREE_VIEW_GRID_LINE,
5135                                          background_area.x, background_area.y,
5136                                          background_area.x + background_area.width,
5137                                          background_area.y);
5138
5139               if (y_offset + max_height >= clip.height)
5140                 gtk_tree_view_draw_line (tree_view, cr,
5141                                          GTK_TREE_VIEW_GRID_LINE,
5142                                          background_area.x, background_area.y + max_height,
5143                                          background_area.x + background_area.width,
5144                                          background_area.y + max_height);
5145             }
5146
5147           if (gtk_tree_view_is_expander_column (tree_view, column) &&
5148               tree_view->priv->tree_lines_enabled)
5149             {
5150               gint x = background_area.x;
5151               gint mult = rtl ? -1 : 1;
5152               gint y0 = background_area.y;
5153               gint y1 = background_area.y + background_area.height/2;
5154               gint y2 = background_area.y + background_area.height;
5155
5156               if (rtl)
5157                 x += background_area.width - 1;
5158
5159               if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT
5160                   && depth > 1)
5161                 {
5162                   gtk_tree_view_draw_line (tree_view, cr,
5163                                            GTK_TREE_VIEW_TREE_LINE,
5164                                            x + expander_size * (depth - 1.5) * mult,
5165                                            y1,
5166                                            x + expander_size * (depth - 1.1) * mult,
5167                                            y1);
5168                 }
5169               else if (depth > 1)
5170                 {
5171                   gtk_tree_view_draw_line (tree_view, cr,
5172                                            GTK_TREE_VIEW_TREE_LINE,
5173                                            x + expander_size * (depth - 1.5) * mult,
5174                                            y1,
5175                                            x + expander_size * (depth - 0.5) * mult,
5176                                            y1);
5177                 }
5178
5179               if (depth > 1)
5180                 {
5181                   gint i;
5182                   GtkRBNode *tmp_node;
5183                   GtkRBTree *tmp_tree;
5184
5185                   if (!_gtk_rbtree_next (tree, node))
5186                     gtk_tree_view_draw_line (tree_view, cr,
5187                                              GTK_TREE_VIEW_TREE_LINE,
5188                                              x + expander_size * (depth - 1.5) * mult,
5189                                              y0,
5190                                              x + expander_size * (depth - 1.5) * mult,
5191                                              y1);
5192                   else
5193                     gtk_tree_view_draw_line (tree_view, cr,
5194                                              GTK_TREE_VIEW_TREE_LINE,
5195                                              x + expander_size * (depth - 1.5) * mult,
5196                                              y0,
5197                                              x + expander_size * (depth - 1.5) * mult,
5198                                              y2);
5199
5200                   tmp_node = tree->parent_node;
5201                   tmp_tree = tree->parent_tree;
5202
5203                   for (i = depth - 2; i > 0; i--)
5204                     {
5205                       if (_gtk_rbtree_next (tmp_tree, tmp_node))
5206                         gtk_tree_view_draw_line (tree_view, cr,
5207                                                  GTK_TREE_VIEW_TREE_LINE,
5208                                                  x + expander_size * (i - 0.5) * mult,
5209                                                  y0,
5210                                                  x + expander_size * (i - 0.5) * mult,
5211                                                  y2);
5212
5213                       tmp_node = tmp_tree->parent_node;
5214                       tmp_tree = tmp_tree->parent_tree;
5215                     }
5216                 }
5217             }
5218
5219           gtk_style_context_restore (context);
5220           cell_offset += gtk_tree_view_column_get_width (column);
5221         }
5222
5223       if (node == drag_highlight)
5224         {
5225           /* Draw indicator for the drop
5226            */
5227           gint highlight_y = -1;
5228           GtkRBTree *tree = NULL;
5229           GtkRBNode *node = NULL;
5230
5231           gtk_style_context_save (context);
5232           gtk_style_context_add_class (context, GTK_STYLE_CLASS_DND);
5233
5234           switch (tree_view->priv->drag_dest_pos)
5235             {
5236             case GTK_TREE_VIEW_DROP_BEFORE:
5237               highlight_y = background_area.y - 1;
5238               if (highlight_y < 0)
5239                       highlight_y = 0;
5240               break;
5241
5242             case GTK_TREE_VIEW_DROP_AFTER:
5243               highlight_y = background_area.y + background_area.height - 1;
5244               break;
5245
5246             case GTK_TREE_VIEW_DROP_INTO_OR_BEFORE:
5247             case GTK_TREE_VIEW_DROP_INTO_OR_AFTER:
5248               _gtk_tree_view_find_node (tree_view, drag_dest_path, &tree, &node);
5249
5250               if (tree == NULL)
5251                 break;
5252
5253               gtk_render_frame (context, cr,
5254                                 0, gtk_tree_view_get_row_y_offset (tree_view, tree, node),
5255                                 gdk_window_get_width (tree_view->priv->bin_window),
5256                                 gtk_tree_view_get_row_height (tree_view, node));
5257               break;
5258             }
5259
5260           if (highlight_y >= 0)
5261             {
5262               gtk_tree_view_draw_line (tree_view, cr,
5263                                        GTK_TREE_VIEW_FOREGROUND_LINE,
5264                                        rtl ? highlight_x + expander_cell_width : highlight_x,
5265                                        highlight_y,
5266                                        rtl ? 0 : bin_window_width,
5267                                        highlight_y);
5268             }
5269
5270           gtk_style_context_restore (context);
5271         }
5272
5273       /* draw the big row-spanning focus rectangle, if needed */
5274       if (!has_can_focus_cell && node == tree_view->priv->cursor_node &&
5275           tree_view->priv->draw_keyfocus &&
5276           gtk_widget_has_visible_focus (widget))
5277         {
5278           gint tmp_y, tmp_height;
5279           GtkStateFlags focus_rect_state = 0;
5280
5281           gtk_style_context_save (context);
5282
5283           focus_rect_state = gtk_cell_renderer_get_state (NULL, widget, flags);
5284           gtk_style_context_set_state (context, focus_rect_state);
5285
5286           if (draw_hgrid_lines)
5287             {
5288               tmp_y = gtk_tree_view_get_row_y_offset (tree_view, tree, node) + grid_line_width / 2;
5289               tmp_height = gtk_tree_view_get_row_height (tree_view, node) - grid_line_width;
5290             }
5291           else
5292             {
5293               tmp_y = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
5294               tmp_height = gtk_tree_view_get_row_height (tree_view, node);
5295             }
5296
5297           gtk_render_focus (context, cr,
5298                             0, tmp_y,
5299                             gdk_window_get_width (tree_view->priv->bin_window),
5300                             tmp_height);
5301
5302           gtk_style_context_restore (context);
5303         }
5304
5305       y_offset += max_height;
5306       if (node->children)
5307         {
5308           GtkTreeIter parent = iter;
5309           gboolean has_child;
5310
5311           tree = node->children;
5312           node = _gtk_rbtree_first (tree);
5313
5314           has_child = gtk_tree_model_iter_children (tree_view->priv->model,
5315                                                     &iter,
5316                                                     &parent);
5317           depth++;
5318
5319           /* Sanity Check! */
5320           TREE_VIEW_INTERNAL_ASSERT (has_child, FALSE);
5321         }
5322       else
5323         {
5324           gboolean done = FALSE;
5325
5326           do
5327             {
5328               node = _gtk_rbtree_next (tree, node);
5329               if (node != NULL)
5330                 {
5331                   gboolean has_next = gtk_tree_model_iter_next (tree_view->priv->model, &iter);
5332                   done = TRUE;
5333
5334                   /* Sanity Check! */
5335                   TREE_VIEW_INTERNAL_ASSERT (has_next, FALSE);
5336                 }
5337               else
5338                 {
5339                   GtkTreeIter parent_iter = iter;
5340                   gboolean has_parent;
5341
5342                   node = tree->parent_node;
5343                   tree = tree->parent_tree;
5344                   if (tree == NULL)
5345                     /* we should go to done to free some memory */
5346                     goto done;
5347                   has_parent = gtk_tree_model_iter_parent (tree_view->priv->model,
5348                                                            &iter,
5349                                                            &parent_iter);
5350                   depth--;
5351
5352                   /* Sanity check */
5353                   TREE_VIEW_INTERNAL_ASSERT (has_parent, FALSE);
5354                 }
5355             }
5356           while (!done);
5357         }
5358     }
5359   while (y_offset < clip.height);
5360
5361 done:
5362   gtk_tree_view_draw_grid_lines (tree_view, cr, n_visible_columns);
5363
5364   if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
5365     gtk_tree_view_paint_rubber_band (tree_view, cr);
5366
5367   if (drag_dest_path)
5368     gtk_tree_path_free (drag_dest_path);
5369
5370   return FALSE;
5371 }
5372
5373 static gboolean
5374 gtk_tree_view_draw (GtkWidget *widget,
5375                     cairo_t   *cr)
5376 {
5377   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
5378   GtkWidget   *button;
5379   GtkStyleContext *context;
5380
5381   context = gtk_widget_get_style_context (widget);
5382   gtk_render_background (context, cr,
5383                          0, 0,
5384                          gtk_widget_get_allocated_width (widget),
5385                          gtk_widget_get_allocated_height (widget));
5386
5387   if (gtk_cairo_should_draw_window (cr, tree_view->priv->bin_window))
5388     {
5389       GList *tmp_list;
5390
5391       cairo_save (cr);
5392
5393       gtk_cairo_transform_to_window (cr, widget, tree_view->priv->bin_window);
5394       gtk_tree_view_bin_draw (widget, cr);
5395
5396       cairo_restore (cr);
5397
5398       /* We can't just chain up to Container::draw as it will try to send the
5399        * event to the headers, so we handle propagating it to our children
5400        * (eg. widgets being edited) ourselves.
5401        */
5402       tmp_list = tree_view->priv->children;
5403       while (tmp_list)
5404         {
5405           GtkTreeViewChild *child = tmp_list->data;
5406           tmp_list = tmp_list->next;
5407
5408           gtk_container_propagate_draw (GTK_CONTAINER (tree_view), child->widget, cr);
5409         }
5410     }
5411
5412   gtk_style_context_save (context);
5413   gtk_style_context_remove_class (context, GTK_STYLE_CLASS_VIEW);
5414
5415   if (gtk_cairo_should_draw_window (cr, tree_view->priv->header_window))
5416     {
5417       GList *list;
5418       
5419       for (list = tree_view->priv->columns; list != NULL; list = list->next)
5420         {
5421           GtkTreeViewColumn *column = list->data;
5422
5423           if (column == tree_view->priv->drag_column)
5424             continue;
5425
5426           if (gtk_tree_view_column_get_visible (column))
5427             {
5428               button = gtk_tree_view_column_get_button (column);
5429               gtk_container_propagate_draw (GTK_CONTAINER (tree_view),
5430                                             button, cr);
5431             }
5432         }
5433     }
5434   
5435   if (tree_view->priv->drag_window &&
5436       gtk_cairo_should_draw_window (cr, tree_view->priv->drag_window))
5437     {
5438       button = gtk_tree_view_column_get_button (tree_view->priv->drag_column);
5439       gtk_container_propagate_draw (GTK_CONTAINER (tree_view),
5440                                     button, cr);
5441     }
5442
5443   gtk_style_context_restore (context);
5444
5445   return FALSE;
5446 }
5447
5448 enum
5449 {
5450   DROP_HOME,
5451   DROP_RIGHT,
5452   DROP_LEFT,
5453   DROP_END
5454 };
5455
5456 /* returns 0x1 when no column has been found -- yes it's hackish */
5457 static GtkTreeViewColumn *
5458 gtk_tree_view_get_drop_column (GtkTreeView       *tree_view,
5459                                GtkTreeViewColumn *column,
5460                                gint               drop_position)
5461 {
5462   GtkTreeViewColumn *left_column = NULL;
5463   GtkTreeViewColumn *cur_column = NULL;
5464   GList *tmp_list;
5465
5466   if (!gtk_tree_view_column_get_reorderable (column))
5467     return (GtkTreeViewColumn *)0x1;
5468
5469   switch (drop_position)
5470     {
5471       case DROP_HOME:
5472         /* find first column where we can drop */
5473         tmp_list = tree_view->priv->columns;
5474         if (column == GTK_TREE_VIEW_COLUMN (tmp_list->data))
5475           return (GtkTreeViewColumn *)0x1;
5476
5477         while (tmp_list)
5478           {
5479             g_assert (tmp_list);
5480
5481             cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5482             tmp_list = tmp_list->next;
5483
5484             if (left_column &&
5485                 gtk_tree_view_column_get_visible (left_column) == FALSE)
5486               continue;
5487
5488             if (!tree_view->priv->column_drop_func)
5489               return left_column;
5490
5491             if (!tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5492               {
5493                 left_column = cur_column;
5494                 continue;
5495               }
5496
5497             return left_column;
5498           }
5499
5500         if (!tree_view->priv->column_drop_func)
5501           return left_column;
5502
5503         if (tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data))
5504           return left_column;
5505         else
5506           return (GtkTreeViewColumn *)0x1;
5507         break;
5508
5509       case DROP_RIGHT:
5510         /* find first column after column where we can drop */
5511         tmp_list = tree_view->priv->columns;
5512
5513         for (; tmp_list; tmp_list = tmp_list->next)
5514           if (GTK_TREE_VIEW_COLUMN (tmp_list->data) == column)
5515             break;
5516
5517         if (!tmp_list || !tmp_list->next)
5518           return (GtkTreeViewColumn *)0x1;
5519
5520         tmp_list = tmp_list->next;
5521         left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5522         tmp_list = tmp_list->next;
5523
5524         while (tmp_list)
5525           {
5526             g_assert (tmp_list);
5527
5528             cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5529             tmp_list = tmp_list->next;
5530
5531             if (left_column &&
5532                 gtk_tree_view_column_get_visible (left_column) == FALSE)
5533               {
5534                 left_column = cur_column;
5535                 if (tmp_list)
5536                   tmp_list = tmp_list->next;
5537                 continue;
5538               }
5539
5540             if (!tree_view->priv->column_drop_func)
5541               return left_column;
5542
5543             if (!tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5544               {
5545                 left_column = cur_column;
5546                 continue;
5547               }
5548
5549             return left_column;
5550           }
5551
5552         if (!tree_view->priv->column_drop_func)
5553           return left_column;
5554
5555         if (tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data))
5556           return left_column;
5557         else
5558           return (GtkTreeViewColumn *)0x1;
5559         break;
5560
5561       case DROP_LEFT:
5562         /* find first column before column where we can drop */
5563         tmp_list = tree_view->priv->columns;
5564
5565         for (; tmp_list; tmp_list = tmp_list->next)
5566           if (GTK_TREE_VIEW_COLUMN (tmp_list->data) == column)
5567             break;
5568
5569         if (!tmp_list || !tmp_list->prev)
5570           return (GtkTreeViewColumn *)0x1;
5571
5572         tmp_list = tmp_list->prev;
5573         cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5574         tmp_list = tmp_list->prev;
5575
5576         while (tmp_list)
5577           {
5578             g_assert (tmp_list);
5579
5580             left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5581
5582             if (left_column &&
5583                 gtk_tree_view_column_get_visible (left_column) == FALSE)
5584               {
5585                 /*if (!tmp_list->prev)
5586                   return (GtkTreeViewColumn *)0x1;
5587                   */
5588 /*
5589                 cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->prev->data);
5590                 tmp_list = tmp_list->prev->prev;
5591                 continue;*/
5592
5593                 cur_column = left_column;
5594                 if (tmp_list)
5595                   tmp_list = tmp_list->prev;
5596                 continue;
5597               }
5598
5599             if (!tree_view->priv->column_drop_func)
5600               return left_column;
5601
5602             if (tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5603               return left_column;
5604
5605             cur_column = left_column;
5606             tmp_list = tmp_list->prev;
5607           }
5608
5609         if (!tree_view->priv->column_drop_func)
5610           return NULL;
5611
5612         if (tree_view->priv->column_drop_func (tree_view, column, NULL, cur_column, tree_view->priv->column_drop_func_data))
5613           return NULL;
5614         else
5615           return (GtkTreeViewColumn *)0x1;
5616         break;
5617
5618       case DROP_END:
5619         /* same as DROP_HOME case, but doing it backwards */
5620         tmp_list = g_list_last (tree_view->priv->columns);
5621         cur_column = NULL;
5622
5623         if (column == GTK_TREE_VIEW_COLUMN (tmp_list->data))
5624           return (GtkTreeViewColumn *)0x1;
5625
5626         while (tmp_list)
5627           {
5628             g_assert (tmp_list);
5629
5630             left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5631
5632             if (left_column &&
5633                 gtk_tree_view_column_get_visible (left_column) == FALSE)
5634               {
5635                 cur_column = left_column;
5636                 tmp_list = tmp_list->prev;
5637               }
5638
5639             if (!tree_view->priv->column_drop_func)
5640               return left_column;
5641
5642             if (tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5643               return left_column;
5644
5645             cur_column = left_column;
5646             tmp_list = tmp_list->prev;
5647           }
5648
5649         if (!tree_view->priv->column_drop_func)
5650           return NULL;
5651
5652         if (tree_view->priv->column_drop_func (tree_view, column, NULL, cur_column, tree_view->priv->column_drop_func_data))
5653           return NULL;
5654         else
5655           return (GtkTreeViewColumn *)0x1;
5656         break;
5657     }
5658
5659   return (GtkTreeViewColumn *)0x1;
5660 }
5661
5662 static gboolean
5663 gtk_tree_view_key_press (GtkWidget   *widget,
5664                          GdkEventKey *event)
5665 {
5666   GtkTreeView *tree_view = (GtkTreeView *) widget;
5667   GtkWidget   *button;
5668
5669   if (tree_view->priv->rubber_band_status)
5670     {
5671       if (event->keyval == GDK_KEY_Escape)
5672         gtk_tree_view_stop_rubber_band (tree_view);
5673
5674       return TRUE;
5675     }
5676
5677   if (tree_view->priv->in_column_drag)
5678     {
5679       if (event->keyval == GDK_KEY_Escape)
5680         {
5681           tree_view->priv->cur_reorder = NULL;
5682           gtk_tree_view_button_release_drag_column (widget, NULL);
5683         }
5684       return TRUE;
5685     }
5686
5687   if (tree_view->priv->headers_visible)
5688     {
5689       GList *focus_column;
5690       gboolean rtl;
5691
5692       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
5693
5694       for (focus_column = tree_view->priv->columns;
5695            focus_column;
5696            focus_column = focus_column->next)
5697         {
5698           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
5699           
5700           button = gtk_tree_view_column_get_button (column);
5701           if (gtk_widget_has_focus (button))
5702             break;
5703         }
5704
5705       if (focus_column &&
5706           (event->state & GDK_SHIFT_MASK) && (event->state & GDK_MOD1_MASK) &&
5707           (event->keyval == GDK_KEY_Left || event->keyval == GDK_KEY_KP_Left
5708            || event->keyval == GDK_KEY_Right || event->keyval == GDK_KEY_KP_Right))
5709         {
5710           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
5711           gint column_width;
5712
5713           if (!gtk_tree_view_column_get_resizable (column))
5714             {
5715               gtk_widget_error_bell (widget);
5716               return TRUE;
5717             }
5718
5719           column_width = gtk_tree_view_column_get_width (column);
5720
5721           if (event->keyval == (rtl ? GDK_KEY_Right : GDK_KEY_Left)
5722               || event->keyval == (rtl ? GDK_KEY_KP_Right : GDK_KEY_KP_Left))
5723             {
5724               column_width = MAX (column_width - 2, 0);
5725             }
5726           else if (event->keyval == (rtl ? GDK_KEY_Left : GDK_KEY_Right)
5727                    || event->keyval == (rtl ? GDK_KEY_KP_Left : GDK_KEY_KP_Right))
5728             {
5729               column_width = column_width + 2;
5730             }
5731
5732           gtk_tree_view_modify_column_width (tree_view, column, column_width);
5733           return TRUE;
5734         }
5735
5736       if (focus_column &&
5737           (event->state & GDK_MOD1_MASK) &&
5738           (event->keyval == GDK_KEY_Left || event->keyval == GDK_KEY_KP_Left
5739            || event->keyval == GDK_KEY_Right || event->keyval == GDK_KEY_KP_Right
5740            || event->keyval == GDK_KEY_Home || event->keyval == GDK_KEY_KP_Home
5741            || event->keyval == GDK_KEY_End || event->keyval == GDK_KEY_KP_End))
5742         {
5743           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
5744
5745           if (event->keyval == (rtl ? GDK_KEY_Right : GDK_KEY_Left)
5746               || event->keyval == (rtl ? GDK_KEY_KP_Right : GDK_KEY_KP_Left))
5747             {
5748               GtkTreeViewColumn *col;
5749               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_LEFT);
5750               if (col != (GtkTreeViewColumn *)0x1)
5751                 gtk_tree_view_move_column_after (tree_view, column, col);
5752               else
5753                 gtk_widget_error_bell (widget);
5754             }
5755           else if (event->keyval == (rtl ? GDK_KEY_Left : GDK_KEY_Right)
5756                    || event->keyval == (rtl ? GDK_KEY_KP_Left : GDK_KEY_KP_Right))
5757             {
5758               GtkTreeViewColumn *col;
5759               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_RIGHT);
5760               if (col != (GtkTreeViewColumn *)0x1)
5761                 gtk_tree_view_move_column_after (tree_view, column, col);
5762               else
5763                 gtk_widget_error_bell (widget);
5764             }
5765           else if (event->keyval == GDK_KEY_Home || event->keyval == GDK_KEY_KP_Home)
5766             {
5767               GtkTreeViewColumn *col;
5768               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_HOME);
5769               if (col != (GtkTreeViewColumn *)0x1)
5770                 gtk_tree_view_move_column_after (tree_view, column, col);
5771               else
5772                 gtk_widget_error_bell (widget);
5773             }
5774           else if (event->keyval == GDK_KEY_End || event->keyval == GDK_KEY_KP_End)
5775             {
5776               GtkTreeViewColumn *col;
5777               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_END);
5778               if (col != (GtkTreeViewColumn *)0x1)
5779                 gtk_tree_view_move_column_after (tree_view, column, col);
5780               else
5781                 gtk_widget_error_bell (widget);
5782             }
5783
5784           return TRUE;
5785         }
5786     }
5787
5788   /* Chain up to the parent class.  It handles the keybindings. */
5789   if (GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->key_press_event (widget, event))
5790     return TRUE;
5791
5792   if (tree_view->priv->search_entry_avoid_unhandled_binding)
5793     {
5794       tree_view->priv->search_entry_avoid_unhandled_binding = FALSE;
5795       return FALSE;
5796     }
5797
5798   /* We pass the event to the search_entry.  If its text changes, then we start
5799    * the typeahead find capabilities. */
5800   if (gtk_widget_has_focus (GTK_WIDGET (tree_view))
5801       && tree_view->priv->enable_search
5802       && !tree_view->priv->search_custom_entry_set)
5803     {
5804       GdkEvent *new_event;
5805       char *old_text;
5806       const char *new_text;
5807       gboolean retval;
5808       GdkScreen *screen;
5809       gboolean text_modified;
5810       gulong popup_menu_id;
5811
5812       gtk_tree_view_ensure_interactive_directory (tree_view);
5813
5814       /* Make a copy of the current text */
5815       old_text = g_strdup (gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry)));
5816       new_event = gdk_event_copy ((GdkEvent *) event);
5817       g_object_unref (((GdkEventKey *) new_event)->window);
5818       ((GdkEventKey *) new_event)->window = g_object_ref (gtk_widget_get_window (tree_view->priv->search_window));
5819       gtk_widget_realize (tree_view->priv->search_window);
5820
5821       popup_menu_id = g_signal_connect (tree_view->priv->search_entry, 
5822                                         "popup-menu", G_CALLBACK (gtk_true),
5823                                         NULL);
5824
5825       /* Move the entry off screen */
5826       screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
5827       gtk_window_move (GTK_WINDOW (tree_view->priv->search_window),
5828                        gdk_screen_get_width (screen) + 1,
5829                        gdk_screen_get_height (screen) + 1);
5830       gtk_widget_show (tree_view->priv->search_window);
5831
5832       /* Send the event to the window.  If the preedit_changed signal is emitted
5833        * during this event, we will set priv->imcontext_changed  */
5834       tree_view->priv->imcontext_changed = FALSE;
5835       retval = gtk_widget_event (tree_view->priv->search_window, new_event);
5836       gdk_event_free (new_event);
5837       gtk_widget_hide (tree_view->priv->search_window);
5838
5839       g_signal_handler_disconnect (tree_view->priv->search_entry, 
5840                                    popup_menu_id);
5841
5842       /* We check to make sure that the entry tried to handle the text, and that
5843        * the text has changed.
5844        */
5845       new_text = gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry));
5846       text_modified = strcmp (old_text, new_text) != 0;
5847       g_free (old_text);
5848       if (tree_view->priv->imcontext_changed ||    /* we're in a preedit */
5849           (retval && text_modified))               /* ...or the text was modified */
5850         {
5851           if (gtk_tree_view_real_start_interactive_search (tree_view,
5852                                                            gdk_event_get_device ((GdkEvent *) event),
5853                                                            FALSE))
5854             {
5855               gtk_widget_grab_focus (GTK_WIDGET (tree_view));
5856               return TRUE;
5857             }
5858           else
5859             {
5860               gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
5861               return FALSE;
5862             }
5863         }
5864     }
5865
5866   return FALSE;
5867 }
5868
5869 static gboolean
5870 gtk_tree_view_key_release (GtkWidget   *widget,
5871                            GdkEventKey *event)
5872 {
5873   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
5874
5875   if (tree_view->priv->rubber_band_status)
5876     return TRUE;
5877
5878   return GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->key_release_event (widget, event);
5879 }
5880
5881 /* FIXME Is this function necessary? Can I get an enter_notify event
5882  * w/o either an expose event or a mouse motion event?
5883  */
5884 static gboolean
5885 gtk_tree_view_enter_notify (GtkWidget        *widget,
5886                             GdkEventCrossing *event)
5887 {
5888   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
5889   GtkRBTree *tree;
5890   GtkRBNode *node;
5891   gint new_y;
5892
5893   /* Sanity check it */
5894   if (event->window != tree_view->priv->bin_window)
5895     return FALSE;
5896
5897   if (tree_view->priv->tree == NULL)
5898     return FALSE;
5899
5900   if (event->mode == GDK_CROSSING_GRAB ||
5901       event->mode == GDK_CROSSING_GTK_GRAB ||
5902       event->mode == GDK_CROSSING_GTK_UNGRAB ||
5903       event->mode == GDK_CROSSING_STATE_CHANGED)
5904     return TRUE;
5905
5906   /* find the node internally */
5907   new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
5908   if (new_y < 0)
5909     new_y = 0;
5910   _gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
5911
5912   tree_view->priv->event_last_x = event->x;
5913   tree_view->priv->event_last_y = event->y;
5914
5915   if ((tree_view->priv->button_pressed_node == NULL) ||
5916       (tree_view->priv->button_pressed_node == node))
5917     prelight_or_select (tree_view, tree, node, event->x, event->y);
5918
5919   return TRUE;
5920 }
5921
5922 static gboolean
5923 gtk_tree_view_leave_notify (GtkWidget        *widget,
5924                             GdkEventCrossing *event)
5925 {
5926   GtkTreeView *tree_view;
5927
5928   if (event->mode == GDK_CROSSING_GRAB ||
5929       event->mode == GDK_CROSSING_GTK_GRAB ||
5930       event->mode == GDK_CROSSING_GTK_UNGRAB)
5931     return TRUE;
5932
5933   tree_view = GTK_TREE_VIEW (widget);
5934
5935   if (tree_view->priv->prelight_node)
5936     _gtk_tree_view_queue_draw_node (tree_view,
5937                                    tree_view->priv->prelight_tree,
5938                                    tree_view->priv->prelight_node,
5939                                    NULL);
5940
5941   tree_view->priv->event_last_x = -10000;
5942   tree_view->priv->event_last_y = -10000;
5943
5944   prelight_or_select (tree_view,
5945                       NULL, NULL,
5946                       -1000, -1000); /* coords not possibly over an arrow */
5947
5948   return TRUE;
5949 }
5950
5951
5952 static gint
5953 gtk_tree_view_focus_out (GtkWidget     *widget,
5954                          GdkEventFocus *event)
5955 {
5956   GtkTreeView *tree_view;
5957
5958   tree_view = GTK_TREE_VIEW (widget);
5959
5960   gtk_widget_queue_draw (widget);
5961
5962   /* destroy interactive search dialog */
5963   if (tree_view->priv->search_window)
5964     gtk_tree_view_search_dialog_hide (tree_view->priv->search_window, tree_view,
5965                                       gdk_event_get_device ((GdkEvent *) event));
5966
5967   return FALSE;
5968 }
5969
5970
5971 /* Incremental Reflow
5972  */
5973
5974 static void
5975 gtk_tree_view_node_queue_redraw (GtkTreeView *tree_view,
5976                                  GtkRBTree   *tree,
5977                                  GtkRBNode   *node)
5978 {
5979   GtkAllocation allocation;
5980   gint y;
5981
5982   y = _gtk_rbtree_node_find_offset (tree, node)
5983     - gtk_adjustment_get_value (tree_view->priv->vadjustment)
5984     + gtk_tree_view_get_effective_header_height (tree_view);
5985
5986   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
5987   gtk_widget_queue_draw_area (GTK_WIDGET (tree_view),
5988                               0, y,
5989                               allocation.width,
5990                               GTK_RBNODE_GET_HEIGHT (node));
5991 }
5992
5993 static gboolean
5994 node_is_visible (GtkTreeView *tree_view,
5995                  GtkRBTree   *tree,
5996                  GtkRBNode   *node)
5997 {
5998   int y;
5999   int height;
6000
6001   y = _gtk_rbtree_node_find_offset (tree, node);
6002   height = gtk_tree_view_get_row_height (tree_view, node);
6003
6004   if (y >= gtk_adjustment_get_value (tree_view->priv->vadjustment) &&
6005       y + height <= (gtk_adjustment_get_value (tree_view->priv->vadjustment)
6006                      + gtk_adjustment_get_page_size (tree_view->priv->vadjustment)))
6007     return TRUE;
6008
6009   return FALSE;
6010 }
6011
6012 /* Returns TRUE if it updated the size
6013  */
6014 static gboolean
6015 validate_row (GtkTreeView *tree_view,
6016               GtkRBTree   *tree,
6017               GtkRBNode   *node,
6018               GtkTreeIter *iter,
6019               GtkTreePath *path)
6020 {
6021   GtkTreeViewColumn *column;
6022   GList *list, *first_column, *last_column;
6023   gint height = 0;
6024   gint horizontal_separator;
6025   gint vertical_separator;
6026   gint depth = gtk_tree_path_get_depth (path);
6027   gboolean retval = FALSE;
6028   gboolean is_separator = FALSE;
6029   gboolean draw_vgrid_lines, draw_hgrid_lines;
6030   gint focus_pad;
6031   gint grid_line_width;
6032   gboolean wide_separators;
6033   gint separator_height;
6034   gint expander_size;
6035
6036   /* double check the row needs validating */
6037   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) &&
6038       ! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6039     return FALSE;
6040
6041   is_separator = row_is_separator (tree_view, iter, NULL);
6042
6043   gtk_widget_style_get (GTK_WIDGET (tree_view),
6044                         "focus-padding", &focus_pad,
6045                         "horizontal-separator", &horizontal_separator,
6046                         "vertical-separator", &vertical_separator,
6047                         "grid-line-width", &grid_line_width,
6048                         "wide-separators",  &wide_separators,
6049                         "separator-height", &separator_height,
6050                         NULL);
6051   
6052   draw_vgrid_lines =
6053     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_VERTICAL
6054     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
6055   draw_hgrid_lines =
6056     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_HORIZONTAL
6057     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
6058   expander_size = gtk_tree_view_get_expander_size (tree_view);
6059
6060   for (last_column = g_list_last (tree_view->priv->columns);
6061        last_column &&
6062        !(gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (last_column->data)));
6063        last_column = last_column->prev)
6064     ;
6065
6066   for (first_column = g_list_first (tree_view->priv->columns);
6067        first_column &&
6068        !(gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (first_column->data)));
6069        first_column = first_column->next)
6070     ;
6071
6072   for (list = tree_view->priv->columns; list; list = list->next)
6073     {
6074       gint padding = 0;
6075       gint original_width;
6076       gint new_width;
6077       gint row_height;
6078
6079       column = list->data;
6080
6081       if (!gtk_tree_view_column_get_visible (column))
6082         continue;
6083
6084       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID) && 
6085           !_gtk_tree_view_column_cell_get_dirty (column))
6086         continue;
6087
6088       original_width = _gtk_tree_view_column_get_requested_width (column);
6089
6090       gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, iter,
6091                                                GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
6092                                                node->children?TRUE:FALSE);
6093       gtk_tree_view_column_cell_get_size (column,
6094                                           NULL, NULL, NULL,
6095                                           NULL, &row_height);
6096
6097       if (!is_separator)
6098         {
6099           row_height += vertical_separator;
6100           height = MAX (height, row_height);
6101           height = MAX (height, expander_size);
6102         }
6103       else
6104         {
6105           if (wide_separators)
6106             height = separator_height + 2 * focus_pad;
6107           else
6108             height = 2 + 2 * focus_pad;
6109         }
6110
6111       if (gtk_tree_view_is_expander_column (tree_view, column))
6112         {
6113           padding += horizontal_separator + (depth - 1) * tree_view->priv->level_indentation;
6114
6115           if (gtk_tree_view_draw_expanders (tree_view))
6116             padding += depth * expander_size;
6117         }
6118       else
6119         padding += horizontal_separator;
6120
6121       if (draw_vgrid_lines)
6122         {
6123           if (list->data == first_column || list->data == last_column)
6124             padding += grid_line_width / 2.0;
6125           else
6126             padding += grid_line_width;
6127         }
6128
6129       /* Update the padding for the column */
6130       _gtk_tree_view_column_push_padding (column, padding);
6131       new_width = _gtk_tree_view_column_get_requested_width (column);
6132
6133       if (new_width > original_width)
6134         retval = TRUE;
6135     }
6136
6137   if (draw_hgrid_lines)
6138     height += grid_line_width;
6139
6140   if (height != GTK_RBNODE_GET_HEIGHT (node))
6141     {
6142       retval = TRUE;
6143       _gtk_rbtree_node_set_height (tree, node, height);
6144     }
6145   _gtk_rbtree_node_mark_valid (tree, node);
6146
6147   return retval;
6148 }
6149
6150
6151 static void
6152 validate_visible_area (GtkTreeView *tree_view)
6153 {
6154   GtkAllocation allocation;
6155   GtkTreePath *path = NULL;
6156   GtkTreePath *above_path = NULL;
6157   GtkTreeIter iter;
6158   GtkRBTree *tree = NULL;
6159   GtkRBNode *node = NULL;
6160   gboolean need_redraw = FALSE;
6161   gboolean size_changed = FALSE;
6162   gint total_height;
6163   gint area_above = 0;
6164   gint area_below = 0;
6165
6166   if (tree_view->priv->tree == NULL)
6167     return;
6168
6169   if (! GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID) &&
6170       tree_view->priv->scroll_to_path == NULL)
6171     return;
6172
6173   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
6174   total_height = allocation.height - gtk_tree_view_get_effective_header_height (tree_view);
6175
6176   if (total_height == 0)
6177     return;
6178
6179   /* First, we check to see if we need to scroll anywhere
6180    */
6181   if (tree_view->priv->scroll_to_path)
6182     {
6183       path = gtk_tree_row_reference_get_path (tree_view->priv->scroll_to_path);
6184       if (path && !_gtk_tree_view_find_node (tree_view, path, &tree, &node))
6185         {
6186           /* we are going to scroll, and will update dy */
6187           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6188           if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6189               GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6190             {
6191               _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
6192               if (validate_row (tree_view, tree, node, &iter, path))
6193                 size_changed = TRUE;
6194             }
6195
6196           if (tree_view->priv->scroll_to_use_align)
6197             {
6198               gint height = gtk_tree_view_get_row_height (tree_view, node);
6199               area_above = (total_height - height) *
6200                 tree_view->priv->scroll_to_row_align;
6201               area_below = total_height - area_above - height;
6202               area_above = MAX (area_above, 0);
6203               area_below = MAX (area_below, 0);
6204             }
6205           else
6206             {
6207               /* two cases:
6208                * 1) row not visible
6209                * 2) row visible
6210                */
6211               gint dy;
6212               gint height = gtk_tree_view_get_row_height (tree_view, node);
6213
6214               dy = _gtk_rbtree_node_find_offset (tree, node);
6215
6216               if (dy >= gtk_adjustment_get_value (tree_view->priv->vadjustment) &&
6217                   dy + height <= (gtk_adjustment_get_value (tree_view->priv->vadjustment)
6218                                   + gtk_adjustment_get_page_size (tree_view->priv->vadjustment)))
6219                 {
6220                   /* row visible: keep the row at the same position */
6221                   area_above = dy - gtk_adjustment_get_value (tree_view->priv->vadjustment);
6222                   area_below = (gtk_adjustment_get_value (tree_view->priv->vadjustment) +
6223                                 gtk_adjustment_get_page_size (tree_view->priv->vadjustment))
6224                                - dy - height;
6225                 }
6226               else
6227                 {
6228                   /* row not visible */
6229                   if (dy >= 0
6230                       && dy + height <= gtk_adjustment_get_page_size (tree_view->priv->vadjustment))
6231                     {
6232                       /* row at the beginning -- fixed */
6233                       area_above = dy;
6234                       area_below = gtk_adjustment_get_page_size (tree_view->priv->vadjustment)
6235                                    - area_above - height;
6236                     }
6237                   else if (dy >= (gtk_adjustment_get_upper (tree_view->priv->vadjustment) -
6238                                   gtk_adjustment_get_page_size (tree_view->priv->vadjustment)))
6239                     {
6240                       /* row at the end -- fixed */
6241                       area_above = dy - (gtk_adjustment_get_upper (tree_view->priv->vadjustment) -
6242                                    gtk_adjustment_get_page_size (tree_view->priv->vadjustment));
6243                       area_below = gtk_adjustment_get_page_size (tree_view->priv->vadjustment) -
6244                                    area_above - height;
6245
6246                       if (area_below < 0)
6247                         {
6248                           area_above = gtk_adjustment_get_page_size (tree_view->priv->vadjustment) - height;
6249                           area_below = 0;
6250                         }
6251                     }
6252                   else
6253                     {
6254                       /* row somewhere in the middle, bring it to the top
6255                        * of the view
6256                        */
6257                       area_above = 0;
6258                       area_below = total_height - height;
6259                     }
6260                 }
6261             }
6262         }
6263       else
6264         /* the scroll to isn't valid; ignore it.
6265          */
6266         {
6267           if (tree_view->priv->scroll_to_path && !path)
6268             {
6269               gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
6270               tree_view->priv->scroll_to_path = NULL;
6271             }
6272           if (path)
6273             gtk_tree_path_free (path);
6274           path = NULL;
6275         }      
6276     }
6277
6278   /* We didn't have a scroll_to set, so we just handle things normally
6279    */
6280   if (path == NULL)
6281     {
6282       gint offset;
6283
6284       offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
6285                                         TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, 0),
6286                                         &tree, &node);
6287       if (node == NULL)
6288         {
6289           /* In this case, nothing has been validated */
6290           path = gtk_tree_path_new_first ();
6291           _gtk_tree_view_find_node (tree_view, path, &tree, &node);
6292         }
6293       else
6294         {
6295           path = _gtk_tree_path_new_from_rbtree (tree, node);
6296           total_height += offset;
6297         }
6298
6299       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6300
6301       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6302           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6303         {
6304           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
6305           if (validate_row (tree_view, tree, node, &iter, path))
6306             size_changed = TRUE;
6307         }
6308       area_above = 0;
6309       area_below = total_height - gtk_tree_view_get_row_height (tree_view, node);
6310     }
6311
6312   above_path = gtk_tree_path_copy (path);
6313
6314   /* if we do not validate any row above the new top_row, we will make sure
6315    * that the row immediately above top_row has been validated. (if we do not
6316    * do this, _gtk_rbtree_find_offset will find the row above top_row, because
6317    * when invalidated that row's height will be zero. and this will mess up
6318    * scrolling).
6319    */
6320   if (area_above == 0)
6321     {
6322       GtkRBTree *tmptree;
6323       GtkRBNode *tmpnode;
6324
6325       _gtk_tree_view_find_node (tree_view, above_path, &tmptree, &tmpnode);
6326       _gtk_rbtree_prev_full (tmptree, tmpnode, &tmptree, &tmpnode);
6327
6328       if (tmpnode)
6329         {
6330           GtkTreePath *tmppath;
6331           GtkTreeIter tmpiter;
6332
6333           tmppath = _gtk_tree_path_new_from_rbtree (tmptree, tmpnode);
6334           gtk_tree_model_get_iter (tree_view->priv->model, &tmpiter, tmppath);
6335
6336           if (GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_INVALID) ||
6337               GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_COLUMN_INVALID))
6338             {
6339               _gtk_tree_view_queue_draw_node (tree_view, tmptree, tmpnode, NULL);
6340               if (validate_row (tree_view, tmptree, tmpnode, &tmpiter, tmppath))
6341                 size_changed = TRUE;
6342             }
6343
6344           gtk_tree_path_free (tmppath);
6345         }
6346     }
6347
6348   /* Now, we walk forwards and backwards, measuring rows. Unfortunately,
6349    * backwards is much slower then forward, as there is no iter_prev function.
6350    * We go forwards first in case we run out of tree.  Then we go backwards to
6351    * fill out the top.
6352    */
6353   while (node && area_below > 0)
6354     {
6355       if (node->children)
6356         {
6357           GtkTreeIter parent = iter;
6358           gboolean has_child;
6359
6360           tree = node->children;
6361           node = _gtk_rbtree_first (tree);
6362
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_path_new_from_rbtree (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_path_new_from_rbtree (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   static gboolean prevent_recursion_hack = FALSE;
6561
6562   GtkRBTree *tree = NULL;
6563   GtkRBNode *node = NULL;
6564   gboolean validated_area = FALSE;
6565   gint retval = TRUE;
6566   GtkTreePath *path = NULL;
6567   GtkTreeIter iter;
6568   GTimer *timer;
6569   gint i = 0;
6570
6571   gint y = -1;
6572   gint prev_height = -1;
6573   gboolean fixed_height = TRUE;
6574
6575   g_assert (tree_view);
6576
6577   /* prevent infinite recursion via get_preferred_width() */
6578   if (prevent_recursion_hack)
6579     return FALSE;
6580
6581   if (tree_view->priv->tree == NULL)
6582       return FALSE;
6583
6584   if (tree_view->priv->fixed_height_mode)
6585     {
6586       if (tree_view->priv->fixed_height < 0)
6587         initialize_fixed_height_mode (tree_view);
6588
6589       return FALSE;
6590     }
6591
6592   timer = g_timer_new ();
6593   g_timer_start (timer);
6594
6595   do
6596     {
6597       gboolean changed = FALSE;
6598
6599       if (! GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID))
6600         {
6601           retval = FALSE;
6602           goto done;
6603         }
6604
6605       if (path != NULL)
6606         {
6607           node = _gtk_rbtree_next (tree, node);
6608           if (node != NULL)
6609             {
6610               TREE_VIEW_INTERNAL_ASSERT (gtk_tree_model_iter_next (tree_view->priv->model, &iter), FALSE);
6611               gtk_tree_path_next (path);
6612             }
6613           else
6614             {
6615               gtk_tree_path_free (path);
6616               path = NULL;
6617             }
6618         }
6619
6620       if (path == NULL)
6621         {
6622           tree = tree_view->priv->tree;
6623           node = tree_view->priv->tree->root;
6624
6625           g_assert (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_DESCENDANTS_INVALID));
6626
6627           do
6628             {
6629               if (!_gtk_rbtree_is_nil (node->left) &&
6630                   GTK_RBNODE_FLAG_SET (node->left, GTK_RBNODE_DESCENDANTS_INVALID))
6631                 {
6632                   node = node->left;
6633                 }
6634               else if (!_gtk_rbtree_is_nil (node->right) &&
6635                        GTK_RBNODE_FLAG_SET (node->right, GTK_RBNODE_DESCENDANTS_INVALID))
6636                 {
6637                   node = node->right;
6638                 }
6639               else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6640                        GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6641                 {
6642                   break;
6643                 }
6644               else if (node->children != NULL)
6645                 {
6646                   tree = node->children;
6647                   node = tree->root;
6648                 }
6649               else
6650                 /* RBTree corruption!  All bad */
6651                 g_assert_not_reached ();
6652             }
6653           while (TRUE);
6654           path = _gtk_tree_path_new_from_rbtree (tree, node);
6655           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6656         }
6657
6658       changed = validate_row (tree_view, tree, node, &iter, path);
6659       validated_area = changed || validated_area;
6660
6661       if (changed)
6662         {
6663           gint offset = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
6664
6665           if (y == -1 || y > offset)
6666             y = offset;
6667         }
6668
6669       if (!tree_view->priv->fixed_height_check)
6670         {
6671           gint height;
6672
6673           height = gtk_tree_view_get_row_height (tree_view, node);
6674           if (prev_height < 0)
6675             prev_height = height;
6676           else if (prev_height != height)
6677             fixed_height = FALSE;
6678         }
6679
6680       i++;
6681     }
6682   while (g_timer_elapsed (timer, NULL) < GTK_TREE_VIEW_TIME_MS_PER_IDLE / 1000.);
6683
6684   if (!tree_view->priv->fixed_height_check)
6685    {
6686      if (fixed_height)
6687        _gtk_rbtree_set_fixed_height (tree_view->priv->tree, prev_height, FALSE);
6688
6689      tree_view->priv->fixed_height_check = 1;
6690    }
6691   
6692  done:
6693   if (validated_area)
6694     {
6695       GtkRequisition requisition;
6696
6697       /* We temporarily guess a size, under the assumption that it will be the
6698        * same when we get our next size_allocate.  If we don't do this, we'll be
6699        * in an inconsistent state when we call top_row_to_dy. */
6700
6701       /* FIXME: This is called from size_request, for some reason it is not infinitely
6702        * recursing, we cannot call gtk_widget_get_preferred_size() here because that's
6703        * not allowed (from inside ->get_preferred_width/height() implementations, one
6704        * should call the vfuncs directly). However what is desired here is the full
6705        * size including any margins and limited by any alignment (i.e. after 
6706        * GtkWidget:adjust_size_request() is called).
6707        *
6708        * Currently bypassing this but the real solution is to not update the scroll adjustments
6709        * untill we've recieved an allocation (never update scroll adjustments from size-requests).
6710        */
6711       prevent_recursion_hack = TRUE;
6712       gtk_tree_view_get_preferred_width (GTK_WIDGET (tree_view), &requisition.width, NULL);
6713       gtk_tree_view_get_preferred_height (GTK_WIDGET (tree_view), &requisition.height, NULL);
6714       prevent_recursion_hack = FALSE;
6715
6716       /* If rows above the current position have changed height, this has
6717        * affected the current view and thus needs a redraw.
6718        */
6719       if (y != -1 && y < gtk_adjustment_get_value (tree_view->priv->vadjustment))
6720         gtk_widget_queue_draw (GTK_WIDGET (tree_view));
6721
6722       gtk_adjustment_set_upper (tree_view->priv->hadjustment,
6723                                 MAX (gtk_adjustment_get_upper (tree_view->priv->hadjustment), requisition.width));
6724       gtk_adjustment_set_upper (tree_view->priv->vadjustment,
6725                                 MAX (gtk_adjustment_get_upper (tree_view->priv->vadjustment), requisition.height));
6726
6727       if (queue_resize)
6728         gtk_widget_queue_resize_no_redraw (GTK_WIDGET (tree_view));
6729     }
6730
6731   if (path) gtk_tree_path_free (path);
6732   g_timer_destroy (timer);
6733
6734   return retval;
6735 }
6736
6737 static gboolean
6738 validate_rows (GtkTreeView *tree_view)
6739 {
6740   gboolean retval;
6741   
6742   retval = do_validate_rows (tree_view, TRUE);
6743   
6744   if (! retval && tree_view->priv->validate_rows_timer)
6745     {
6746       g_source_remove (tree_view->priv->validate_rows_timer);
6747       tree_view->priv->validate_rows_timer = 0;
6748     }
6749
6750   return retval;
6751 }
6752
6753 static gboolean
6754 validate_rows_handler (GtkTreeView *tree_view)
6755 {
6756   gboolean retval;
6757
6758   retval = do_validate_rows (tree_view, TRUE);
6759   if (! retval && tree_view->priv->validate_rows_timer)
6760     {
6761       g_source_remove (tree_view->priv->validate_rows_timer);
6762       tree_view->priv->validate_rows_timer = 0;
6763     }
6764
6765   return retval;
6766 }
6767
6768 static gboolean
6769 do_presize_handler (GtkTreeView *tree_view)
6770 {
6771   if (tree_view->priv->mark_rows_col_dirty)
6772     {
6773       if (tree_view->priv->tree)
6774         _gtk_rbtree_column_invalid (tree_view->priv->tree);
6775       tree_view->priv->mark_rows_col_dirty = FALSE;
6776     }
6777   validate_visible_area (tree_view);
6778   tree_view->priv->presize_handler_timer = 0;
6779
6780   if (tree_view->priv->fixed_height_mode)
6781     {
6782       GtkRequisition requisition;
6783
6784       gtk_widget_get_preferred_size (GTK_WIDGET (tree_view),
6785                                      &requisition, NULL);
6786
6787       gtk_adjustment_set_upper (tree_view->priv->hadjustment,
6788                                 MAX (gtk_adjustment_get_upper (tree_view->priv->hadjustment), requisition.width));
6789       gtk_adjustment_set_upper (tree_view->priv->vadjustment,
6790                                 MAX (gtk_adjustment_get_upper (tree_view->priv->vadjustment), requisition.height));
6791       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6792     }
6793                    
6794   return FALSE;
6795 }
6796
6797 static gboolean
6798 presize_handler_callback (gpointer data)
6799 {
6800   do_presize_handler (GTK_TREE_VIEW (data));
6801                    
6802   return FALSE;
6803 }
6804
6805 static void
6806 install_presize_handler (GtkTreeView *tree_view)
6807 {
6808   if (! gtk_widget_get_realized (GTK_WIDGET (tree_view)))
6809     return;
6810
6811   if (! tree_view->priv->presize_handler_timer)
6812     {
6813       tree_view->priv->presize_handler_timer =
6814         gdk_threads_add_idle_full (GTK_PRIORITY_RESIZE - 2, presize_handler_callback, tree_view, NULL);
6815     }
6816   if (! tree_view->priv->validate_rows_timer)
6817     {
6818       tree_view->priv->validate_rows_timer =
6819         gdk_threads_add_idle_full (GTK_TREE_VIEW_PRIORITY_VALIDATE, (GSourceFunc) validate_rows_handler, tree_view, NULL);
6820     }
6821 }
6822
6823 static gboolean
6824 scroll_sync_handler (GtkTreeView *tree_view)
6825 {
6826   if (tree_view->priv->height <= gtk_adjustment_get_page_size (tree_view->priv->vadjustment))
6827     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
6828   else if (gtk_tree_row_reference_valid (tree_view->priv->top_row))
6829     gtk_tree_view_top_row_to_dy (tree_view);
6830   else
6831     gtk_tree_view_dy_to_top_row (tree_view);
6832
6833   tree_view->priv->scroll_sync_timer = 0;
6834
6835   return FALSE;
6836 }
6837
6838 static void
6839 install_scroll_sync_handler (GtkTreeView *tree_view)
6840 {
6841   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
6842     return;
6843
6844   if (!tree_view->priv->scroll_sync_timer)
6845     {
6846       tree_view->priv->scroll_sync_timer =
6847         gdk_threads_add_idle_full (GTK_TREE_VIEW_PRIORITY_SCROLL_SYNC, (GSourceFunc) scroll_sync_handler, tree_view, NULL);
6848     }
6849 }
6850
6851 static void
6852 gtk_tree_view_set_top_row (GtkTreeView *tree_view,
6853                            GtkTreePath *path,
6854                            gint         offset)
6855 {
6856   gtk_tree_row_reference_free (tree_view->priv->top_row);
6857
6858   if (!path)
6859     {
6860       tree_view->priv->top_row = NULL;
6861       tree_view->priv->top_row_dy = 0;
6862     }
6863   else
6864     {
6865       tree_view->priv->top_row = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
6866       tree_view->priv->top_row_dy = offset;
6867     }
6868 }
6869
6870 /* Always call this iff dy is in the visible range.  If the tree is empty, then
6871  * it's set to be NULL, and top_row_dy is 0;
6872  */
6873 static void
6874 gtk_tree_view_dy_to_top_row (GtkTreeView *tree_view)
6875 {
6876   gint offset;
6877   GtkTreePath *path;
6878   GtkRBTree *tree;
6879   GtkRBNode *node;
6880
6881   if (tree_view->priv->tree == NULL)
6882     {
6883       gtk_tree_view_set_top_row (tree_view, NULL, 0);
6884     }
6885   else
6886     {
6887       offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
6888                                         tree_view->priv->dy,
6889                                         &tree, &node);
6890
6891       if (tree == NULL)
6892         {
6893           gtk_tree_view_set_top_row (tree_view, NULL, 0);
6894         }
6895       else
6896         {
6897           path = _gtk_tree_path_new_from_rbtree (tree, node);
6898           gtk_tree_view_set_top_row (tree_view, path, offset);
6899           gtk_tree_path_free (path);
6900         }
6901     }
6902 }
6903
6904 static void
6905 gtk_tree_view_top_row_to_dy (GtkTreeView *tree_view)
6906 {
6907   GtkTreePath *path;
6908   GtkRBTree *tree;
6909   GtkRBNode *node;
6910   int new_dy;
6911
6912   /* Avoid recursive calls */
6913   if (tree_view->priv->in_top_row_to_dy)
6914     return;
6915
6916   if (tree_view->priv->top_row)
6917     path = gtk_tree_row_reference_get_path (tree_view->priv->top_row);
6918   else
6919     path = NULL;
6920
6921   if (!path)
6922     tree = NULL;
6923   else
6924     _gtk_tree_view_find_node (tree_view, path, &tree, &node);
6925
6926   if (path)
6927     gtk_tree_path_free (path);
6928
6929   if (tree == NULL)
6930     {
6931       /* keep dy and set new toprow */
6932       gtk_tree_row_reference_free (tree_view->priv->top_row);
6933       tree_view->priv->top_row = NULL;
6934       tree_view->priv->top_row_dy = 0;
6935       /* DO NOT install the idle handler */
6936       gtk_tree_view_dy_to_top_row (tree_view);
6937       return;
6938     }
6939
6940   if (gtk_tree_view_get_row_height (tree_view, node)
6941       < tree_view->priv->top_row_dy)
6942     {
6943       /* new top row -- do NOT install the idle handler */
6944       gtk_tree_view_dy_to_top_row (tree_view);
6945       return;
6946     }
6947
6948   new_dy = _gtk_rbtree_node_find_offset (tree, node);
6949   new_dy += tree_view->priv->top_row_dy;
6950
6951   if (new_dy + gtk_adjustment_get_page_size (tree_view->priv->vadjustment) > tree_view->priv->height)
6952     new_dy = tree_view->priv->height - gtk_adjustment_get_page_size (tree_view->priv->vadjustment);
6953
6954   new_dy = MAX (0, new_dy);
6955
6956   tree_view->priv->in_top_row_to_dy = TRUE;
6957   gtk_adjustment_set_value (tree_view->priv->vadjustment, (gdouble)new_dy);
6958   tree_view->priv->in_top_row_to_dy = FALSE;
6959 }
6960
6961
6962 void
6963 _gtk_tree_view_install_mark_rows_col_dirty (GtkTreeView *tree_view,
6964                                             gboolean     install_handler)
6965 {
6966   tree_view->priv->mark_rows_col_dirty = TRUE;
6967
6968   if (install_handler)
6969     install_presize_handler (tree_view);
6970 }
6971
6972 /*
6973  * This function works synchronously (due to the while (validate_rows...)
6974  * loop).
6975  *
6976  * There was a check for column_type != GTK_TREE_VIEW_COLUMN_AUTOSIZE
6977  * here. You now need to check that yourself.
6978  */
6979 void
6980 _gtk_tree_view_column_autosize (GtkTreeView *tree_view,
6981                                 GtkTreeViewColumn *column)
6982 {
6983   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
6984   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (column));
6985
6986   _gtk_tree_view_column_cell_set_dirty (column, FALSE);
6987
6988   do_presize_handler (tree_view);
6989   while (validate_rows (tree_view));
6990
6991   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6992 }
6993
6994 /* Drag-and-drop */
6995
6996 static void
6997 set_source_row (GdkDragContext *context,
6998                 GtkTreeModel   *model,
6999                 GtkTreePath    *source_row)
7000 {
7001   g_object_set_data_full (G_OBJECT (context),
7002                           I_("gtk-tree-view-source-row"),
7003                           source_row ? gtk_tree_row_reference_new (model, source_row) : NULL,
7004                           (GDestroyNotify) (source_row ? gtk_tree_row_reference_free : NULL));
7005 }
7006
7007 static GtkTreePath*
7008 get_source_row (GdkDragContext *context)
7009 {
7010   GtkTreeRowReference *ref =
7011     g_object_get_data (G_OBJECT (context), "gtk-tree-view-source-row");
7012
7013   if (ref)
7014     return gtk_tree_row_reference_get_path (ref);
7015   else
7016     return NULL;
7017 }
7018
7019 typedef struct
7020 {
7021   GtkTreeRowReference *dest_row;
7022   guint                path_down_mode   : 1;
7023   guint                empty_view_drop  : 1;
7024   guint                drop_append_mode : 1;
7025 }
7026 DestRow;
7027
7028 static void
7029 dest_row_free (gpointer data)
7030 {
7031   DestRow *dr = (DestRow *)data;
7032
7033   gtk_tree_row_reference_free (dr->dest_row);
7034   g_slice_free (DestRow, dr);
7035 }
7036
7037 static void
7038 set_dest_row (GdkDragContext *context,
7039               GtkTreeModel   *model,
7040               GtkTreePath    *dest_row,
7041               gboolean        path_down_mode,
7042               gboolean        empty_view_drop,
7043               gboolean        drop_append_mode)
7044 {
7045   DestRow *dr;
7046
7047   if (!dest_row)
7048     {
7049       g_object_set_data_full (G_OBJECT (context), I_("gtk-tree-view-dest-row"),
7050                               NULL, NULL);
7051       return;
7052     }
7053
7054   dr = g_slice_new (DestRow);
7055
7056   dr->dest_row = gtk_tree_row_reference_new (model, dest_row);
7057   dr->path_down_mode = path_down_mode != FALSE;
7058   dr->empty_view_drop = empty_view_drop != FALSE;
7059   dr->drop_append_mode = drop_append_mode != FALSE;
7060
7061   g_object_set_data_full (G_OBJECT (context), I_("gtk-tree-view-dest-row"),
7062                           dr, (GDestroyNotify) dest_row_free);
7063 }
7064
7065 static GtkTreePath*
7066 get_dest_row (GdkDragContext *context,
7067               gboolean       *path_down_mode)
7068 {
7069   DestRow *dr =
7070     g_object_get_data (G_OBJECT (context), "gtk-tree-view-dest-row");
7071
7072   if (dr)
7073     {
7074       GtkTreePath *path = NULL;
7075
7076       if (path_down_mode)
7077         *path_down_mode = dr->path_down_mode;
7078
7079       if (dr->dest_row)
7080         path = gtk_tree_row_reference_get_path (dr->dest_row);
7081       else if (dr->empty_view_drop)
7082         path = gtk_tree_path_new_from_indices (0, -1);
7083       else
7084         path = NULL;
7085
7086       if (path && dr->drop_append_mode)
7087         gtk_tree_path_next (path);
7088
7089       return path;
7090     }
7091   else
7092     return NULL;
7093 }
7094
7095 /* Get/set whether drag_motion requested the drag data and
7096  * drag_data_received should thus not actually insert the data,
7097  * since the data doesn't result from a drop.
7098  */
7099 static void
7100 set_status_pending (GdkDragContext *context,
7101                     GdkDragAction   suggested_action)
7102 {
7103   g_object_set_data (G_OBJECT (context),
7104                      I_("gtk-tree-view-status-pending"),
7105                      GINT_TO_POINTER (suggested_action));
7106 }
7107
7108 static GdkDragAction
7109 get_status_pending (GdkDragContext *context)
7110 {
7111   return GPOINTER_TO_INT (g_object_get_data (G_OBJECT (context),
7112                                              "gtk-tree-view-status-pending"));
7113 }
7114
7115 static TreeViewDragInfo*
7116 get_info (GtkTreeView *tree_view)
7117 {
7118   return g_object_get_data (G_OBJECT (tree_view), "gtk-tree-view-drag-info");
7119 }
7120
7121 static void
7122 destroy_info (TreeViewDragInfo *di)
7123 {
7124   g_slice_free (TreeViewDragInfo, di);
7125 }
7126
7127 static TreeViewDragInfo*
7128 ensure_info (GtkTreeView *tree_view)
7129 {
7130   TreeViewDragInfo *di;
7131
7132   di = get_info (tree_view);
7133
7134   if (di == NULL)
7135     {
7136       di = g_slice_new0 (TreeViewDragInfo);
7137
7138       g_object_set_data_full (G_OBJECT (tree_view),
7139                               I_("gtk-tree-view-drag-info"),
7140                               di,
7141                               (GDestroyNotify) destroy_info);
7142     }
7143
7144   return di;
7145 }
7146
7147 static void
7148 remove_info (GtkTreeView *tree_view)
7149 {
7150   g_object_set_data (G_OBJECT (tree_view), I_("gtk-tree-view-drag-info"), NULL);
7151 }
7152
7153 #if 0
7154 static gint
7155 drag_scan_timeout (gpointer data)
7156 {
7157   GtkTreeView *tree_view;
7158   gint x, y;
7159   GdkModifierType state;
7160   GtkTreePath *path = NULL;
7161   GtkTreeViewColumn *column = NULL;
7162   GdkRectangle visible_rect;
7163
7164   gdk_threads_enter ();
7165
7166   tree_view = GTK_TREE_VIEW (data);
7167
7168   gdk_window_get_device_position (tree_view->priv->bin_window,
7169                                   gdk_device_manager_get_client_pointer (
7170                                     gdk_display_get_device_manager (
7171                                       gtk_widget_get_display (GTK_WIDGET (tree_view)))),
7172                                   &x, &y, &state);
7173
7174   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
7175
7176   /* See if we are near the edge. */
7177   if ((x - visible_rect.x) < SCROLL_EDGE_SIZE ||
7178       (visible_rect.x + visible_rect.width - x) < SCROLL_EDGE_SIZE ||
7179       (y - visible_rect.y) < SCROLL_EDGE_SIZE ||
7180       (visible_rect.y + visible_rect.height - y) < SCROLL_EDGE_SIZE)
7181     {
7182       gtk_tree_view_get_path_at_pos (tree_view,
7183                                      tree_view->priv->bin_window,
7184                                      x, y,
7185                                      &path,
7186                                      &column,
7187                                      NULL,
7188                                      NULL);
7189
7190       if (path != NULL)
7191         {
7192           gtk_tree_view_scroll_to_cell (tree_view,
7193                                         path,
7194                                         column,
7195                                         TRUE,
7196                                         0.5, 0.5);
7197
7198           gtk_tree_path_free (path);
7199         }
7200     }
7201
7202   gdk_threads_leave ();
7203
7204   return TRUE;
7205 }
7206 #endif /* 0 */
7207
7208 static void
7209 add_scroll_timeout (GtkTreeView *tree_view)
7210 {
7211   if (tree_view->priv->scroll_timeout == 0)
7212     {
7213       tree_view->priv->scroll_timeout =
7214         gdk_threads_add_timeout (150, scroll_row_timeout, tree_view);
7215     }
7216 }
7217
7218 static void
7219 remove_scroll_timeout (GtkTreeView *tree_view)
7220 {
7221   if (tree_view->priv->scroll_timeout != 0)
7222     {
7223       g_source_remove (tree_view->priv->scroll_timeout);
7224       tree_view->priv->scroll_timeout = 0;
7225     }
7226 }
7227
7228 static gboolean
7229 check_model_dnd (GtkTreeModel *model,
7230                  GType         required_iface,
7231                  const gchar  *signal)
7232 {
7233   if (model == NULL || !G_TYPE_CHECK_INSTANCE_TYPE ((model), required_iface))
7234     {
7235       g_warning ("You must override the default '%s' handler "
7236                  "on GtkTreeView when using models that don't support "
7237                  "the %s interface and enabling drag-and-drop. The simplest way to do this "
7238                  "is to connect to '%s' and call "
7239                  "g_signal_stop_emission_by_name() in your signal handler to prevent "
7240                  "the default handler from running. Look at the source code "
7241                  "for the default handler in gtktreeview.c to get an idea what "
7242                  "your handler should do. (gtktreeview.c is in the GTK source "
7243                  "code.) If you're using GTK from a language other than C, "
7244                  "there may be a more natural way to override default handlers, e.g. via derivation.",
7245                  signal, g_type_name (required_iface), signal);
7246       return FALSE;
7247     }
7248   else
7249     return TRUE;
7250 }
7251
7252 static void
7253 remove_open_timeout (GtkTreeView *tree_view)
7254 {
7255   if (tree_view->priv->open_dest_timeout != 0)
7256     {
7257       g_source_remove (tree_view->priv->open_dest_timeout);
7258       tree_view->priv->open_dest_timeout = 0;
7259     }
7260 }
7261
7262
7263 static gint
7264 open_row_timeout (gpointer data)
7265 {
7266   GtkTreeView *tree_view = data;
7267   GtkTreePath *dest_path = NULL;
7268   GtkTreeViewDropPosition pos;
7269   gboolean result = FALSE;
7270
7271   gtk_tree_view_get_drag_dest_row (tree_view,
7272                                    &dest_path,
7273                                    &pos);
7274
7275   if (dest_path &&
7276       (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
7277        pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
7278     {
7279       gtk_tree_view_expand_row (tree_view, dest_path, FALSE);
7280       tree_view->priv->open_dest_timeout = 0;
7281
7282       gtk_tree_path_free (dest_path);
7283     }
7284   else
7285     {
7286       if (dest_path)
7287         gtk_tree_path_free (dest_path);
7288
7289       result = TRUE;
7290     }
7291
7292   return result;
7293 }
7294
7295 static gboolean
7296 scroll_row_timeout (gpointer data)
7297 {
7298   GtkTreeView *tree_view = data;
7299
7300   gtk_tree_view_vertical_autoscroll (tree_view);
7301
7302   if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
7303     gtk_tree_view_update_rubber_band (tree_view);
7304
7305   return TRUE;
7306 }
7307
7308 /* Returns TRUE if event should not be propagated to parent widgets */
7309 static gboolean
7310 set_destination_row (GtkTreeView    *tree_view,
7311                      GdkDragContext *context,
7312                      /* coordinates relative to the widget */
7313                      gint            x,
7314                      gint            y,
7315                      GdkDragAction  *suggested_action,
7316                      GdkAtom        *target)
7317 {
7318   GtkTreePath *path = NULL;
7319   GtkTreeViewDropPosition pos;
7320   GtkTreeViewDropPosition old_pos;
7321   TreeViewDragInfo *di;
7322   GtkWidget *widget;
7323   GtkTreePath *old_dest_path = NULL;
7324   gboolean can_drop = FALSE;
7325
7326   *suggested_action = 0;
7327   *target = GDK_NONE;
7328
7329   widget = GTK_WIDGET (tree_view);
7330
7331   di = get_info (tree_view);
7332
7333   if (di == NULL || y - gtk_tree_view_get_effective_header_height (tree_view) < 0)
7334     {
7335       /* someone unset us as a drag dest, note that if
7336        * we return FALSE drag_leave isn't called
7337        */
7338
7339       gtk_tree_view_set_drag_dest_row (tree_view,
7340                                        NULL,
7341                                        GTK_TREE_VIEW_DROP_BEFORE);
7342
7343       remove_scroll_timeout (GTK_TREE_VIEW (widget));
7344       remove_open_timeout (GTK_TREE_VIEW (widget));
7345
7346       return FALSE; /* no longer a drop site */
7347     }
7348
7349   *target = gtk_drag_dest_find_target (widget, context,
7350                                        gtk_drag_dest_get_target_list (widget));
7351   if (*target == GDK_NONE)
7352     {
7353       return FALSE;
7354     }
7355
7356   if (!gtk_tree_view_get_dest_row_at_pos (tree_view,
7357                                           x, y,
7358                                           &path,
7359                                           &pos))
7360     {
7361       gint n_children;
7362       GtkTreeModel *model;
7363
7364       remove_open_timeout (tree_view);
7365
7366       /* the row got dropped on empty space, let's setup a special case
7367        */
7368
7369       if (path)
7370         gtk_tree_path_free (path);
7371
7372       model = gtk_tree_view_get_model (tree_view);
7373
7374       n_children = gtk_tree_model_iter_n_children (model, NULL);
7375       if (n_children)
7376         {
7377           pos = GTK_TREE_VIEW_DROP_AFTER;
7378           path = gtk_tree_path_new_from_indices (n_children - 1, -1);
7379         }
7380       else
7381         {
7382           pos = GTK_TREE_VIEW_DROP_BEFORE;
7383           path = gtk_tree_path_new_from_indices (0, -1);
7384         }
7385
7386       can_drop = TRUE;
7387
7388       goto out;
7389     }
7390
7391   g_assert (path);
7392
7393   /* If we left the current row's "open" zone, unset the timeout for
7394    * opening the row
7395    */
7396   gtk_tree_view_get_drag_dest_row (tree_view,
7397                                    &old_dest_path,
7398                                    &old_pos);
7399
7400   if (old_dest_path &&
7401       (gtk_tree_path_compare (path, old_dest_path) != 0 ||
7402        !(pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
7403          pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE)))
7404     remove_open_timeout (tree_view);
7405
7406   if (old_dest_path)
7407     gtk_tree_path_free (old_dest_path);
7408
7409   if (TRUE /* FIXME if the location droppable predicate */)
7410     {
7411       can_drop = TRUE;
7412     }
7413
7414 out:
7415   if (can_drop)
7416     {
7417       GtkWidget *source_widget;
7418
7419       *suggested_action = gdk_drag_context_get_suggested_action (context);
7420       source_widget = gtk_drag_get_source_widget (context);
7421
7422       if (source_widget == widget)
7423         {
7424           /* Default to MOVE, unless the user has
7425            * pressed ctrl or shift to affect available actions
7426            */
7427           if ((gdk_drag_context_get_actions (context) & GDK_ACTION_MOVE) != 0)
7428             *suggested_action = GDK_ACTION_MOVE;
7429         }
7430
7431       gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7432                                        path, pos);
7433     }
7434   else
7435     {
7436       /* can't drop here */
7437       remove_open_timeout (tree_view);
7438
7439       gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7440                                        NULL,
7441                                        GTK_TREE_VIEW_DROP_BEFORE);
7442     }
7443
7444   if (path)
7445     gtk_tree_path_free (path);
7446
7447   return TRUE;
7448 }
7449
7450 static GtkTreePath*
7451 get_logical_dest_row (GtkTreeView *tree_view,
7452                       gboolean    *path_down_mode,
7453                       gboolean    *drop_append_mode)
7454 {
7455   /* adjust path to point to the row the drop goes in front of */
7456   GtkTreePath *path = NULL;
7457   GtkTreeViewDropPosition pos;
7458
7459   g_return_val_if_fail (path_down_mode != NULL, NULL);
7460   g_return_val_if_fail (drop_append_mode != NULL, NULL);
7461
7462   *path_down_mode = FALSE;
7463   *drop_append_mode = 0;
7464
7465   gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
7466
7467   if (path == NULL)
7468     return NULL;
7469
7470   if (pos == GTK_TREE_VIEW_DROP_BEFORE)
7471     ; /* do nothing */
7472   else if (pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE ||
7473            pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER)
7474     *path_down_mode = TRUE;
7475   else
7476     {
7477       GtkTreeIter iter;
7478       GtkTreeModel *model = gtk_tree_view_get_model (tree_view);
7479
7480       g_assert (pos == GTK_TREE_VIEW_DROP_AFTER);
7481
7482       if (!gtk_tree_model_get_iter (model, &iter, path) ||
7483           !gtk_tree_model_iter_next (model, &iter))
7484         *drop_append_mode = 1;
7485       else
7486         {
7487           *drop_append_mode = 0;
7488           gtk_tree_path_next (path);
7489         }
7490     }
7491
7492   return path;
7493 }
7494
7495 static gboolean
7496 gtk_tree_view_maybe_begin_dragging_row (GtkTreeView      *tree_view,
7497                                         GdkEventMotion   *event)
7498 {
7499   GtkWidget *widget = GTK_WIDGET (tree_view);
7500   GdkDragContext *context;
7501   TreeViewDragInfo *di;
7502   GtkTreePath *path = NULL;
7503   gint button;
7504   gint cell_x, cell_y;
7505   GtkTreeModel *model;
7506   gboolean retval = FALSE;
7507
7508   di = get_info (tree_view);
7509
7510   if (di == NULL || !di->source_set)
7511     goto out;
7512
7513   if (tree_view->priv->pressed_button < 0)
7514     goto out;
7515
7516   if (!gtk_drag_check_threshold (widget,
7517                                  tree_view->priv->press_start_x,
7518                                  tree_view->priv->press_start_y,
7519                                  event->x, event->y))
7520     goto out;
7521
7522   model = gtk_tree_view_get_model (tree_view);
7523
7524   if (model == NULL)
7525     goto out;
7526
7527   button = tree_view->priv->pressed_button;
7528   tree_view->priv->pressed_button = -1;
7529
7530   gtk_tree_view_get_path_at_pos (tree_view,
7531                                  tree_view->priv->press_start_x,
7532                                  tree_view->priv->press_start_y,
7533                                  &path,
7534                                  NULL,
7535                                  &cell_x,
7536                                  &cell_y);
7537
7538   if (path == NULL)
7539     goto out;
7540
7541   if (!GTK_IS_TREE_DRAG_SOURCE (model) ||
7542       !gtk_tree_drag_source_row_draggable (GTK_TREE_DRAG_SOURCE (model),
7543                                            path))
7544     goto out;
7545
7546   if (!(GDK_BUTTON1_MASK << (button - 1) & di->start_button_mask))
7547     goto out;
7548
7549   /* Now we can begin the drag */
7550
7551   retval = TRUE;
7552
7553   context = gtk_drag_begin (widget,
7554                             gtk_drag_source_get_target_list (widget),
7555                             di->source_actions,
7556                             button,
7557                             (GdkEvent*)event);
7558
7559   set_source_row (context, model, path);
7560
7561  out:
7562   if (path)
7563     gtk_tree_path_free (path);
7564
7565   return retval;
7566 }
7567
7568
7569 static void
7570 gtk_tree_view_drag_begin (GtkWidget      *widget,
7571                           GdkDragContext *context)
7572 {
7573   GtkTreeView *tree_view;
7574   GtkTreePath *path = NULL;
7575   gint cell_x, cell_y;
7576   cairo_surface_t *row_pix;
7577   TreeViewDragInfo *di;
7578
7579   tree_view = GTK_TREE_VIEW (widget);
7580
7581   /* if the user uses a custom DND source impl, we don't set the icon here */
7582   di = get_info (tree_view);
7583
7584   if (di == NULL || !di->source_set)
7585     return;
7586
7587   gtk_tree_view_get_path_at_pos (tree_view,
7588                                  tree_view->priv->press_start_x,
7589                                  tree_view->priv->press_start_y,
7590                                  &path,
7591                                  NULL,
7592                                  &cell_x,
7593                                  &cell_y);
7594
7595   /* If path is NULL, there's nothing we can drag.  For now, we silently
7596    * bail out.  Actually, dragging should not be possible from an empty
7597    * tree view, but there's no way we can cancel that from here.
7598    * Automatically unsetting the tree view as drag source for empty models
7599    * is something that would likely break other people's code ...
7600    */
7601   if (!path)
7602     return;
7603
7604   row_pix = gtk_tree_view_create_row_drag_icon (tree_view,
7605                                                 path);
7606   cairo_surface_set_device_offset (row_pix,
7607                                    /* the + 1 is for the black border in the icon */
7608                                    - (tree_view->priv->press_start_x + 1),
7609                                    - (cell_y + 1));
7610
7611   gtk_drag_set_icon_surface (context, row_pix);
7612
7613   cairo_surface_destroy (row_pix);
7614   gtk_tree_path_free (path);
7615 }
7616
7617 static void
7618 gtk_tree_view_drag_end (GtkWidget      *widget,
7619                         GdkDragContext *context)
7620 {
7621   /* do nothing */
7622 }
7623
7624 /* Default signal implementations for the drag signals */
7625 static void
7626 gtk_tree_view_drag_data_get (GtkWidget        *widget,
7627                              GdkDragContext   *context,
7628                              GtkSelectionData *selection_data,
7629                              guint             info,
7630                              guint             time)
7631 {
7632   GtkTreeView *tree_view;
7633   GtkTreeModel *model;
7634   TreeViewDragInfo *di;
7635   GtkTreePath *source_row;
7636
7637   tree_view = GTK_TREE_VIEW (widget);
7638
7639   model = gtk_tree_view_get_model (tree_view);
7640
7641   if (model == NULL)
7642     return;
7643
7644   di = get_info (GTK_TREE_VIEW (widget));
7645
7646   if (di == NULL)
7647     return;
7648
7649   source_row = get_source_row (context);
7650
7651   if (source_row == NULL)
7652     return;
7653
7654   /* We can implement the GTK_TREE_MODEL_ROW target generically for
7655    * any model; for DragSource models there are some other targets
7656    * we also support.
7657    */
7658
7659   if (GTK_IS_TREE_DRAG_SOURCE (model) &&
7660       gtk_tree_drag_source_drag_data_get (GTK_TREE_DRAG_SOURCE (model),
7661                                           source_row,
7662                                           selection_data))
7663     goto done;
7664
7665   /* If drag_data_get does nothing, try providing row data. */
7666   if (gtk_selection_data_get_target (selection_data) == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
7667     {
7668       gtk_tree_set_row_drag_data (selection_data,
7669                                   model,
7670                                   source_row);
7671     }
7672
7673  done:
7674   gtk_tree_path_free (source_row);
7675 }
7676
7677
7678 static void
7679 gtk_tree_view_drag_data_delete (GtkWidget      *widget,
7680                                 GdkDragContext *context)
7681 {
7682   TreeViewDragInfo *di;
7683   GtkTreeModel *model;
7684   GtkTreeView *tree_view;
7685   GtkTreePath *source_row;
7686
7687   tree_view = GTK_TREE_VIEW (widget);
7688   model = gtk_tree_view_get_model (tree_view);
7689
7690   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_SOURCE, "drag_data_delete"))
7691     return;
7692
7693   di = get_info (tree_view);
7694
7695   if (di == NULL)
7696     return;
7697
7698   source_row = get_source_row (context);
7699
7700   if (source_row == NULL)
7701     return;
7702
7703   gtk_tree_drag_source_drag_data_delete (GTK_TREE_DRAG_SOURCE (model),
7704                                          source_row);
7705
7706   gtk_tree_path_free (source_row);
7707
7708   set_source_row (context, NULL, NULL);
7709 }
7710
7711 static void
7712 gtk_tree_view_drag_leave (GtkWidget      *widget,
7713                           GdkDragContext *context,
7714                           guint             time)
7715 {
7716   /* unset any highlight row */
7717   gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7718                                    NULL,
7719                                    GTK_TREE_VIEW_DROP_BEFORE);
7720
7721   remove_scroll_timeout (GTK_TREE_VIEW (widget));
7722   remove_open_timeout (GTK_TREE_VIEW (widget));
7723 }
7724
7725
7726 static gboolean
7727 gtk_tree_view_drag_motion (GtkWidget        *widget,
7728                            GdkDragContext   *context,
7729                            /* coordinates relative to the widget */
7730                            gint              x,
7731                            gint              y,
7732                            guint             time)
7733 {
7734   gboolean empty;
7735   GtkTreePath *path = NULL;
7736   GtkTreeViewDropPosition pos;
7737   GtkTreeView *tree_view;
7738   GdkDragAction suggested_action = 0;
7739   GdkAtom target;
7740
7741   tree_view = GTK_TREE_VIEW (widget);
7742
7743   if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
7744     return FALSE;
7745
7746   gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
7747
7748   /* we only know this *after* set_desination_row */
7749   empty = tree_view->priv->empty_view_drop;
7750
7751   if (path == NULL && !empty)
7752     {
7753       /* Can't drop here. */
7754       gdk_drag_status (context, 0, time);
7755     }
7756   else
7757     {
7758       if (tree_view->priv->open_dest_timeout == 0 &&
7759           (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
7760            pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
7761         {
7762           tree_view->priv->open_dest_timeout =
7763             gdk_threads_add_timeout (AUTO_EXPAND_TIMEOUT, open_row_timeout, tree_view);
7764         }
7765       else
7766         {
7767           add_scroll_timeout (tree_view);
7768         }
7769
7770       if (target == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
7771         {
7772           /* Request data so we can use the source row when
7773            * determining whether to accept the drop
7774            */
7775           set_status_pending (context, suggested_action);
7776           gtk_drag_get_data (widget, context, target, time);
7777         }
7778       else
7779         {
7780           set_status_pending (context, 0);
7781           gdk_drag_status (context, suggested_action, time);
7782         }
7783     }
7784
7785   if (path)
7786     gtk_tree_path_free (path);
7787
7788   return TRUE;
7789 }
7790
7791
7792 static gboolean
7793 gtk_tree_view_drag_drop (GtkWidget        *widget,
7794                          GdkDragContext   *context,
7795                          /* coordinates relative to the widget */
7796                          gint              x,
7797                          gint              y,
7798                          guint             time)
7799 {
7800   GtkTreeView *tree_view;
7801   GtkTreePath *path;
7802   GdkDragAction suggested_action = 0;
7803   GdkAtom target = GDK_NONE;
7804   TreeViewDragInfo *di;
7805   GtkTreeModel *model;
7806   gboolean path_down_mode;
7807   gboolean drop_append_mode;
7808
7809   tree_view = GTK_TREE_VIEW (widget);
7810
7811   model = gtk_tree_view_get_model (tree_view);
7812
7813   remove_scroll_timeout (GTK_TREE_VIEW (widget));
7814   remove_open_timeout (GTK_TREE_VIEW (widget));
7815
7816   di = get_info (tree_view);
7817
7818   if (di == NULL)
7819     return FALSE;
7820
7821   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_drop"))
7822     return FALSE;
7823
7824   if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
7825     return FALSE;
7826
7827   path = get_logical_dest_row (tree_view, &path_down_mode, &drop_append_mode);
7828
7829   if (target != GDK_NONE && path != NULL)
7830     {
7831       /* in case a motion had requested drag data, change things so we
7832        * treat drag data receives as a drop.
7833        */
7834       set_status_pending (context, 0);
7835       set_dest_row (context, model, path,
7836                     path_down_mode, tree_view->priv->empty_view_drop,
7837                     drop_append_mode);
7838     }
7839
7840   if (path)
7841     gtk_tree_path_free (path);
7842
7843   /* Unset this thing */
7844   gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7845                                    NULL,
7846                                    GTK_TREE_VIEW_DROP_BEFORE);
7847
7848   if (target != GDK_NONE)
7849     {
7850       gtk_drag_get_data (widget, context, target, time);
7851       return TRUE;
7852     }
7853   else
7854     return FALSE;
7855 }
7856
7857 static void
7858 gtk_tree_view_drag_data_received (GtkWidget        *widget,
7859                                   GdkDragContext   *context,
7860                                   /* coordinates relative to the widget */
7861                                   gint              x,
7862                                   gint              y,
7863                                   GtkSelectionData *selection_data,
7864                                   guint             info,
7865                                   guint             time)
7866 {
7867   GtkTreePath *path;
7868   TreeViewDragInfo *di;
7869   gboolean accepted = FALSE;
7870   GtkTreeModel *model;
7871   GtkTreeView *tree_view;
7872   GtkTreePath *dest_row;
7873   GdkDragAction suggested_action;
7874   gboolean path_down_mode;
7875   gboolean drop_append_mode;
7876
7877   tree_view = GTK_TREE_VIEW (widget);
7878
7879   model = gtk_tree_view_get_model (tree_view);
7880
7881   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_data_received"))
7882     return;
7883
7884   di = get_info (tree_view);
7885
7886   if (di == NULL)
7887     return;
7888
7889   suggested_action = get_status_pending (context);
7890
7891   if (suggested_action)
7892     {
7893       /* We are getting this data due to a request in drag_motion,
7894        * rather than due to a request in drag_drop, so we are just
7895        * supposed to call drag_status, not actually paste in the
7896        * data.
7897        */
7898       path = get_logical_dest_row (tree_view, &path_down_mode,
7899                                    &drop_append_mode);
7900
7901       if (path == NULL)
7902         suggested_action = 0;
7903       else if (path_down_mode)
7904         gtk_tree_path_down (path);
7905
7906       if (suggested_action)
7907         {
7908           if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
7909                                                      path,
7910                                                      selection_data))
7911             {
7912               if (path_down_mode)
7913                 {
7914                   path_down_mode = FALSE;
7915                   gtk_tree_path_up (path);
7916
7917                   if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
7918                                                              path,
7919                                                              selection_data))
7920                     suggested_action = 0;
7921                 }
7922               else
7923                 suggested_action = 0;
7924             }
7925         }
7926
7927       gdk_drag_status (context, suggested_action, time);
7928
7929       if (path)
7930         gtk_tree_path_free (path);
7931
7932       /* If you can't drop, remove user drop indicator until the next motion */
7933       if (suggested_action == 0)
7934         gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7935                                          NULL,
7936                                          GTK_TREE_VIEW_DROP_BEFORE);
7937
7938       return;
7939     }
7940
7941   dest_row = get_dest_row (context, &path_down_mode);
7942
7943   if (dest_row == NULL)
7944     return;
7945
7946   if (gtk_selection_data_get_length (selection_data) >= 0)
7947     {
7948       if (path_down_mode)
7949         {
7950           gtk_tree_path_down (dest_row);
7951           if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
7952                                                      dest_row, selection_data))
7953             gtk_tree_path_up (dest_row);
7954         }
7955     }
7956
7957   if (gtk_selection_data_get_length (selection_data) >= 0)
7958     {
7959       if (gtk_tree_drag_dest_drag_data_received (GTK_TREE_DRAG_DEST (model),
7960                                                  dest_row,
7961                                                  selection_data))
7962         accepted = TRUE;
7963     }
7964
7965   gtk_drag_finish (context,
7966                    accepted,
7967                    (gdk_drag_context_get_selected_action (context) == GDK_ACTION_MOVE),
7968                    time);
7969
7970   if (gtk_tree_path_get_depth (dest_row) == 1 &&
7971       gtk_tree_path_get_indices (dest_row)[0] == 0 &&
7972       gtk_tree_model_iter_n_children (tree_view->priv->model, NULL) != 0)
7973     {
7974       /* special special case drag to "0", scroll to first item */
7975       if (!tree_view->priv->scroll_to_path)
7976         gtk_tree_view_scroll_to_cell (tree_view, dest_row, NULL, FALSE, 0.0, 0.0);
7977     }
7978
7979   gtk_tree_path_free (dest_row);
7980
7981   /* drop dest_row */
7982   set_dest_row (context, NULL, NULL, FALSE, FALSE, FALSE);
7983 }
7984
7985
7986
7987 /* GtkContainer Methods
7988  */
7989
7990
7991 static void
7992 gtk_tree_view_remove (GtkContainer *container,
7993                       GtkWidget    *widget)
7994 {
7995   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
7996   GtkTreeViewChild *child = NULL;
7997   GList *tmp_list;
7998
7999   tmp_list = tree_view->priv->children;
8000   while (tmp_list)
8001     {
8002       child = tmp_list->data;
8003       if (child->widget == widget)
8004         {
8005           gtk_widget_unparent (widget);
8006
8007           tree_view->priv->children = g_list_remove_link (tree_view->priv->children, tmp_list);
8008           g_list_free_1 (tmp_list);
8009           g_slice_free (GtkTreeViewChild, child);
8010           return;
8011         }
8012
8013       tmp_list = tmp_list->next;
8014     }
8015
8016   tmp_list = tree_view->priv->columns;
8017
8018   while (tmp_list)
8019     {
8020       GtkTreeViewColumn *column;
8021       GtkWidget         *button;
8022
8023       column = tmp_list->data;
8024       button = gtk_tree_view_column_get_button (column);
8025
8026       if (button == widget)
8027         {
8028           gtk_widget_unparent (widget);
8029           return;
8030         }
8031       tmp_list = tmp_list->next;
8032     }
8033 }
8034
8035 static void
8036 gtk_tree_view_forall (GtkContainer *container,
8037                       gboolean      include_internals,
8038                       GtkCallback   callback,
8039                       gpointer      callback_data)
8040 {
8041   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
8042   GtkTreeViewChild *child = NULL;
8043   GtkTreeViewColumn *column;
8044   GtkWidget *button;
8045   GList *tmp_list;
8046
8047   tmp_list = tree_view->priv->children;
8048   while (tmp_list)
8049     {
8050       child = tmp_list->data;
8051       tmp_list = tmp_list->next;
8052
8053       (* callback) (child->widget, callback_data);
8054     }
8055   if (include_internals == FALSE)
8056     return;
8057
8058   for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
8059     {
8060       column = tmp_list->data;
8061       button = gtk_tree_view_column_get_button (column);
8062
8063       if (button)
8064         (* callback) (button, callback_data);
8065     }
8066 }
8067
8068 /* Returns TRUE is any of the columns contains a cell that can-focus.
8069  * If this is not the case, a column-spanning focus rectangle will be
8070  * drawn.
8071  */
8072 static gboolean
8073 gtk_tree_view_has_can_focus_cell (GtkTreeView *tree_view)
8074 {
8075   GList *list;
8076
8077   for (list = tree_view->priv->columns; list; list = list->next)
8078     {
8079       GtkTreeViewColumn *column = list->data;
8080
8081       if (!gtk_tree_view_column_get_visible (column))
8082         continue;
8083       if (gtk_cell_area_is_activatable (gtk_cell_layout_get_area (GTK_CELL_LAYOUT (column))))
8084         return TRUE;
8085     }
8086
8087   return FALSE;
8088 }
8089
8090 static void
8091 column_sizing_notify (GObject    *object,
8092                       GParamSpec *pspec,
8093                       gpointer    data)
8094 {
8095   GtkTreeViewColumn *c = GTK_TREE_VIEW_COLUMN (object);
8096
8097   if (gtk_tree_view_column_get_sizing (c) != GTK_TREE_VIEW_COLUMN_FIXED)
8098     /* disable fixed height mode */
8099     g_object_set (data, "fixed-height-mode", FALSE, NULL);
8100 }
8101
8102 /**
8103  * gtk_tree_view_set_fixed_height_mode:
8104  * @tree_view: a #GtkTreeView 
8105  * @enable: %TRUE to enable fixed height mode
8106  * 
8107  * Enables or disables the fixed height mode of @tree_view. 
8108  * Fixed height mode speeds up #GtkTreeView by assuming that all 
8109  * rows have the same height. 
8110  * Only enable this option if all rows are the same height and all
8111  * columns are of type %GTK_TREE_VIEW_COLUMN_FIXED.
8112  *
8113  * Since: 2.6 
8114  **/
8115 void
8116 gtk_tree_view_set_fixed_height_mode (GtkTreeView *tree_view,
8117                                      gboolean     enable)
8118 {
8119   GList *l;
8120   
8121   enable = enable != FALSE;
8122
8123   if (enable == tree_view->priv->fixed_height_mode)
8124     return;
8125
8126   if (!enable)
8127     {
8128       tree_view->priv->fixed_height_mode = 0;
8129       tree_view->priv->fixed_height = -1;
8130     }
8131   else 
8132     {
8133       /* make sure all columns are of type FIXED */
8134       for (l = tree_view->priv->columns; l; l = l->next)
8135         {
8136           GtkTreeViewColumn *c = l->data;
8137           
8138           g_return_if_fail (gtk_tree_view_column_get_sizing (c) == GTK_TREE_VIEW_COLUMN_FIXED);
8139         }
8140       
8141       /* yes, we really have to do this is in a separate loop */
8142       for (l = tree_view->priv->columns; l; l = l->next)
8143         g_signal_connect (l->data, "notify::sizing",
8144                           G_CALLBACK (column_sizing_notify), tree_view);
8145       
8146       tree_view->priv->fixed_height_mode = 1;
8147       tree_view->priv->fixed_height = -1;
8148     }
8149
8150   /* force a revalidation */
8151   install_presize_handler (tree_view);
8152
8153   g_object_notify (G_OBJECT (tree_view), "fixed-height-mode");
8154 }
8155
8156 /**
8157  * gtk_tree_view_get_fixed_height_mode:
8158  * @tree_view: a #GtkTreeView
8159  * 
8160  * Returns whether fixed height mode is turned on for @tree_view.
8161  * 
8162  * Return value: %TRUE if @tree_view is in fixed height mode
8163  * 
8164  * Since: 2.6
8165  **/
8166 gboolean
8167 gtk_tree_view_get_fixed_height_mode (GtkTreeView *tree_view)
8168 {
8169   return tree_view->priv->fixed_height_mode;
8170 }
8171
8172 /* Returns TRUE if the focus is within the headers, after the focus operation is
8173  * done
8174  */
8175 static gboolean
8176 gtk_tree_view_header_focus (GtkTreeView      *tree_view,
8177                             GtkDirectionType  dir,
8178                             gboolean          clamp_column_visible)
8179 {
8180   GtkTreeViewColumn *column;
8181   GtkWidget *focus_child;
8182   GtkWidget *button;
8183   GList *last_column, *first_column;
8184   GList *tmp_list;
8185   gboolean rtl;
8186
8187   if (! tree_view->priv->headers_visible)
8188     return FALSE;
8189
8190   focus_child = gtk_container_get_focus_child (GTK_CONTAINER (tree_view));
8191
8192   first_column = tree_view->priv->columns;
8193   while (first_column)
8194     {
8195       column = GTK_TREE_VIEW_COLUMN (first_column->data);
8196       button = gtk_tree_view_column_get_button (column);
8197
8198       if (gtk_widget_get_can_focus (button) &&
8199           gtk_tree_view_column_get_visible (column) &&
8200           (gtk_tree_view_column_get_clickable (column) ||
8201            gtk_tree_view_column_get_reorderable (column)))
8202         break;
8203       first_column = first_column->next;
8204     }
8205
8206   /* No headers are visible, or are focusable.  We can't focus in or out.
8207    */
8208   if (first_column == NULL)
8209     return FALSE;
8210
8211   last_column = g_list_last (tree_view->priv->columns);
8212   while (last_column)
8213     {
8214       column = GTK_TREE_VIEW_COLUMN (last_column->data);
8215       button = gtk_tree_view_column_get_button (column);
8216
8217       if (gtk_widget_get_can_focus (button) &&
8218           gtk_tree_view_column_get_visible (column) &&
8219           (gtk_tree_view_column_get_clickable (column) ||
8220            gtk_tree_view_column_get_reorderable (column)))
8221         break;
8222       last_column = last_column->prev;
8223     }
8224
8225
8226   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
8227
8228   switch (dir)
8229     {
8230     case GTK_DIR_TAB_BACKWARD:
8231     case GTK_DIR_TAB_FORWARD:
8232     case GTK_DIR_UP:
8233     case GTK_DIR_DOWN:
8234       if (focus_child == NULL)
8235         {
8236           if (tree_view->priv->focus_column != NULL)
8237             button = gtk_tree_view_column_get_button (tree_view->priv->focus_column);
8238           else 
8239             button = NULL;
8240
8241           if (button && gtk_widget_get_can_focus (button))
8242             focus_child = button;
8243           else
8244             focus_child = gtk_tree_view_column_get_button (GTK_TREE_VIEW_COLUMN (first_column->data));
8245
8246           gtk_widget_grab_focus (focus_child);
8247           break;
8248         }
8249       return FALSE;
8250
8251     case GTK_DIR_LEFT:
8252     case GTK_DIR_RIGHT:
8253       if (focus_child == NULL)
8254         {
8255           if (tree_view->priv->focus_column != NULL)
8256             focus_child = gtk_tree_view_column_get_button (tree_view->priv->focus_column);
8257           else if (dir == GTK_DIR_LEFT)
8258             focus_child = gtk_tree_view_column_get_button (GTK_TREE_VIEW_COLUMN (last_column->data));
8259           else
8260             focus_child = gtk_tree_view_column_get_button (GTK_TREE_VIEW_COLUMN (first_column->data));
8261
8262           gtk_widget_grab_focus (focus_child);
8263           break;
8264         }
8265
8266       if (gtk_widget_child_focus (focus_child, dir))
8267         {
8268           /* The focus moves inside the button. */
8269           /* This is probably a great example of bad UI */
8270           break;
8271         }
8272
8273       /* We need to move the focus among the row of buttons. */
8274       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
8275         if (gtk_tree_view_column_get_button (GTK_TREE_VIEW_COLUMN (tmp_list->data)) == focus_child)
8276           break;
8277
8278       if ((tmp_list == first_column && dir == (rtl ? GTK_DIR_RIGHT : GTK_DIR_LEFT))
8279           || (tmp_list == last_column && dir == (rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT)))
8280         {
8281           gtk_widget_error_bell (GTK_WIDGET (tree_view));
8282           break;
8283         }
8284
8285       while (tmp_list)
8286         {
8287           GtkTreeViewColumn *column;
8288           GtkWidget         *button;
8289
8290           if (dir == (rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT))
8291             tmp_list = tmp_list->next;
8292           else
8293             tmp_list = tmp_list->prev;
8294
8295           if (tmp_list == NULL)
8296             {
8297               g_warning ("Internal button not found");
8298               break;
8299             }
8300           column = tmp_list->data;
8301           button = gtk_tree_view_column_get_button (column);
8302           if (button &&
8303               gtk_tree_view_column_get_visible (column) &&
8304               gtk_widget_get_can_focus (button))
8305             {
8306               focus_child = button;
8307               gtk_widget_grab_focus (button);
8308               break;
8309             }
8310         }
8311       break;
8312     default:
8313       g_assert_not_reached ();
8314       break;
8315     }
8316
8317   /* if focus child is non-null, we assume it's been set to the current focus child
8318    */
8319   if (focus_child)
8320     {
8321       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
8322         if (gtk_tree_view_column_get_button (GTK_TREE_VIEW_COLUMN (tmp_list->data)) == focus_child)
8323           {
8324             _gtk_tree_view_set_focus_column (tree_view, GTK_TREE_VIEW_COLUMN (tmp_list->data));
8325             break;
8326           }
8327
8328       if (clamp_column_visible)
8329         {
8330           gtk_tree_view_clamp_column_visible (tree_view,
8331                                               tree_view->priv->focus_column,
8332                                               FALSE);
8333         }
8334     }
8335
8336   return (focus_child != NULL);
8337 }
8338
8339 /* This function returns in 'path' the first focusable path, if the given path
8340  * is already focusable, it's the returned one.
8341  */
8342 static gboolean
8343 search_first_focusable_path (GtkTreeView  *tree_view,
8344                              GtkTreePath **path,
8345                              gboolean      search_forward,
8346                              GtkRBTree   **new_tree,
8347                              GtkRBNode   **new_node)
8348 {
8349   GtkRBTree *tree = NULL;
8350   GtkRBNode *node = NULL;
8351
8352   if (!path || !*path)
8353     return FALSE;
8354
8355   _gtk_tree_view_find_node (tree_view, *path, &tree, &node);
8356
8357   if (!tree || !node)
8358     return FALSE;
8359
8360   while (node && row_is_separator (tree_view, NULL, *path))
8361     {
8362       if (search_forward)
8363         _gtk_rbtree_next_full (tree, node, &tree, &node);
8364       else
8365         _gtk_rbtree_prev_full (tree, node, &tree, &node);
8366
8367       if (*path)
8368         gtk_tree_path_free (*path);
8369
8370       if (node)
8371         *path = _gtk_tree_path_new_from_rbtree (tree, node);
8372       else
8373         *path = NULL;
8374     }
8375
8376   if (new_tree)
8377     *new_tree = tree;
8378
8379   if (new_node)
8380     *new_node = node;
8381
8382   return (*path != NULL);
8383 }
8384
8385 static gint
8386 gtk_tree_view_focus (GtkWidget        *widget,
8387                      GtkDirectionType  direction)
8388 {
8389   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
8390   GtkContainer *container = GTK_CONTAINER (widget);
8391   GtkWidget *focus_child;
8392
8393   if (!gtk_widget_is_sensitive (widget) || !gtk_widget_get_can_focus (widget))
8394     return FALSE;
8395
8396   focus_child = gtk_container_get_focus_child (container);
8397
8398   gtk_tree_view_stop_editing (GTK_TREE_VIEW (widget), FALSE);
8399   /* Case 1.  Headers currently have focus. */
8400   if (focus_child)
8401     {
8402       switch (direction)
8403         {
8404         case GTK_DIR_LEFT:
8405         case GTK_DIR_RIGHT:
8406           gtk_tree_view_header_focus (tree_view, direction, TRUE);
8407           return TRUE;
8408         case GTK_DIR_TAB_BACKWARD:
8409         case GTK_DIR_UP:
8410           return FALSE;
8411         case GTK_DIR_TAB_FORWARD:
8412         case GTK_DIR_DOWN:
8413           gtk_widget_grab_focus (widget);
8414           return TRUE;
8415         default:
8416           g_assert_not_reached ();
8417           return FALSE;
8418         }
8419     }
8420
8421   /* Case 2. We don't have focus at all. */
8422   if (!gtk_widget_has_focus (widget))
8423     {
8424       gtk_widget_grab_focus (widget);
8425       return TRUE;
8426     }
8427
8428   /* Case 3. We have focus already. */
8429   if (direction == GTK_DIR_TAB_BACKWARD)
8430     return (gtk_tree_view_header_focus (tree_view, direction, FALSE));
8431   else if (direction == GTK_DIR_TAB_FORWARD)
8432     return FALSE;
8433
8434   /* Other directions caught by the keybindings */
8435   gtk_widget_grab_focus (widget);
8436   return TRUE;
8437 }
8438
8439 static void
8440 gtk_tree_view_grab_focus (GtkWidget *widget)
8441 {
8442   GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->grab_focus (widget);
8443
8444   gtk_tree_view_focus_to_cursor (GTK_TREE_VIEW (widget));
8445 }
8446
8447 static void
8448 gtk_tree_view_style_updated (GtkWidget *widget)
8449 {
8450   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
8451   GList *list;
8452   GtkTreeViewColumn *column;
8453   GtkStyleContext *style_context;
8454   const GtkBitmask *changes;
8455
8456   GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->style_updated (widget);
8457
8458   if (gtk_widget_get_realized (widget))
8459     {
8460       gtk_tree_view_ensure_background (tree_view);
8461
8462       gtk_tree_view_set_grid_lines (tree_view, tree_view->priv->grid_lines);
8463       gtk_tree_view_set_enable_tree_lines (tree_view, tree_view->priv->tree_lines_enabled);
8464     }
8465
8466   style_context = gtk_widget_get_style_context (widget);
8467   changes = _gtk_style_context_get_changes (style_context);
8468   if (changes == NULL || _gtk_css_style_property_changes_affect_size (changes))
8469     {
8470       for (list = tree_view->priv->columns; list; list = list->next)
8471         {
8472           column = list->data;
8473           _gtk_tree_view_column_cell_set_dirty (column, TRUE);
8474         }
8475
8476       tree_view->priv->fixed_height = -1;
8477       _gtk_rbtree_mark_invalid (tree_view->priv->tree);
8478     }
8479 }
8480
8481
8482 static void
8483 gtk_tree_view_set_focus_child (GtkContainer *container,
8484                                GtkWidget    *child)
8485 {
8486   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
8487   GList *list;
8488
8489   for (list = tree_view->priv->columns; list; list = list->next)
8490     {
8491       if (gtk_tree_view_column_get_button (GTK_TREE_VIEW_COLUMN (list->data)) == child)
8492         {
8493           _gtk_tree_view_set_focus_column (tree_view, GTK_TREE_VIEW_COLUMN (list->data));
8494           break;
8495         }
8496     }
8497
8498   GTK_CONTAINER_CLASS (gtk_tree_view_parent_class)->set_focus_child (container, child);
8499 }
8500
8501 static GtkWidgetPath *
8502 gtk_tree_view_get_path_for_child (GtkContainer *container,
8503                                   GtkWidget    *child)
8504 {
8505   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
8506   GtkWidgetPath *path;
8507   gboolean rtl;
8508   GList *list, *visible_columns = NULL;
8509   gint n_col = 0;
8510
8511   path = GTK_CONTAINER_CLASS (gtk_tree_view_parent_class)->get_path_for_child (container, child);
8512   rtl = (gtk_widget_get_direction (GTK_WIDGET (container)) == GTK_TEXT_DIR_RTL);
8513
8514   for (list = tree_view->priv->columns; list; list = list->next)
8515     {
8516       GtkTreeViewColumn *column = list->data;
8517
8518       if (gtk_tree_view_column_get_visible (column))
8519         visible_columns = g_list_prepend (visible_columns, column);
8520     }
8521
8522   if (!rtl)
8523     visible_columns = g_list_reverse (visible_columns);
8524
8525   for (list = visible_columns; list != NULL; list = list->next)
8526     {
8527       GtkTreeViewColumn *column = list->data;
8528       GtkRegionFlags flags = 0;
8529
8530       n_col++;
8531
8532       if (gtk_tree_view_column_get_widget (column) != child &&
8533           gtk_tree_view_column_get_button (column) != child)
8534         continue;
8535
8536       if ((n_col % 2) == 0)
8537         flags |= GTK_REGION_EVEN;
8538       else
8539         flags |= GTK_REGION_ODD;
8540
8541       if (n_col == 1)
8542         flags |= GTK_REGION_FIRST;
8543
8544       if (!list->next)
8545         flags |= GTK_REGION_LAST;
8546
8547       gtk_widget_path_iter_add_region (path, gtk_widget_path_length (path) - 2, GTK_STYLE_REGION_COLUMN_HEADER, flags);
8548       break;
8549     }
8550   g_list_free (visible_columns);
8551
8552   return path;
8553 }
8554
8555 static gboolean
8556 gtk_tree_view_real_move_cursor (GtkTreeView       *tree_view,
8557                                 GtkMovementStep    step,
8558                                 gint               count)
8559 {
8560   GdkModifierType state;
8561
8562   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
8563   g_return_val_if_fail (step == GTK_MOVEMENT_LOGICAL_POSITIONS ||
8564                         step == GTK_MOVEMENT_VISUAL_POSITIONS ||
8565                         step == GTK_MOVEMENT_DISPLAY_LINES ||
8566                         step == GTK_MOVEMENT_PAGES ||
8567                         step == GTK_MOVEMENT_BUFFER_ENDS, FALSE);
8568
8569   if (tree_view->priv->tree == NULL)
8570     return FALSE;
8571   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
8572     return FALSE;
8573
8574   gtk_tree_view_stop_editing (tree_view, FALSE);
8575   tree_view->priv->draw_keyfocus = TRUE;
8576   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
8577
8578   if (gtk_get_current_event_state (&state))
8579     {
8580       GdkModifierType extend_mod_mask;
8581       GdkModifierType modify_mod_mask;
8582
8583       extend_mod_mask =
8584         gtk_widget_get_modifier_mask (GTK_WIDGET (tree_view),
8585                                       GDK_MODIFIER_INTENT_EXTEND_SELECTION);
8586
8587       modify_mod_mask =
8588         gtk_widget_get_modifier_mask (GTK_WIDGET (tree_view),
8589                                       GDK_MODIFIER_INTENT_MODIFY_SELECTION);
8590
8591       if ((state & modify_mod_mask) == modify_mod_mask)
8592         tree_view->priv->modify_selection_pressed = TRUE;
8593       if ((state & extend_mod_mask) == extend_mod_mask)
8594         tree_view->priv->extend_selection_pressed = TRUE;
8595     }
8596   /* else we assume not pressed */
8597
8598   switch (step)
8599     {
8600       /* currently we make no distinction.  When we go bi-di, we need to */
8601     case GTK_MOVEMENT_LOGICAL_POSITIONS:
8602     case GTK_MOVEMENT_VISUAL_POSITIONS:
8603       gtk_tree_view_move_cursor_left_right (tree_view, count);
8604       break;
8605     case GTK_MOVEMENT_DISPLAY_LINES:
8606       gtk_tree_view_move_cursor_up_down (tree_view, count);
8607       break;
8608     case GTK_MOVEMENT_PAGES:
8609       gtk_tree_view_move_cursor_page_up_down (tree_view, count);
8610       break;
8611     case GTK_MOVEMENT_BUFFER_ENDS:
8612       gtk_tree_view_move_cursor_start_end (tree_view, count);
8613       break;
8614     default:
8615       g_assert_not_reached ();
8616     }
8617
8618   tree_view->priv->modify_selection_pressed = FALSE;
8619   tree_view->priv->extend_selection_pressed = FALSE;
8620
8621   return TRUE;
8622 }
8623
8624 static void
8625 gtk_tree_view_put (GtkTreeView *tree_view,
8626                    GtkWidget   *child_widget,
8627                    /* in bin_window coordinates */
8628                    gint         x,
8629                    gint         y,
8630                    gint         width,
8631                    gint         height)
8632 {
8633   GtkTreeViewChild *child;
8634   
8635   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8636   g_return_if_fail (GTK_IS_WIDGET (child_widget));
8637
8638   child = g_slice_new (GtkTreeViewChild);
8639
8640   child->widget = child_widget;
8641   child->x = x;
8642   child->y = y;
8643   child->width = width;
8644   child->height = height;
8645
8646   tree_view->priv->children = g_list_append (tree_view->priv->children, child);
8647
8648   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
8649     gtk_widget_set_parent_window (child->widget, tree_view->priv->bin_window);
8650   
8651   gtk_widget_set_parent (child_widget, GTK_WIDGET (tree_view));
8652 }
8653
8654 void
8655 _gtk_tree_view_child_move_resize (GtkTreeView *tree_view,
8656                                   GtkWidget   *widget,
8657                                   /* in tree coordinates */
8658                                   gint         x,
8659                                   gint         y,
8660                                   gint         width,
8661                                   gint         height)
8662 {
8663   GtkTreeViewChild *child = NULL;
8664   GList *list;
8665   GdkRectangle allocation;
8666
8667   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8668   g_return_if_fail (GTK_IS_WIDGET (widget));
8669
8670   for (list = tree_view->priv->children; list; list = list->next)
8671     {
8672       if (((GtkTreeViewChild *)list->data)->widget == widget)
8673         {
8674           child = list->data;
8675           break;
8676         }
8677     }
8678   if (child == NULL)
8679     return;
8680
8681   allocation.x = child->x = x;
8682   allocation.y = child->y = y;
8683   allocation.width = child->width = width;
8684   allocation.height = child->height = height;
8685
8686   if (gtk_widget_get_realized (widget))
8687     gtk_widget_size_allocate (widget, &allocation);
8688 }
8689
8690
8691 /* TreeModel Callbacks
8692  */
8693
8694 static void
8695 gtk_tree_view_row_changed (GtkTreeModel *model,
8696                            GtkTreePath  *path,
8697                            GtkTreeIter  *iter,
8698                            gpointer      data)
8699 {
8700   GtkTreeView *tree_view = (GtkTreeView *)data;
8701   GtkRBTree *tree;
8702   GtkRBNode *node;
8703   gboolean free_path = FALSE;
8704   GList *list;
8705   GtkTreePath *cursor_path;
8706
8707   g_return_if_fail (path != NULL || iter != NULL);
8708
8709   if (tree_view->priv->cursor_node != NULL)
8710     cursor_path = _gtk_tree_path_new_from_rbtree (tree_view->priv->cursor_tree,
8711                                                   tree_view->priv->cursor_node);
8712   else
8713     cursor_path = NULL;
8714
8715   if (tree_view->priv->edited_column &&
8716       (cursor_path == NULL || gtk_tree_path_compare (cursor_path, path) == 0))
8717     gtk_tree_view_stop_editing (tree_view, TRUE);
8718
8719   if (cursor_path != NULL)
8720     gtk_tree_path_free (cursor_path);
8721
8722   if (path == NULL)
8723     {
8724       path = gtk_tree_model_get_path (model, iter);
8725       free_path = TRUE;
8726     }
8727   else if (iter == NULL)
8728     gtk_tree_model_get_iter (model, iter, path);
8729
8730   if (_gtk_tree_view_find_node (tree_view,
8731                                 path,
8732                                 &tree,
8733                                 &node))
8734     /* We aren't actually showing the node */
8735     goto done;
8736
8737   if (tree == NULL)
8738     goto done;
8739
8740   _gtk_tree_view_accessible_changed (tree_view, tree, node);
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 *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   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 (tree == NULL)
8821         {
8822           /* We aren't showing the node */
8823           node_visible = FALSE;
8824           goto done;
8825         }
8826
8827       tmpnode = _gtk_rbtree_find_count (tree, 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_path_new_from_rbtree (tree, tmpnode);
8842           gtk_tree_view_row_has_child_toggled (model, tmppath, NULL, data);
8843           gtk_tree_path_free (tmppath);
8844           goto done;
8845         }
8846
8847       tree = tmpnode->children;
8848       i++;
8849     }
8850
8851   if (tree == NULL)
8852     {
8853       node_visible = FALSE;
8854       goto done;
8855     }
8856
8857   /* ref the node */
8858   gtk_tree_model_ref_node (tree_view->priv->model, iter);
8859   if (indices[depth - 1] == 0)
8860     {
8861       tmpnode = _gtk_rbtree_find_count (tree, 1);
8862       tmpnode = _gtk_rbtree_insert_before (tree, tmpnode, height, FALSE);
8863     }
8864   else
8865     {
8866       tmpnode = _gtk_rbtree_find_count (tree, indices[depth - 1]);
8867       tmpnode = _gtk_rbtree_insert_after (tree, tmpnode, height, FALSE);
8868     }
8869
8870   _gtk_tree_view_accessible_add (tree_view, tree, tmpnode);
8871
8872  done:
8873   if (height > 0)
8874     {
8875       if (tree)
8876         _gtk_rbtree_node_mark_valid (tree, tmpnode);
8877
8878       if (node_visible && node_is_visible (tree_view, tree, tmpnode))
8879         gtk_widget_queue_resize (GTK_WIDGET (tree_view));
8880       else
8881         gtk_widget_queue_resize_no_redraw (GTK_WIDGET (tree_view));
8882     }
8883   else
8884     install_presize_handler (tree_view);
8885   if (free_path)
8886     gtk_tree_path_free (path);
8887 }
8888
8889 static void
8890 gtk_tree_view_row_has_child_toggled (GtkTreeModel *model,
8891                                      GtkTreePath  *path,
8892                                      GtkTreeIter  *iter,
8893                                      gpointer      data)
8894 {
8895   GtkTreeView *tree_view = (GtkTreeView *)data;
8896   GtkTreeIter real_iter;
8897   gboolean has_child;
8898   GtkRBTree *tree;
8899   GtkRBNode *node;
8900   gboolean free_path = FALSE;
8901
8902   g_return_if_fail (path != NULL || iter != NULL);
8903
8904   if (iter)
8905     real_iter = *iter;
8906
8907   if (path == NULL)
8908     {
8909       path = gtk_tree_model_get_path (model, iter);
8910       free_path = TRUE;
8911     }
8912   else if (iter == NULL)
8913     gtk_tree_model_get_iter (model, &real_iter, path);
8914
8915   if (_gtk_tree_view_find_node (tree_view,
8916                                 path,
8917                                 &tree,
8918                                 &node))
8919     /* We aren't actually showing the node */
8920     goto done;
8921
8922   if (tree == NULL)
8923     goto done;
8924
8925   has_child = gtk_tree_model_iter_has_child (model, &real_iter);
8926   /* Sanity check.
8927    */
8928   if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT) == has_child)
8929     goto done;
8930
8931   if (has_child)
8932     {
8933       GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_PARENT);
8934       _gtk_tree_view_accessible_add_state (tree_view, tree, node, GTK_CELL_RENDERER_EXPANDABLE);
8935     }
8936   else
8937     {
8938       GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_PARENT);
8939       _gtk_tree_view_accessible_remove_state (tree_view, tree, node, GTK_CELL_RENDERER_EXPANDABLE);
8940     }
8941
8942   if (has_child && tree_view->priv->is_list)
8943     {
8944       tree_view->priv->is_list = FALSE;
8945       if (tree_view->priv->show_expanders)
8946         {
8947           GList *list;
8948
8949           for (list = tree_view->priv->columns; list; list = list->next)
8950             if (gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (list->data)))
8951               {
8952                 _gtk_tree_view_column_cell_set_dirty (GTK_TREE_VIEW_COLUMN (list->data), TRUE);
8953                 break;
8954               }
8955         }
8956       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
8957     }
8958   else
8959     {
8960       _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
8961     }
8962
8963  done:
8964   if (free_path)
8965     gtk_tree_path_free (path);
8966 }
8967
8968 static void
8969 count_children_helper (GtkRBTree *tree,
8970                        GtkRBNode *node,
8971                        gpointer   data)
8972 {
8973   if (node->children)
8974     _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, data);
8975   (*((gint *)data))++;
8976 }
8977
8978 static void
8979 check_selection_helper (GtkRBTree *tree,
8980                         GtkRBNode *node,
8981                         gpointer   data)
8982 {
8983   gint *value = (gint *)data;
8984
8985   *value |= GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED);
8986
8987   if (node->children && !*value)
8988     _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, check_selection_helper, data);
8989 }
8990
8991 static void
8992 gtk_tree_view_row_deleted (GtkTreeModel *model,
8993                            GtkTreePath  *path,
8994                            gpointer      data)
8995 {
8996   GtkTreeView *tree_view = (GtkTreeView *)data;
8997   GtkRBTree *tree;
8998   GtkRBNode *node;
8999   GList *list;
9000   gboolean selection_changed = FALSE, cursor_changed = FALSE;
9001   GtkRBTree *cursor_tree = NULL;
9002   GtkRBNode *cursor_node = NULL;
9003
9004   g_return_if_fail (path != NULL);
9005
9006   gtk_tree_row_reference_deleted (G_OBJECT (data), path);
9007
9008   if (_gtk_tree_view_find_node (tree_view, path, &tree, &node))
9009     return;
9010
9011   if (tree == NULL)
9012     return;
9013
9014   /* check if the selection has been changed */
9015   _gtk_rbtree_traverse (tree, node, G_POST_ORDER,
9016                         check_selection_helper, &selection_changed);
9017
9018   for (list = tree_view->priv->columns; list; list = list->next)
9019     if (gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (list->data)) &&
9020         gtk_tree_view_column_get_sizing (GTK_TREE_VIEW_COLUMN (list->data)) == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
9021       _gtk_tree_view_column_cell_set_dirty ((GtkTreeViewColumn *)list->data, TRUE);
9022
9023   /* Ensure we don't have a dangling pointer to a dead node */
9024   ensure_unprelighted (tree_view);
9025
9026   /* Cancel editting if we've started */
9027   gtk_tree_view_stop_editing (tree_view, TRUE);
9028
9029   /* If the cursor row got deleted, move the cursor to the next row */
9030   if (tree_view->priv->cursor_node &&
9031       (tree_view->priv->cursor_node == node ||
9032        (node->children && (tree_view->priv->cursor_tree == node->children ||
9033                            _gtk_rbtree_contains (node->children, tree_view->priv->cursor_tree)))))
9034     {
9035       GtkTreePath *cursor_path;
9036
9037       cursor_tree = tree;
9038       cursor_node = _gtk_rbtree_next (tree, node);
9039       /* find the first node that is not going to be deleted */
9040       while (cursor_node == NULL && cursor_tree->parent_tree)
9041         {
9042           cursor_node = _gtk_rbtree_next (cursor_tree->parent_tree,
9043                                           cursor_tree->parent_node);
9044           cursor_tree = cursor_tree->parent_tree;
9045         }
9046
9047       if (cursor_node != NULL)
9048         cursor_path = _gtk_tree_path_new_from_rbtree (cursor_tree, cursor_node);
9049       else
9050         cursor_path = NULL;
9051
9052       if (cursor_path == NULL ||
9053           ! search_first_focusable_path (tree_view, &cursor_path, TRUE, 
9054                                          &cursor_tree, &cursor_node))
9055         {
9056           /* It looks like we reached the end of the view without finding
9057            * a focusable row.  We will step backwards to find the last
9058            * focusable row.
9059            */
9060           _gtk_rbtree_prev_full (tree, node, &cursor_tree, &cursor_node);
9061           if (cursor_node)
9062             {
9063               cursor_path = _gtk_tree_path_new_from_rbtree (cursor_tree, cursor_node);
9064               if (! search_first_focusable_path (tree_view, &cursor_path, FALSE,
9065                                                  &cursor_tree, &cursor_node))
9066                 cursor_node = NULL;
9067               gtk_tree_path_free (cursor_path);
9068             }
9069         }
9070       else if (cursor_path)
9071         gtk_tree_path_free (cursor_path);
9072
9073       cursor_changed = TRUE;
9074     }
9075
9076   if (tree_view->priv->destroy_count_func)
9077     {
9078       gint child_count = 0;
9079       if (node->children)
9080         _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, &child_count);
9081       tree_view->priv->destroy_count_func (tree_view, path, child_count, tree_view->priv->destroy_count_data);
9082     }
9083
9084   if (tree->root->count == 1)
9085     {
9086       if (tree_view->priv->tree == tree)
9087         tree_view->priv->tree = NULL;
9088
9089       _gtk_tree_view_accessible_remove_state (tree_view,
9090                                               tree->parent_tree, tree->parent_node,
9091                                               GTK_CELL_RENDERER_EXPANDED);
9092       _gtk_tree_view_accessible_remove (tree_view, tree, NULL);
9093       _gtk_rbtree_remove (tree);
9094     }
9095   else
9096     {
9097       _gtk_tree_view_accessible_remove (tree_view, tree, node);
9098       _gtk_rbtree_remove_node (tree, node);
9099     }
9100
9101   if (! gtk_tree_row_reference_valid (tree_view->priv->top_row))
9102     {
9103       gtk_tree_row_reference_free (tree_view->priv->top_row);
9104       tree_view->priv->top_row = NULL;
9105     }
9106
9107   install_scroll_sync_handler (tree_view);
9108
9109   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
9110
9111   if (cursor_changed)
9112     {
9113       if (cursor_node)
9114         {
9115           GtkTreePath *cursor_path = _gtk_tree_path_new_from_rbtree (cursor_tree, cursor_node);
9116           gtk_tree_view_real_set_cursor (tree_view, cursor_path, CLEAR_AND_SELECT | CURSOR_INVALID);
9117           gtk_tree_path_free (cursor_path);
9118         }
9119       else
9120         gtk_tree_view_real_set_cursor (tree_view, NULL, CLEAR_AND_SELECT | CURSOR_INVALID);
9121     }
9122   if (selection_changed)
9123     g_signal_emit_by_name (tree_view->priv->selection, "changed");
9124 }
9125
9126 static void
9127 gtk_tree_view_rows_reordered (GtkTreeModel *model,
9128                               GtkTreePath  *parent,
9129                               GtkTreeIter  *iter,
9130                               gint         *new_order,
9131                               gpointer      data)
9132 {
9133   GtkTreeView *tree_view = GTK_TREE_VIEW (data);
9134   GtkRBTree *tree;
9135   GtkRBNode *node;
9136   gint len;
9137
9138   len = gtk_tree_model_iter_n_children (model, iter);
9139
9140   if (len < 2)
9141     return;
9142
9143   gtk_tree_row_reference_reordered (G_OBJECT (data),
9144                                     parent,
9145                                     iter,
9146                                     new_order);
9147
9148   if (_gtk_tree_view_find_node (tree_view,
9149                                 parent,
9150                                 &tree,
9151                                 &node))
9152     return;
9153
9154   /* We need to special case the parent path */
9155   if (tree == NULL)
9156     tree = tree_view->priv->tree;
9157   else
9158     tree = node->children;
9159
9160   if (tree == NULL)
9161     return;
9162
9163   if (tree_view->priv->edited_column)
9164     gtk_tree_view_stop_editing (tree_view, TRUE);
9165
9166   /* we need to be unprelighted */
9167   ensure_unprelighted (tree_view);
9168
9169   _gtk_rbtree_reorder (tree, new_order, len);
9170
9171   _gtk_tree_view_accessible_reorder (tree_view);
9172
9173   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
9174
9175   gtk_tree_view_dy_to_top_row (tree_view);
9176 }
9177
9178
9179 /* Internal tree functions
9180  */
9181
9182
9183 static void
9184 gtk_tree_view_get_background_xrange (GtkTreeView       *tree_view,
9185                                      GtkRBTree         *tree,
9186                                      GtkTreeViewColumn *column,
9187                                      gint              *x1,
9188                                      gint              *x2)
9189 {
9190   GtkTreeViewColumn *tmp_column = NULL;
9191   gint total_width;
9192   GList *list;
9193   gboolean rtl;
9194
9195   if (x1)
9196     *x1 = 0;
9197
9198   if (x2)
9199     *x2 = 0;
9200
9201   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
9202
9203   total_width = 0;
9204   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
9205        list;
9206        list = (rtl ? list->prev : list->next))
9207     {
9208       tmp_column = list->data;
9209
9210       if (tmp_column == column)
9211         break;
9212
9213       if (gtk_tree_view_column_get_visible (tmp_column))
9214         total_width += gtk_tree_view_column_get_width (tmp_column);
9215     }
9216
9217   if (tmp_column != column)
9218     {
9219       g_warning (G_STRLOC": passed-in column isn't in the tree");
9220       return;
9221     }
9222
9223   if (x1)
9224     *x1 = total_width;
9225
9226   if (x2)
9227     {
9228       if (gtk_tree_view_column_get_visible (column))
9229         *x2 = total_width + gtk_tree_view_column_get_width (column);
9230       else
9231         *x2 = total_width; /* width of 0 */
9232     }
9233 }
9234
9235 static void
9236 gtk_tree_view_get_arrow_xrange (GtkTreeView *tree_view,
9237                                 GtkRBTree   *tree,
9238                                 gint        *x1,
9239                                 gint        *x2)
9240 {
9241   gint x_offset = 0;
9242   GList *list;
9243   GtkTreeViewColumn *tmp_column = NULL;
9244   gint total_width;
9245   gint expander_size;
9246   gboolean indent_expanders;
9247   gboolean rtl;
9248
9249   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
9250   expander_size = gtk_tree_view_get_expander_size (tree_view);
9251
9252   total_width = 0;
9253   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
9254        list;
9255        list = (rtl ? list->prev : list->next))
9256     {
9257       tmp_column = list->data;
9258
9259       if (gtk_tree_view_is_expander_column (tree_view, tmp_column))
9260         {
9261           if (rtl)
9262             x_offset = total_width + gtk_tree_view_column_get_width (tmp_column) - expander_size;
9263           else
9264             x_offset = total_width;
9265           break;
9266         }
9267
9268       if (gtk_tree_view_column_get_visible (tmp_column))
9269         total_width += gtk_tree_view_column_get_width (tmp_column);
9270     }
9271
9272   gtk_widget_style_get (GTK_WIDGET (tree_view),
9273                         "indent-expanders", &indent_expanders,
9274                         NULL);
9275
9276   if (indent_expanders)
9277     {
9278       if (rtl)
9279         x_offset -= expander_size * _gtk_rbtree_get_depth (tree);
9280       else
9281         x_offset += expander_size * _gtk_rbtree_get_depth (tree);
9282     }
9283
9284   *x1 = x_offset;
9285
9286   if (tmp_column &&
9287       gtk_tree_view_column_get_visible (tmp_column))
9288     /* +1 because x2 isn't included in the range. */
9289     *x2 = *x1 + expander_size + 1;
9290   else
9291     *x2 = *x1;
9292 }
9293
9294 static void
9295 gtk_tree_view_build_tree (GtkTreeView *tree_view,
9296                           GtkRBTree   *tree,
9297                           GtkTreeIter *iter,
9298                           gint         depth,
9299                           gboolean     recurse)
9300 {
9301   GtkRBNode *temp = NULL;
9302   GtkTreePath *path = NULL;
9303
9304   do
9305     {
9306       gtk_tree_model_ref_node (tree_view->priv->model, iter);
9307       temp = _gtk_rbtree_insert_after (tree, temp, 0, FALSE);
9308
9309       if (tree_view->priv->fixed_height > 0)
9310         {
9311           if (GTK_RBNODE_FLAG_SET (temp, GTK_RBNODE_INVALID))
9312             {
9313               _gtk_rbtree_node_set_height (tree, temp, tree_view->priv->fixed_height);
9314               _gtk_rbtree_node_mark_valid (tree, temp);
9315             }
9316         }
9317
9318       if (tree_view->priv->is_list)
9319         continue;
9320
9321       if (recurse)
9322         {
9323           GtkTreeIter child;
9324
9325           if (!path)
9326             path = gtk_tree_model_get_path (tree_view->priv->model, iter);
9327           else
9328             gtk_tree_path_next (path);
9329
9330           if (gtk_tree_model_iter_children (tree_view->priv->model, &child, iter))
9331             {
9332               gboolean expand;
9333
9334               g_signal_emit (tree_view, tree_view_signals[TEST_EXPAND_ROW], 0, iter, path, &expand);
9335
9336               if (gtk_tree_model_iter_has_child (tree_view->priv->model, iter)
9337                   && !expand)
9338                 {
9339                   temp->children = _gtk_rbtree_new ();
9340                   temp->children->parent_tree = tree;
9341                   temp->children->parent_node = temp;
9342                   gtk_tree_view_build_tree (tree_view, temp->children, &child, depth + 1, recurse);
9343                 }
9344             }
9345         }
9346
9347       if (gtk_tree_model_iter_has_child (tree_view->priv->model, iter))
9348         {
9349           if ((temp->flags&GTK_RBNODE_IS_PARENT) != GTK_RBNODE_IS_PARENT)
9350             temp->flags ^= GTK_RBNODE_IS_PARENT;
9351         }
9352     }
9353   while (gtk_tree_model_iter_next (tree_view->priv->model, iter));
9354
9355   if (path)
9356     gtk_tree_path_free (path);
9357 }
9358
9359 /* Make sure the node is visible vertically */
9360 static void
9361 gtk_tree_view_clamp_node_visible (GtkTreeView *tree_view,
9362                                   GtkRBTree   *tree,
9363                                   GtkRBNode   *node)
9364 {
9365   gint node_dy, height;
9366   GtkTreePath *path = NULL;
9367
9368   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
9369     return;
9370
9371   /* just return if the node is visible, avoiding a costly expose */
9372   node_dy = _gtk_rbtree_node_find_offset (tree, node);
9373   height = gtk_tree_view_get_row_height (tree_view, node);
9374   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID)
9375       && node_dy >= gtk_adjustment_get_value (tree_view->priv->vadjustment)
9376       && node_dy + height <= (gtk_adjustment_get_value (tree_view->priv->vadjustment)
9377                               + gtk_adjustment_get_page_size (tree_view->priv->vadjustment)))
9378     return;
9379
9380   path = _gtk_tree_path_new_from_rbtree (tree, node);
9381   if (path)
9382     {
9383       gtk_tree_view_scroll_to_cell (tree_view, path, NULL, FALSE, 0.0, 0.0);
9384       gtk_tree_path_free (path);
9385     }
9386 }
9387
9388 static void
9389 gtk_tree_view_clamp_column_visible (GtkTreeView       *tree_view,
9390                                     GtkTreeViewColumn *column,
9391                                     gboolean           focus_to_cell)
9392 {
9393   GtkAllocation allocation;
9394   gint x, width;
9395
9396   if (column == NULL)
9397     return;
9398
9399   gtk_widget_get_allocation (gtk_tree_view_column_get_button (column), &allocation);
9400   x = allocation.x;
9401   width = allocation.width;
9402
9403   if (width > gtk_adjustment_get_page_size (tree_view->priv->hadjustment))
9404     {
9405       /* The column is larger than the horizontal page size.  If the
9406        * column has cells which can be focussed individually, then we make
9407        * sure the cell which gets focus is fully visible (if even the
9408        * focus cell is bigger than the page size, we make sure the
9409        * left-hand side of the cell is visible).
9410        *
9411        * If the column does not have an activatable cell, we
9412        * make sure the left-hand side of the column is visible.
9413        */
9414
9415       if (focus_to_cell && gtk_tree_view_has_can_focus_cell (tree_view))
9416         {
9417           GtkCellArea *cell_area;
9418           GtkCellRenderer *focus_cell;
9419
9420           cell_area = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (column));
9421           focus_cell = gtk_cell_area_get_focus_cell (cell_area);
9422
9423           if (gtk_tree_view_column_cell_get_position (column, focus_cell,
9424                                                       &x, &width))
9425             {
9426               if (width < gtk_adjustment_get_page_size (tree_view->priv->hadjustment))
9427                 {
9428                   if (gtk_adjustment_get_value (tree_view->priv->hadjustment) + gtk_adjustment_get_page_size (tree_view->priv->hadjustment) < x + width)
9429                     gtk_adjustment_set_value (tree_view->priv->hadjustment,
9430                                               x + width - gtk_adjustment_get_page_size (tree_view->priv->hadjustment));
9431                   else if (gtk_adjustment_get_value (tree_view->priv->hadjustment) > x)
9432                     gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
9433                 }
9434             }
9435         }
9436
9437       gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
9438     }
9439   else
9440     {
9441       if ((gtk_adjustment_get_value (tree_view->priv->hadjustment) + gtk_adjustment_get_page_size (tree_view->priv->hadjustment)) < (x + width))
9442           gtk_adjustment_set_value (tree_view->priv->hadjustment,
9443                                     x + width - gtk_adjustment_get_page_size (tree_view->priv->hadjustment));
9444       else if (gtk_adjustment_get_value (tree_view->priv->hadjustment) > x)
9445         gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
9446   }
9447 }
9448
9449 /* This function could be more efficient.  I'll optimize it if profiling seems
9450  * to imply that it is important */
9451 GtkTreePath *
9452 _gtk_tree_path_new_from_rbtree (GtkRBTree   *tree,
9453                                 GtkRBNode   *node)
9454 {
9455   GtkTreePath *path;
9456   GtkRBTree *tmp_tree;
9457   GtkRBNode *tmp_node, *last;
9458   gint count;
9459
9460   path = gtk_tree_path_new ();
9461
9462   g_return_val_if_fail (node != NULL, path);
9463
9464   count = 1 + node->left->count;
9465
9466   last = node;
9467   tmp_node = node->parent;
9468   tmp_tree = tree;
9469   while (tmp_tree)
9470     {
9471       while (!_gtk_rbtree_is_nil (tmp_node))
9472         {
9473           if (tmp_node->right == last)
9474             count += 1 + tmp_node->left->count;
9475           last = tmp_node;
9476           tmp_node = tmp_node->parent;
9477         }
9478       gtk_tree_path_prepend_index (path, count - 1);
9479       last = tmp_tree->parent_node;
9480       tmp_tree = tmp_tree->parent_tree;
9481       if (last)
9482         {
9483           count = 1 + last->left->count;
9484           tmp_node = last->parent;
9485         }
9486     }
9487   return path;
9488 }
9489
9490 /* Returns TRUE if we ran out of tree before finding the path.  If the path is
9491  * invalid (ie. points to a node that's not in the tree), *tree and *node are
9492  * both set to NULL.
9493  */
9494 gboolean
9495 _gtk_tree_view_find_node (GtkTreeView  *tree_view,
9496                           GtkTreePath  *path,
9497                           GtkRBTree   **tree,
9498                           GtkRBNode   **node)
9499 {
9500   GtkRBNode *tmpnode = NULL;
9501   GtkRBTree *tmptree = tree_view->priv->tree;
9502   gint *indices = gtk_tree_path_get_indices (path);
9503   gint depth = gtk_tree_path_get_depth (path);
9504   gint i = 0;
9505
9506   *node = NULL;
9507   *tree = NULL;
9508
9509   if (depth == 0 || tmptree == NULL)
9510     return FALSE;
9511   do
9512     {
9513       tmpnode = _gtk_rbtree_find_count (tmptree, indices[i] + 1);
9514       ++i;
9515       if (tmpnode == NULL)
9516         {
9517           *tree = NULL;
9518           *node = NULL;
9519           return FALSE;
9520         }
9521       if (i >= depth)
9522         {
9523           *tree = tmptree;
9524           *node = tmpnode;
9525           return FALSE;
9526         }
9527       *tree = tmptree;
9528       *node = tmpnode;
9529       tmptree = tmpnode->children;
9530       if (tmptree == NULL)
9531         return TRUE;
9532     }
9533   while (1);
9534 }
9535
9536 static gboolean
9537 gtk_tree_view_is_expander_column (GtkTreeView       *tree_view,
9538                                   GtkTreeViewColumn *column)
9539 {
9540   GList *list;
9541
9542   if (tree_view->priv->is_list)
9543     return FALSE;
9544
9545   if (tree_view->priv->expander_column != NULL)
9546     {
9547       if (tree_view->priv->expander_column == column)
9548         return TRUE;
9549       return FALSE;
9550     }
9551   else
9552     {
9553       for (list = tree_view->priv->columns;
9554            list;
9555            list = list->next)
9556         if (gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (list->data)))
9557           break;
9558       if (list && list->data == column)
9559         return TRUE;
9560     }
9561   return FALSE;
9562 }
9563
9564 static inline gboolean
9565 gtk_tree_view_draw_expanders (GtkTreeView *tree_view)
9566 {
9567   if (!tree_view->priv->is_list && tree_view->priv->show_expanders)
9568     return TRUE;
9569   /* else */
9570   return FALSE;
9571 }
9572
9573 static void
9574 gtk_tree_view_add_move_binding (GtkBindingSet  *binding_set,
9575                                 guint           keyval,
9576                                 guint           modmask,
9577                                 gboolean        add_shifted_binding,
9578                                 GtkMovementStep step,
9579                                 gint            count)
9580 {
9581   
9582   gtk_binding_entry_add_signal (binding_set, keyval, modmask,
9583                                 "move-cursor", 2,
9584                                 G_TYPE_ENUM, step,
9585                                 G_TYPE_INT, count);
9586
9587   if (add_shifted_binding)
9588     gtk_binding_entry_add_signal (binding_set, keyval, GDK_SHIFT_MASK,
9589                                   "move-cursor", 2,
9590                                   G_TYPE_ENUM, step,
9591                                   G_TYPE_INT, count);
9592
9593   if ((modmask & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
9594    return;
9595
9596   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK | GDK_SHIFT_MASK,
9597                                 "move-cursor", 2,
9598                                 G_TYPE_ENUM, step,
9599                                 G_TYPE_INT, count);
9600
9601   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK,
9602                                 "move-cursor", 2,
9603                                 G_TYPE_ENUM, step,
9604                                 G_TYPE_INT, count);
9605 }
9606
9607 static gint
9608 gtk_tree_view_unref_tree_helper (GtkTreeModel *model,
9609                                  GtkTreeIter  *iter,
9610                                  GtkRBTree    *tree,
9611                                  GtkRBNode    *node)
9612 {
9613   gint retval = FALSE;
9614   do
9615     {
9616       g_return_val_if_fail (node != NULL, FALSE);
9617
9618       if (node->children)
9619         {
9620           GtkTreeIter child;
9621           GtkRBTree *new_tree;
9622           GtkRBNode *new_node;
9623
9624           new_tree = node->children;
9625           new_node = _gtk_rbtree_first (new_tree);
9626
9627           if (!gtk_tree_model_iter_children (model, &child, iter))
9628             return FALSE;
9629
9630           retval = gtk_tree_view_unref_tree_helper (model, &child, new_tree, new_node) | retval;
9631         }
9632
9633       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
9634         retval = TRUE;
9635       gtk_tree_model_unref_node (model, iter);
9636       node = _gtk_rbtree_next (tree, node);
9637     }
9638   while (gtk_tree_model_iter_next (model, iter));
9639
9640   return retval;
9641 }
9642
9643 static gint
9644 gtk_tree_view_unref_and_check_selection_tree (GtkTreeView *tree_view,
9645                                               GtkRBTree   *tree)
9646 {
9647   GtkTreeIter iter;
9648   GtkTreePath *path;
9649   GtkRBNode *node;
9650   gint retval;
9651
9652   if (!tree)
9653     return FALSE;
9654
9655   node = _gtk_rbtree_first (tree);
9656
9657   g_return_val_if_fail (node != NULL, FALSE);
9658   path = _gtk_tree_path_new_from_rbtree (tree, node);
9659   gtk_tree_model_get_iter (GTK_TREE_MODEL (tree_view->priv->model),
9660                            &iter, path);
9661   retval = gtk_tree_view_unref_tree_helper (GTK_TREE_MODEL (tree_view->priv->model), &iter, tree, node);
9662   gtk_tree_path_free (path);
9663
9664   return retval;
9665 }
9666
9667 static void
9668 gtk_tree_view_set_column_drag_info (GtkTreeView       *tree_view,
9669                                     GtkTreeViewColumn *column)
9670 {
9671   GtkTreeViewColumn *left_column;
9672   GtkTreeViewColumn *cur_column = NULL;
9673   GtkTreeViewColumnReorder *reorder;
9674   gboolean rtl;
9675   GList *tmp_list;
9676   gint left;
9677
9678   /* We want to precalculate the motion list such that we know what column slots
9679    * are available.
9680    */
9681   left_column = NULL;
9682   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
9683
9684   /* First, identify all possible drop spots */
9685   if (rtl)
9686     tmp_list = g_list_last (tree_view->priv->columns);
9687   else
9688     tmp_list = g_list_first (tree_view->priv->columns);
9689
9690   while (tmp_list)
9691     {
9692       cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
9693       tmp_list = rtl?g_list_previous (tmp_list):g_list_next (tmp_list);
9694
9695       if (gtk_tree_view_column_get_visible (cur_column) == FALSE)
9696         continue;
9697
9698       /* If it's not the column moving and func tells us to skip over the column, we continue. */
9699       if (left_column != column && cur_column != column &&
9700           tree_view->priv->column_drop_func &&
9701           ! tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
9702         {
9703           left_column = cur_column;
9704           continue;
9705         }
9706       reorder = g_slice_new0 (GtkTreeViewColumnReorder);
9707       reorder->left_column = left_column;
9708       left_column = reorder->right_column = cur_column;
9709
9710       tree_view->priv->column_drag_info = g_list_append (tree_view->priv->column_drag_info, reorder);
9711     }
9712
9713   /* Add the last one */
9714   if (tree_view->priv->column_drop_func == NULL ||
9715       ((left_column != column) &&
9716        tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data)))
9717     {
9718       reorder = g_slice_new0 (GtkTreeViewColumnReorder);
9719       reorder->left_column = left_column;
9720       reorder->right_column = NULL;
9721       tree_view->priv->column_drag_info = g_list_append (tree_view->priv->column_drag_info, reorder);
9722     }
9723
9724   /* We quickly check to see if it even makes sense to reorder columns. */
9725   /* If there is nothing that can be moved, then we return */
9726
9727   if (tree_view->priv->column_drag_info == NULL)
9728     return;
9729
9730   /* We know there are always 2 slots possbile, as you can always return column. */
9731   /* If that's all there is, return */
9732   if (tree_view->priv->column_drag_info->next == NULL || 
9733       (tree_view->priv->column_drag_info->next->next == NULL &&
9734        ((GtkTreeViewColumnReorder *)tree_view->priv->column_drag_info->data)->right_column == column &&
9735        ((GtkTreeViewColumnReorder *)tree_view->priv->column_drag_info->next->data)->left_column == column))
9736     {
9737       for (tmp_list = tree_view->priv->column_drag_info; tmp_list; tmp_list = tmp_list->next)
9738         g_slice_free (GtkTreeViewColumnReorder, tmp_list->data);
9739       g_list_free (tree_view->priv->column_drag_info);
9740       tree_view->priv->column_drag_info = NULL;
9741       return;
9742     }
9743   /* We fill in the ranges for the columns, now that we've isolated them */
9744   left = - TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER (tree_view);
9745
9746   for (tmp_list = tree_view->priv->column_drag_info; tmp_list; tmp_list = tmp_list->next)
9747     {
9748       reorder = (GtkTreeViewColumnReorder *) tmp_list->data;
9749
9750       reorder->left_align = left;
9751       if (tmp_list->next != NULL)
9752         {
9753           GtkAllocation right_allocation, left_allocation;
9754           GtkWidget    *left_button, *right_button;
9755
9756           g_assert (tmp_list->next->data);
9757
9758           right_button = gtk_tree_view_column_get_button (reorder->right_column);
9759           left_button  = gtk_tree_view_column_get_button
9760             (((GtkTreeViewColumnReorder *)tmp_list->next->data)->left_column);
9761
9762           gtk_widget_get_allocation (right_button, &right_allocation);
9763           gtk_widget_get_allocation (left_button, &left_allocation);
9764           left = reorder->right_align = (right_allocation.x + right_allocation.width + left_allocation.x) / 2;
9765         }
9766       else
9767         {
9768           reorder->right_align = gdk_window_get_width (tree_view->priv->header_window)
9769                                  + TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER (tree_view);
9770         }
9771     }
9772 }
9773
9774 void
9775 _gtk_tree_view_column_start_drag (GtkTreeView       *tree_view,
9776                                   GtkTreeViewColumn *column,
9777                                   GdkDevice         *device)
9778 {
9779   GdkEvent *send_event;
9780   GtkAllocation allocation;
9781   GtkAllocation button_allocation;
9782   GdkScreen *screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
9783   GtkWidget *button;
9784   GdkDevice *pointer, *keyboard;
9785   GdkWindowAttr attributes;
9786   guint attributes_mask;
9787   GtkStyleContext *context;
9788
9789   g_return_if_fail (tree_view->priv->column_drag_info == NULL);
9790   g_return_if_fail (tree_view->priv->cur_reorder == NULL);
9791   g_return_if_fail (tree_view->priv->drag_window == NULL);
9792
9793   gtk_tree_view_set_column_drag_info (tree_view, column);
9794
9795   if (tree_view->priv->column_drag_info == NULL)
9796     return;
9797
9798   button = gtk_tree_view_column_get_button (column);
9799
9800   context = gtk_widget_get_style_context (button);
9801   gtk_style_context_add_class (context, GTK_STYLE_CLASS_DND);
9802
9803   gtk_widget_get_allocation (button, &button_allocation);
9804
9805   attributes.window_type = GDK_WINDOW_CHILD;
9806   attributes.wclass = GDK_INPUT_OUTPUT;
9807   attributes.x = button_allocation.x;
9808   attributes.y = 0;
9809   attributes.width = button_allocation.width;
9810   attributes.height = button_allocation.height;
9811   attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
9812   attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
9813   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
9814
9815   tree_view->priv->drag_window = gdk_window_new (tree_view->priv->header_window,
9816                                                  &attributes,
9817                                                  attributes_mask);
9818   gdk_window_set_user_data (tree_view->priv->drag_window, GTK_WIDGET (tree_view));
9819
9820   if (gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD)
9821     {
9822       keyboard = device;
9823       pointer = gdk_device_get_associated_device (device);
9824     }
9825   else
9826     {
9827       pointer = device;
9828       keyboard = gdk_device_get_associated_device (device);
9829     }
9830
9831   gdk_device_ungrab (pointer, GDK_CURRENT_TIME);
9832   gdk_device_ungrab (keyboard, GDK_CURRENT_TIME);
9833
9834   gtk_grab_remove (button);
9835
9836   send_event = gdk_event_new (GDK_LEAVE_NOTIFY);
9837   send_event->crossing.send_event = TRUE;
9838   send_event->crossing.window = g_object_ref (gtk_button_get_event_window (GTK_BUTTON (button)));
9839   send_event->crossing.subwindow = NULL;
9840   send_event->crossing.detail = GDK_NOTIFY_ANCESTOR;
9841   send_event->crossing.time = GDK_CURRENT_TIME;
9842   gdk_event_set_device (send_event, device);
9843
9844   gtk_propagate_event (button, send_event);
9845   gdk_event_free (send_event);
9846
9847   send_event = gdk_event_new (GDK_BUTTON_RELEASE);
9848   send_event->button.window = g_object_ref (gdk_screen_get_root_window (screen));
9849   send_event->button.send_event = TRUE;
9850   send_event->button.time = GDK_CURRENT_TIME;
9851   send_event->button.x = -1;
9852   send_event->button.y = -1;
9853   send_event->button.axes = NULL;
9854   send_event->button.state = 0;
9855   send_event->button.button = GDK_BUTTON_PRIMARY;
9856   send_event->button.x_root = 0;
9857   send_event->button.y_root = 0;
9858   gdk_event_set_device (send_event, device);
9859
9860   gtk_propagate_event (button, send_event);
9861   gdk_event_free (send_event);
9862
9863   /* Kids, don't try this at home */
9864   g_object_ref (button);
9865   gtk_container_remove (GTK_CONTAINER (tree_view), button);
9866   gtk_widget_set_parent_window (button, tree_view->priv->drag_window);
9867   gtk_widget_set_parent (button, GTK_WIDGET (tree_view));
9868   g_object_unref (button);
9869
9870   gtk_widget_get_allocation (button, &button_allocation);
9871   tree_view->priv->drag_column_x = button_allocation.x;
9872   allocation = button_allocation;
9873   allocation.x = 0;
9874   gtk_widget_size_allocate (button, &allocation);
9875   gtk_widget_set_parent_window (button, tree_view->priv->drag_window);
9876
9877   tree_view->priv->drag_column = column;
9878   gdk_window_show (tree_view->priv->drag_window);
9879
9880   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
9881   while (gtk_events_pending ())
9882     gtk_main_iteration ();
9883
9884   tree_view->priv->in_column_drag = TRUE;
9885
9886   gdk_device_grab (pointer,
9887                    tree_view->priv->drag_window,
9888                    GDK_OWNERSHIP_NONE,
9889                    FALSE,
9890                    GDK_POINTER_MOTION_MASK|GDK_BUTTON_RELEASE_MASK,
9891                    NULL,
9892                    GDK_CURRENT_TIME);
9893   gdk_device_grab (keyboard,
9894                    tree_view->priv->drag_window,
9895                    GDK_OWNERSHIP_NONE,
9896                    FALSE,
9897                    GDK_KEY_PRESS_MASK|GDK_KEY_RELEASE_MASK,
9898                    NULL,
9899                    GDK_CURRENT_TIME);
9900 }
9901
9902 static void
9903 gtk_tree_view_queue_draw_arrow (GtkTreeView        *tree_view,
9904                                 GtkRBTree          *tree,
9905                                 GtkRBNode          *node)
9906 {
9907   GtkAllocation allocation;
9908   GdkRectangle rect;
9909
9910   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
9911     return;
9912
9913   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
9914   rect.x = 0;
9915   rect.width = gtk_tree_view_get_expander_size (tree_view);
9916   rect.width = MAX (rect.width, MAX (tree_view->priv->width, allocation.width));
9917
9918   rect.y = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
9919   rect.height = gtk_tree_view_get_row_height (tree_view, node);
9920
9921   gdk_window_invalidate_rect (tree_view->priv->bin_window, &rect, TRUE);
9922 }
9923
9924 void
9925 _gtk_tree_view_queue_draw_node (GtkTreeView        *tree_view,
9926                                 GtkRBTree          *tree,
9927                                 GtkRBNode          *node,
9928                                 const GdkRectangle *clip_rect)
9929 {
9930   GtkAllocation allocation;
9931   GdkRectangle rect;
9932
9933   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
9934     return;
9935
9936   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
9937   rect.x = 0;
9938   rect.width = MAX (tree_view->priv->width, allocation.width);
9939
9940   rect.y = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
9941   rect.height = gtk_tree_view_get_row_height (tree_view, node);
9942
9943   if (clip_rect)
9944     {
9945       GdkRectangle new_rect;
9946
9947       gdk_rectangle_intersect (clip_rect, &rect, &new_rect);
9948
9949       gdk_window_invalidate_rect (tree_view->priv->bin_window, &new_rect, TRUE);
9950     }
9951   else
9952     {
9953       gdk_window_invalidate_rect (tree_view->priv->bin_window, &rect, TRUE);
9954     }
9955 }
9956
9957 static inline gint
9958 gtk_tree_view_get_effective_header_height (GtkTreeView *tree_view)
9959 {
9960   if (tree_view->priv->headers_visible)
9961     return tree_view->priv->header_height;
9962   /* else */
9963   return 0;
9964 }
9965
9966 gint
9967 _gtk_tree_view_get_header_height (GtkTreeView *tree_view)
9968 {
9969   return tree_view->priv->header_height;
9970 }
9971
9972 void
9973 _gtk_tree_view_get_row_separator_func (GtkTreeView                 *tree_view,
9974                                        GtkTreeViewRowSeparatorFunc *func,
9975                                        gpointer                    *data)
9976 {
9977   *func = tree_view->priv->row_separator_func;
9978   *data = tree_view->priv->row_separator_data;
9979 }
9980
9981 GtkTreePath *
9982 _gtk_tree_view_get_anchor_path (GtkTreeView *tree_view)
9983 {
9984   if (tree_view->priv->anchor)
9985     return gtk_tree_row_reference_get_path (tree_view->priv->anchor);
9986
9987   return NULL;
9988 }
9989
9990 void
9991 _gtk_tree_view_set_anchor_path (GtkTreeView *tree_view,
9992                                 GtkTreePath *anchor_path)
9993 {
9994   if (tree_view->priv->anchor)
9995     {
9996       gtk_tree_row_reference_free (tree_view->priv->anchor);
9997       tree_view->priv->anchor = NULL;
9998     }
9999
10000   if (anchor_path && tree_view->priv->model)
10001     tree_view->priv->anchor =
10002       gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), 
10003                                         tree_view->priv->model, anchor_path);
10004 }
10005
10006 GtkRBTree *
10007 _gtk_tree_view_get_rbtree (GtkTreeView *tree_view)
10008 {
10009   return tree_view->priv->tree;
10010 }
10011
10012 gboolean
10013 _gtk_tree_view_get_cursor_node (GtkTreeView  *tree_view,
10014                                 GtkRBTree   **tree,
10015                                 GtkRBNode   **node)
10016 {
10017   GtkTreeViewPrivate *priv;
10018
10019   priv = tree_view->priv;
10020
10021   if (priv->cursor_node == NULL)
10022     return FALSE;
10023
10024   *tree = priv->cursor_tree;
10025   *node = priv->cursor_node;
10026
10027   return TRUE;
10028 }
10029
10030 GdkWindow *
10031 _gtk_tree_view_get_header_window (GtkTreeView *tree_view)
10032 {
10033   return tree_view->priv->header_window;
10034 }
10035
10036 GtkTreeViewColumn *
10037 _gtk_tree_view_get_focus_column (GtkTreeView *tree_view)
10038 {
10039   return tree_view->priv->focus_column;
10040 }
10041
10042 void
10043 _gtk_tree_view_set_focus_column (GtkTreeView       *tree_view,
10044                                  GtkTreeViewColumn *column)
10045 {
10046   GtkTreeViewColumn *old_column = tree_view->priv->focus_column;
10047
10048   if (old_column == column)
10049     return;
10050
10051   tree_view->priv->focus_column = column;
10052
10053   _gtk_tree_view_accessible_update_focus_column (tree_view, 
10054                                                  old_column,
10055                                                  column);
10056 }
10057
10058
10059 static void
10060 gtk_tree_view_queue_draw_path (GtkTreeView        *tree_view,
10061                                GtkTreePath        *path,
10062                                const GdkRectangle *clip_rect)
10063 {
10064   GtkRBTree *tree = NULL;
10065   GtkRBNode *node = NULL;
10066
10067   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
10068
10069   if (tree)
10070     _gtk_tree_view_queue_draw_node (tree_view, tree, node, clip_rect);
10071 }
10072
10073 /* x and y are the mouse position
10074  */
10075 static void
10076 gtk_tree_view_draw_arrow (GtkTreeView *tree_view,
10077                           cairo_t     *cr,
10078                           GtkRBTree   *tree,
10079                           GtkRBNode   *node)
10080 {
10081   GdkRectangle area;
10082   GtkStateFlags state = 0;
10083   GtkStyleContext *context;
10084   GtkWidget *widget;
10085   gint x_offset = 0;
10086   gint x2;
10087   gint vertical_separator;
10088   gint expander_size;
10089   GtkCellRendererState flags = 0;
10090
10091   widget = GTK_WIDGET (tree_view);
10092   context = gtk_widget_get_style_context (widget);
10093
10094   gtk_widget_style_get (widget,
10095                         "vertical-separator", &vertical_separator,
10096                         NULL);
10097   expander_size = gtk_tree_view_get_expander_size (tree_view) - EXPANDER_EXTRA_PADDING;
10098
10099   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
10100     return;
10101
10102   gtk_tree_view_get_arrow_xrange (tree_view, tree, &x_offset, &x2);
10103
10104   area.x = x_offset;
10105   area.y = gtk_tree_view_get_cell_area_y_offset (tree_view, tree, node,
10106                                                  vertical_separator);
10107   area.width = expander_size;
10108   area.height = gtk_tree_view_get_cell_area_height (tree_view, node,
10109                                                     vertical_separator);
10110
10111   if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
10112     flags |= GTK_CELL_RENDERER_SELECTED;
10113
10114   if (node == tree_view->priv->prelight_node &&
10115       tree_view->priv->arrow_prelit)
10116     flags |= GTK_CELL_RENDERER_PRELIT;
10117
10118   state = gtk_cell_renderer_get_state (NULL, widget, flags);
10119
10120   if (node->children != NULL)
10121     state |= GTK_STATE_FLAG_ACTIVE;
10122   else
10123     state &= ~(GTK_STATE_FLAG_ACTIVE);
10124
10125   gtk_style_context_save (context);
10126
10127   gtk_style_context_set_state (context, state);
10128   gtk_style_context_add_class (context, GTK_STYLE_CLASS_EXPANDER);
10129
10130   gtk_render_expander (context, cr,
10131                        area.x, area.y,
10132                        area.width, area.height);
10133
10134   gtk_style_context_restore (context);
10135 }
10136
10137 static void
10138 gtk_tree_view_focus_to_cursor (GtkTreeView *tree_view)
10139
10140 {
10141   GtkTreePath *cursor_path;
10142
10143   if ((tree_view->priv->tree == NULL) ||
10144       (! gtk_widget_get_realized (GTK_WIDGET (tree_view))))
10145     return;
10146
10147   cursor_path = NULL;
10148   if (tree_view->priv->cursor_node)
10149     cursor_path = _gtk_tree_path_new_from_rbtree (tree_view->priv->cursor_tree,
10150                                                   tree_view->priv->cursor_node);
10151
10152   if (cursor_path == NULL)
10153     {
10154       /* Consult the selection before defaulting to the
10155        * first focusable element
10156        */
10157       GList *selected_rows;
10158       GtkTreeModel *model;
10159       GtkTreeSelection *selection;
10160
10161       selection = gtk_tree_view_get_selection (tree_view);
10162       selected_rows = gtk_tree_selection_get_selected_rows (selection, &model);
10163
10164       if (selected_rows)
10165         {
10166           cursor_path = gtk_tree_path_copy((const GtkTreePath *)(selected_rows->data));
10167           g_list_free_full (selected_rows, (GDestroyNotify) gtk_tree_path_free);
10168         }
10169       else
10170         {
10171           cursor_path = gtk_tree_path_new_first ();
10172           search_first_focusable_path (tree_view, &cursor_path,
10173                                        TRUE, NULL, NULL);
10174         }
10175
10176       if (cursor_path)
10177         {
10178           if (gtk_tree_selection_get_mode (tree_view->priv->selection) == GTK_SELECTION_MULTIPLE)
10179             gtk_tree_view_real_set_cursor (tree_view, cursor_path, 0);
10180           else
10181             gtk_tree_view_real_set_cursor (tree_view, cursor_path, CLEAR_AND_SELECT);
10182         }
10183     }
10184
10185   if (cursor_path)
10186     {
10187       tree_view->priv->draw_keyfocus = TRUE;
10188
10189       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10190       gtk_tree_path_free (cursor_path);
10191
10192       if (tree_view->priv->focus_column == NULL)
10193         {
10194           GList *list;
10195           for (list = tree_view->priv->columns; list; list = list->next)
10196             {
10197               if (gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (list->data)))
10198                 {
10199                   GtkCellArea *cell_area;
10200
10201                   _gtk_tree_view_set_focus_column (tree_view, GTK_TREE_VIEW_COLUMN (list->data));
10202
10203                   /* This happens when the treeview initially grabs focus and there
10204                    * is no column in focus, here we explicitly focus into the first cell */
10205                   cell_area = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (tree_view->priv->focus_column));
10206                   if (!gtk_cell_area_get_focus_cell (cell_area))
10207                     {
10208                       gboolean rtl;
10209
10210                       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
10211                       gtk_cell_area_focus (cell_area,
10212                                            rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT);
10213                     }
10214
10215                   break;
10216                 }
10217             }
10218         }
10219     }
10220 }
10221
10222 static void
10223 gtk_tree_view_move_cursor_up_down (GtkTreeView *tree_view,
10224                                    gint         count)
10225 {
10226   gint selection_count;
10227   GtkRBTree *new_cursor_tree = NULL;
10228   GtkRBNode *new_cursor_node = NULL;
10229   GtkTreePath *cursor_path = NULL;
10230   gboolean grab_focus = TRUE;
10231   gboolean selectable;
10232   GtkDirectionType direction;
10233   GtkCellArea *cell_area = NULL;
10234   GtkCellRenderer *last_focus_cell = NULL;
10235   GtkTreeIter iter;
10236
10237   if (! gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10238     return;
10239
10240   if (tree_view->priv->cursor_node == NULL)
10241     return;
10242
10243   cursor_path = _gtk_tree_path_new_from_rbtree (tree_view->priv->cursor_tree,
10244                                                 tree_view->priv->cursor_node);
10245
10246   direction = count < 0 ? GTK_DIR_UP : GTK_DIR_DOWN;
10247
10248   if (tree_view->priv->focus_column)
10249     cell_area = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (tree_view->priv->focus_column));
10250
10251   /* If focus stays in the area for this row, then just return for this round */
10252   if (cell_area && (count == -1 || count == 1) &&
10253       gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path))
10254     {
10255       gtk_tree_view_column_cell_set_cell_data (tree_view->priv->focus_column,
10256                                                tree_view->priv->model,
10257                                                &iter,
10258                                                GTK_RBNODE_FLAG_SET (tree_view->priv->cursor_node, GTK_RBNODE_IS_PARENT),
10259                                                tree_view->priv->cursor_node->children ? TRUE : FALSE);
10260
10261       /* Save the last cell that had focus, if we hit the end of the view we'll give
10262        * focus back to it. */
10263       last_focus_cell = gtk_cell_area_get_focus_cell (cell_area);
10264
10265       /* If focus stays in the area, no need to change the cursor row */
10266       if (gtk_cell_area_focus (cell_area, direction))
10267         return;
10268     }
10269
10270   selection_count = gtk_tree_selection_count_selected_rows (tree_view->priv->selection);
10271   selectable = _gtk_tree_selection_row_is_selectable (tree_view->priv->selection,
10272                                                       tree_view->priv->cursor_node,
10273                                                       cursor_path);
10274
10275   if (selection_count == 0
10276       && gtk_tree_selection_get_mode (tree_view->priv->selection) != GTK_SELECTION_NONE
10277       && !tree_view->priv->modify_selection_pressed
10278       && selectable)
10279     {
10280       /* Don't move the cursor, but just select the current node */
10281       new_cursor_tree = tree_view->priv->cursor_tree;
10282       new_cursor_node = tree_view->priv->cursor_node;
10283     }
10284   else
10285     {
10286       if (count == -1)
10287         _gtk_rbtree_prev_full (tree_view->priv->cursor_tree, tree_view->priv->cursor_node,
10288                                &new_cursor_tree, &new_cursor_node);
10289       else
10290         _gtk_rbtree_next_full (tree_view->priv->cursor_tree, tree_view->priv->cursor_node,
10291                                &new_cursor_tree, &new_cursor_node);
10292     }
10293
10294   gtk_tree_path_free (cursor_path);
10295
10296   if (new_cursor_node)
10297     {
10298       cursor_path = _gtk_tree_path_new_from_rbtree (new_cursor_tree, new_cursor_node);
10299
10300       search_first_focusable_path (tree_view, &cursor_path,
10301                                    (count != -1),
10302                                    &new_cursor_tree,
10303                                    &new_cursor_node);
10304
10305       if (cursor_path)
10306         gtk_tree_path_free (cursor_path);
10307     }
10308
10309   /*
10310    * If the list has only one item and multi-selection is set then select
10311    * the row (if not yet selected).
10312    */
10313   if (gtk_tree_selection_get_mode (tree_view->priv->selection) == GTK_SELECTION_MULTIPLE &&
10314       new_cursor_node == NULL)
10315     {
10316       if (count == -1)
10317         _gtk_rbtree_next_full (tree_view->priv->cursor_tree, tree_view->priv->cursor_node,
10318                                &new_cursor_tree, &new_cursor_node);
10319       else
10320         _gtk_rbtree_prev_full (tree_view->priv->cursor_tree, tree_view->priv->cursor_node,
10321                                &new_cursor_tree, &new_cursor_node);
10322
10323       if (new_cursor_node == NULL
10324           && !GTK_RBNODE_FLAG_SET (tree_view->priv->cursor_node, GTK_RBNODE_IS_SELECTED))
10325         {
10326           new_cursor_node = tree_view->priv->cursor_node;
10327           new_cursor_tree = tree_view->priv->cursor_tree;
10328         }
10329       else
10330         {
10331           new_cursor_tree = NULL;
10332           new_cursor_node = NULL;
10333         }
10334     }
10335
10336   if (new_cursor_node)
10337     {
10338       cursor_path = _gtk_tree_path_new_from_rbtree (new_cursor_tree, new_cursor_node);
10339       gtk_tree_view_real_set_cursor (tree_view, cursor_path, CLEAR_AND_SELECT | CLAMP_NODE);
10340       gtk_tree_path_free (cursor_path);
10341
10342       /* Give focus to the area in the new row */
10343       if (cell_area)
10344         gtk_cell_area_focus (cell_area, direction);
10345     }
10346   else
10347     {
10348       gtk_tree_view_clamp_node_visible (tree_view, 
10349                                         tree_view->priv->cursor_tree,
10350                                         tree_view->priv->cursor_node);
10351
10352       if (!tree_view->priv->extend_selection_pressed)
10353         {
10354           if (! gtk_widget_keynav_failed (GTK_WIDGET (tree_view),
10355                                           count < 0 ?
10356                                           GTK_DIR_UP : GTK_DIR_DOWN))
10357             {
10358               GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (tree_view));
10359
10360               if (toplevel)
10361                 gtk_widget_child_focus (toplevel,
10362                                         count < 0 ?
10363                                         GTK_DIR_TAB_BACKWARD :
10364                                         GTK_DIR_TAB_FORWARD);
10365
10366               grab_focus = FALSE;
10367             }
10368         }
10369       else
10370         {
10371           gtk_widget_error_bell (GTK_WIDGET (tree_view));
10372         }
10373
10374       if (cell_area)
10375         gtk_cell_area_set_focus_cell (cell_area, last_focus_cell);
10376     }
10377
10378   if (grab_focus)
10379     gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10380 }
10381
10382 static void
10383 gtk_tree_view_move_cursor_page_up_down (GtkTreeView *tree_view,
10384                                         gint         count)
10385 {
10386   GtkTreePath *old_cursor_path = NULL;
10387   GtkTreePath *cursor_path = NULL;
10388   GtkRBTree *start_cursor_tree = NULL;
10389   GtkRBNode *start_cursor_node = NULL;
10390   GtkRBTree *cursor_tree;
10391   GtkRBNode *cursor_node;
10392   gint y;
10393   gint window_y;
10394   gint vertical_separator;
10395
10396   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10397     return;
10398
10399   if (tree_view->priv->cursor_node == NULL)
10400     return;
10401
10402   old_cursor_path = _gtk_tree_path_new_from_rbtree (tree_view->priv->cursor_tree,
10403                                                     tree_view->priv->cursor_node);
10404
10405   gtk_widget_style_get (GTK_WIDGET (tree_view), "vertical-separator", &vertical_separator, NULL);
10406
10407   y = _gtk_rbtree_node_find_offset (tree_view->priv->cursor_tree, tree_view->priv->cursor_node);
10408   window_y = RBTREE_Y_TO_TREE_WINDOW_Y (tree_view, y);
10409   y += tree_view->priv->cursor_offset;
10410   y += count * (int)gtk_adjustment_get_page_increment (tree_view->priv->vadjustment);
10411   y = CLAMP (y, (gint)gtk_adjustment_get_lower (tree_view->priv->vadjustment),  (gint)gtk_adjustment_get_upper (tree_view->priv->vadjustment) - vertical_separator);
10412
10413   if (y >= tree_view->priv->height)
10414     y = tree_view->priv->height - 1;
10415
10416   tree_view->priv->cursor_offset =
10417     _gtk_rbtree_find_offset (tree_view->priv->tree, y,
10418                              &cursor_tree, &cursor_node);
10419
10420   if (cursor_tree == NULL)
10421     {
10422       /* FIXME: we lost the cursor.  Should we try to get one? */
10423       gtk_tree_path_free (old_cursor_path);
10424       return;
10425     }
10426
10427   if (tree_view->priv->cursor_offset
10428       > gtk_tree_view_get_row_height (tree_view, cursor_node))
10429     {
10430       _gtk_rbtree_next_full (cursor_tree, cursor_node,
10431                              &cursor_tree, &cursor_node);
10432       tree_view->priv->cursor_offset -= gtk_tree_view_get_row_height (tree_view, cursor_node);
10433     }
10434
10435   y -= tree_view->priv->cursor_offset;
10436   cursor_path = _gtk_tree_path_new_from_rbtree (cursor_tree, cursor_node);
10437
10438   start_cursor_tree = cursor_tree;
10439   start_cursor_node = cursor_node;
10440
10441   if (! search_first_focusable_path (tree_view, &cursor_path,
10442                                      (count != -1),
10443                                      &cursor_tree, &cursor_node))
10444     {
10445       /* It looks like we reached the end of the view without finding
10446        * a focusable row.  We will step backwards to find the last
10447        * focusable row.
10448        */
10449       cursor_tree = start_cursor_tree;
10450       cursor_node = start_cursor_node;
10451       cursor_path = _gtk_tree_path_new_from_rbtree (cursor_tree, cursor_node);
10452
10453       search_first_focusable_path (tree_view, &cursor_path,
10454                                    (count == -1),
10455                                    &cursor_tree, &cursor_node);
10456     }
10457
10458   if (!cursor_path)
10459     goto cleanup;
10460
10461   /* update y */
10462   y = _gtk_rbtree_node_find_offset (cursor_tree, cursor_node);
10463
10464   gtk_tree_view_real_set_cursor (tree_view, cursor_path, CLEAR_AND_SELECT);
10465
10466   y -= window_y;
10467   gtk_tree_view_scroll_to_point (tree_view, -1, y);
10468   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10469   _gtk_tree_view_queue_draw_node (tree_view, cursor_tree, cursor_node, NULL);
10470
10471   if (!gtk_tree_path_compare (old_cursor_path, cursor_path))
10472     gtk_widget_error_bell (GTK_WIDGET (tree_view));
10473
10474   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10475
10476 cleanup:
10477   gtk_tree_path_free (old_cursor_path);
10478   gtk_tree_path_free (cursor_path);
10479 }
10480
10481 static void
10482 gtk_tree_view_move_cursor_left_right (GtkTreeView *tree_view,
10483                                       gint         count)
10484 {
10485   GtkTreePath *cursor_path = NULL;
10486   GtkTreeViewColumn *column;
10487   GtkTreeIter iter;
10488   GList *list;
10489   gboolean found_column = FALSE;
10490   gboolean rtl;
10491   GtkDirectionType direction;
10492   GtkCellArea     *cell_area;
10493   GtkCellRenderer *last_focus_cell = NULL;
10494   GtkCellArea     *last_focus_area = NULL;
10495
10496   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
10497
10498   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10499     return;
10500
10501   if (tree_view->priv->cursor_node == NULL)
10502     return;
10503
10504   cursor_path = _gtk_tree_path_new_from_rbtree (tree_view->priv->cursor_tree,
10505                                                 tree_view->priv->cursor_node);
10506
10507   if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path) == FALSE)
10508     {
10509       gtk_tree_path_free (cursor_path);
10510       return;
10511     }
10512   gtk_tree_path_free (cursor_path);
10513
10514   list = rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns);
10515   if (tree_view->priv->focus_column)
10516     {
10517       /* Save the cell/area we are moving focus from, if moving the cursor
10518        * by one step hits the end we'll set focus back here */
10519       last_focus_area = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (tree_view->priv->focus_column));
10520       last_focus_cell = gtk_cell_area_get_focus_cell (last_focus_area);
10521
10522       for (; list; list = (rtl ? list->prev : list->next))
10523         {
10524           if (list->data == tree_view->priv->focus_column)
10525             break;
10526         }
10527     }
10528
10529   direction = count > 0 ? GTK_DIR_RIGHT : GTK_DIR_LEFT;
10530
10531   while (list)
10532     {
10533       column = list->data;
10534       if (gtk_tree_view_column_get_visible (column) == FALSE)
10535         goto loop_end;
10536
10537       gtk_tree_view_column_cell_set_cell_data (column,
10538                                                tree_view->priv->model,
10539                                                &iter,
10540                                                GTK_RBNODE_FLAG_SET (tree_view->priv->cursor_node, GTK_RBNODE_IS_PARENT),
10541                                                tree_view->priv->cursor_node->children ? TRUE : FALSE);
10542
10543       cell_area = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (column));
10544       if (gtk_cell_area_focus (cell_area, direction))
10545         {
10546           _gtk_tree_view_set_focus_column (tree_view, column);
10547           found_column = TRUE;
10548           break;
10549         }
10550
10551     loop_end:
10552       if (count == 1)
10553         list = rtl ? list->prev : list->next;
10554       else
10555         list = rtl ? list->next : list->prev;
10556     }
10557
10558   if (found_column)
10559     {
10560       if (!gtk_tree_view_has_can_focus_cell (tree_view))
10561         _gtk_tree_view_queue_draw_node (tree_view,
10562                                         tree_view->priv->cursor_tree,
10563                                         tree_view->priv->cursor_node,
10564                                         NULL);
10565       g_signal_emit (tree_view, tree_view_signals[CURSOR_CHANGED], 0);
10566       gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10567     }
10568   else
10569     {
10570       gtk_widget_error_bell (GTK_WIDGET (tree_view));
10571
10572       if (last_focus_area)
10573         gtk_cell_area_set_focus_cell (last_focus_area, last_focus_cell);
10574     }
10575
10576   gtk_tree_view_clamp_column_visible (tree_view,
10577                                       tree_view->priv->focus_column, TRUE);
10578 }
10579
10580 static void
10581 gtk_tree_view_move_cursor_start_end (GtkTreeView *tree_view,
10582                                      gint         count)
10583 {
10584   GtkRBTree *cursor_tree;
10585   GtkRBNode *cursor_node;
10586   GtkTreePath *path;
10587   GtkTreePath *old_path;
10588
10589   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10590     return;
10591
10592   g_return_if_fail (tree_view->priv->tree != NULL);
10593
10594   gtk_tree_view_get_cursor (tree_view, &old_path, NULL);
10595
10596   cursor_tree = tree_view->priv->tree;
10597
10598   if (count == -1)
10599     {
10600       cursor_node = _gtk_rbtree_first (cursor_tree);
10601
10602       /* Now go forward to find the first focusable row. */
10603       path = _gtk_tree_path_new_from_rbtree (cursor_tree, cursor_node);
10604       search_first_focusable_path (tree_view, &path,
10605                                    TRUE, &cursor_tree, &cursor_node);
10606     }
10607   else
10608     {
10609       cursor_node = cursor_tree->root;
10610
10611       do
10612         {
10613           while (cursor_node && !_gtk_rbtree_is_nil (cursor_node->right))
10614             cursor_node = cursor_node->right;
10615           if (cursor_node->children == NULL)
10616             break;
10617
10618           cursor_tree = cursor_node->children;
10619           cursor_node = cursor_tree->root;
10620         }
10621       while (1);
10622
10623       /* Now go backwards to find last focusable row. */
10624       path = _gtk_tree_path_new_from_rbtree (cursor_tree, cursor_node);
10625       search_first_focusable_path (tree_view, &path,
10626                                    FALSE, &cursor_tree, &cursor_node);
10627     }
10628
10629   if (!path)
10630     goto cleanup;
10631
10632   if (gtk_tree_path_compare (old_path, path))
10633     {
10634       gtk_tree_view_real_set_cursor (tree_view, path, CLEAR_AND_SELECT | CLAMP_NODE);
10635       gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10636     }
10637   else
10638     {
10639       gtk_widget_error_bell (GTK_WIDGET (tree_view));
10640     }
10641
10642 cleanup:
10643   gtk_tree_path_free (old_path);
10644   gtk_tree_path_free (path);
10645 }
10646
10647 static gboolean
10648 gtk_tree_view_real_select_all (GtkTreeView *tree_view)
10649 {
10650   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10651     return FALSE;
10652
10653   if (gtk_tree_selection_get_mode (tree_view->priv->selection) != GTK_SELECTION_MULTIPLE)
10654     return FALSE;
10655
10656   gtk_tree_selection_select_all (tree_view->priv->selection);
10657
10658   return TRUE;
10659 }
10660
10661 static gboolean
10662 gtk_tree_view_real_unselect_all (GtkTreeView *tree_view)
10663 {
10664   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10665     return FALSE;
10666
10667   if (gtk_tree_selection_get_mode (tree_view->priv->selection) != GTK_SELECTION_MULTIPLE)
10668     return FALSE;
10669
10670   gtk_tree_selection_unselect_all (tree_view->priv->selection);
10671
10672   return TRUE;
10673 }
10674
10675 static gboolean
10676 gtk_tree_view_real_select_cursor_row (GtkTreeView *tree_view,
10677                                       gboolean     start_editing)
10678 {
10679   GtkRBTree *new_tree = NULL;
10680   GtkRBNode *new_node = NULL;
10681   GtkRBTree *cursor_tree = NULL;
10682   GtkRBNode *cursor_node = NULL;
10683   GtkTreePath *cursor_path = NULL;
10684   GtkTreeSelectMode mode = 0;
10685
10686   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10687     return FALSE;
10688
10689   if (tree_view->priv->cursor_node == NULL)
10690     return FALSE;
10691
10692   cursor_path = _gtk_tree_path_new_from_rbtree (tree_view->priv->cursor_tree,
10693                                                 tree_view->priv->cursor_node);
10694
10695   _gtk_tree_view_find_node (tree_view, cursor_path,
10696                             &cursor_tree, &cursor_node);
10697
10698   if (cursor_tree == NULL)
10699     {
10700       gtk_tree_path_free (cursor_path);
10701       return FALSE;
10702     }
10703
10704   if (!tree_view->priv->extend_selection_pressed && start_editing &&
10705       tree_view->priv->focus_column)
10706     {
10707       if (gtk_tree_view_start_editing (tree_view, cursor_path, FALSE))
10708         {
10709           gtk_tree_path_free (cursor_path);
10710           return TRUE;
10711         }
10712     }
10713
10714   if (tree_view->priv->modify_selection_pressed)
10715     mode |= GTK_TREE_SELECT_MODE_TOGGLE;
10716   if (tree_view->priv->extend_selection_pressed)
10717     mode |= GTK_TREE_SELECT_MODE_EXTEND;
10718
10719   _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
10720                                             cursor_node,
10721                                             cursor_tree,
10722                                             cursor_path,
10723                                             mode,
10724                                             FALSE);
10725
10726   /* We bail out if the original (tree, node) don't exist anymore after
10727    * handling the selection-changed callback.  We do return TRUE because
10728    * the key press has been handled at this point.
10729    */
10730   _gtk_tree_view_find_node (tree_view, cursor_path, &new_tree, &new_node);
10731
10732   if (cursor_tree != new_tree || cursor_node != new_node)
10733     return FALSE;
10734
10735   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10736
10737   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10738   _gtk_tree_view_queue_draw_node (tree_view, cursor_tree, cursor_node, NULL);
10739
10740   if (!tree_view->priv->extend_selection_pressed)
10741     gtk_tree_view_row_activated (tree_view, cursor_path,
10742                                  tree_view->priv->focus_column);
10743     
10744   gtk_tree_path_free (cursor_path);
10745
10746   return TRUE;
10747 }
10748
10749 static gboolean
10750 gtk_tree_view_real_toggle_cursor_row (GtkTreeView *tree_view)
10751 {
10752   GtkRBTree *new_tree = NULL;
10753   GtkRBNode *new_node = NULL;
10754   GtkTreePath *cursor_path = NULL;
10755
10756   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10757     return FALSE;
10758
10759   if (tree_view->priv->cursor_node == NULL)
10760     return FALSE;
10761
10762   cursor_path = _gtk_tree_path_new_from_rbtree (tree_view->priv->cursor_tree,
10763                                                 tree_view->priv->cursor_node);
10764
10765   _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
10766                                             tree_view->priv->cursor_node,
10767                                             tree_view->priv->cursor_tree,
10768                                             cursor_path,
10769                                             GTK_TREE_SELECT_MODE_TOGGLE,
10770                                             FALSE);
10771
10772   /* We bail out if the original (tree, node) don't exist anymore after
10773    * handling the selection-changed callback.  We do return TRUE because
10774    * the key press has been handled at this point.
10775    */
10776   _gtk_tree_view_find_node (tree_view, cursor_path, &new_tree, &new_node);
10777
10778   if (tree_view->priv->cursor_node != new_node)
10779     return FALSE;
10780
10781   gtk_tree_view_clamp_node_visible (tree_view,
10782                                     tree_view->priv->cursor_tree,
10783                                     tree_view->priv->cursor_node);
10784
10785   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10786   gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10787   gtk_tree_path_free (cursor_path);
10788
10789   return TRUE;
10790 }
10791
10792 static gboolean
10793 gtk_tree_view_real_expand_collapse_cursor_row (GtkTreeView *tree_view,
10794                                                gboolean     logical,
10795                                                gboolean     expand,
10796                                                gboolean     open_all)
10797 {
10798   GtkTreePath *cursor_path = NULL;
10799
10800   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10801     return FALSE;
10802
10803   if (tree_view->priv->cursor_node == NULL)
10804     return FALSE;
10805
10806   cursor_path = _gtk_tree_path_new_from_rbtree (tree_view->priv->cursor_tree,
10807                                                 tree_view->priv->cursor_node);
10808
10809   /* Don't handle the event if we aren't an expander */
10810   if (!GTK_RBNODE_FLAG_SET (tree_view->priv->cursor_node, GTK_RBNODE_IS_PARENT))
10811     return FALSE;
10812
10813   if (!logical
10814       && gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL)
10815     expand = !expand;
10816
10817   if (expand)
10818     gtk_tree_view_real_expand_row (tree_view,
10819                                    cursor_path,
10820                                    tree_view->priv->cursor_tree,
10821                                    tree_view->priv->cursor_node,
10822                                    open_all,
10823                                    TRUE);
10824   else
10825     gtk_tree_view_real_collapse_row (tree_view,
10826                                      cursor_path,
10827                                      tree_view->priv->cursor_tree,
10828                                      tree_view->priv->cursor_node,
10829                                      TRUE);
10830
10831   gtk_tree_path_free (cursor_path);
10832
10833   return TRUE;
10834 }
10835
10836 static gboolean
10837 gtk_tree_view_real_select_cursor_parent (GtkTreeView *tree_view)
10838 {
10839   GtkTreePath *cursor_path = NULL;
10840   GdkModifierType state;
10841
10842   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10843     goto out;
10844
10845   if (tree_view->priv->cursor_node == NULL)
10846     goto out;
10847
10848   cursor_path = _gtk_tree_path_new_from_rbtree (tree_view->priv->cursor_tree,
10849                                                 tree_view->priv->cursor_node);
10850
10851   if (tree_view->priv->cursor_tree->parent_node)
10852     {
10853       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10854
10855       gtk_tree_path_up (cursor_path);
10856
10857       if (gtk_get_current_event_state (&state))
10858         {
10859           GdkModifierType modify_mod_mask;
10860
10861           modify_mod_mask =
10862             gtk_widget_get_modifier_mask (GTK_WIDGET (tree_view),
10863                                           GDK_MODIFIER_INTENT_MODIFY_SELECTION);
10864
10865           if ((state & modify_mod_mask) == modify_mod_mask)
10866             tree_view->priv->modify_selection_pressed = TRUE;
10867         }
10868
10869       gtk_tree_view_real_set_cursor (tree_view, cursor_path, CLEAR_AND_SELECT | CLAMP_NODE);
10870       gtk_tree_path_free (cursor_path);
10871
10872       gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10873
10874       tree_view->priv->modify_selection_pressed = FALSE;
10875
10876       return TRUE;
10877     }
10878
10879  out:
10880
10881   tree_view->priv->search_entry_avoid_unhandled_binding = TRUE;
10882   return FALSE;
10883 }
10884
10885 static gboolean
10886 gtk_tree_view_search_entry_flush_timeout (GtkTreeView *tree_view)
10887 {
10888   gtk_tree_view_search_dialog_hide (tree_view->priv->search_window, tree_view, NULL);
10889   tree_view->priv->typeselect_flush_timeout = 0;
10890
10891   return FALSE;
10892 }
10893
10894 /* Cut and paste from gtkwindow.c */
10895 static void
10896 send_focus_change (GtkWidget *widget,
10897                    GdkDevice *device,
10898                    gboolean   in)
10899 {
10900   GdkDeviceManager *device_manager;
10901   GList *devices, *d;
10902
10903   device_manager = gdk_display_get_device_manager (gtk_widget_get_display (widget));
10904   devices = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER);
10905   devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_SLAVE));
10906   devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_FLOATING));
10907
10908   for (d = devices; d; d = d->next)
10909     {
10910       GdkDevice *dev = d->data;
10911       GdkEvent *fevent;
10912       GdkWindow *window;
10913
10914       if (gdk_device_get_source (dev) != GDK_SOURCE_KEYBOARD)
10915         continue;
10916
10917       window = gtk_widget_get_window (widget);
10918
10919       /* Skip non-master keyboards that haven't
10920        * selected for events from this window
10921        */
10922       if (gdk_device_get_device_type (dev) != GDK_DEVICE_TYPE_MASTER &&
10923           !gdk_window_get_device_events (window, dev))
10924         continue;
10925
10926       fevent = gdk_event_new (GDK_FOCUS_CHANGE);
10927
10928       fevent->focus_change.type = GDK_FOCUS_CHANGE;
10929       fevent->focus_change.window = g_object_ref (window);
10930       fevent->focus_change.in = in;
10931       gdk_event_set_device (fevent, device);
10932
10933       gtk_widget_send_focus_change (widget, fevent);
10934
10935       gdk_event_free (fevent);
10936     }
10937
10938   g_list_free (devices);
10939 }
10940
10941 static void
10942 gtk_tree_view_ensure_interactive_directory (GtkTreeView *tree_view)
10943 {
10944   GtkWidget *frame, *vbox, *toplevel;
10945   GdkScreen *screen;
10946
10947   if (tree_view->priv->search_custom_entry_set)
10948     return;
10949
10950   toplevel = gtk_widget_get_toplevel (GTK_WIDGET (tree_view));
10951   screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
10952
10953    if (tree_view->priv->search_window != NULL)
10954      {
10955        if (gtk_window_has_group (GTK_WINDOW (toplevel)))
10956          gtk_window_group_add_window (gtk_window_get_group (GTK_WINDOW (toplevel)),
10957                                       GTK_WINDOW (tree_view->priv->search_window));
10958        else if (gtk_window_has_group (GTK_WINDOW (tree_view->priv->search_window)))
10959          gtk_window_group_remove_window (gtk_window_get_group (GTK_WINDOW (tree_view->priv->search_window)),
10960                                          GTK_WINDOW (tree_view->priv->search_window));
10961
10962        gtk_window_set_screen (GTK_WINDOW (tree_view->priv->search_window), screen);
10963
10964        return;
10965      }
10966    
10967   tree_view->priv->search_window = gtk_window_new (GTK_WINDOW_POPUP);
10968   gtk_window_set_screen (GTK_WINDOW (tree_view->priv->search_window), screen);
10969
10970   if (gtk_window_has_group (GTK_WINDOW (toplevel)))
10971     gtk_window_group_add_window (gtk_window_get_group (GTK_WINDOW (toplevel)),
10972                                  GTK_WINDOW (tree_view->priv->search_window));
10973
10974   gtk_window_set_type_hint (GTK_WINDOW (tree_view->priv->search_window),
10975                             GDK_WINDOW_TYPE_HINT_UTILITY);
10976   gtk_window_set_modal (GTK_WINDOW (tree_view->priv->search_window), TRUE);
10977   g_signal_connect (tree_view->priv->search_window, "delete-event",
10978                     G_CALLBACK (gtk_tree_view_search_delete_event),
10979                     tree_view);
10980   g_signal_connect (tree_view->priv->search_window, "key-press-event",
10981                     G_CALLBACK (gtk_tree_view_search_key_press_event),
10982                     tree_view);
10983   g_signal_connect (tree_view->priv->search_window, "button-press-event",
10984                     G_CALLBACK (gtk_tree_view_search_button_press_event),
10985                     tree_view);
10986   g_signal_connect (tree_view->priv->search_window, "scroll-event",
10987                     G_CALLBACK (gtk_tree_view_search_scroll_event),
10988                     tree_view);
10989
10990   frame = gtk_frame_new (NULL);
10991   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
10992   gtk_widget_show (frame);
10993   gtk_container_add (GTK_CONTAINER (tree_view->priv->search_window), frame);
10994
10995   vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
10996   gtk_widget_show (vbox);
10997   gtk_container_add (GTK_CONTAINER (frame), vbox);
10998   gtk_container_set_border_width (GTK_CONTAINER (vbox), 3);
10999
11000   /* add entry */
11001   tree_view->priv->search_entry = gtk_entry_new ();
11002   gtk_widget_show (tree_view->priv->search_entry);
11003   g_signal_connect (tree_view->priv->search_entry, "populate-popup",
11004                     G_CALLBACK (gtk_tree_view_search_disable_popdown),
11005                     tree_view);
11006   g_signal_connect (tree_view->priv->search_entry,
11007                     "activate", G_CALLBACK (gtk_tree_view_search_activate),
11008                     tree_view);
11009
11010   g_signal_connect (_gtk_entry_get_im_context (GTK_ENTRY (tree_view->priv->search_entry)),
11011                     "preedit-changed",
11012                     G_CALLBACK (gtk_tree_view_search_preedit_changed),
11013                     tree_view);
11014
11015   gtk_container_add (GTK_CONTAINER (vbox),
11016                      tree_view->priv->search_entry);
11017
11018   gtk_widget_realize (tree_view->priv->search_entry);
11019 }
11020
11021 /* Pops up the interactive search entry.  If keybinding is TRUE then the user
11022  * started this by typing the start_interactive_search keybinding.  Otherwise, it came from 
11023  */
11024 static gboolean
11025 gtk_tree_view_real_start_interactive_search (GtkTreeView *tree_view,
11026                                              GdkDevice   *device,
11027                                              gboolean     keybinding)
11028 {
11029   /* We only start interactive search if we have focus or the columns
11030    * have focus.  If one of our children have focus, we don't want to
11031    * start the search.
11032    */
11033   GList *list;
11034   gboolean found_focus = FALSE;
11035   GtkWidgetClass *entry_parent_class;
11036   
11037   if (!tree_view->priv->enable_search && !keybinding)
11038     return FALSE;
11039
11040   if (tree_view->priv->search_custom_entry_set)
11041     return FALSE;
11042
11043   if (tree_view->priv->search_window != NULL &&
11044       gtk_widget_get_visible (tree_view->priv->search_window))
11045     return TRUE;
11046
11047   for (list = tree_view->priv->columns; list; list = list->next)
11048     {
11049       GtkTreeViewColumn *column;
11050       GtkWidget         *button;
11051
11052       column = list->data;
11053       if (!gtk_tree_view_column_get_visible (column))
11054         continue;
11055
11056       button = gtk_tree_view_column_get_button (column);
11057       if (gtk_widget_has_focus (button))
11058         {
11059           found_focus = TRUE;
11060           break;
11061         }
11062     }
11063   
11064   if (gtk_widget_has_focus (GTK_WIDGET (tree_view)))
11065     found_focus = TRUE;
11066
11067   if (!found_focus)
11068     return FALSE;
11069
11070   if (tree_view->priv->search_column < 0)
11071     return FALSE;
11072
11073   gtk_tree_view_ensure_interactive_directory (tree_view);
11074
11075   if (keybinding)
11076     gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
11077
11078   /* done, show it */
11079   tree_view->priv->search_position_func (tree_view, tree_view->priv->search_window, tree_view->priv->search_position_user_data);
11080   gtk_widget_show (tree_view->priv->search_window);
11081   if (tree_view->priv->search_entry_changed_id == 0)
11082     {
11083       tree_view->priv->search_entry_changed_id =
11084         g_signal_connect (tree_view->priv->search_entry, "changed",
11085                           G_CALLBACK (gtk_tree_view_search_init),
11086                           tree_view);
11087     }
11088
11089   tree_view->priv->typeselect_flush_timeout =
11090     gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
11091                    (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
11092                    tree_view);
11093
11094   /* Grab focus will select all the text.  We don't want that to happen, so we
11095    * call the parent instance and bypass the selection change.  This is probably
11096    * really non-kosher. */
11097   entry_parent_class = g_type_class_peek_parent (GTK_ENTRY_GET_CLASS (tree_view->priv->search_entry));
11098   (entry_parent_class->grab_focus) (tree_view->priv->search_entry);
11099
11100   /* send focus-in event */
11101   send_focus_change (tree_view->priv->search_entry, device, TRUE);
11102
11103   /* search first matching iter */
11104   gtk_tree_view_search_init (tree_view->priv->search_entry, tree_view);
11105
11106   return TRUE;
11107 }
11108
11109 static gboolean
11110 gtk_tree_view_start_interactive_search (GtkTreeView *tree_view)
11111 {
11112   return gtk_tree_view_real_start_interactive_search (tree_view,
11113                                                       gtk_get_current_event_device (),
11114                                                       TRUE);
11115 }
11116
11117 /* FIXME this adjust_allocation is a big cut-and-paste from
11118  * GtkCList, needs to be some "official" way to do this
11119  * factored out.
11120  */
11121 typedef struct
11122 {
11123   GdkWindow *window;
11124   int dx;
11125   int dy;
11126 } ScrollData;
11127
11128 /* The window to which widget->window is relative */
11129 #define ALLOCATION_WINDOW(widget)               \
11130    (!gtk_widget_get_has_window (widget) ?                   \
11131     gtk_widget_get_window (widget) :                        \
11132     gdk_window_get_parent (gtk_widget_get_window (widget)))
11133
11134 static void
11135 adjust_allocation_recurse (GtkWidget *widget,
11136                            gpointer   data)
11137 {
11138   GtkAllocation allocation;
11139   ScrollData *scroll_data = data;
11140
11141   /* Need to really size allocate instead of just poking
11142    * into widget->allocation if the widget is not realized.
11143    * FIXME someone figure out why this was.
11144    */
11145   gtk_widget_get_allocation (widget, &allocation);
11146   if (!gtk_widget_get_realized (widget))
11147     {
11148       if (gtk_widget_get_visible (widget))
11149         {
11150           GdkRectangle tmp_rectangle = allocation;
11151           tmp_rectangle.x += scroll_data->dx;
11152           tmp_rectangle.y += scroll_data->dy;
11153           
11154           gtk_widget_size_allocate (widget, &tmp_rectangle);
11155         }
11156     }
11157   else
11158     {
11159       if (ALLOCATION_WINDOW (widget) == scroll_data->window)
11160         {
11161           allocation.x += scroll_data->dx;
11162           allocation.y += scroll_data->dy;
11163           gtk_widget_set_allocation (widget, &allocation);
11164
11165           if (GTK_IS_CONTAINER (widget))
11166             gtk_container_forall (GTK_CONTAINER (widget),
11167                                   adjust_allocation_recurse,
11168                                   data);
11169         }
11170     }
11171 }
11172
11173 static void
11174 adjust_allocation (GtkWidget *widget,
11175                    int        dx,
11176                    int        dy)
11177 {
11178   ScrollData scroll_data;
11179
11180   if (gtk_widget_get_realized (widget))
11181     scroll_data.window = ALLOCATION_WINDOW (widget);
11182   else
11183     scroll_data.window = NULL;
11184     
11185   scroll_data.dx = dx;
11186   scroll_data.dy = dy;
11187   
11188   adjust_allocation_recurse (widget, &scroll_data);
11189 }
11190
11191 /* Callbacks */
11192 static void
11193 gtk_tree_view_adjustment_changed (GtkAdjustment *adjustment,
11194                                   GtkTreeView   *tree_view)
11195 {
11196   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11197     {
11198       gint dy;
11199         
11200       gdk_window_move (tree_view->priv->bin_window,
11201                        - gtk_adjustment_get_value (tree_view->priv->hadjustment),
11202                        gtk_tree_view_get_effective_header_height (tree_view));
11203       gdk_window_move (tree_view->priv->header_window,
11204                        - gtk_adjustment_get_value (tree_view->priv->hadjustment),
11205                        0);
11206       dy = tree_view->priv->dy - (int) gtk_adjustment_get_value (tree_view->priv->vadjustment);
11207       if (dy)
11208         {
11209           update_prelight (tree_view,
11210                            tree_view->priv->event_last_x,
11211                            tree_view->priv->event_last_y - dy);
11212
11213           if (tree_view->priv->edited_column)
11214             {
11215               GList *list;
11216               GtkTreeViewChild *child = NULL;
11217               GtkCellEditable *edit_widget;
11218               GtkCellArea *area;
11219
11220               area        = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (tree_view->priv->edited_column));
11221               edit_widget = gtk_cell_area_get_edit_widget (area);
11222               if (GTK_IS_WIDGET (edit_widget))
11223                 {
11224                   adjust_allocation (GTK_WIDGET (edit_widget), 0, dy);
11225
11226                   for (list = tree_view->priv->children; list; list = list->next)
11227                     {
11228                       child = (GtkTreeViewChild *)list->data;
11229                       if (child->widget == GTK_WIDGET (edit_widget))
11230                         {
11231                           child->y += dy;
11232                           break;
11233                         }
11234                     }
11235                 }
11236             }
11237         }
11238       gdk_window_scroll (tree_view->priv->bin_window, 0, dy);
11239
11240       if (tree_view->priv->dy != (int) gtk_adjustment_get_value (tree_view->priv->vadjustment))
11241         {
11242           /* update our dy and top_row */
11243           tree_view->priv->dy = (int) gtk_adjustment_get_value (tree_view->priv->vadjustment);
11244
11245           if (!tree_view->priv->in_top_row_to_dy)
11246             gtk_tree_view_dy_to_top_row (tree_view);
11247         }
11248     }
11249 }
11250
11251 \f
11252
11253 /* Public methods
11254  */
11255
11256 /**
11257  * gtk_tree_view_new:
11258  *
11259  * Creates a new #GtkTreeView widget.
11260  *
11261  * Return value: A newly created #GtkTreeView widget.
11262  **/
11263 GtkWidget *
11264 gtk_tree_view_new (void)
11265 {
11266   return g_object_new (GTK_TYPE_TREE_VIEW, NULL);
11267 }
11268
11269 /**
11270  * gtk_tree_view_new_with_model:
11271  * @model: the model.
11272  *
11273  * Creates a new #GtkTreeView widget with the model initialized to @model.
11274  *
11275  * Return value: A newly created #GtkTreeView widget.
11276  **/
11277 GtkWidget *
11278 gtk_tree_view_new_with_model (GtkTreeModel *model)
11279 {
11280   return g_object_new (GTK_TYPE_TREE_VIEW, "model", model, NULL);
11281 }
11282
11283 /* Public Accessors
11284  */
11285
11286 /**
11287  * gtk_tree_view_get_model:
11288  * @tree_view: a #GtkTreeView
11289  *
11290  * Returns the model the #GtkTreeView is based on.  Returns %NULL if the
11291  * model is unset.
11292  *
11293  * Return value: (transfer none): A #GtkTreeModel, or %NULL if none is currently being used.
11294  **/
11295 GtkTreeModel *
11296 gtk_tree_view_get_model (GtkTreeView *tree_view)
11297 {
11298   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11299
11300   return tree_view->priv->model;
11301 }
11302
11303 /**
11304  * gtk_tree_view_set_model:
11305  * @tree_view: A #GtkTreeView.
11306  * @model: (allow-none): The model.
11307  *
11308  * Sets the model for a #GtkTreeView.  If the @tree_view already has a model
11309  * set, it will remove it before setting the new model.  If @model is %NULL,
11310  * then it will unset the old model.
11311  **/
11312 void
11313 gtk_tree_view_set_model (GtkTreeView  *tree_view,
11314                          GtkTreeModel *model)
11315 {
11316   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11317   g_return_if_fail (model == NULL || GTK_IS_TREE_MODEL (model));
11318
11319   if (model == tree_view->priv->model)
11320     return;
11321
11322   if (tree_view->priv->scroll_to_path)
11323     {
11324       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
11325       tree_view->priv->scroll_to_path = NULL;
11326     }
11327
11328   if (tree_view->priv->rubber_band_status)
11329     gtk_tree_view_stop_rubber_band (tree_view);
11330
11331   if (tree_view->priv->model)
11332     {
11333       GList *tmplist = tree_view->priv->columns;
11334
11335       gtk_tree_view_unref_and_check_selection_tree (tree_view, tree_view->priv->tree);
11336       gtk_tree_view_stop_editing (tree_view, TRUE);
11337
11338       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
11339                                             gtk_tree_view_row_changed,
11340                                             tree_view);
11341       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
11342                                             gtk_tree_view_row_inserted,
11343                                             tree_view);
11344       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
11345                                             gtk_tree_view_row_has_child_toggled,
11346                                             tree_view);
11347       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
11348                                             gtk_tree_view_row_deleted,
11349                                             tree_view);
11350       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
11351                                             gtk_tree_view_rows_reordered,
11352                                             tree_view);
11353
11354       for (; tmplist; tmplist = tmplist->next)
11355         _gtk_tree_view_column_unset_model (tmplist->data,
11356                                            tree_view->priv->model);
11357
11358       if (tree_view->priv->tree)
11359         gtk_tree_view_free_rbtree (tree_view);
11360
11361       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
11362       tree_view->priv->drag_dest_row = NULL;
11363       gtk_tree_row_reference_free (tree_view->priv->anchor);
11364       tree_view->priv->anchor = NULL;
11365       gtk_tree_row_reference_free (tree_view->priv->top_row);
11366       tree_view->priv->top_row = NULL;
11367       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
11368       tree_view->priv->scroll_to_path = NULL;
11369
11370       tree_view->priv->scroll_to_column = NULL;
11371
11372       g_object_unref (tree_view->priv->model);
11373
11374       tree_view->priv->search_column = -1;
11375       tree_view->priv->fixed_height_check = 0;
11376       tree_view->priv->fixed_height = -1;
11377       tree_view->priv->dy = tree_view->priv->top_row_dy = 0;
11378       tree_view->priv->last_button_x = -1;
11379       tree_view->priv->last_button_y = -1;
11380     }
11381
11382   tree_view->priv->model = model;
11383
11384   if (tree_view->priv->model)
11385     {
11386       gint i;
11387       GtkTreePath *path;
11388       GtkTreeIter iter;
11389       GtkTreeModelFlags flags;
11390
11391       if (tree_view->priv->search_column == -1)
11392         {
11393           for (i = 0; i < gtk_tree_model_get_n_columns (model); i++)
11394             {
11395               GType type = gtk_tree_model_get_column_type (model, i);
11396
11397               if (g_value_type_transformable (type, G_TYPE_STRING))
11398                 {
11399                   tree_view->priv->search_column = i;
11400                   break;
11401                 }
11402             }
11403         }
11404
11405       g_object_ref (tree_view->priv->model);
11406       g_signal_connect (tree_view->priv->model,
11407                         "row-changed",
11408                         G_CALLBACK (gtk_tree_view_row_changed),
11409                         tree_view);
11410       g_signal_connect (tree_view->priv->model,
11411                         "row-inserted",
11412                         G_CALLBACK (gtk_tree_view_row_inserted),
11413                         tree_view);
11414       g_signal_connect (tree_view->priv->model,
11415                         "row-has-child-toggled",
11416                         G_CALLBACK (gtk_tree_view_row_has_child_toggled),
11417                         tree_view);
11418       g_signal_connect (tree_view->priv->model,
11419                         "row-deleted",
11420                         G_CALLBACK (gtk_tree_view_row_deleted),
11421                         tree_view);
11422       g_signal_connect (tree_view->priv->model,
11423                         "rows-reordered",
11424                         G_CALLBACK (gtk_tree_view_rows_reordered),
11425                         tree_view);
11426
11427       flags = gtk_tree_model_get_flags (tree_view->priv->model);
11428       if ((flags & GTK_TREE_MODEL_LIST_ONLY) == GTK_TREE_MODEL_LIST_ONLY)
11429         tree_view->priv->is_list = TRUE;
11430       else
11431         tree_view->priv->is_list = FALSE;
11432
11433       path = gtk_tree_path_new_first ();
11434       if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, path))
11435         {
11436           tree_view->priv->tree = _gtk_rbtree_new ();
11437           gtk_tree_view_build_tree (tree_view, tree_view->priv->tree, &iter, 1, FALSE);
11438           _gtk_tree_view_accessible_add (tree_view, tree_view->priv->tree, NULL);
11439         }
11440       gtk_tree_path_free (path);
11441
11442       /*  FIXME: do I need to do this? gtk_tree_view_create_buttons (tree_view); */
11443       install_presize_handler (tree_view);
11444     }
11445
11446   gtk_tree_view_real_set_cursor (tree_view, NULL, CURSOR_INVALID);
11447
11448   g_object_notify (G_OBJECT (tree_view), "model");
11449
11450   if (tree_view->priv->selection)
11451   _gtk_tree_selection_emit_changed (tree_view->priv->selection);
11452
11453   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11454     gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11455 }
11456
11457 /**
11458  * gtk_tree_view_get_selection:
11459  * @tree_view: A #GtkTreeView.
11460  *
11461  * Gets the #GtkTreeSelection associated with @tree_view.
11462  *
11463  * Return value: (transfer none): A #GtkTreeSelection object.
11464  **/
11465 GtkTreeSelection *
11466 gtk_tree_view_get_selection (GtkTreeView *tree_view)
11467 {
11468   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11469
11470   return tree_view->priv->selection;
11471 }
11472
11473 /**
11474  * gtk_tree_view_get_hadjustment:
11475  * @tree_view: A #GtkTreeView
11476  *
11477  * Gets the #GtkAdjustment currently being used for the horizontal aspect.
11478  *
11479  * Return value: (transfer none): A #GtkAdjustment object, or %NULL
11480  *     if none is currently being used.
11481  *
11482  * Deprecated: 3.0: Use gtk_scrollable_get_hadjustment()
11483  **/
11484 GtkAdjustment *
11485 gtk_tree_view_get_hadjustment (GtkTreeView *tree_view)
11486 {
11487   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11488
11489   return gtk_tree_view_do_get_hadjustment (tree_view);
11490 }
11491
11492 static GtkAdjustment *
11493 gtk_tree_view_do_get_hadjustment (GtkTreeView *tree_view)
11494 {
11495   return tree_view->priv->hadjustment;
11496 }
11497
11498 /**
11499  * gtk_tree_view_set_hadjustment:
11500  * @tree_view: A #GtkTreeView
11501  * @adjustment: (allow-none): The #GtkAdjustment to set, or %NULL
11502  *
11503  * Sets the #GtkAdjustment for the current horizontal aspect.
11504  *
11505  * Deprecated: 3.0: Use gtk_scrollable_set_hadjustment()
11506  **/
11507 void
11508 gtk_tree_view_set_hadjustment (GtkTreeView   *tree_view,
11509                                GtkAdjustment *adjustment)
11510 {
11511   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11512   g_return_if_fail (adjustment == NULL || GTK_IS_ADJUSTMENT (adjustment));
11513
11514   gtk_tree_view_do_set_hadjustment (tree_view, adjustment);
11515 }
11516
11517 static void
11518 gtk_tree_view_do_set_hadjustment (GtkTreeView   *tree_view,
11519                                   GtkAdjustment *adjustment)
11520 {
11521   GtkTreeViewPrivate *priv = tree_view->priv;
11522
11523   if (adjustment && priv->hadjustment == adjustment)
11524     return;
11525
11526   if (priv->hadjustment != NULL)
11527     {
11528       g_signal_handlers_disconnect_by_func (priv->hadjustment,
11529                                             gtk_tree_view_adjustment_changed,
11530                                             tree_view);
11531       g_object_unref (priv->hadjustment);
11532     }
11533
11534   if (adjustment == NULL)
11535     adjustment = gtk_adjustment_new (0.0, 0.0, 0.0,
11536                                      0.0, 0.0, 0.0);
11537
11538   g_signal_connect (adjustment, "value-changed",
11539                     G_CALLBACK (gtk_tree_view_adjustment_changed), tree_view);
11540   priv->hadjustment = g_object_ref_sink (adjustment);
11541   /* FIXME: Adjustment should probably be populated here with fresh values, but
11542    * internal details are too complicated for me to decipher right now.
11543    */
11544   gtk_tree_view_adjustment_changed (NULL, tree_view);
11545
11546   g_object_notify (G_OBJECT (tree_view), "hadjustment");
11547 }
11548
11549 /**
11550  * gtk_tree_view_get_vadjustment:
11551  * @tree_view: A #GtkTreeView
11552  *
11553  * Gets the #GtkAdjustment currently being used for the vertical aspect.
11554  *
11555  * Return value: (transfer none): A #GtkAdjustment object, or %NULL
11556  *     if none is currently being used.
11557  *
11558  * Deprecated: 3.0: Use gtk_scrollable_get_vadjustment()
11559  **/
11560 GtkAdjustment *
11561 gtk_tree_view_get_vadjustment (GtkTreeView *tree_view)
11562 {
11563   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11564
11565   return gtk_tree_view_do_get_vadjustment (tree_view);
11566 }
11567
11568 static GtkAdjustment *
11569 gtk_tree_view_do_get_vadjustment (GtkTreeView *tree_view)
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   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11588   g_return_if_fail (adjustment == NULL || GTK_IS_ADJUSTMENT (adjustment));
11589
11590   gtk_tree_view_do_set_vadjustment (tree_view, adjustment);
11591 }
11592
11593 static void
11594 gtk_tree_view_do_set_vadjustment (GtkTreeView   *tree_view,
11595                                   GtkAdjustment *adjustment)
11596 {
11597   GtkTreeViewPrivate *priv = tree_view->priv;
11598
11599   if (adjustment && priv->vadjustment == adjustment)
11600     return;
11601
11602   if (priv->vadjustment != NULL)
11603     {
11604       g_signal_handlers_disconnect_by_func (priv->vadjustment,
11605                                             gtk_tree_view_adjustment_changed,
11606                                             tree_view);
11607       g_object_unref (priv->vadjustment);
11608     }
11609
11610   if (adjustment == NULL)
11611     adjustment = gtk_adjustment_new (0.0, 0.0, 0.0,
11612                                      0.0, 0.0, 0.0);
11613
11614   g_signal_connect (adjustment, "value-changed",
11615                     G_CALLBACK (gtk_tree_view_adjustment_changed), tree_view);
11616   priv->vadjustment = g_object_ref_sink (adjustment);
11617   /* FIXME: Adjustment should probably be populated here with fresh values, but
11618    * internal details are too complicated for me to decipher right now.
11619    */
11620   gtk_tree_view_adjustment_changed (NULL, tree_view);
11621   g_object_notify (G_OBJECT (tree_view), "vadjustment");
11622 }
11623
11624 /* Column and header operations */
11625
11626 /**
11627  * gtk_tree_view_get_headers_visible:
11628  * @tree_view: A #GtkTreeView.
11629  *
11630  * Returns %TRUE if the headers on the @tree_view are visible.
11631  *
11632  * Return value: Whether the headers are visible or not.
11633  **/
11634 gboolean
11635 gtk_tree_view_get_headers_visible (GtkTreeView *tree_view)
11636 {
11637   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
11638
11639   return tree_view->priv->headers_visible;
11640 }
11641
11642 /**
11643  * gtk_tree_view_set_headers_visible:
11644  * @tree_view: A #GtkTreeView.
11645  * @headers_visible: %TRUE if the headers are visible
11646  *
11647  * Sets the visibility state of the headers.
11648  **/
11649 void
11650 gtk_tree_view_set_headers_visible (GtkTreeView *tree_view,
11651                                    gboolean     headers_visible)
11652 {
11653   gint x, y;
11654   GList *list;
11655   GtkTreeViewColumn *column;
11656   GtkAllocation allocation;
11657   GtkWidget *button;
11658
11659   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11660
11661   headers_visible = !! headers_visible;
11662
11663   if (tree_view->priv->headers_visible == headers_visible)
11664     return;
11665
11666   tree_view->priv->headers_visible = headers_visible == TRUE;
11667
11668   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11669     {
11670       gdk_window_get_position (tree_view->priv->bin_window, &x, &y);
11671       if (headers_visible)
11672         {
11673           gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
11674           gdk_window_move_resize (tree_view->priv->bin_window,
11675                                   x, y  + gtk_tree_view_get_effective_header_height (tree_view),
11676                                   tree_view->priv->width, allocation.height -  + gtk_tree_view_get_effective_header_height (tree_view));
11677
11678           if (gtk_widget_get_mapped (GTK_WIDGET (tree_view)))
11679             gtk_tree_view_map_buttons (tree_view);
11680         }
11681       else
11682         {
11683           gdk_window_move_resize (tree_view->priv->bin_window, x, y, tree_view->priv->width, tree_view->priv->height);
11684
11685           for (list = tree_view->priv->columns; list; list = list->next)
11686             {
11687               column = list->data;
11688               button = gtk_tree_view_column_get_button (column);
11689
11690               gtk_widget_hide (button);
11691               gtk_widget_unmap (button);
11692             }
11693           gdk_window_hide (tree_view->priv->header_window);
11694         }
11695     }
11696
11697   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
11698   gtk_adjustment_configure (tree_view->priv->vadjustment,
11699                             gtk_adjustment_get_value (tree_view->priv->vadjustment),
11700                             0,
11701                             tree_view->priv->height,
11702                             gtk_adjustment_get_step_increment (tree_view->priv->vadjustment),
11703                             (allocation.height - gtk_tree_view_get_effective_header_height (tree_view)) / 2,
11704                             allocation.height - gtk_tree_view_get_effective_header_height (tree_view));
11705
11706   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11707
11708   g_object_notify (G_OBJECT (tree_view), "headers-visible");
11709 }
11710
11711 /**
11712  * gtk_tree_view_columns_autosize:
11713  * @tree_view: A #GtkTreeView.
11714  *
11715  * Resizes all columns to their optimal width. Only works after the
11716  * treeview has been realized.
11717  **/
11718 void
11719 gtk_tree_view_columns_autosize (GtkTreeView *tree_view)
11720 {
11721   gboolean dirty = FALSE;
11722   GList *list;
11723   GtkTreeViewColumn *column;
11724
11725   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11726
11727   for (list = tree_view->priv->columns; list; list = list->next)
11728     {
11729       column = list->data;
11730       if (gtk_tree_view_column_get_sizing (column) == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
11731         continue;
11732       _gtk_tree_view_column_cell_set_dirty (column, TRUE);
11733       dirty = TRUE;
11734     }
11735
11736   if (dirty)
11737     gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11738 }
11739
11740 /**
11741  * gtk_tree_view_set_headers_clickable:
11742  * @tree_view: A #GtkTreeView.
11743  * @setting: %TRUE if the columns are clickable.
11744  *
11745  * Allow the column title buttons to be clicked.
11746  **/
11747 void
11748 gtk_tree_view_set_headers_clickable (GtkTreeView *tree_view,
11749                                      gboolean   setting)
11750 {
11751   GList *list;
11752
11753   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11754
11755   for (list = tree_view->priv->columns; list; list = list->next)
11756     gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (list->data), setting);
11757
11758   g_object_notify (G_OBJECT (tree_view), "headers-clickable");
11759 }
11760
11761
11762 /**
11763  * gtk_tree_view_get_headers_clickable:
11764  * @tree_view: A #GtkTreeView.
11765  *
11766  * Returns whether all header columns are clickable.
11767  *
11768  * Return value: %TRUE if all header columns are clickable, otherwise %FALSE
11769  *
11770  * Since: 2.10
11771  **/
11772 gboolean 
11773 gtk_tree_view_get_headers_clickable (GtkTreeView *tree_view)
11774 {
11775   GList *list;
11776   
11777   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
11778
11779   for (list = tree_view->priv->columns; list; list = list->next)
11780     if (!gtk_tree_view_column_get_clickable (GTK_TREE_VIEW_COLUMN (list->data)))
11781       return FALSE;
11782
11783   return TRUE;
11784 }
11785
11786 /**
11787  * gtk_tree_view_set_rules_hint:
11788  * @tree_view: a #GtkTreeView
11789  * @setting: %TRUE if the tree requires reading across rows
11790  *
11791  * This function tells GTK+ that the user interface for your
11792  * application requires users to read across tree rows and associate
11793  * cells with one another. By default, GTK+ will then render the tree
11794  * with alternating row colors. Do <emphasis>not</emphasis> use it
11795  * just because you prefer the appearance of the ruled tree; that's a
11796  * question for the theme. Some themes will draw tree rows in
11797  * alternating colors even when rules are turned off, and users who
11798  * prefer that appearance all the time can choose those themes. You
11799  * should call this function only as a <emphasis>semantic</emphasis>
11800  * hint to the theme engine that your tree makes alternating colors
11801  * useful from a functional standpoint (since it has lots of columns,
11802  * generally).
11803  *
11804  **/
11805 void
11806 gtk_tree_view_set_rules_hint (GtkTreeView  *tree_view,
11807                               gboolean      setting)
11808 {
11809   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11810
11811   setting = setting != FALSE;
11812
11813   if (tree_view->priv->has_rules != setting)
11814     {
11815       tree_view->priv->has_rules = setting;
11816       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
11817     }
11818
11819   g_object_notify (G_OBJECT (tree_view), "rules-hint");
11820 }
11821
11822 /**
11823  * gtk_tree_view_get_rules_hint:
11824  * @tree_view: a #GtkTreeView
11825  *
11826  * Gets the setting set by gtk_tree_view_set_rules_hint().
11827  *
11828  * Return value: %TRUE if rules are useful for the user of this tree
11829  **/
11830 gboolean
11831 gtk_tree_view_get_rules_hint (GtkTreeView  *tree_view)
11832 {
11833   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
11834
11835   return tree_view->priv->has_rules;
11836 }
11837
11838
11839 /**
11840  * gtk_tree_view_set_activate_on_single_click:
11841  * @tree_view: a #GtkTreeView
11842  * @setting: %TRUE to emit row-activated on a single click
11843  *
11844  * Cause the "row-activated" signal to be emitted on a single click
11845  * instead of a double click.
11846  *
11847  * Since: 3.8
11848  **/
11849 void
11850 gtk_tree_view_set_activate_on_single_click  (GtkTreeView *tree_view,
11851                                              gboolean     setting)
11852 {
11853   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11854
11855   setting = setting != FALSE;
11856
11857   if (tree_view->priv->activate_on_single_click == setting)
11858     return;
11859
11860   tree_view->priv->activate_on_single_click = setting;
11861   g_object_notify (G_OBJECT (tree_view), "activate-on-single-click");
11862 }
11863
11864 /**
11865  * gtk_tree_view_get_activate_on_single_click:
11866  * @tree_view: a #GtkTreeView
11867  *
11868  * Gets the setting set by gtk_tree_view_set_activate_on_single_click().
11869  *
11870  * Return value: %TRUE if row-activated will be emitted on a single click
11871  *
11872  * Since: 3.8
11873  **/
11874 gboolean
11875 gtk_tree_view_get_activate_on_single_click  (GtkTreeView *tree_view)
11876 {
11877   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
11878
11879   return tree_view->priv->activate_on_single_click;
11880 }
11881
11882 /* Public Column functions
11883  */
11884
11885 /**
11886  * gtk_tree_view_append_column:
11887  * @tree_view: A #GtkTreeView.
11888  * @column: The #GtkTreeViewColumn to add.
11889  *
11890  * Appends @column to the list of columns. If @tree_view has "fixed_height"
11891  * mode enabled, then @column must have its "sizing" property set to be
11892  * GTK_TREE_VIEW_COLUMN_FIXED.
11893  *
11894  * Return value: The number of columns in @tree_view after appending.
11895  **/
11896 gint
11897 gtk_tree_view_append_column (GtkTreeView       *tree_view,
11898                              GtkTreeViewColumn *column)
11899 {
11900   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11901   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
11902   g_return_val_if_fail (gtk_tree_view_column_get_tree_view (column) == NULL, -1);
11903
11904   return gtk_tree_view_insert_column (tree_view, column, -1);
11905 }
11906
11907 void
11908 _gtk_tree_view_reset_header_styles (GtkTreeView *tree_view)
11909 {
11910   GList *columns;
11911
11912   for (columns = tree_view->priv->columns; columns; columns = columns->next)
11913     {
11914       GtkTreeViewColumn *column = columns->data;
11915       GtkWidget *header_widget;
11916
11917       if (!gtk_tree_view_column_get_visible (column))
11918         continue;
11919
11920       header_widget = gtk_tree_view_column_get_widget (column);
11921
11922       if (!header_widget)
11923         header_widget = gtk_tree_view_column_get_button (column);
11924
11925       _gtk_widget_invalidate_style_context (header_widget, GTK_CSS_CHANGE_PARENT_REGION);
11926     }
11927 }
11928
11929
11930 /**
11931  * gtk_tree_view_remove_column:
11932  * @tree_view: A #GtkTreeView.
11933  * @column: The #GtkTreeViewColumn to remove.
11934  *
11935  * Removes @column from @tree_view.
11936  *
11937  * Return value: The number of columns in @tree_view after removing.
11938  **/
11939 gint
11940 gtk_tree_view_remove_column (GtkTreeView       *tree_view,
11941                              GtkTreeViewColumn *column)
11942 {
11943   guint position;
11944
11945   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11946   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
11947   g_return_val_if_fail (gtk_tree_view_column_get_tree_view (column) == GTK_WIDGET (tree_view), -1);
11948
11949   if (tree_view->priv->focus_column == column)
11950     _gtk_tree_view_set_focus_column (tree_view, NULL);
11951
11952   if (tree_view->priv->edited_column == column)
11953     {
11954       gtk_tree_view_stop_editing (tree_view, TRUE);
11955
11956       /* no need to, but just to be sure ... */
11957       tree_view->priv->edited_column = NULL;
11958     }
11959
11960   if (tree_view->priv->expander_column == column)
11961     tree_view->priv->expander_column = NULL;
11962
11963   g_signal_handlers_disconnect_by_func (column,
11964                                         G_CALLBACK (column_sizing_notify),
11965                                         tree_view);
11966
11967   _gtk_tree_view_column_unset_tree_view (column);
11968
11969   position = g_list_index (tree_view->priv->columns, column);
11970
11971   tree_view->priv->columns = g_list_remove (tree_view->priv->columns, column);
11972   tree_view->priv->n_columns--;
11973
11974   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11975     {
11976       GList *list;
11977
11978       _gtk_tree_view_column_unrealize_button (column);
11979       for (list = tree_view->priv->columns; list; list = list->next)
11980         {
11981           GtkTreeViewColumn *tmp_column;
11982
11983           tmp_column = GTK_TREE_VIEW_COLUMN (list->data);
11984           if (gtk_tree_view_column_get_visible (tmp_column))
11985             _gtk_tree_view_column_cell_set_dirty (tmp_column, TRUE);
11986         }
11987
11988       if (tree_view->priv->n_columns == 0 &&
11989           gtk_tree_view_get_headers_visible (tree_view))
11990         gdk_window_hide (tree_view->priv->header_window);
11991
11992       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11993     }
11994
11995   _gtk_tree_view_reset_header_styles (tree_view);
11996
11997   _gtk_tree_view_accessible_remove_column (tree_view, column, position);
11998
11999   g_object_unref (column);
12000   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
12001
12002   return tree_view->priv->n_columns;
12003 }
12004
12005 /**
12006  * gtk_tree_view_insert_column:
12007  * @tree_view: A #GtkTreeView.
12008  * @column: The #GtkTreeViewColumn to be inserted.
12009  * @position: The position to insert @column in.
12010  *
12011  * This inserts the @column into the @tree_view at @position.  If @position is
12012  * -1, then the column is inserted at the end. If @tree_view has
12013  * "fixed_height" mode enabled, then @column must have its "sizing" property
12014  * set to be GTK_TREE_VIEW_COLUMN_FIXED.
12015  *
12016  * Return value: The number of columns in @tree_view after insertion.
12017  **/
12018 gint
12019 gtk_tree_view_insert_column (GtkTreeView       *tree_view,
12020                              GtkTreeViewColumn *column,
12021                              gint               position)
12022 {
12023   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
12024   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
12025   g_return_val_if_fail (gtk_tree_view_column_get_tree_view (column) == NULL, -1);
12026
12027   if (tree_view->priv->fixed_height_mode)
12028     g_return_val_if_fail (gtk_tree_view_column_get_sizing (column)
12029                           == GTK_TREE_VIEW_COLUMN_FIXED, -1);
12030
12031   if (position < 0 || position > tree_view->priv->n_columns)
12032     position = tree_view->priv->n_columns;
12033
12034   g_object_ref_sink (column);
12035
12036   if (tree_view->priv->n_columns == 0 &&
12037       gtk_widget_get_realized (GTK_WIDGET (tree_view)) &&
12038       gtk_tree_view_get_headers_visible (tree_view))
12039     {
12040       gdk_window_show (tree_view->priv->header_window);
12041     }
12042
12043   g_signal_connect (column, "notify::sizing",
12044                     G_CALLBACK (column_sizing_notify), tree_view);
12045
12046   tree_view->priv->columns = g_list_insert (tree_view->priv->columns,
12047                                             column, position);
12048   tree_view->priv->n_columns++;
12049
12050   _gtk_tree_view_column_set_tree_view (column, tree_view);
12051
12052   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
12053     {
12054       GList *list;
12055
12056       _gtk_tree_view_column_realize_button (column);
12057
12058       for (list = tree_view->priv->columns; list; list = list->next)
12059         {
12060           column = GTK_TREE_VIEW_COLUMN (list->data);
12061           if (gtk_tree_view_column_get_visible (column))
12062             _gtk_tree_view_column_cell_set_dirty (column, TRUE);
12063         }
12064       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
12065     }
12066
12067   _gtk_tree_view_reset_header_styles (tree_view);
12068
12069   _gtk_tree_view_accessible_add_column (tree_view, column, position);
12070
12071   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
12072
12073   return tree_view->priv->n_columns;
12074 }
12075
12076 /**
12077  * gtk_tree_view_insert_column_with_attributes:
12078  * @tree_view: A #GtkTreeView
12079  * @position: The position to insert the new column in
12080  * @title: The title to set the header to
12081  * @cell: The #GtkCellRenderer
12082  * @...: A %NULL-terminated list of attributes
12083  *
12084  * Creates a new #GtkTreeViewColumn and inserts it into the @tree_view at
12085  * @position.  If @position is -1, then the newly created column is inserted at
12086  * the end.  The column is initialized with the attributes given. If @tree_view
12087  * has "fixed_height" mode enabled, then the new column will have its sizing
12088  * property set to be GTK_TREE_VIEW_COLUMN_FIXED.
12089  *
12090  * Return value: The number of columns in @tree_view after insertion.
12091  **/
12092 gint
12093 gtk_tree_view_insert_column_with_attributes (GtkTreeView     *tree_view,
12094                                              gint             position,
12095                                              const gchar     *title,
12096                                              GtkCellRenderer *cell,
12097                                              ...)
12098 {
12099   GtkTreeViewColumn *column;
12100   gchar *attribute;
12101   va_list args;
12102   gint column_id;
12103
12104   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
12105
12106   column = gtk_tree_view_column_new ();
12107   if (tree_view->priv->fixed_height_mode)
12108     gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
12109
12110   gtk_tree_view_column_set_title (column, title);
12111   gtk_tree_view_column_pack_start (column, cell, TRUE);
12112
12113   va_start (args, cell);
12114
12115   attribute = va_arg (args, gchar *);
12116
12117   while (attribute != NULL)
12118     {
12119       column_id = va_arg (args, gint);
12120       gtk_tree_view_column_add_attribute (column, cell, attribute, column_id);
12121       attribute = va_arg (args, gchar *);
12122     }
12123
12124   va_end (args);
12125
12126   return gtk_tree_view_insert_column (tree_view, column, position);
12127 }
12128
12129 /**
12130  * gtk_tree_view_insert_column_with_data_func:
12131  * @tree_view: a #GtkTreeView
12132  * @position: Position to insert, -1 for append
12133  * @title: column title
12134  * @cell: cell renderer for column
12135  * @func: function to set attributes of cell renderer
12136  * @data: data for @func
12137  * @dnotify: destroy notifier for @data
12138  *
12139  * Convenience function that inserts a new column into the #GtkTreeView
12140  * with the given cell renderer and a #GtkTreeCellDataFunc to set cell renderer
12141  * attributes (normally using data from the model). See also
12142  * gtk_tree_view_column_set_cell_data_func(), gtk_tree_view_column_pack_start().
12143  * If @tree_view has "fixed_height" mode enabled, then the new column will have its
12144  * "sizing" property set to be GTK_TREE_VIEW_COLUMN_FIXED.
12145  *
12146  * Return value: number of columns in the tree view post-insert
12147  **/
12148 gint
12149 gtk_tree_view_insert_column_with_data_func  (GtkTreeView               *tree_view,
12150                                              gint                       position,
12151                                              const gchar               *title,
12152                                              GtkCellRenderer           *cell,
12153                                              GtkTreeCellDataFunc        func,
12154                                              gpointer                   data,
12155                                              GDestroyNotify             dnotify)
12156 {
12157   GtkTreeViewColumn *column;
12158
12159   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
12160
12161   column = gtk_tree_view_column_new ();
12162   if (tree_view->priv->fixed_height_mode)
12163     gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
12164
12165   gtk_tree_view_column_set_title (column, title);
12166   gtk_tree_view_column_pack_start (column, cell, TRUE);
12167   gtk_tree_view_column_set_cell_data_func (column, cell, func, data, dnotify);
12168
12169   return gtk_tree_view_insert_column (tree_view, column, position);
12170 }
12171
12172 /**
12173  * gtk_tree_view_get_n_columns:
12174  * @tree_view: a #GtkTreeView
12175  *
12176  * Queries the number of columns in the given @tree_view.
12177  *
12178  * Returns: The number of columns in the @tree_view
12179  *
12180  * Since: 3.4
12181  **/
12182 guint
12183 gtk_tree_view_get_n_columns (GtkTreeView *tree_view)
12184 {
12185   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
12186
12187   return tree_view->priv->n_columns;
12188 }
12189
12190 /**
12191  * gtk_tree_view_get_column:
12192  * @tree_view: A #GtkTreeView.
12193  * @n: The position of the column, counting from 0.
12194  *
12195  * Gets the #GtkTreeViewColumn at the given position in the #tree_view.
12196  *
12197  * Return value: (transfer none): The #GtkTreeViewColumn, or %NULL if the
12198  *     position is outside the range of columns.
12199  **/
12200 GtkTreeViewColumn *
12201 gtk_tree_view_get_column (GtkTreeView *tree_view,
12202                           gint         n)
12203 {
12204   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
12205
12206   if (n < 0 || n >= tree_view->priv->n_columns)
12207     return NULL;
12208
12209   if (tree_view->priv->columns == NULL)
12210     return NULL;
12211
12212   return GTK_TREE_VIEW_COLUMN (g_list_nth (tree_view->priv->columns, n)->data);
12213 }
12214
12215 /**
12216  * gtk_tree_view_get_columns:
12217  * @tree_view: A #GtkTreeView
12218  *
12219  * Returns a #GList of all the #GtkTreeViewColumn s currently in @tree_view.
12220  * The returned list must be freed with g_list_free ().
12221  *
12222  * Return value: (element-type GtkTreeViewColumn) (transfer container): A list of #GtkTreeViewColumn s
12223  **/
12224 GList *
12225 gtk_tree_view_get_columns (GtkTreeView *tree_view)
12226 {
12227   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
12228
12229   return g_list_copy (tree_view->priv->columns);
12230 }
12231
12232 /**
12233  * gtk_tree_view_move_column_after:
12234  * @tree_view: A #GtkTreeView
12235  * @column: The #GtkTreeViewColumn to be moved.
12236  * @base_column: (allow-none): The #GtkTreeViewColumn to be moved relative to, or %NULL.
12237  *
12238  * Moves @column to be after to @base_column.  If @base_column is %NULL, then
12239  * @column is placed in the first position.
12240  **/
12241 void
12242 gtk_tree_view_move_column_after (GtkTreeView       *tree_view,
12243                                  GtkTreeViewColumn *column,
12244                                  GtkTreeViewColumn *base_column)
12245 {
12246   GList *column_list_el, *base_el = NULL;
12247
12248   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12249
12250   column_list_el = g_list_find (tree_view->priv->columns, column);
12251   g_return_if_fail (column_list_el != NULL);
12252
12253   if (base_column)
12254     {
12255       base_el = g_list_find (tree_view->priv->columns, base_column);
12256       g_return_if_fail (base_el != NULL);
12257     }
12258
12259   if (column_list_el->prev == base_el)
12260     return;
12261
12262   tree_view->priv->columns = g_list_remove_link (tree_view->priv->columns, column_list_el);
12263   if (base_el == NULL)
12264     {
12265       column_list_el->prev = NULL;
12266       column_list_el->next = tree_view->priv->columns;
12267       if (column_list_el->next)
12268         column_list_el->next->prev = column_list_el;
12269       tree_view->priv->columns = column_list_el;
12270     }
12271   else
12272     {
12273       column_list_el->prev = base_el;
12274       column_list_el->next = base_el->next;
12275       if (column_list_el->next)
12276         column_list_el->next->prev = column_list_el;
12277       base_el->next = column_list_el;
12278     }
12279
12280   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
12281     {
12282       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
12283       gtk_tree_view_size_allocate_columns (GTK_WIDGET (tree_view), NULL);
12284     }
12285
12286   _gtk_tree_view_reset_header_styles (tree_view);
12287
12288   _gtk_tree_view_accessible_reorder_column (tree_view, column);
12289
12290   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
12291 }
12292
12293 /**
12294  * gtk_tree_view_set_expander_column:
12295  * @tree_view: A #GtkTreeView
12296  * @column: %NULL, or the column to draw the expander arrow at.
12297  *
12298  * Sets the column to draw the expander arrow at. It must be in @tree_view.  
12299  * If @column is %NULL, then the expander arrow is always at the first 
12300  * visible column.
12301  *
12302  * If you do not want expander arrow to appear in your tree, set the 
12303  * expander column to a hidden column.
12304  **/
12305 void
12306 gtk_tree_view_set_expander_column (GtkTreeView       *tree_view,
12307                                    GtkTreeViewColumn *column)
12308 {
12309   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12310   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
12311   g_return_if_fail (column == NULL || gtk_tree_view_column_get_tree_view (column) == GTK_WIDGET (tree_view));
12312
12313   if (tree_view->priv->expander_column != column)
12314     {
12315       tree_view->priv->expander_column = column;
12316       g_object_notify (G_OBJECT (tree_view), "expander-column");
12317     }
12318 }
12319
12320 /**
12321  * gtk_tree_view_get_expander_column:
12322  * @tree_view: A #GtkTreeView
12323  *
12324  * Returns the column that is the current expander column.
12325  * This column has the expander arrow drawn next to it.
12326  *
12327  * Return value: (transfer none): The expander column.
12328  **/
12329 GtkTreeViewColumn *
12330 gtk_tree_view_get_expander_column (GtkTreeView *tree_view)
12331 {
12332   GList *list;
12333
12334   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
12335
12336   for (list = tree_view->priv->columns; list; list = list->next)
12337     if (gtk_tree_view_is_expander_column (tree_view, GTK_TREE_VIEW_COLUMN (list->data)))
12338       return (GtkTreeViewColumn *) list->data;
12339   return NULL;
12340 }
12341
12342
12343 /**
12344  * gtk_tree_view_set_column_drag_function:
12345  * @tree_view: A #GtkTreeView.
12346  * @func: (allow-none): A function to determine which columns are reorderable, or %NULL.
12347  * @user_data: (allow-none): User data to be passed to @func, or %NULL
12348  * @destroy: (allow-none): Destroy notifier for @user_data, or %NULL
12349  *
12350  * Sets a user function for determining where a column may be dropped when
12351  * dragged.  This function is called on every column pair in turn at the
12352  * beginning of a column drag to determine where a drop can take place.  The
12353  * arguments passed to @func are: the @tree_view, the #GtkTreeViewColumn being
12354  * dragged, the two #GtkTreeViewColumn s determining the drop spot, and
12355  * @user_data.  If either of the #GtkTreeViewColumn arguments for the drop spot
12356  * are %NULL, then they indicate an edge.  If @func is set to be %NULL, then
12357  * @tree_view reverts to the default behavior of allowing all columns to be
12358  * dropped everywhere.
12359  **/
12360 void
12361 gtk_tree_view_set_column_drag_function (GtkTreeView               *tree_view,
12362                                         GtkTreeViewColumnDropFunc  func,
12363                                         gpointer                   user_data,
12364                                         GDestroyNotify             destroy)
12365 {
12366   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12367
12368   if (tree_view->priv->column_drop_func_data_destroy)
12369     tree_view->priv->column_drop_func_data_destroy (tree_view->priv->column_drop_func_data);
12370
12371   tree_view->priv->column_drop_func = func;
12372   tree_view->priv->column_drop_func_data = user_data;
12373   tree_view->priv->column_drop_func_data_destroy = destroy;
12374 }
12375
12376 /**
12377  * gtk_tree_view_scroll_to_point:
12378  * @tree_view: a #GtkTreeView
12379  * @tree_x: X coordinate of new top-left pixel of visible area, or -1
12380  * @tree_y: Y coordinate of new top-left pixel of visible area, or -1
12381  *
12382  * Scrolls the tree view such that the top-left corner of the visible
12383  * area is @tree_x, @tree_y, where @tree_x and @tree_y are specified
12384  * in tree coordinates.  The @tree_view must be realized before
12385  * this function is called.  If it isn't, you probably want to be
12386  * using gtk_tree_view_scroll_to_cell().
12387  *
12388  * If either @tree_x or @tree_y are -1, then that direction isn't scrolled.
12389  **/
12390 void
12391 gtk_tree_view_scroll_to_point (GtkTreeView *tree_view,
12392                                gint         tree_x,
12393                                gint         tree_y)
12394 {
12395   GtkAdjustment *hadj;
12396   GtkAdjustment *vadj;
12397
12398   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12399   g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (tree_view)));
12400
12401   hadj = tree_view->priv->hadjustment;
12402   vadj = tree_view->priv->vadjustment;
12403
12404   if (tree_x != -1)
12405     gtk_adjustment_set_value (hadj, tree_x);
12406   if (tree_y != -1)
12407     gtk_adjustment_set_value (vadj, tree_y);
12408 }
12409
12410 /**
12411  * gtk_tree_view_scroll_to_cell:
12412  * @tree_view: A #GtkTreeView.
12413  * @path: (allow-none): The path of the row to move to, or %NULL.
12414  * @column: (allow-none): The #GtkTreeViewColumn to move horizontally to, or %NULL.
12415  * @use_align: whether to use alignment arguments, or %FALSE.
12416  * @row_align: The vertical alignment of the row specified by @path.
12417  * @col_align: The horizontal alignment of the column specified by @column.
12418  *
12419  * Moves the alignments of @tree_view to the position specified by @column and
12420  * @path.  If @column is %NULL, then no horizontal scrolling occurs.  Likewise,
12421  * if @path is %NULL no vertical scrolling occurs.  At a minimum, one of @column
12422  * or @path need to be non-%NULL.  @row_align determines where the row is
12423  * placed, and @col_align determines where @column is placed.  Both are expected
12424  * to be between 0.0 and 1.0. 0.0 means left/top alignment, 1.0 means
12425  * right/bottom alignment, 0.5 means center.
12426  *
12427  * If @use_align is %FALSE, then the alignment arguments are ignored, and the
12428  * tree does the minimum amount of work to scroll the cell onto the screen.
12429  * This means that the cell will be scrolled to the edge closest to its current
12430  * position.  If the cell is currently visible on the screen, nothing is done.
12431  *
12432  * This function only works if the model is set, and @path is a valid row on the
12433  * model.  If the model changes before the @tree_view is realized, the centered
12434  * path will be modified to reflect this change.
12435  **/
12436 void
12437 gtk_tree_view_scroll_to_cell (GtkTreeView       *tree_view,
12438                               GtkTreePath       *path,
12439                               GtkTreeViewColumn *column,
12440                               gboolean           use_align,
12441                               gfloat             row_align,
12442                               gfloat             col_align)
12443 {
12444   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12445   g_return_if_fail (tree_view->priv->model != NULL);
12446   g_return_if_fail (tree_view->priv->tree != NULL);
12447   g_return_if_fail (row_align >= 0.0 && row_align <= 1.0);
12448   g_return_if_fail (col_align >= 0.0 && col_align <= 1.0);
12449   g_return_if_fail (path != NULL || column != NULL);
12450
12451 #if 0
12452   g_print ("gtk_tree_view_scroll_to_cell:\npath: %s\ncolumn: %s\nuse_align: %d\nrow_align: %f\ncol_align: %f\n",
12453            gtk_tree_path_to_string (path), column?"non-null":"null", use_align, row_align, col_align);
12454 #endif
12455   row_align = CLAMP (row_align, 0.0, 1.0);
12456   col_align = CLAMP (col_align, 0.0, 1.0);
12457
12458
12459   /* Note: Despite the benefits that come from having one code path for the
12460    * scrolling code, we short-circuit validate_visible_area's immplementation as
12461    * it is much slower than just going to the point.
12462    */
12463   if (!gtk_widget_get_visible (GTK_WIDGET (tree_view)) ||
12464       !gtk_widget_get_realized (GTK_WIDGET (tree_view)) ||
12465       _gtk_widget_get_alloc_needed (GTK_WIDGET (tree_view)) ||
12466       GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID))
12467     {
12468       if (tree_view->priv->scroll_to_path)
12469         gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
12470
12471       tree_view->priv->scroll_to_path = NULL;
12472       tree_view->priv->scroll_to_column = NULL;
12473
12474       if (path)
12475         tree_view->priv->scroll_to_path = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
12476       if (column)
12477         tree_view->priv->scroll_to_column = column;
12478       tree_view->priv->scroll_to_use_align = use_align;
12479       tree_view->priv->scroll_to_row_align = row_align;
12480       tree_view->priv->scroll_to_col_align = col_align;
12481
12482       install_presize_handler (tree_view);
12483     }
12484   else
12485     {
12486       GdkRectangle cell_rect;
12487       GdkRectangle vis_rect;
12488       gint dest_x, dest_y;
12489
12490       gtk_tree_view_get_background_area (tree_view, path, column, &cell_rect);
12491       gtk_tree_view_get_visible_rect (tree_view, &vis_rect);
12492
12493       cell_rect.y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, cell_rect.y);
12494
12495       dest_x = vis_rect.x;
12496       dest_y = vis_rect.y;
12497
12498       if (column)
12499         {
12500           if (use_align)
12501             {
12502               dest_x = cell_rect.x - ((vis_rect.width - cell_rect.width) * col_align);
12503             }
12504           else
12505             {
12506               if (cell_rect.x < vis_rect.x)
12507                 dest_x = cell_rect.x;
12508               if (cell_rect.x + cell_rect.width > vis_rect.x + vis_rect.width)
12509                 dest_x = cell_rect.x + cell_rect.width - vis_rect.width;
12510             }
12511         }
12512
12513       if (path)
12514         {
12515           if (use_align)
12516             {
12517               dest_y = cell_rect.y - ((vis_rect.height - cell_rect.height) * row_align);
12518               dest_y = MAX (dest_y, 0);
12519             }
12520           else
12521             {
12522               if (cell_rect.y < vis_rect.y)
12523                 dest_y = cell_rect.y;
12524               if (cell_rect.y + cell_rect.height > vis_rect.y + vis_rect.height)
12525                 dest_y = cell_rect.y + cell_rect.height - vis_rect.height;
12526             }
12527         }
12528
12529       gtk_tree_view_scroll_to_point (tree_view, dest_x, dest_y);
12530     }
12531 }
12532
12533 /**
12534  * gtk_tree_view_row_activated:
12535  * @tree_view: A #GtkTreeView
12536  * @path: The #GtkTreePath to be activated.
12537  * @column: The #GtkTreeViewColumn to be activated.
12538  *
12539  * Activates the cell determined by @path and @column.
12540  **/
12541 void
12542 gtk_tree_view_row_activated (GtkTreeView       *tree_view,
12543                              GtkTreePath       *path,
12544                              GtkTreeViewColumn *column)
12545 {
12546   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12547
12548   g_signal_emit (tree_view, tree_view_signals[ROW_ACTIVATED], 0, path, column);
12549 }
12550
12551
12552 static void
12553 gtk_tree_view_expand_all_emission_helper (GtkRBTree *tree,
12554                                           GtkRBNode *node,
12555                                           gpointer   data)
12556 {
12557   GtkTreeView *tree_view = data;
12558
12559   if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT &&
12560       node->children)
12561     {
12562       GtkTreePath *path;
12563       GtkTreeIter iter;
12564
12565       path = _gtk_tree_path_new_from_rbtree (tree, node);
12566       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
12567
12568       g_signal_emit (tree_view, tree_view_signals[ROW_EXPANDED], 0, &iter, path);
12569
12570       gtk_tree_path_free (path);
12571     }
12572
12573   if (node->children)
12574     _gtk_rbtree_traverse (node->children,
12575                           node->children->root,
12576                           G_PRE_ORDER,
12577                           gtk_tree_view_expand_all_emission_helper,
12578                           tree_view);
12579 }
12580
12581 /**
12582  * gtk_tree_view_expand_all:
12583  * @tree_view: A #GtkTreeView.
12584  *
12585  * Recursively expands all nodes in the @tree_view.
12586  **/
12587 void
12588 gtk_tree_view_expand_all (GtkTreeView *tree_view)
12589 {
12590   GtkTreePath *path;
12591   GtkRBTree *tree;
12592   GtkRBNode *node;
12593
12594   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12595
12596   if (tree_view->priv->tree == NULL)
12597     return;
12598
12599   path = gtk_tree_path_new_first ();
12600   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
12601
12602   while (node)
12603     {
12604       gtk_tree_view_real_expand_row (tree_view, path, tree, node, TRUE, FALSE);
12605       node = _gtk_rbtree_next (tree, node);
12606       gtk_tree_path_next (path);
12607   }
12608
12609   gtk_tree_path_free (path);
12610 }
12611
12612 /**
12613  * gtk_tree_view_collapse_all:
12614  * @tree_view: A #GtkTreeView.
12615  *
12616  * Recursively collapses all visible, expanded nodes in @tree_view.
12617  **/
12618 void
12619 gtk_tree_view_collapse_all (GtkTreeView *tree_view)
12620 {
12621   GtkRBTree *tree;
12622   GtkRBNode *node;
12623   GtkTreePath *path;
12624   gint *indices;
12625
12626   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12627
12628   if (tree_view->priv->tree == NULL)
12629     return;
12630
12631   path = gtk_tree_path_new ();
12632   gtk_tree_path_down (path);
12633   indices = gtk_tree_path_get_indices (path);
12634
12635   tree = tree_view->priv->tree;
12636   node = _gtk_rbtree_first (tree);
12637
12638   while (node)
12639     {
12640       if (node->children)
12641         gtk_tree_view_real_collapse_row (tree_view, path, tree, node, FALSE);
12642       indices[0]++;
12643       node = _gtk_rbtree_next (tree, node);
12644     }
12645
12646   gtk_tree_path_free (path);
12647 }
12648
12649 /**
12650  * gtk_tree_view_expand_to_path:
12651  * @tree_view: A #GtkTreeView.
12652  * @path: path to a row.
12653  *
12654  * Expands the row at @path. This will also expand all parent rows of
12655  * @path as necessary.
12656  *
12657  * Since: 2.2
12658  **/
12659 void
12660 gtk_tree_view_expand_to_path (GtkTreeView *tree_view,
12661                               GtkTreePath *path)
12662 {
12663   gint i, depth;
12664   gint *indices;
12665   GtkTreePath *tmp;
12666
12667   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12668   g_return_if_fail (path != NULL);
12669
12670   depth = gtk_tree_path_get_depth (path);
12671   indices = gtk_tree_path_get_indices (path);
12672
12673   tmp = gtk_tree_path_new ();
12674   g_return_if_fail (tmp != NULL);
12675
12676   for (i = 0; i < depth; i++)
12677     {
12678       gtk_tree_path_append_index (tmp, indices[i]);
12679       gtk_tree_view_expand_row (tree_view, tmp, FALSE);
12680     }
12681
12682   gtk_tree_path_free (tmp);
12683 }
12684
12685 /* FIXME the bool return values for expand_row and collapse_row are
12686  * not analagous; they should be TRUE if the row had children and
12687  * was not already in the requested state.
12688  */
12689
12690
12691 static gboolean
12692 gtk_tree_view_real_expand_row (GtkTreeView *tree_view,
12693                                GtkTreePath *path,
12694                                GtkRBTree   *tree,
12695                                GtkRBNode   *node,
12696                                gboolean     open_all,
12697                                gboolean     animate)
12698 {
12699   GtkTreeIter iter;
12700   GtkTreeIter temp;
12701   gboolean expand;
12702
12703   if (animate)
12704     g_object_get (gtk_widget_get_settings (GTK_WIDGET (tree_view)),
12705                   "gtk-enable-animations", &animate,
12706                   NULL);
12707
12708   remove_auto_expand_timeout (tree_view);
12709
12710   if (node->children && !open_all)
12711     return FALSE;
12712
12713   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
12714     return FALSE;
12715
12716   gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
12717   if (! gtk_tree_model_iter_has_child (tree_view->priv->model, &iter))
12718     return FALSE;
12719
12720
12721    if (node->children && open_all)
12722     {
12723       gboolean retval = FALSE;
12724       GtkTreePath *tmp_path = gtk_tree_path_copy (path);
12725
12726       gtk_tree_path_append_index (tmp_path, 0);
12727       tree = node->children;
12728       node = _gtk_rbtree_first (tree);
12729       /* try to expand the children */
12730       do
12731         {
12732          gboolean t;
12733          t = gtk_tree_view_real_expand_row (tree_view, tmp_path, tree, node,
12734                                             TRUE, animate);
12735          if (t)
12736            retval = TRUE;
12737
12738          gtk_tree_path_next (tmp_path);
12739          node = _gtk_rbtree_next (tree, node);
12740        }
12741       while (node != NULL);
12742
12743       gtk_tree_path_free (tmp_path);
12744
12745       return retval;
12746     }
12747
12748   g_signal_emit (tree_view, tree_view_signals[TEST_EXPAND_ROW], 0, &iter, path, &expand);
12749
12750   if (!gtk_tree_model_iter_has_child (tree_view->priv->model, &iter))
12751     return FALSE;
12752
12753   if (expand)
12754     return FALSE;
12755
12756   node->children = _gtk_rbtree_new ();
12757   node->children->parent_tree = tree;
12758   node->children->parent_node = node;
12759
12760   gtk_tree_model_iter_children (tree_view->priv->model, &temp, &iter);
12761
12762   gtk_tree_view_build_tree (tree_view,
12763                             node->children,
12764                             &temp,
12765                             gtk_tree_path_get_depth (path) + 1,
12766                             open_all);
12767
12768   _gtk_tree_view_accessible_add (tree_view, node->children, NULL);
12769   _gtk_tree_view_accessible_add_state (tree_view,
12770                                        tree, node,
12771                                        GTK_CELL_RENDERER_EXPANDED);
12772
12773   install_presize_handler (tree_view);
12774
12775   g_signal_emit (tree_view, tree_view_signals[ROW_EXPANDED], 0, &iter, path);
12776   if (open_all && node->children)
12777     {
12778       _gtk_rbtree_traverse (node->children,
12779                             node->children->root,
12780                             G_PRE_ORDER,
12781                             gtk_tree_view_expand_all_emission_helper,
12782                             tree_view);
12783     }
12784   return TRUE;
12785 }
12786
12787
12788 /**
12789  * gtk_tree_view_expand_row:
12790  * @tree_view: a #GtkTreeView
12791  * @path: path to a row
12792  * @open_all: whether to recursively expand, or just expand immediate children
12793  *
12794  * Opens the row so its children are visible.
12795  *
12796  * Return value: %TRUE if the row existed and had children
12797  **/
12798 gboolean
12799 gtk_tree_view_expand_row (GtkTreeView *tree_view,
12800                           GtkTreePath *path,
12801                           gboolean     open_all)
12802 {
12803   GtkRBTree *tree;
12804   GtkRBNode *node;
12805
12806   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12807   g_return_val_if_fail (tree_view->priv->model != NULL, FALSE);
12808   g_return_val_if_fail (path != NULL, FALSE);
12809
12810   if (_gtk_tree_view_find_node (tree_view,
12811                                 path,
12812                                 &tree,
12813                                 &node))
12814     return FALSE;
12815
12816   if (tree != NULL)
12817     return gtk_tree_view_real_expand_row (tree_view, path, tree, node, open_all, FALSE);
12818   else
12819     return FALSE;
12820 }
12821
12822 static gboolean
12823 gtk_tree_view_real_collapse_row (GtkTreeView *tree_view,
12824                                  GtkTreePath *path,
12825                                  GtkRBTree   *tree,
12826                                  GtkRBNode   *node,
12827                                  gboolean     animate)
12828 {
12829   GtkTreeIter iter;
12830   GtkTreeIter children;
12831   gboolean collapse;
12832   gint x, y;
12833   GList *list;
12834   GdkWindow *child;
12835   gboolean selection_changed, cursor_changed;
12836
12837   if (animate)
12838     g_object_get (gtk_widget_get_settings (GTK_WIDGET (tree_view)),
12839                   "gtk-enable-animations", &animate,
12840                   NULL);
12841
12842   remove_auto_expand_timeout (tree_view);
12843
12844   if (node->children == NULL)
12845     return FALSE;
12846   gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
12847
12848   g_signal_emit (tree_view, tree_view_signals[TEST_COLLAPSE_ROW], 0, &iter, path, &collapse);
12849
12850   if (collapse)
12851     return FALSE;
12852
12853   /* if the prelighted node is a child of us, we want to unprelight it.  We have
12854    * a chance to prelight the correct node below */
12855
12856   if (tree_view->priv->prelight_tree)
12857     {
12858       GtkRBTree *parent_tree;
12859       GtkRBNode *parent_node;
12860
12861       parent_tree = tree_view->priv->prelight_tree->parent_tree;
12862       parent_node = tree_view->priv->prelight_tree->parent_node;
12863       while (parent_tree)
12864         {
12865           if (parent_tree == tree && parent_node == node)
12866             {
12867               ensure_unprelighted (tree_view);
12868               break;
12869             }
12870           parent_node = parent_tree->parent_node;
12871           parent_tree = parent_tree->parent_tree;
12872         }
12873     }
12874
12875   TREE_VIEW_INTERNAL_ASSERT (gtk_tree_model_iter_children (tree_view->priv->model, &children, &iter), FALSE);
12876
12877   for (list = tree_view->priv->columns; list; list = list->next)
12878     {
12879       GtkTreeViewColumn *column = list->data;
12880
12881       if (gtk_tree_view_column_get_visible (column) == FALSE)
12882         continue;
12883       if (gtk_tree_view_column_get_sizing (column) == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
12884         _gtk_tree_view_column_cell_set_dirty (column, TRUE);
12885     }
12886
12887   if (tree_view->priv->destroy_count_func)
12888     {
12889       GtkTreePath *child_path;
12890       gint child_count = 0;
12891       child_path = gtk_tree_path_copy (path);
12892       gtk_tree_path_down (child_path);
12893       if (node->children)
12894         _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, &child_count);
12895       tree_view->priv->destroy_count_func (tree_view, child_path, child_count, tree_view->priv->destroy_count_data);
12896       gtk_tree_path_free (child_path);
12897     }
12898
12899   if (tree_view->priv->cursor_node)
12900     {
12901       cursor_changed = (node->children == tree_view->priv->cursor_tree)
12902                        || _gtk_rbtree_contains (node->children, tree_view->priv->cursor_tree);
12903     }
12904   else
12905     cursor_changed = FALSE;
12906
12907   if (gtk_tree_row_reference_valid (tree_view->priv->anchor))
12908     {
12909       GtkTreePath *anchor_path = gtk_tree_row_reference_get_path (tree_view->priv->anchor);
12910       if (gtk_tree_path_is_ancestor (path, anchor_path))
12911         {
12912           gtk_tree_row_reference_free (tree_view->priv->anchor);
12913           tree_view->priv->anchor = NULL;
12914         }
12915       gtk_tree_path_free (anchor_path);
12916     }
12917
12918   selection_changed = gtk_tree_view_unref_and_check_selection_tree (tree_view, node->children);
12919   
12920   /* Stop a pending double click */
12921   tree_view->priv->last_button_x = -1;
12922   tree_view->priv->last_button_y = -1;
12923
12924   _gtk_tree_view_accessible_remove (tree_view, node->children, NULL);
12925   _gtk_tree_view_accessible_remove_state (tree_view,
12926                                           tree, node,
12927                                           GTK_CELL_RENDERER_EXPANDED);
12928
12929   _gtk_rbtree_remove (node->children);
12930
12931   if (cursor_changed)
12932     gtk_tree_view_real_set_cursor (tree_view, path, CLEAR_AND_SELECT | CURSOR_INVALID);
12933   if (selection_changed)
12934     g_signal_emit_by_name (tree_view->priv->selection, "changed");
12935
12936   if (gtk_widget_get_mapped (GTK_WIDGET (tree_view)))
12937     {
12938       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
12939     }
12940
12941   g_signal_emit (tree_view, tree_view_signals[ROW_COLLAPSED], 0, &iter, path);
12942   
12943   if (gtk_widget_get_mapped (GTK_WIDGET (tree_view)))
12944     {
12945       /* now that we've collapsed all rows, we want to try to set the prelight
12946        * again. To do this, we fake a motion event and send it to ourselves. */
12947
12948       child = gdk_window_get_device_position (gdk_window_get_parent (tree_view->priv->bin_window),
12949                                               gdk_device_manager_get_client_pointer (
12950                                                 gdk_display_get_device_manager (
12951                                                   gtk_widget_get_display (GTK_WIDGET (tree_view)))),
12952                                               &x, &y, NULL);
12953       if (child == tree_view->priv->bin_window)
12954         {
12955           GdkEventMotion event;
12956           gint child_x, child_y;
12957
12958           gdk_window_get_position (child, &child_x, &child_y);
12959
12960           event.window = tree_view->priv->bin_window;
12961           event.x = x - child_x;
12962           event.y = y - child_y;
12963
12964           /* despite the fact this isn't a real event, I'm almost positive it will
12965            * never trigger a drag event.  maybe_drag is the only function that uses
12966            * more than just event.x and event.y. */
12967           gtk_tree_view_motion_bin_window (GTK_WIDGET (tree_view), &event);
12968         }
12969     }
12970
12971   return TRUE;
12972 }
12973
12974 /**
12975  * gtk_tree_view_collapse_row:
12976  * @tree_view: a #GtkTreeView
12977  * @path: path to a row in the @tree_view
12978  *
12979  * Collapses a row (hides its child rows, if they exist).
12980  *
12981  * Return value: %TRUE if the row was collapsed.
12982  **/
12983 gboolean
12984 gtk_tree_view_collapse_row (GtkTreeView *tree_view,
12985                             GtkTreePath *path)
12986 {
12987   GtkRBTree *tree;
12988   GtkRBNode *node;
12989
12990   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12991   g_return_val_if_fail (tree_view->priv->tree != NULL, FALSE);
12992   g_return_val_if_fail (path != NULL, FALSE);
12993
12994   if (_gtk_tree_view_find_node (tree_view,
12995                                 path,
12996                                 &tree,
12997                                 &node))
12998     return FALSE;
12999
13000   if (tree == NULL || node->children == NULL)
13001     return FALSE;
13002
13003   return gtk_tree_view_real_collapse_row (tree_view, path, tree, node, FALSE);
13004 }
13005
13006 static void
13007 gtk_tree_view_map_expanded_rows_helper (GtkTreeView            *tree_view,
13008                                         GtkRBTree              *tree,
13009                                         GtkTreePath            *path,
13010                                         GtkTreeViewMappingFunc  func,
13011                                         gpointer                user_data)
13012 {
13013   GtkRBNode *node;
13014
13015   if (tree == NULL || tree->root == NULL)
13016     return;
13017
13018   node = _gtk_rbtree_first (tree);
13019
13020   while (node)
13021     {
13022       if (node->children)
13023         {
13024           (* func) (tree_view, path, user_data);
13025           gtk_tree_path_down (path);
13026           gtk_tree_view_map_expanded_rows_helper (tree_view, node->children, path, func, user_data);
13027           gtk_tree_path_up (path);
13028         }
13029       gtk_tree_path_next (path);
13030       node = _gtk_rbtree_next (tree, node);
13031     }
13032 }
13033
13034 /**
13035  * gtk_tree_view_map_expanded_rows:
13036  * @tree_view: A #GtkTreeView
13037  * @func: (scope call): A function to be called
13038  * @data: User data to be passed to the function.
13039  *
13040  * Calls @func on all expanded rows.
13041  **/
13042 void
13043 gtk_tree_view_map_expanded_rows (GtkTreeView            *tree_view,
13044                                  GtkTreeViewMappingFunc  func,
13045                                  gpointer                user_data)
13046 {
13047   GtkTreePath *path;
13048
13049   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13050   g_return_if_fail (func != NULL);
13051
13052   path = gtk_tree_path_new_first ();
13053
13054   gtk_tree_view_map_expanded_rows_helper (tree_view,
13055                                           tree_view->priv->tree,
13056                                           path, func, user_data);
13057
13058   gtk_tree_path_free (path);
13059 }
13060
13061 /**
13062  * gtk_tree_view_row_expanded:
13063  * @tree_view: A #GtkTreeView.
13064  * @path: A #GtkTreePath to test expansion state.
13065  *
13066  * Returns %TRUE if the node pointed to by @path is expanded in @tree_view.
13067  *
13068  * Return value: %TRUE if #path is expanded.
13069  **/
13070 gboolean
13071 gtk_tree_view_row_expanded (GtkTreeView *tree_view,
13072                             GtkTreePath *path)
13073 {
13074   GtkRBTree *tree;
13075   GtkRBNode *node;
13076
13077   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
13078   g_return_val_if_fail (path != NULL, FALSE);
13079
13080   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
13081
13082   if (node == NULL)
13083     return FALSE;
13084
13085   return (node->children != NULL);
13086 }
13087
13088 /**
13089  * gtk_tree_view_get_reorderable:
13090  * @tree_view: a #GtkTreeView
13091  *
13092  * Retrieves whether the user can reorder the tree via drag-and-drop. See
13093  * gtk_tree_view_set_reorderable().
13094  *
13095  * Return value: %TRUE if the tree can be reordered.
13096  **/
13097 gboolean
13098 gtk_tree_view_get_reorderable (GtkTreeView *tree_view)
13099 {
13100   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
13101
13102   return tree_view->priv->reorderable;
13103 }
13104
13105 /**
13106  * gtk_tree_view_set_reorderable:
13107  * @tree_view: A #GtkTreeView.
13108  * @reorderable: %TRUE, if the tree can be reordered.
13109  *
13110  * This function is a convenience function to allow you to reorder
13111  * models that support the #GtkTreeDragSourceIface and the
13112  * #GtkTreeDragDestIface.  Both #GtkTreeStore and #GtkListStore support
13113  * these.  If @reorderable is %TRUE, then the user can reorder the
13114  * model by dragging and dropping rows. The developer can listen to
13115  * these changes by connecting to the model's row_inserted and
13116  * row_deleted signals. The reordering is implemented by setting up
13117  * the tree view as a drag source and destination. Therefore, drag and
13118  * drop can not be used in a reorderable view for any other purpose.
13119  *
13120  * This function does not give you any degree of control over the order -- any
13121  * reordering is allowed.  If more control is needed, you should probably
13122  * handle drag and drop manually.
13123  **/
13124 void
13125 gtk_tree_view_set_reorderable (GtkTreeView *tree_view,
13126                                gboolean     reorderable)
13127 {
13128   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13129
13130   reorderable = reorderable != FALSE;
13131
13132   if (tree_view->priv->reorderable == reorderable)
13133     return;
13134
13135   if (reorderable)
13136     {
13137       const GtkTargetEntry row_targets[] = {
13138         { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, 0 }
13139       };
13140
13141       gtk_tree_view_enable_model_drag_source (tree_view,
13142                                               GDK_BUTTON1_MASK,
13143                                               row_targets,
13144                                               G_N_ELEMENTS (row_targets),
13145                                               GDK_ACTION_MOVE);
13146       gtk_tree_view_enable_model_drag_dest (tree_view,
13147                                             row_targets,
13148                                             G_N_ELEMENTS (row_targets),
13149                                             GDK_ACTION_MOVE);
13150     }
13151   else
13152     {
13153       gtk_tree_view_unset_rows_drag_source (tree_view);
13154       gtk_tree_view_unset_rows_drag_dest (tree_view);
13155     }
13156
13157   tree_view->priv->reorderable = reorderable;
13158
13159   g_object_notify (G_OBJECT (tree_view), "reorderable");
13160 }
13161
13162 static void
13163 gtk_tree_view_real_set_cursor (GtkTreeView     *tree_view,
13164                                GtkTreePath     *path,
13165                                SetCursorFlags   flags)
13166 {
13167   if (!(flags & CURSOR_INVALID) && tree_view->priv->cursor_node)
13168     {
13169       _gtk_tree_view_accessible_remove_state (tree_view,
13170                                               tree_view->priv->cursor_tree,
13171                                               tree_view->priv->cursor_node,
13172                                               GTK_CELL_RENDERER_FOCUSED);
13173       _gtk_tree_view_queue_draw_node (tree_view,
13174                                       tree_view->priv->cursor_tree,
13175                                       tree_view->priv->cursor_node,
13176                                       NULL);
13177     }
13178
13179   /* One cannot set the cursor on a separator.   Also, if
13180    * _gtk_tree_view_find_node returns TRUE, it ran out of tree
13181    * before finding the tree and node belonging to path.  The
13182    * path maps to a non-existing path and we will silently bail out.
13183    * We unset tree and node to avoid further processing.
13184    */
13185   if (path == NULL || 
13186       row_is_separator (tree_view, NULL, path)
13187       || _gtk_tree_view_find_node (tree_view,
13188                                    path,
13189                                    &tree_view->priv->cursor_tree,
13190                                    &tree_view->priv->cursor_node))
13191     {
13192       tree_view->priv->cursor_tree = NULL;
13193       tree_view->priv->cursor_node = NULL;
13194     }
13195
13196   if (tree_view->priv->cursor_node != NULL)
13197     {
13198       GtkRBTree *new_tree = NULL;
13199       GtkRBNode *new_node = NULL;
13200
13201       if ((flags & CLEAR_AND_SELECT) && !tree_view->priv->modify_selection_pressed)
13202         {
13203           GtkTreeSelectMode mode = 0;
13204
13205           if (tree_view->priv->extend_selection_pressed)
13206             mode |= GTK_TREE_SELECT_MODE_EXTEND;
13207
13208           _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
13209                                                     tree_view->priv->cursor_node,
13210                                                     tree_view->priv->cursor_tree,
13211                                                     path,
13212                                                     mode,
13213                                                     FALSE);
13214         }
13215
13216       /* We have to re-find tree and node here again, somebody might have
13217        * cleared the node or the whole tree in the GtkTreeSelection::changed
13218        * callback. If the nodes differ we bail out here.
13219        */
13220       _gtk_tree_view_find_node (tree_view, path, &new_tree, &new_node);
13221
13222       if (tree_view->priv->cursor_node != new_node)
13223         return;
13224
13225       if (flags & CLAMP_NODE)
13226         {
13227           gtk_tree_view_clamp_node_visible (tree_view,
13228                                             tree_view->priv->cursor_tree,
13229                                             tree_view->priv->cursor_node);
13230           _gtk_tree_view_queue_draw_node (tree_view,
13231                                           tree_view->priv->cursor_tree,
13232                                           tree_view->priv->cursor_node,
13233                                           NULL);
13234         }
13235
13236       _gtk_tree_view_accessible_add_state (tree_view,
13237                                            tree_view->priv->cursor_tree,
13238                                            tree_view->priv->cursor_node,
13239                                            GTK_CELL_RENDERER_FOCUSED);
13240     }
13241
13242   g_signal_emit (tree_view, tree_view_signals[CURSOR_CHANGED], 0);
13243 }
13244
13245 /**
13246  * gtk_tree_view_get_cursor:
13247  * @tree_view: A #GtkTreeView
13248  * @path: (out) (transfer full) (allow-none): A pointer to be filled with the current cursor path, or %NULL
13249  * @focus_column: (out) (transfer none) (allow-none): A pointer to be filled with the current focus column, or %NULL
13250  *
13251  * Fills in @path and @focus_column with the current path and focus column.  If
13252  * the cursor isn't currently set, then *@path will be %NULL.  If no column
13253  * currently has focus, then *@focus_column will be %NULL.
13254  *
13255  * The returned #GtkTreePath must be freed with gtk_tree_path_free() when
13256  * you are done with it.
13257  **/
13258 void
13259 gtk_tree_view_get_cursor (GtkTreeView        *tree_view,
13260                           GtkTreePath       **path,
13261                           GtkTreeViewColumn **focus_column)
13262 {
13263   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13264
13265   if (path)
13266     {
13267       if (tree_view->priv->cursor_node)
13268         *path = _gtk_tree_path_new_from_rbtree (tree_view->priv->cursor_tree,
13269                                                 tree_view->priv->cursor_node);
13270       else
13271         *path = NULL;
13272     }
13273
13274   if (focus_column)
13275     {
13276       *focus_column = tree_view->priv->focus_column;
13277     }
13278 }
13279
13280 /**
13281  * gtk_tree_view_set_cursor:
13282  * @tree_view: A #GtkTreeView
13283  * @path: A #GtkTreePath
13284  * @focus_column: (allow-none): A #GtkTreeViewColumn, or %NULL
13285  * @start_editing: %TRUE if the specified cell should start being edited.
13286  *
13287  * Sets the current keyboard focus to be at @path, and selects it.  This is
13288  * useful when you want to focus the user's attention on a particular row.  If
13289  * @focus_column is not %NULL, then focus is given to the column specified by 
13290  * it. Additionally, if @focus_column is specified, and @start_editing is 
13291  * %TRUE, then editing should be started in the specified cell.  
13292  * This function is often followed by @gtk_widget_grab_focus (@tree_view) 
13293  * in order to give keyboard focus to the widget.  Please note that editing 
13294  * can only happen when the widget is realized.
13295  *
13296  * If @path is invalid for @model, the current cursor (if any) will be unset
13297  * and the function will return without failing.
13298  **/
13299 void
13300 gtk_tree_view_set_cursor (GtkTreeView       *tree_view,
13301                           GtkTreePath       *path,
13302                           GtkTreeViewColumn *focus_column,
13303                           gboolean           start_editing)
13304 {
13305   gtk_tree_view_set_cursor_on_cell (tree_view, path, focus_column,
13306                                     NULL, start_editing);
13307 }
13308
13309 /**
13310  * gtk_tree_view_set_cursor_on_cell:
13311  * @tree_view: A #GtkTreeView
13312  * @path: A #GtkTreePath
13313  * @focus_column: (allow-none): A #GtkTreeViewColumn, or %NULL
13314  * @focus_cell: (allow-none): A #GtkCellRenderer, or %NULL
13315  * @start_editing: %TRUE if the specified cell should start being edited.
13316  *
13317  * Sets the current keyboard focus to be at @path, and selects it.  This is
13318  * useful when you want to focus the user's attention on a particular row.  If
13319  * @focus_column is not %NULL, then focus is given to the column specified by
13320  * it. If @focus_column and @focus_cell are not %NULL, and @focus_column
13321  * contains 2 or more editable or activatable cells, then focus is given to
13322  * the cell specified by @focus_cell. Additionally, if @focus_column is
13323  * specified, and @start_editing is %TRUE, then editing should be started in
13324  * the specified cell.  This function is often followed by
13325  * @gtk_widget_grab_focus (@tree_view) in order to give keyboard focus to the
13326  * widget.  Please note that editing can only happen when the widget is
13327  * realized.
13328  *
13329  * If @path is invalid for @model, the current cursor (if any) will be unset
13330  * and the function will return without failing.
13331  *
13332  * Since: 2.2
13333  **/
13334 void
13335 gtk_tree_view_set_cursor_on_cell (GtkTreeView       *tree_view,
13336                                   GtkTreePath       *path,
13337                                   GtkTreeViewColumn *focus_column,
13338                                   GtkCellRenderer   *focus_cell,
13339                                   gboolean           start_editing)
13340 {
13341   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13342   g_return_if_fail (path != NULL);
13343   g_return_if_fail (focus_column == NULL || GTK_IS_TREE_VIEW_COLUMN (focus_column));
13344
13345   if (!tree_view->priv->model)
13346     return;
13347
13348   if (focus_cell)
13349     {
13350       g_return_if_fail (focus_column);
13351       g_return_if_fail (GTK_IS_CELL_RENDERER (focus_cell));
13352     }
13353
13354   /* cancel the current editing, if it exists */
13355   if (tree_view->priv->edited_column &&
13356       gtk_cell_area_get_edit_widget
13357       (gtk_cell_layout_get_area (GTK_CELL_LAYOUT (tree_view->priv->edited_column))))
13358     gtk_tree_view_stop_editing (tree_view, TRUE);
13359
13360   gtk_tree_view_real_set_cursor (tree_view, path, CLEAR_AND_SELECT | CLAMP_NODE);
13361
13362   if (focus_column &&
13363       gtk_tree_view_column_get_visible (focus_column))
13364     {
13365       GList *list;
13366       gboolean column_in_tree = FALSE;
13367
13368       for (list = tree_view->priv->columns; list; list = list->next)
13369         if (list->data == focus_column)
13370           {
13371             column_in_tree = TRUE;
13372             break;
13373           }
13374       g_return_if_fail (column_in_tree);
13375       _gtk_tree_view_set_focus_column (tree_view, focus_column);
13376       if (focus_cell)
13377         gtk_tree_view_column_focus_cell (focus_column, focus_cell);
13378       if (start_editing)
13379         gtk_tree_view_start_editing (tree_view, path, TRUE);
13380     }
13381 }
13382
13383 /**
13384  * gtk_tree_view_get_bin_window:
13385  * @tree_view: A #GtkTreeView
13386  *
13387  * Returns the window that @tree_view renders to.
13388  * This is used primarily to compare to <literal>event->window</literal>
13389  * to confirm that the event on @tree_view is on the right window.
13390  *
13391  * Return value: (transfer none): A #GdkWindow, or %NULL when @tree_view
13392  *     hasn't been realized yet
13393  **/
13394 GdkWindow *
13395 gtk_tree_view_get_bin_window (GtkTreeView *tree_view)
13396 {
13397   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
13398
13399   return tree_view->priv->bin_window;
13400 }
13401
13402 /**
13403  * gtk_tree_view_get_path_at_pos:
13404  * @tree_view: A #GtkTreeView.
13405  * @x: The x position to be identified (relative to bin_window).
13406  * @y: The y position to be identified (relative to bin_window).
13407  * @path: (out) (allow-none): A pointer to a #GtkTreePath pointer to be filled in, or %NULL
13408  * @column: (out) (transfer none) (allow-none): A pointer to a #GtkTreeViewColumn pointer to be filled in, or %NULL
13409  * @cell_x: (out) (allow-none): A pointer where the X coordinate relative to the cell can be placed, or %NULL
13410  * @cell_y: (out) (allow-none): A pointer where the Y coordinate relative to the cell can be placed, or %NULL
13411  *
13412  * Finds the path at the point (@x, @y), relative to bin_window coordinates
13413  * (please see gtk_tree_view_get_bin_window()).
13414  * That is, @x and @y are relative to an events coordinates. @x and @y must
13415  * come from an event on the @tree_view only where <literal>event->window ==
13416  * gtk_tree_view_get_bin_window (<!-- -->)</literal>. It is primarily for
13417  * things like popup menus. If @path is non-%NULL, then it will be filled
13418  * with the #GtkTreePath at that point.  This path should be freed with
13419  * gtk_tree_path_free().  If @column is non-%NULL, then it will be filled
13420  * with the column at that point.  @cell_x and @cell_y return the coordinates
13421  * relative to the cell background (i.e. the @background_area passed to
13422  * gtk_cell_renderer_render()).  This function is only meaningful if
13423  * @tree_view is realized.  Therefore this function will always return %FALSE
13424  * if @tree_view is not realized or does not have a model.
13425  *
13426  * For converting widget coordinates (eg. the ones you get from
13427  * GtkWidget::query-tooltip), please see
13428  * gtk_tree_view_convert_widget_to_bin_window_coords().
13429  *
13430  * Return value: %TRUE if a row exists at that coordinate.
13431  **/
13432 gboolean
13433 gtk_tree_view_get_path_at_pos (GtkTreeView        *tree_view,
13434                                gint                x,
13435                                gint                y,
13436                                GtkTreePath       **path,
13437                                GtkTreeViewColumn **column,
13438                                gint               *cell_x,
13439                                gint               *cell_y)
13440 {
13441   GtkRBTree *tree;
13442   GtkRBNode *node;
13443   gint y_offset;
13444
13445   g_return_val_if_fail (tree_view != NULL, FALSE);
13446
13447   if (path)
13448     *path = NULL;
13449   if (column)
13450     *column = NULL;
13451
13452   if (tree_view->priv->bin_window == NULL)
13453     return FALSE;
13454
13455   if (tree_view->priv->tree == NULL)
13456     return FALSE;
13457
13458   if (x > gtk_adjustment_get_upper (tree_view->priv->hadjustment))
13459     return FALSE;
13460
13461   if (x < 0 || y < 0)
13462     return FALSE;
13463
13464   if (column || cell_x)
13465     {
13466       GtkTreeViewColumn *tmp_column;
13467       GtkTreeViewColumn *last_column = NULL;
13468       GList *list;
13469       gint remaining_x = x;
13470       gboolean found = FALSE;
13471       gboolean rtl;
13472       gint width;
13473
13474       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
13475       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
13476            list;
13477            list = (rtl ? list->prev : list->next))
13478         {
13479           tmp_column = list->data;
13480
13481           if (gtk_tree_view_column_get_visible (tmp_column) == FALSE)
13482             continue;
13483
13484           last_column = tmp_column;
13485           width = gtk_tree_view_column_get_width (tmp_column);
13486           if (remaining_x <= width)
13487             {
13488               found = TRUE;
13489
13490               if (column)
13491                 *column = tmp_column;
13492
13493               if (cell_x)
13494                 *cell_x = remaining_x;
13495
13496               break;
13497             }
13498           remaining_x -= width;
13499         }
13500
13501       /* If found is FALSE and there is a last_column, then it the remainder
13502        * space is in that area
13503        */
13504       if (!found)
13505         {
13506           if (last_column)
13507             {
13508               if (column)
13509                 *column = last_column;
13510               
13511               if (cell_x)
13512                 *cell_x = gtk_tree_view_column_get_width (last_column) + remaining_x;
13513             }
13514           else
13515             {
13516               return FALSE;
13517             }
13518         }
13519     }
13520
13521   y_offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
13522                                       TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, y),
13523                                       &tree, &node);
13524
13525   if (tree == NULL)
13526     return FALSE;
13527
13528   if (cell_y)
13529     *cell_y = y_offset;
13530
13531   if (path)
13532     *path = _gtk_tree_path_new_from_rbtree (tree, node);
13533
13534   return TRUE;
13535 }
13536
13537
13538 static inline gint
13539 gtk_tree_view_get_cell_area_height (GtkTreeView *tree_view,
13540                                     GtkRBNode   *node,
13541                                     gint         vertical_separator)
13542 {
13543   int expander_size = gtk_tree_view_get_expander_size (tree_view);
13544   int height;
13545
13546   /* The "cell" areas are the cell_area passed in to gtk_cell_renderer_render(),
13547    * i.e. just the cells, no spacing.
13548    *
13549    * The cell area height is at least expander_size - vertical_separator.
13550    * For regular nodes, the height is then at least expander_size. We should
13551    * be able to enforce the expander_size minimum here, because this
13552    * function will not be called for irregular (e.g. separator) rows.
13553    */
13554   height = gtk_tree_view_get_row_height (tree_view, node);
13555   if (height < expander_size)
13556     height = expander_size;
13557
13558   return height - vertical_separator;
13559 }
13560
13561 static inline gint
13562 gtk_tree_view_get_cell_area_y_offset (GtkTreeView *tree_view,
13563                                       GtkRBTree   *tree,
13564                                       GtkRBNode   *node,
13565                                       gint         vertical_separator)
13566 {
13567   int offset;
13568
13569   offset = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
13570   offset += vertical_separator / 2;
13571
13572   return offset;
13573 }
13574
13575 /**
13576  * gtk_tree_view_get_cell_area:
13577  * @tree_view: a #GtkTreeView
13578  * @path: (allow-none): a #GtkTreePath for the row, or %NULL to get only horizontal coordinates
13579  * @column: (allow-none): a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordinates
13580  * @rect: (out): rectangle to fill with cell rect
13581  *
13582  * Fills the bounding rectangle in bin_window coordinates for the cell at the
13583  * row specified by @path and the column specified by @column.  If @path is
13584  * %NULL, or points to a path not currently displayed, the @y and @height fields
13585  * of the rectangle will be filled with 0. If @column is %NULL, the @x and @width
13586  * fields will be filled with 0.  The sum of all cell rects does not cover the
13587  * entire tree; there are extra pixels in between rows, for example. The
13588  * returned rectangle is equivalent to the @cell_area passed to
13589  * gtk_cell_renderer_render().  This function is only valid if @tree_view is
13590  * realized.
13591  **/
13592 void
13593 gtk_tree_view_get_cell_area (GtkTreeView        *tree_view,
13594                              GtkTreePath        *path,
13595                              GtkTreeViewColumn  *column,
13596                              GdkRectangle       *rect)
13597 {
13598   GtkRBTree *tree = NULL;
13599   GtkRBNode *node = NULL;
13600   gint vertical_separator;
13601   gint horizontal_separator;
13602
13603   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13604   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
13605   g_return_if_fail (rect != NULL);
13606   g_return_if_fail (!column || gtk_tree_view_column_get_tree_view (column) == (GtkWidget *) tree_view);
13607   g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (tree_view)));
13608
13609   gtk_widget_style_get (GTK_WIDGET (tree_view),
13610                         "vertical-separator", &vertical_separator,
13611                         "horizontal-separator", &horizontal_separator,
13612                         NULL);
13613
13614   rect->x = 0;
13615   rect->y = 0;
13616   rect->width = 0;
13617   rect->height = 0;
13618
13619   if (column)
13620     {
13621       rect->x = gtk_tree_view_column_get_x_offset (column) + horizontal_separator/2;
13622       rect->width = gtk_tree_view_column_get_width (column) - horizontal_separator;
13623     }
13624
13625   if (path)
13626     {
13627       gboolean ret = _gtk_tree_view_find_node (tree_view, path, &tree, &node);
13628
13629       /* Get vertical coords */
13630       if ((!ret && tree == NULL) || ret)
13631         return;
13632
13633       if (row_is_separator (tree_view, NULL, path))
13634         {
13635           /* There isn't really a "cell area" for separator, so we
13636            * return the y, height values for background area instead.
13637            */
13638           rect->y = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
13639           rect->height = gtk_tree_view_get_row_height (tree_view, node);
13640         }
13641       else
13642         {
13643           rect->y = gtk_tree_view_get_cell_area_y_offset (tree_view, tree, node,
13644                                                           vertical_separator);
13645           rect->height = gtk_tree_view_get_cell_area_height (tree_view, node,
13646                                                              vertical_separator);
13647         }
13648
13649       if (column &&
13650           gtk_tree_view_is_expander_column (tree_view, column))
13651         {
13652           gint depth = gtk_tree_path_get_depth (path);
13653           gboolean rtl;
13654
13655           rtl = gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL;
13656
13657           if (!rtl)
13658             rect->x += (depth - 1) * tree_view->priv->level_indentation;
13659           rect->width -= (depth - 1) * tree_view->priv->level_indentation;
13660
13661           if (gtk_tree_view_draw_expanders (tree_view))
13662             {
13663               int expander_size = gtk_tree_view_get_expander_size (tree_view);
13664               if (!rtl)
13665                 rect->x += depth * expander_size;
13666               rect->width -= depth * expander_size;
13667             }
13668
13669           rect->width = MAX (rect->width, 0);
13670         }
13671     }
13672 }
13673
13674 static inline gint
13675 gtk_tree_view_get_row_height (GtkTreeView *tree_view,
13676                               GtkRBNode   *node)
13677 {
13678   int expander_size = gtk_tree_view_get_expander_size (tree_view);
13679   int height;
13680
13681   /* The "background" areas of all rows/cells add up to cover the entire tree.
13682    * The background includes all inter-row and inter-cell spacing.
13683    *
13684    * If the row pointed at by node does not have a height set, we default
13685    * to expander_size, which is the minimum height for regular nodes.
13686    * Non-regular nodes (e.g. separators) can have a height set smaller
13687    * than expander_size and should not be overruled here.
13688    */
13689   height = GTK_RBNODE_GET_HEIGHT (node);
13690   if (height <= 0)
13691     height = expander_size;
13692
13693   return height;
13694 }
13695
13696 static inline gint
13697 gtk_tree_view_get_row_y_offset (GtkTreeView *tree_view,
13698                                 GtkRBTree   *tree,
13699                                 GtkRBNode   *node)
13700 {
13701   int offset;
13702
13703   offset = _gtk_rbtree_node_find_offset (tree, node);
13704
13705   return RBTREE_Y_TO_TREE_WINDOW_Y (tree_view, offset);
13706 }
13707
13708 /**
13709  * gtk_tree_view_get_background_area:
13710  * @tree_view: a #GtkTreeView
13711  * @path: (allow-none): a #GtkTreePath for the row, or %NULL to get only horizontal coordinates
13712  * @column: (allow-none): a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordiantes
13713  * @rect: (out): rectangle to fill with cell background rect
13714  *
13715  * Fills the bounding rectangle in bin_window coordinates for the cell at the
13716  * row specified by @path and the column specified by @column.  If @path is
13717  * %NULL, or points to a node not found in the tree, the @y and @height fields of
13718  * the rectangle will be filled with 0. If @column is %NULL, the @x and @width
13719  * fields will be filled with 0.  The returned rectangle is equivalent to the
13720  * @background_area passed to gtk_cell_renderer_render().  These background
13721  * areas tile to cover the entire bin window.  Contrast with the @cell_area,
13722  * returned by gtk_tree_view_get_cell_area(), which returns only the cell
13723  * itself, excluding surrounding borders and the tree expander area.
13724  *
13725  **/
13726 void
13727 gtk_tree_view_get_background_area (GtkTreeView        *tree_view,
13728                                    GtkTreePath        *path,
13729                                    GtkTreeViewColumn  *column,
13730                                    GdkRectangle       *rect)
13731 {
13732   GtkRBTree *tree = NULL;
13733   GtkRBNode *node = NULL;
13734
13735   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13736   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
13737   g_return_if_fail (rect != NULL);
13738
13739   rect->x = 0;
13740   rect->y = 0;
13741   rect->width = 0;
13742   rect->height = 0;
13743
13744   if (path)
13745     {
13746       /* Get vertical coords */
13747
13748       if (!_gtk_tree_view_find_node (tree_view, path, &tree, &node) &&
13749           tree == NULL)
13750         return;
13751
13752       rect->y = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
13753       rect->height = gtk_tree_view_get_row_height (tree_view, node);
13754     }
13755
13756   if (column)
13757     {
13758       gint x2 = 0;
13759
13760       gtk_tree_view_get_background_xrange (tree_view, tree, column, &rect->x, &x2);
13761       rect->width = x2 - rect->x;
13762     }
13763 }
13764
13765 /**
13766  * gtk_tree_view_get_visible_rect:
13767  * @tree_view: a #GtkTreeView
13768  * @visible_rect: (out): rectangle to fill
13769  *
13770  * Fills @visible_rect with the currently-visible region of the
13771  * buffer, in tree coordinates. Convert to bin_window coordinates with
13772  * gtk_tree_view_convert_tree_to_bin_window_coords().
13773  * Tree coordinates start at 0,0 for row 0 of the tree, and cover the entire
13774  * scrollable area of the tree.
13775  **/
13776 void
13777 gtk_tree_view_get_visible_rect (GtkTreeView  *tree_view,
13778                                 GdkRectangle *visible_rect)
13779 {
13780   GtkAllocation allocation;
13781   GtkWidget *widget;
13782
13783   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13784
13785   widget = GTK_WIDGET (tree_view);
13786
13787   if (visible_rect)
13788     {
13789       gtk_widget_get_allocation (widget, &allocation);
13790       visible_rect->x = gtk_adjustment_get_value (tree_view->priv->hadjustment);
13791       visible_rect->y = gtk_adjustment_get_value (tree_view->priv->vadjustment);
13792       visible_rect->width = allocation.width;
13793       visible_rect->height = allocation.height - gtk_tree_view_get_effective_header_height (tree_view);
13794     }
13795 }
13796
13797 /**
13798  * gtk_tree_view_convert_widget_to_tree_coords:
13799  * @tree_view: a #GtkTreeView
13800  * @wx: X coordinate relative to the widget
13801  * @wy: Y coordinate relative to the widget
13802  * @tx: (out): return location for tree X coordinate
13803  * @ty: (out): return location for tree Y coordinate
13804  *
13805  * Converts widget coordinates to coordinates for the
13806  * tree (the full scrollable area of the tree).
13807  *
13808  * Since: 2.12
13809  **/
13810 void
13811 gtk_tree_view_convert_widget_to_tree_coords (GtkTreeView *tree_view,
13812                                              gint         wx,
13813                                              gint         wy,
13814                                              gint        *tx,
13815                                              gint        *ty)
13816 {
13817   gint x, y;
13818
13819   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13820
13821   gtk_tree_view_convert_widget_to_bin_window_coords (tree_view,
13822                                                      wx, wy,
13823                                                      &x, &y);
13824   gtk_tree_view_convert_bin_window_to_tree_coords (tree_view,
13825                                                    x, y,
13826                                                    tx, ty);
13827 }
13828
13829 /**
13830  * gtk_tree_view_convert_tree_to_widget_coords:
13831  * @tree_view: a #GtkTreeView
13832  * @tx: X coordinate relative to the tree
13833  * @ty: Y coordinate relative to the tree
13834  * @wx: (out): return location for widget X coordinate
13835  * @wy: (out): return location for widget Y coordinate
13836  *
13837  * Converts tree coordinates (coordinates in full scrollable area of the tree)
13838  * to widget coordinates.
13839  *
13840  * Since: 2.12
13841  **/
13842 void
13843 gtk_tree_view_convert_tree_to_widget_coords (GtkTreeView *tree_view,
13844                                              gint         tx,
13845                                              gint         ty,
13846                                              gint        *wx,
13847                                              gint        *wy)
13848 {
13849   gint x, y;
13850
13851   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13852
13853   gtk_tree_view_convert_tree_to_bin_window_coords (tree_view,
13854                                                    tx, ty,
13855                                                    &x, &y);
13856   gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
13857                                                      x, y,
13858                                                      wx, wy);
13859 }
13860
13861 /**
13862  * gtk_tree_view_convert_widget_to_bin_window_coords:
13863  * @tree_view: a #GtkTreeView
13864  * @wx: X coordinate relative to the widget
13865  * @wy: Y coordinate relative to the widget
13866  * @bx: (out): return location for bin_window X coordinate
13867  * @by: (out): return location for bin_window Y coordinate
13868  *
13869  * Converts widget coordinates to coordinates for the bin_window
13870  * (see gtk_tree_view_get_bin_window()).
13871  *
13872  * Since: 2.12
13873  **/
13874 void
13875 gtk_tree_view_convert_widget_to_bin_window_coords (GtkTreeView *tree_view,
13876                                                    gint         wx,
13877                                                    gint         wy,
13878                                                    gint        *bx,
13879                                                    gint        *by)
13880 {
13881   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13882
13883   if (bx)
13884     *bx = wx + gtk_adjustment_get_value (tree_view->priv->hadjustment);
13885   if (by)
13886     *by = wy - gtk_tree_view_get_effective_header_height (tree_view);
13887 }
13888
13889 /**
13890  * gtk_tree_view_convert_bin_window_to_widget_coords:
13891  * @tree_view: a #GtkTreeView
13892  * @bx: bin_window X coordinate
13893  * @by: bin_window Y coordinate
13894  * @wx: (out): return location for widget X coordinate
13895  * @wy: (out): return location for widget Y coordinate
13896  *
13897  * Converts bin_window coordinates (see gtk_tree_view_get_bin_window())
13898  * to widget relative coordinates.
13899  *
13900  * Since: 2.12
13901  **/
13902 void
13903 gtk_tree_view_convert_bin_window_to_widget_coords (GtkTreeView *tree_view,
13904                                                    gint         bx,
13905                                                    gint         by,
13906                                                    gint        *wx,
13907                                                    gint        *wy)
13908 {
13909   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13910
13911   if (wx)
13912     *wx = bx - gtk_adjustment_get_value (tree_view->priv->hadjustment);
13913   if (wy)
13914     *wy = by + gtk_tree_view_get_effective_header_height (tree_view);
13915 }
13916
13917 /**
13918  * gtk_tree_view_convert_tree_to_bin_window_coords:
13919  * @tree_view: a #GtkTreeView
13920  * @tx: tree X coordinate
13921  * @ty: tree Y coordinate
13922  * @bx: (out): return location for X coordinate relative to bin_window
13923  * @by: (out): return location for Y coordinate relative to bin_window
13924  *
13925  * Converts tree coordinates (coordinates in full scrollable area of the tree)
13926  * to bin_window coordinates.
13927  *
13928  * Since: 2.12
13929  **/
13930 void
13931 gtk_tree_view_convert_tree_to_bin_window_coords (GtkTreeView *tree_view,
13932                                                  gint         tx,
13933                                                  gint         ty,
13934                                                  gint        *bx,
13935                                                  gint        *by)
13936 {
13937   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13938
13939   if (bx)
13940     *bx = tx;
13941   if (by)
13942     *by = ty - tree_view->priv->dy;
13943 }
13944
13945 /**
13946  * gtk_tree_view_convert_bin_window_to_tree_coords:
13947  * @tree_view: a #GtkTreeView
13948  * @bx: X coordinate relative to bin_window
13949  * @by: Y coordinate relative to bin_window
13950  * @tx: (out): return location for tree X coordinate
13951  * @ty: (out): return location for tree Y coordinate
13952  *
13953  * Converts bin_window coordinates to coordinates for the
13954  * tree (the full scrollable area of the tree).
13955  *
13956  * Since: 2.12
13957  **/
13958 void
13959 gtk_tree_view_convert_bin_window_to_tree_coords (GtkTreeView *tree_view,
13960                                                  gint         bx,
13961                                                  gint         by,
13962                                                  gint        *tx,
13963                                                  gint        *ty)
13964 {
13965   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13966
13967   if (tx)
13968     *tx = bx;
13969   if (ty)
13970     *ty = by + tree_view->priv->dy;
13971 }
13972
13973
13974
13975 /**
13976  * gtk_tree_view_get_visible_range:
13977  * @tree_view: A #GtkTreeView
13978  * @start_path: (out) (allow-none): Return location for start of region,
13979  *              or %NULL.
13980  * @end_path: (out) (allow-none): Return location for end of region, or %NULL.
13981  *
13982  * Sets @start_path and @end_path to be the first and last visible path.
13983  * Note that there may be invisible paths in between.
13984  *
13985  * The paths should be freed with gtk_tree_path_free() after use.
13986  *
13987  * Returns: %TRUE, if valid paths were placed in @start_path and @end_path.
13988  *
13989  * Since: 2.8
13990  **/
13991 gboolean
13992 gtk_tree_view_get_visible_range (GtkTreeView  *tree_view,
13993                                  GtkTreePath **start_path,
13994                                  GtkTreePath **end_path)
13995 {
13996   GtkRBTree *tree;
13997   GtkRBNode *node;
13998   gboolean retval;
13999   
14000   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
14001
14002   if (!tree_view->priv->tree)
14003     return FALSE;
14004
14005   retval = TRUE;
14006
14007   if (start_path)
14008     {
14009       _gtk_rbtree_find_offset (tree_view->priv->tree,
14010                                TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, 0),
14011                                &tree, &node);
14012       if (node)
14013         *start_path = _gtk_tree_path_new_from_rbtree (tree, node);
14014       else
14015         retval = FALSE;
14016     }
14017
14018   if (end_path)
14019     {
14020       gint y;
14021
14022       if (tree_view->priv->height < gtk_adjustment_get_page_size (tree_view->priv->vadjustment))
14023         y = tree_view->priv->height - 1;
14024       else
14025         y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, gtk_adjustment_get_page_size (tree_view->priv->vadjustment)) - 1;
14026
14027       _gtk_rbtree_find_offset (tree_view->priv->tree, y, &tree, &node);
14028       if (node)
14029         *end_path = _gtk_tree_path_new_from_rbtree (tree, node);
14030       else
14031         retval = FALSE;
14032     }
14033
14034   return retval;
14035 }
14036
14037 /**
14038  * gtk_tree_view_is_blank_at_pos:
14039  * @tree_view: A #GtkTreeView
14040  * @x: The x position to be identified (relative to bin_window)
14041  * @y: The y position to be identified (relative to bin_window)
14042  * @path: (out) (allow-none): A pointer to a #GtkTreePath pointer to be filled in, or %NULL
14043  * @column: (out) (allow-none): A pointer to a #GtkTreeViewColumn pointer to be filled in, or %NULL
14044  * @cell_x: (out) (allow-none): A pointer where the X coordinate relative to the cell can be placed, or %NULL
14045  * @cell_y: (out) (allow-none): A pointer where the Y coordinate relative to the cell can be placed, or %NULL
14046  *
14047  * Determine whether the point (@x, @y) in @tree_view is blank, that is no
14048  * cell content nor an expander arrow is drawn at the location. If so, the
14049  * location can be considered as the background. You might wish to take
14050  * special action on clicks on the background, such as clearing a current
14051  * selection, having a custom context menu or starting rubber banding.
14052  *
14053  * The @x and @y coordinate that are provided must be relative to bin_window
14054  * coordinates.  That is, @x and @y must come from an event on @tree_view
14055  * where <literal>event->window == gtk_tree_view_get_bin_window (<!-- -->)</literal>.
14056  *
14057  * For converting widget coordinates (eg. the ones you get from
14058  * GtkWidget::query-tooltip), please see
14059  * gtk_tree_view_convert_widget_to_bin_window_coords().
14060  *
14061  * The @path, @column, @cell_x and @cell_y arguments will be filled in
14062  * likewise as for gtk_tree_view_get_path_at_pos().  Please see
14063  * gtk_tree_view_get_path_at_pos() for more information.
14064  *
14065  * Return value: %TRUE if the area at the given coordinates is blank,
14066  * %FALSE otherwise.
14067  *
14068  * Since: 3.0
14069  */
14070 gboolean
14071 gtk_tree_view_is_blank_at_pos (GtkTreeView       *tree_view,
14072                                gint                x,
14073                                gint                y,
14074                                GtkTreePath       **path,
14075                                GtkTreeViewColumn **column,
14076                                gint               *cell_x,
14077                                gint               *cell_y)
14078 {
14079   GtkRBTree *tree;
14080   GtkRBNode *node;
14081   GtkTreeIter iter;
14082   GtkTreePath *real_path;
14083   GtkTreeViewColumn *real_column;
14084   GdkRectangle cell_area, background_area;
14085
14086   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
14087
14088   if (!gtk_tree_view_get_path_at_pos (tree_view, x, y,
14089                                       &real_path, &real_column,
14090                                       cell_x, cell_y))
14091     /* If there's no path here, it is blank */
14092     return TRUE;
14093
14094   if (path)
14095     *path = real_path;
14096
14097   if (column)
14098     *column = real_column;
14099
14100   gtk_tree_model_get_iter (tree_view->priv->model, &iter, real_path);
14101   _gtk_tree_view_find_node (tree_view, real_path, &tree, &node);
14102
14103   /* Check if there's an expander arrow at (x, y) */
14104   if (real_column == tree_view->priv->expander_column
14105       && gtk_tree_view_draw_expanders (tree_view))
14106     {
14107       gboolean over_arrow;
14108
14109       over_arrow = coords_are_over_arrow (tree_view, tree, node, x, y);
14110
14111       if (over_arrow)
14112         {
14113           if (!path)
14114             gtk_tree_path_free (real_path);
14115           return FALSE;
14116         }
14117     }
14118
14119   /* Otherwise, have the column see if there's a cell at (x, y) */
14120   gtk_tree_view_column_cell_set_cell_data (real_column,
14121                                            tree_view->priv->model,
14122                                            &iter,
14123                                            GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
14124                                            node->children ? TRUE : FALSE);
14125
14126   gtk_tree_view_get_background_area (tree_view, real_path, real_column,
14127                                      &background_area);
14128   gtk_tree_view_get_cell_area (tree_view, real_path, real_column,
14129                                &cell_area);
14130
14131   if (!path)
14132     gtk_tree_path_free (real_path);
14133
14134   return _gtk_tree_view_column_is_blank_at_pos (real_column,
14135                                                 &cell_area,
14136                                                 &background_area,
14137                                                 x, y);
14138 }
14139
14140 static void
14141 unset_reorderable (GtkTreeView *tree_view)
14142 {
14143   if (tree_view->priv->reorderable)
14144     {
14145       tree_view->priv->reorderable = FALSE;
14146       g_object_notify (G_OBJECT (tree_view), "reorderable");
14147     }
14148 }
14149
14150 /**
14151  * gtk_tree_view_enable_model_drag_source:
14152  * @tree_view: a #GtkTreeView
14153  * @start_button_mask: Mask of allowed buttons to start drag
14154  * @targets: (array length=n_targets): the table of targets that the drag will support
14155  * @n_targets: the number of items in @targets
14156  * @actions: the bitmask of possible actions for a drag from this
14157  *    widget
14158  *
14159  * Turns @tree_view into a drag source for automatic DND. Calling this
14160  * method sets #GtkTreeView:reorderable to %FALSE.
14161  **/
14162 void
14163 gtk_tree_view_enable_model_drag_source (GtkTreeView              *tree_view,
14164                                         GdkModifierType           start_button_mask,
14165                                         const GtkTargetEntry     *targets,
14166                                         gint                      n_targets,
14167                                         GdkDragAction             actions)
14168 {
14169   TreeViewDragInfo *di;
14170
14171   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14172
14173   gtk_drag_source_set (GTK_WIDGET (tree_view),
14174                        0,
14175                        targets,
14176                        n_targets,
14177                        actions);
14178
14179   di = ensure_info (tree_view);
14180
14181   di->start_button_mask = start_button_mask;
14182   di->source_actions = actions;
14183   di->source_set = TRUE;
14184
14185   unset_reorderable (tree_view);
14186 }
14187
14188 /**
14189  * gtk_tree_view_enable_model_drag_dest:
14190  * @tree_view: a #GtkTreeView
14191  * @targets: (array length=n_targets): the table of targets that
14192  *           the drag will support
14193  * @n_targets: the number of items in @targets
14194  * @actions: the bitmask of possible actions for a drag from this
14195  *    widget
14196  * 
14197  * Turns @tree_view into a drop destination for automatic DND. Calling
14198  * this method sets #GtkTreeView:reorderable to %FALSE.
14199  **/
14200 void
14201 gtk_tree_view_enable_model_drag_dest (GtkTreeView              *tree_view,
14202                                       const GtkTargetEntry     *targets,
14203                                       gint                      n_targets,
14204                                       GdkDragAction             actions)
14205 {
14206   TreeViewDragInfo *di;
14207
14208   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14209
14210   gtk_drag_dest_set (GTK_WIDGET (tree_view),
14211                      0,
14212                      targets,
14213                      n_targets,
14214                      actions);
14215
14216   di = ensure_info (tree_view);
14217   di->dest_set = TRUE;
14218
14219   unset_reorderable (tree_view);
14220 }
14221
14222 /**
14223  * gtk_tree_view_unset_rows_drag_source:
14224  * @tree_view: a #GtkTreeView
14225  *
14226  * Undoes the effect of
14227  * gtk_tree_view_enable_model_drag_source(). Calling this method sets
14228  * #GtkTreeView:reorderable to %FALSE.
14229  **/
14230 void
14231 gtk_tree_view_unset_rows_drag_source (GtkTreeView *tree_view)
14232 {
14233   TreeViewDragInfo *di;
14234
14235   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14236
14237   di = get_info (tree_view);
14238
14239   if (di)
14240     {
14241       if (di->source_set)
14242         {
14243           gtk_drag_source_unset (GTK_WIDGET (tree_view));
14244           di->source_set = FALSE;
14245         }
14246
14247       if (!di->dest_set && !di->source_set)
14248         remove_info (tree_view);
14249     }
14250   
14251   unset_reorderable (tree_view);
14252 }
14253
14254 /**
14255  * gtk_tree_view_unset_rows_drag_dest:
14256  * @tree_view: a #GtkTreeView
14257  *
14258  * Undoes the effect of
14259  * gtk_tree_view_enable_model_drag_dest(). Calling this method sets
14260  * #GtkTreeView:reorderable to %FALSE.
14261  **/
14262 void
14263 gtk_tree_view_unset_rows_drag_dest (GtkTreeView *tree_view)
14264 {
14265   TreeViewDragInfo *di;
14266
14267   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14268
14269   di = get_info (tree_view);
14270
14271   if (di)
14272     {
14273       if (di->dest_set)
14274         {
14275           gtk_drag_dest_unset (GTK_WIDGET (tree_view));
14276           di->dest_set = FALSE;
14277         }
14278
14279       if (!di->dest_set && !di->source_set)
14280         remove_info (tree_view);
14281     }
14282
14283   unset_reorderable (tree_view);
14284 }
14285
14286 /**
14287  * gtk_tree_view_set_drag_dest_row:
14288  * @tree_view: a #GtkTreeView
14289  * @path: (allow-none): The path of the row to highlight, or %NULL
14290  * @pos: Specifies whether to drop before, after or into the row
14291  *
14292  * Sets the row that is highlighted for feedback.
14293  * If @path is %NULL, an existing highlight is removed.
14294  */
14295 void
14296 gtk_tree_view_set_drag_dest_row (GtkTreeView            *tree_view,
14297                                  GtkTreePath            *path,
14298                                  GtkTreeViewDropPosition pos)
14299 {
14300   GtkTreePath *current_dest;
14301
14302   /* Note; this function is exported to allow a custom DND
14303    * implementation, so it can't touch TreeViewDragInfo
14304    */
14305
14306   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14307
14308   current_dest = NULL;
14309
14310   if (tree_view->priv->drag_dest_row)
14311     {
14312       current_dest = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
14313       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
14314     }
14315
14316   /* special case a drop on an empty model */
14317   tree_view->priv->empty_view_drop = 0;
14318
14319   if (pos == GTK_TREE_VIEW_DROP_BEFORE && path
14320       && gtk_tree_path_get_depth (path) == 1
14321       && gtk_tree_path_get_indices (path)[0] == 0)
14322     {
14323       gint n_children;
14324
14325       n_children = gtk_tree_model_iter_n_children (tree_view->priv->model,
14326                                                    NULL);
14327
14328       if (!n_children)
14329         tree_view->priv->empty_view_drop = 1;
14330     }
14331
14332   tree_view->priv->drag_dest_pos = pos;
14333
14334   if (path)
14335     {
14336       tree_view->priv->drag_dest_row =
14337         gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
14338       gtk_tree_view_queue_draw_path (tree_view, path, NULL);
14339     }
14340   else
14341     tree_view->priv->drag_dest_row = NULL;
14342
14343   if (current_dest)
14344     {
14345       GtkRBTree *tree, *new_tree;
14346       GtkRBNode *node, *new_node;
14347
14348       _gtk_tree_view_find_node (tree_view, current_dest, &tree, &node);
14349       _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
14350
14351       if (tree && node)
14352         {
14353           _gtk_rbtree_next_full (tree, node, &new_tree, &new_node);
14354           if (new_tree && new_node)
14355             _gtk_tree_view_queue_draw_node (tree_view, new_tree, new_node, NULL);
14356
14357           _gtk_rbtree_prev_full (tree, node, &new_tree, &new_node);
14358           if (new_tree && new_node)
14359             _gtk_tree_view_queue_draw_node (tree_view, new_tree, new_node, NULL);
14360         }
14361       gtk_tree_path_free (current_dest);
14362     }
14363 }
14364
14365 /**
14366  * gtk_tree_view_get_drag_dest_row:
14367  * @tree_view: a #GtkTreeView
14368  * @path: (out) (allow-none): Return location for the path of the highlighted row, or %NULL.
14369  * @pos: (out) (allow-none): Return location for the drop position, or %NULL
14370  * 
14371  * Gets information about the row that is highlighted for feedback.
14372  **/
14373 void
14374 gtk_tree_view_get_drag_dest_row (GtkTreeView              *tree_view,
14375                                  GtkTreePath             **path,
14376                                  GtkTreeViewDropPosition  *pos)
14377 {
14378   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14379
14380   if (path)
14381     {
14382       if (tree_view->priv->drag_dest_row)
14383         *path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
14384       else
14385         {
14386           if (tree_view->priv->empty_view_drop)
14387             *path = gtk_tree_path_new_from_indices (0, -1);
14388           else
14389             *path = NULL;
14390         }
14391     }
14392
14393   if (pos)
14394     *pos = tree_view->priv->drag_dest_pos;
14395 }
14396
14397 /**
14398  * gtk_tree_view_get_dest_row_at_pos:
14399  * @tree_view: a #GtkTreeView
14400  * @drag_x: the position to determine the destination row for
14401  * @drag_y: the position to determine the destination row for
14402  * @path: (out) (allow-none): Return location for the path of the highlighted row, or %NULL.
14403  * @pos: (out) (allow-none): Return location for the drop position, or %NULL
14404  * 
14405  * Determines the destination row for a given position.  @drag_x and
14406  * @drag_y are expected to be in widget coordinates.  This function is only
14407  * meaningful if @tree_view is realized.  Therefore this function will always
14408  * return %FALSE if @tree_view is not realized or does not have a model.
14409  * 
14410  * Return value: whether there is a row at the given position, %TRUE if this
14411  * is indeed the case.
14412  **/
14413 gboolean
14414 gtk_tree_view_get_dest_row_at_pos (GtkTreeView             *tree_view,
14415                                    gint                     drag_x,
14416                                    gint                     drag_y,
14417                                    GtkTreePath            **path,
14418                                    GtkTreeViewDropPosition *pos)
14419 {
14420   gint cell_y;
14421   gint bin_x, bin_y;
14422   gdouble offset_into_row;
14423   gdouble third;
14424   GdkRectangle cell;
14425   GtkTreeViewColumn *column = NULL;
14426   GtkTreePath *tmp_path = NULL;
14427
14428   /* Note; this function is exported to allow a custom DND
14429    * implementation, so it can't touch TreeViewDragInfo
14430    */
14431
14432   g_return_val_if_fail (tree_view != NULL, FALSE);
14433   g_return_val_if_fail (drag_x >= 0, FALSE);
14434   g_return_val_if_fail (drag_y >= 0, FALSE);
14435
14436   if (path)
14437     *path = NULL;
14438
14439   if (tree_view->priv->bin_window == NULL)
14440     return FALSE;
14441
14442   if (tree_view->priv->tree == NULL)
14443     return FALSE;
14444
14445   /* If in the top third of a row, we drop before that row; if
14446    * in the bottom third, drop after that row; if in the middle,
14447    * and the row has children, drop into the row.
14448    */
14449   gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, drag_x, drag_y,
14450                                                      &bin_x, &bin_y);
14451
14452   if (!gtk_tree_view_get_path_at_pos (tree_view,
14453                                       bin_x,
14454                                       bin_y,
14455                                       &tmp_path,
14456                                       &column,
14457                                       NULL,
14458                                       &cell_y))
14459     return FALSE;
14460
14461   gtk_tree_view_get_background_area (tree_view, tmp_path, column,
14462                                      &cell);
14463
14464   offset_into_row = cell_y;
14465
14466   if (path)
14467     *path = tmp_path;
14468   else
14469     gtk_tree_path_free (tmp_path);
14470
14471   tmp_path = NULL;
14472
14473   third = cell.height / 3.0;
14474
14475   if (pos)
14476     {
14477       if (offset_into_row < third)
14478         {
14479           *pos = GTK_TREE_VIEW_DROP_BEFORE;
14480         }
14481       else if (offset_into_row < (cell.height / 2.0))
14482         {
14483           *pos = GTK_TREE_VIEW_DROP_INTO_OR_BEFORE;
14484         }
14485       else if (offset_into_row < third * 2.0)
14486         {
14487           *pos = GTK_TREE_VIEW_DROP_INTO_OR_AFTER;
14488         }
14489       else
14490         {
14491           *pos = GTK_TREE_VIEW_DROP_AFTER;
14492         }
14493     }
14494
14495   return TRUE;
14496 }
14497
14498
14499
14500 /* KEEP IN SYNC WITH GTK_TREE_VIEW_BIN_EXPOSE */
14501 /**
14502  * gtk_tree_view_create_row_drag_icon:
14503  * @tree_view: a #GtkTreeView
14504  * @path: a #GtkTreePath in @tree_view
14505  *
14506  * Creates a #cairo_surface_t representation of the row at @path.  
14507  * This image is used for a drag icon.
14508  *
14509  * Return value: (transfer full): a newly-allocated surface of the drag icon.
14510  **/
14511 cairo_surface_t *
14512 gtk_tree_view_create_row_drag_icon (GtkTreeView  *tree_view,
14513                                     GtkTreePath  *path)
14514 {
14515   GtkTreeIter   iter;
14516   GtkRBTree    *tree;
14517   GtkRBNode    *node;
14518   GtkStyleContext *context;
14519   gint cell_offset;
14520   GList *list;
14521   GdkRectangle background_area;
14522   GtkWidget *widget;
14523   gint depth;
14524   /* start drawing inside the black outline */
14525   gint x = 1, y = 1;
14526   cairo_surface_t *surface;
14527   gint bin_window_width;
14528   gboolean is_separator = FALSE;
14529   gboolean rtl, allow_rules;
14530   cairo_t *cr;
14531
14532   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14533   g_return_val_if_fail (path != NULL, NULL);
14534
14535   widget = GTK_WIDGET (tree_view);
14536
14537   if (!gtk_widget_get_realized (widget))
14538     return NULL;
14539
14540   depth = gtk_tree_path_get_depth (path);
14541
14542   _gtk_tree_view_find_node (tree_view,
14543                             path,
14544                             &tree,
14545                             &node);
14546
14547   if (tree == NULL)
14548     return NULL;
14549
14550   if (!gtk_tree_model_get_iter (tree_view->priv->model,
14551                                 &iter,
14552                                 path))
14553     return NULL;
14554
14555   context = gtk_widget_get_style_context (widget);
14556
14557   gtk_style_context_save (context);
14558   gtk_style_context_add_region (context, GTK_STYLE_REGION_COLUMN, 0);
14559
14560   gtk_widget_style_get (widget,
14561                         "allow-rules", &allow_rules,
14562                         NULL);
14563
14564   if (allow_rules && tree_view->priv->has_rules)
14565     {
14566       GtkRegionFlags row_flags;
14567
14568       if ((_gtk_rbtree_node_get_index (tree, node) % 2))
14569         row_flags = GTK_REGION_ODD;
14570       else
14571         row_flags = GTK_REGION_EVEN;
14572
14573       gtk_style_context_add_region (context, GTK_STYLE_REGION_ROW, row_flags);
14574     }
14575
14576   is_separator = row_is_separator (tree_view, &iter, NULL);
14577
14578   cell_offset = x;
14579
14580   background_area.y = y;
14581   background_area.height = gtk_tree_view_get_row_height (tree_view, node);
14582
14583   bin_window_width = gdk_window_get_width (tree_view->priv->bin_window);
14584
14585   surface = gdk_window_create_similar_surface (tree_view->priv->bin_window,
14586                                                CAIRO_CONTENT_COLOR,
14587                                                bin_window_width + 2,
14588                                                background_area.height + 2);
14589
14590   cr = cairo_create (surface);
14591
14592   gtk_render_background (context, cr, 0, 0,
14593                          bin_window_width + 2,
14594                          background_area.height + 2);
14595
14596   rtl = gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL;
14597
14598   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
14599       list;
14600       list = (rtl ? list->prev : list->next))
14601     {
14602       GtkTreeViewColumn *column = list->data;
14603       GdkRectangle cell_area;
14604       gint vertical_separator;
14605
14606       if (!gtk_tree_view_column_get_visible (column))
14607         continue;
14608
14609       gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, &iter,
14610                                                GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
14611                                                node->children?TRUE:FALSE);
14612
14613       background_area.x = cell_offset;
14614       background_area.width = gtk_tree_view_column_get_width (column);
14615
14616       gtk_widget_style_get (widget,
14617                             "vertical-separator", &vertical_separator,
14618                             NULL);
14619
14620       cell_area = background_area;
14621
14622       cell_area.y += vertical_separator / 2;
14623       cell_area.height -= vertical_separator;
14624
14625       if (gtk_tree_view_is_expander_column (tree_view, column))
14626         {
14627           if (!rtl)
14628             cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
14629           cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
14630
14631           if (gtk_tree_view_draw_expanders (tree_view))
14632             {
14633               int expander_size = gtk_tree_view_get_expander_size (tree_view);
14634               if (!rtl)
14635                 cell_area.x += depth * expander_size;
14636               cell_area.width -= depth * expander_size;
14637             }
14638         }
14639
14640       if (gtk_tree_view_column_cell_is_visible (column))
14641         {
14642           if (is_separator)
14643             {
14644               gtk_style_context_save (context);
14645               gtk_style_context_add_class (context, GTK_STYLE_CLASS_SEPARATOR);
14646
14647               gtk_render_line (context, cr,
14648                                cell_area.x,
14649                                cell_area.y + cell_area.height / 2,
14650                                cell_area.x + cell_area.width,
14651                                cell_area.y + cell_area.height / 2);
14652
14653               gtk_style_context_restore (context);
14654             }
14655           else
14656             {
14657               _gtk_tree_view_column_cell_render (column,
14658                                                  cr,
14659                                                  &background_area,
14660                                                  &cell_area,
14661                                                  0, FALSE);
14662             }
14663         }
14664       cell_offset += gtk_tree_view_column_get_width (column);
14665     }
14666
14667   cairo_set_source_rgb (cr, 0, 0, 0);
14668   cairo_rectangle (cr, 
14669                    0.5, 0.5, 
14670                    bin_window_width + 1,
14671                    background_area.height + 1);
14672   cairo_set_line_width (cr, 1.0);
14673   cairo_stroke (cr);
14674
14675   cairo_destroy (cr);
14676
14677   cairo_surface_set_device_offset (surface, 2, 2);
14678
14679   gtk_style_context_restore (context);
14680
14681   return surface;
14682 }
14683
14684
14685 /**
14686  * gtk_tree_view_set_destroy_count_func:
14687  * @tree_view: A #GtkTreeView
14688  * @func: (allow-none): Function to be called when a view row is destroyed, or %NULL
14689  * @data: (allow-none): User data to be passed to @func, or %NULL
14690  * @destroy: (allow-none): Destroy notifier for @data, or %NULL
14691  *
14692  * This function should almost never be used.  It is meant for private use by
14693  * ATK for determining the number of visible children that are removed when the
14694  * user collapses a row, or a row is deleted.
14695  *
14696  * Deprecated: 3.4: Accessibility does not need the function anymore.
14697  **/
14698 void
14699 gtk_tree_view_set_destroy_count_func (GtkTreeView             *tree_view,
14700                                       GtkTreeDestroyCountFunc  func,
14701                                       gpointer                 data,
14702                                       GDestroyNotify           destroy)
14703 {
14704   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14705
14706   if (tree_view->priv->destroy_count_destroy)
14707     tree_view->priv->destroy_count_destroy (tree_view->priv->destroy_count_data);
14708
14709   tree_view->priv->destroy_count_func = func;
14710   tree_view->priv->destroy_count_data = data;
14711   tree_view->priv->destroy_count_destroy = destroy;
14712 }
14713
14714
14715 /*
14716  * Interactive search
14717  */
14718
14719 /**
14720  * gtk_tree_view_set_enable_search:
14721  * @tree_view: A #GtkTreeView
14722  * @enable_search: %TRUE, if the user can search interactively
14723  *
14724  * If @enable_search is set, then the user can type in text to search through
14725  * the tree interactively (this is sometimes called "typeahead find").
14726  * 
14727  * Note that even if this is %FALSE, the user can still initiate a search 
14728  * using the "start-interactive-search" key binding.
14729  */
14730 void
14731 gtk_tree_view_set_enable_search (GtkTreeView *tree_view,
14732                                  gboolean     enable_search)
14733 {
14734   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14735
14736   enable_search = !!enable_search;
14737   
14738   if (tree_view->priv->enable_search != enable_search)
14739     {
14740        tree_view->priv->enable_search = enable_search;
14741        g_object_notify (G_OBJECT (tree_view), "enable-search");
14742     }
14743 }
14744
14745 /**
14746  * gtk_tree_view_get_enable_search:
14747  * @tree_view: A #GtkTreeView
14748  *
14749  * Returns whether or not the tree allows to start interactive searching 
14750  * by typing in text.
14751  *
14752  * Return value: whether or not to let the user search interactively
14753  */
14754 gboolean
14755 gtk_tree_view_get_enable_search (GtkTreeView *tree_view)
14756 {
14757   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
14758
14759   return tree_view->priv->enable_search;
14760 }
14761
14762
14763 /**
14764  * gtk_tree_view_get_search_column:
14765  * @tree_view: A #GtkTreeView
14766  *
14767  * Gets the column searched on by the interactive search code.
14768  *
14769  * Return value: the column the interactive search code searches in.
14770  */
14771 gint
14772 gtk_tree_view_get_search_column (GtkTreeView *tree_view)
14773 {
14774   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
14775
14776   return (tree_view->priv->search_column);
14777 }
14778
14779 /**
14780  * gtk_tree_view_set_search_column:
14781  * @tree_view: A #GtkTreeView
14782  * @column: the column of the model to search in, or -1 to disable searching
14783  *
14784  * Sets @column as the column where the interactive search code should
14785  * search in for the current model. 
14786  * 
14787  * If the search column is set, users can use the "start-interactive-search"
14788  * key binding to bring up search popup. The enable-search property controls
14789  * whether simply typing text will also start an interactive search.
14790  *
14791  * Note that @column refers to a column of the current model. The search 
14792  * column is reset to -1 when the model is changed.
14793  */
14794 void
14795 gtk_tree_view_set_search_column (GtkTreeView *tree_view,
14796                                  gint         column)
14797 {
14798   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14799   g_return_if_fail (column >= -1);
14800
14801   if (tree_view->priv->search_column == column)
14802     return;
14803
14804   tree_view->priv->search_column = column;
14805   g_object_notify (G_OBJECT (tree_view), "search-column");
14806 }
14807
14808 /**
14809  * gtk_tree_view_get_search_equal_func: (skip)
14810  * @tree_view: A #GtkTreeView
14811  *
14812  * Returns the compare function currently in use.
14813  *
14814  * Return value: the currently used compare function for the search code.
14815  */
14816
14817 GtkTreeViewSearchEqualFunc
14818 gtk_tree_view_get_search_equal_func (GtkTreeView *tree_view)
14819 {
14820   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14821
14822   return tree_view->priv->search_equal_func;
14823 }
14824
14825 /**
14826  * gtk_tree_view_set_search_equal_func:
14827  * @tree_view: A #GtkTreeView
14828  * @search_equal_func: the compare function to use during the search
14829  * @search_user_data: (allow-none): user data to pass to @search_equal_func, or %NULL
14830  * @search_destroy: (allow-none): Destroy notifier for @search_user_data, or %NULL
14831  *
14832  * Sets the compare function for the interactive search capabilities; note
14833  * that somewhat like strcmp() returning 0 for equality
14834  * #GtkTreeViewSearchEqualFunc returns %FALSE on matches.
14835  **/
14836 void
14837 gtk_tree_view_set_search_equal_func (GtkTreeView                *tree_view,
14838                                      GtkTreeViewSearchEqualFunc  search_equal_func,
14839                                      gpointer                    search_user_data,
14840                                      GDestroyNotify              search_destroy)
14841 {
14842   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14843   g_return_if_fail (search_equal_func != NULL);
14844
14845   if (tree_view->priv->search_destroy)
14846     tree_view->priv->search_destroy (tree_view->priv->search_user_data);
14847
14848   tree_view->priv->search_equal_func = search_equal_func;
14849   tree_view->priv->search_user_data = search_user_data;
14850   tree_view->priv->search_destroy = search_destroy;
14851   if (tree_view->priv->search_equal_func == NULL)
14852     tree_view->priv->search_equal_func = gtk_tree_view_search_equal_func;
14853 }
14854
14855 /**
14856  * gtk_tree_view_get_search_entry:
14857  * @tree_view: A #GtkTreeView
14858  *
14859  * Returns the #GtkEntry which is currently in use as interactive search
14860  * entry for @tree_view.  In case the built-in entry is being used, %NULL
14861  * will be returned.
14862  *
14863  * Return value: (transfer none): the entry currently in use as search entry.
14864  *
14865  * Since: 2.10
14866  */
14867 GtkEntry *
14868 gtk_tree_view_get_search_entry (GtkTreeView *tree_view)
14869 {
14870   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14871
14872   if (tree_view->priv->search_custom_entry_set)
14873     return GTK_ENTRY (tree_view->priv->search_entry);
14874
14875   return NULL;
14876 }
14877
14878 /**
14879  * gtk_tree_view_set_search_entry:
14880  * @tree_view: A #GtkTreeView
14881  * @entry: (allow-none): the entry the interactive search code of @tree_view should use or %NULL
14882  *
14883  * Sets the entry which the interactive search code will use for this
14884  * @tree_view.  This is useful when you want to provide a search entry
14885  * in our interface at all time at a fixed position.  Passing %NULL for
14886  * @entry will make the interactive search code use the built-in popup
14887  * entry again.
14888  *
14889  * Since: 2.10
14890  */
14891 void
14892 gtk_tree_view_set_search_entry (GtkTreeView *tree_view,
14893                                 GtkEntry    *entry)
14894 {
14895   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14896   g_return_if_fail (entry == NULL || GTK_IS_ENTRY (entry));
14897
14898   if (tree_view->priv->search_custom_entry_set)
14899     {
14900       if (tree_view->priv->search_entry_changed_id)
14901         {
14902           g_signal_handler_disconnect (tree_view->priv->search_entry,
14903                                        tree_view->priv->search_entry_changed_id);
14904           tree_view->priv->search_entry_changed_id = 0;
14905         }
14906       g_signal_handlers_disconnect_by_func (tree_view->priv->search_entry,
14907                                             G_CALLBACK (gtk_tree_view_search_key_press_event),
14908                                             tree_view);
14909
14910       g_object_unref (tree_view->priv->search_entry);
14911     }
14912   else if (tree_view->priv->search_window)
14913     {
14914       gtk_widget_destroy (tree_view->priv->search_window);
14915
14916       tree_view->priv->search_window = NULL;
14917     }
14918
14919   if (entry)
14920     {
14921       tree_view->priv->search_entry = g_object_ref (entry);
14922       tree_view->priv->search_custom_entry_set = TRUE;
14923
14924       if (tree_view->priv->search_entry_changed_id == 0)
14925         {
14926           tree_view->priv->search_entry_changed_id =
14927             g_signal_connect (tree_view->priv->search_entry, "changed",
14928                               G_CALLBACK (gtk_tree_view_search_init),
14929                               tree_view);
14930         }
14931       
14932         g_signal_connect (tree_view->priv->search_entry, "key-press-event",
14933                           G_CALLBACK (gtk_tree_view_search_key_press_event),
14934                           tree_view);
14935
14936         gtk_tree_view_search_init (tree_view->priv->search_entry, tree_view);
14937     }
14938   else
14939     {
14940       tree_view->priv->search_entry = NULL;
14941       tree_view->priv->search_custom_entry_set = FALSE;
14942     }
14943 }
14944
14945 /**
14946  * gtk_tree_view_set_search_position_func:
14947  * @tree_view: A #GtkTreeView
14948  * @func: (allow-none): the function to use to position the search dialog, or %NULL
14949  *    to use the default search position function
14950  * @data: (allow-none): user data to pass to @func, or %NULL
14951  * @destroy: (allow-none): Destroy notifier for @data, or %NULL
14952  *
14953  * Sets the function to use when positioning the search dialog.
14954  *
14955  * Since: 2.10
14956  **/
14957 void
14958 gtk_tree_view_set_search_position_func (GtkTreeView                   *tree_view,
14959                                         GtkTreeViewSearchPositionFunc  func,
14960                                         gpointer                       user_data,
14961                                         GDestroyNotify                 destroy)
14962 {
14963   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14964
14965   if (tree_view->priv->search_position_destroy)
14966     tree_view->priv->search_position_destroy (tree_view->priv->search_position_user_data);
14967
14968   tree_view->priv->search_position_func = func;
14969   tree_view->priv->search_position_user_data = user_data;
14970   tree_view->priv->search_position_destroy = destroy;
14971   if (tree_view->priv->search_position_func == NULL)
14972     tree_view->priv->search_position_func = gtk_tree_view_search_position_func;
14973 }
14974
14975 /**
14976  * gtk_tree_view_get_search_position_func: (skip)
14977  * @tree_view: A #GtkTreeView
14978  *
14979  * Returns the positioning function currently in use.
14980  *
14981  * Return value: the currently used function for positioning the search dialog.
14982  *
14983  * Since: 2.10
14984  */
14985 GtkTreeViewSearchPositionFunc
14986 gtk_tree_view_get_search_position_func (GtkTreeView *tree_view)
14987 {
14988   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14989
14990   return tree_view->priv->search_position_func;
14991 }
14992
14993
14994 static void
14995 gtk_tree_view_search_dialog_hide (GtkWidget   *search_dialog,
14996                                   GtkTreeView *tree_view,
14997                                   GdkDevice   *device)
14998 {
14999   if (tree_view->priv->disable_popdown)
15000     return;
15001
15002   if (tree_view->priv->search_entry_changed_id)
15003     {
15004       g_signal_handler_disconnect (tree_view->priv->search_entry,
15005                                    tree_view->priv->search_entry_changed_id);
15006       tree_view->priv->search_entry_changed_id = 0;
15007     }
15008   if (tree_view->priv->typeselect_flush_timeout)
15009     {
15010       g_source_remove (tree_view->priv->typeselect_flush_timeout);
15011       tree_view->priv->typeselect_flush_timeout = 0;
15012     }
15013         
15014   if (gtk_widget_get_visible (search_dialog))
15015     {
15016       /* send focus-in event */
15017       send_focus_change (GTK_WIDGET (tree_view->priv->search_entry), device, FALSE);
15018       gtk_widget_hide (search_dialog);
15019       gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
15020       send_focus_change (GTK_WIDGET (tree_view), device, TRUE);
15021     }
15022 }
15023
15024 static void
15025 gtk_tree_view_search_position_func (GtkTreeView *tree_view,
15026                                     GtkWidget   *search_dialog,
15027                                     gpointer     user_data)
15028 {
15029   gint x, y;
15030   gint tree_x, tree_y;
15031   gint tree_width, tree_height;
15032   GdkWindow *tree_window = gtk_widget_get_window (GTK_WIDGET (tree_view));
15033   GdkScreen *screen = gdk_window_get_screen (tree_window);
15034   GtkRequisition requisition;
15035   gint monitor_num;
15036   GdkRectangle monitor;
15037
15038   monitor_num = gdk_screen_get_monitor_at_window (screen, tree_window);
15039   gdk_screen_get_monitor_workarea (screen, monitor_num, &monitor);
15040
15041   gtk_widget_realize (search_dialog);
15042
15043   gdk_window_get_origin (tree_window, &tree_x, &tree_y);
15044   tree_width = gdk_window_get_width (tree_window);
15045   tree_height = gdk_window_get_height (tree_window);
15046   gtk_widget_get_preferred_size (search_dialog, &requisition, NULL);
15047
15048   if (tree_x + tree_width > gdk_screen_get_width (screen))
15049     x = gdk_screen_get_width (screen) - requisition.width;
15050   else if (tree_x + tree_width - requisition.width < 0)
15051     x = 0;
15052   else
15053     x = tree_x + tree_width - requisition.width;
15054
15055   if (tree_y + tree_height + requisition.height > gdk_screen_get_height (screen))
15056     y = gdk_screen_get_height (screen) - requisition.height;
15057   else if (tree_y + tree_height < 0) /* isn't really possible ... */
15058     y = 0;
15059   else
15060     y = tree_y + tree_height;
15061
15062   gtk_window_move (GTK_WINDOW (search_dialog), x, y);
15063 }
15064
15065 static void
15066 gtk_tree_view_search_disable_popdown (GtkEntry *entry,
15067                                       GtkMenu  *menu,
15068                                       gpointer  data)
15069 {
15070   GtkTreeView *tree_view = (GtkTreeView *)data;
15071
15072   tree_view->priv->disable_popdown = 1;
15073   g_signal_connect (menu, "hide",
15074                     G_CALLBACK (gtk_tree_view_search_enable_popdown), data);
15075 }
15076
15077 /* Because we're visible but offscreen, we just set a flag in the preedit
15078  * callback.
15079  */
15080 static void
15081 gtk_tree_view_search_preedit_changed (GtkIMContext *im_context,
15082                                       GtkTreeView  *tree_view)
15083 {
15084   tree_view->priv->imcontext_changed = 1;
15085   if (tree_view->priv->typeselect_flush_timeout)
15086     {
15087       g_source_remove (tree_view->priv->typeselect_flush_timeout);
15088       tree_view->priv->typeselect_flush_timeout =
15089         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
15090                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
15091                        tree_view);
15092     }
15093
15094 }
15095
15096 static void
15097 gtk_tree_view_search_activate (GtkEntry    *entry,
15098                                GtkTreeView *tree_view)
15099 {
15100   GtkTreePath *path;
15101
15102   gtk_tree_view_search_dialog_hide (tree_view->priv->search_window,
15103                                     tree_view,
15104                                     gtk_get_current_event_device ());
15105
15106   /* If we have a row selected and it's the cursor row, we activate
15107    * the row XXX */
15108   if (tree_view->priv->cursor_node &&
15109       GTK_RBNODE_FLAG_SET (tree_view->priv->cursor_node, GTK_RBNODE_IS_SELECTED))
15110     {
15111       path = _gtk_tree_path_new_from_rbtree (tree_view->priv->cursor_tree,
15112                                              tree_view->priv->cursor_node);
15113       
15114       gtk_tree_view_row_activated (tree_view, path, tree_view->priv->focus_column);
15115       
15116       gtk_tree_path_free (path);
15117     }
15118 }
15119
15120 static gboolean
15121 gtk_tree_view_real_search_enable_popdown (gpointer data)
15122 {
15123   GtkTreeView *tree_view = (GtkTreeView *)data;
15124
15125   tree_view->priv->disable_popdown = 0;
15126
15127   return FALSE;
15128 }
15129
15130 static void
15131 gtk_tree_view_search_enable_popdown (GtkWidget *widget,
15132                                      gpointer   data)
15133 {
15134   gdk_threads_add_timeout_full (G_PRIORITY_HIGH, 200, gtk_tree_view_real_search_enable_popdown, g_object_ref (data), g_object_unref);
15135 }
15136
15137 static gboolean
15138 gtk_tree_view_search_delete_event (GtkWidget *widget,
15139                                    GdkEventAny *event,
15140                                    GtkTreeView *tree_view)
15141 {
15142   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
15143
15144   gtk_tree_view_search_dialog_hide (widget, tree_view, NULL);
15145
15146   return TRUE;
15147 }
15148
15149 static gboolean
15150 gtk_tree_view_search_button_press_event (GtkWidget *widget,
15151                                          GdkEventButton *event,
15152                                          GtkTreeView *tree_view)
15153 {
15154   GdkDevice *keyb_device;
15155
15156   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
15157
15158   keyb_device = gdk_device_get_associated_device (event->device);
15159   gtk_tree_view_search_dialog_hide (widget, tree_view, keyb_device);
15160
15161   if (event->window == tree_view->priv->bin_window)
15162     gtk_tree_view_button_press (GTK_WIDGET (tree_view), event);
15163
15164   return TRUE;
15165 }
15166
15167 static gboolean
15168 gtk_tree_view_search_scroll_event (GtkWidget *widget,
15169                                    GdkEventScroll *event,
15170                                    GtkTreeView *tree_view)
15171 {
15172   gboolean retval = FALSE;
15173
15174   if (event->direction == GDK_SCROLL_UP)
15175     {
15176       gtk_tree_view_search_move (widget, tree_view, TRUE);
15177       retval = TRUE;
15178     }
15179   else if (event->direction == GDK_SCROLL_DOWN)
15180     {
15181       gtk_tree_view_search_move (widget, tree_view, FALSE);
15182       retval = TRUE;
15183     }
15184
15185   /* renew the flush timeout */
15186   if (retval && tree_view->priv->typeselect_flush_timeout
15187       && !tree_view->priv->search_custom_entry_set)
15188     {
15189       g_source_remove (tree_view->priv->typeselect_flush_timeout);
15190       tree_view->priv->typeselect_flush_timeout =
15191         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
15192                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
15193                        tree_view);
15194     }
15195
15196   return retval;
15197 }
15198
15199 static gboolean
15200 gtk_tree_view_search_key_press_event (GtkWidget *widget,
15201                                       GdkEventKey *event,
15202                                       GtkTreeView *tree_view)
15203 {
15204   GdkModifierType default_accel;
15205   gboolean        retval = FALSE;
15206
15207   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
15208   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15209
15210   /* close window and cancel the search */
15211   if (!tree_view->priv->search_custom_entry_set
15212       && (event->keyval == GDK_KEY_Escape ||
15213           event->keyval == GDK_KEY_Tab ||
15214             event->keyval == GDK_KEY_KP_Tab ||
15215             event->keyval == GDK_KEY_ISO_Left_Tab))
15216     {
15217       gtk_tree_view_search_dialog_hide (widget, tree_view,
15218                                         gdk_event_get_device ((GdkEvent *) event));
15219       return TRUE;
15220     }
15221
15222   default_accel = gtk_widget_get_modifier_mask (widget,
15223                                                 GDK_MODIFIER_INTENT_PRIMARY_ACCELERATOR);
15224
15225   /* select previous matching iter */
15226   if (event->keyval == GDK_KEY_Up || event->keyval == GDK_KEY_KP_Up)
15227     {
15228       if (!gtk_tree_view_search_move (widget, tree_view, TRUE))
15229         gtk_widget_error_bell (widget);
15230
15231       retval = TRUE;
15232     }
15233
15234   if (((event->state & (default_accel | GDK_SHIFT_MASK)) == (default_accel | GDK_SHIFT_MASK))
15235       && (event->keyval == GDK_KEY_g || event->keyval == GDK_KEY_G))
15236     {
15237       if (!gtk_tree_view_search_move (widget, tree_view, TRUE))
15238         gtk_widget_error_bell (widget);
15239
15240       retval = TRUE;
15241     }
15242
15243   /* select next matching iter */
15244   if (event->keyval == GDK_KEY_Down || event->keyval == GDK_KEY_KP_Down)
15245     {
15246       if (!gtk_tree_view_search_move (widget, tree_view, FALSE))
15247         gtk_widget_error_bell (widget);
15248
15249       retval = TRUE;
15250     }
15251
15252   if (((event->state & (default_accel | GDK_SHIFT_MASK)) == default_accel)
15253       && (event->keyval == GDK_KEY_g || event->keyval == GDK_KEY_G))
15254     {
15255       if (!gtk_tree_view_search_move (widget, tree_view, FALSE))
15256         gtk_widget_error_bell (widget);
15257
15258       retval = TRUE;
15259     }
15260
15261   /* renew the flush timeout */
15262   if (retval && tree_view->priv->typeselect_flush_timeout
15263       && !tree_view->priv->search_custom_entry_set)
15264     {
15265       g_source_remove (tree_view->priv->typeselect_flush_timeout);
15266       tree_view->priv->typeselect_flush_timeout =
15267         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
15268                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
15269                        tree_view);
15270     }
15271
15272   return retval;
15273 }
15274
15275 /*  this function returns FALSE if there is a search string but
15276  *  nothing was found, and TRUE otherwise.
15277  */
15278 static gboolean
15279 gtk_tree_view_search_move (GtkWidget   *window,
15280                            GtkTreeView *tree_view,
15281                            gboolean     up)
15282 {
15283   gboolean ret;
15284   gint len;
15285   gint count = 0;
15286   const gchar *text;
15287   GtkTreeIter iter;
15288   GtkTreeModel *model;
15289   GtkTreeSelection *selection;
15290
15291   text = gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry));
15292
15293   g_return_val_if_fail (text != NULL, FALSE);
15294
15295   len = strlen (text);
15296
15297   if (up && tree_view->priv->selected_iter == 1)
15298     return strlen (text) < 1;
15299
15300   len = strlen (text);
15301
15302   if (len < 1)
15303     return TRUE;
15304
15305   model = gtk_tree_view_get_model (tree_view);
15306   selection = gtk_tree_view_get_selection (tree_view);
15307
15308   /* search */
15309   gtk_tree_selection_unselect_all (selection);
15310   if (!gtk_tree_model_get_iter_first (model, &iter))
15311     return TRUE;
15312
15313   ret = gtk_tree_view_search_iter (model, selection, &iter, text,
15314                                    &count, up?((tree_view->priv->selected_iter) - 1):((tree_view->priv->selected_iter + 1)));
15315
15316   if (ret)
15317     {
15318       /* found */
15319       tree_view->priv->selected_iter += up?(-1):(1);
15320       return TRUE;
15321     }
15322   else
15323     {
15324       /* return to old iter */
15325       count = 0;
15326       gtk_tree_model_get_iter_first (model, &iter);
15327       gtk_tree_view_search_iter (model, selection,
15328                                  &iter, text,
15329                                  &count, tree_view->priv->selected_iter);
15330       return FALSE;
15331     }
15332 }
15333
15334 static gboolean
15335 gtk_tree_view_search_equal_func (GtkTreeModel *model,
15336                                  gint          column,
15337                                  const gchar  *key,
15338                                  GtkTreeIter  *iter,
15339                                  gpointer      search_data)
15340 {
15341   gboolean retval = TRUE;
15342   const gchar *str;
15343   gchar *normalized_string;
15344   gchar *normalized_key;
15345   gchar *case_normalized_string = NULL;
15346   gchar *case_normalized_key = NULL;
15347   GValue value = G_VALUE_INIT;
15348   GValue transformed = G_VALUE_INIT;
15349
15350   gtk_tree_model_get_value (model, iter, column, &value);
15351
15352   g_value_init (&transformed, G_TYPE_STRING);
15353
15354   if (!g_value_transform (&value, &transformed))
15355     {
15356       g_value_unset (&value);
15357       return TRUE;
15358     }
15359
15360   g_value_unset (&value);
15361
15362   str = g_value_get_string (&transformed);
15363   if (!str)
15364     {
15365       g_value_unset (&transformed);
15366       return TRUE;
15367     }
15368
15369   normalized_string = g_utf8_normalize (str, -1, G_NORMALIZE_ALL);
15370   normalized_key = g_utf8_normalize (key, -1, G_NORMALIZE_ALL);
15371
15372   if (normalized_string && normalized_key)
15373     {
15374       case_normalized_string = g_utf8_casefold (normalized_string, -1);
15375       case_normalized_key = g_utf8_casefold (normalized_key, -1);
15376
15377       if (strncmp (case_normalized_key, case_normalized_string, strlen (case_normalized_key)) == 0)
15378         retval = FALSE;
15379     }
15380
15381   g_value_unset (&transformed);
15382   g_free (normalized_key);
15383   g_free (normalized_string);
15384   g_free (case_normalized_key);
15385   g_free (case_normalized_string);
15386
15387   return retval;
15388 }
15389
15390 static gboolean
15391 gtk_tree_view_search_iter (GtkTreeModel     *model,
15392                            GtkTreeSelection *selection,
15393                            GtkTreeIter      *iter,
15394                            const gchar      *text,
15395                            gint             *count,
15396                            gint              n)
15397 {
15398   GtkRBTree *tree = NULL;
15399   GtkRBNode *node = NULL;
15400   GtkTreePath *path;
15401
15402   GtkTreeView *tree_view = gtk_tree_selection_get_tree_view (selection);
15403
15404   path = gtk_tree_model_get_path (model, iter);
15405   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
15406
15407   do
15408     {
15409       if (! tree_view->priv->search_equal_func (model, tree_view->priv->search_column, text, iter, tree_view->priv->search_user_data))
15410         {
15411           (*count)++;
15412           if (*count == n)
15413             {
15414               gtk_tree_view_scroll_to_cell (tree_view, path, NULL,
15415                                             TRUE, 0.5, 0.0);
15416               gtk_tree_selection_select_iter (selection, iter);
15417               gtk_tree_view_real_set_cursor (tree_view, path, CLAMP_NODE);
15418
15419               if (path)
15420                 gtk_tree_path_free (path);
15421
15422               return TRUE;
15423             }
15424         }
15425
15426       if (node->children)
15427         {
15428           gboolean has_child;
15429           GtkTreeIter tmp;
15430
15431           tree = node->children;
15432           node = _gtk_rbtree_first (tree);
15433
15434           tmp = *iter;
15435           has_child = gtk_tree_model_iter_children (model, iter, &tmp);
15436           gtk_tree_path_down (path);
15437
15438           /* sanity check */
15439           TREE_VIEW_INTERNAL_ASSERT (has_child, FALSE);
15440         }
15441       else
15442         {
15443           gboolean done = FALSE;
15444
15445           do
15446             {
15447               node = _gtk_rbtree_next (tree, node);
15448
15449               if (node)
15450                 {
15451                   gboolean has_next;
15452
15453                   has_next = gtk_tree_model_iter_next (model, iter);
15454
15455                   done = TRUE;
15456                   gtk_tree_path_next (path);
15457
15458                   /* sanity check */
15459                   TREE_VIEW_INTERNAL_ASSERT (has_next, FALSE);
15460                 }
15461               else
15462                 {
15463                   gboolean has_parent;
15464                   GtkTreeIter tmp_iter = *iter;
15465
15466                   node = tree->parent_node;
15467                   tree = tree->parent_tree;
15468
15469                   if (!tree)
15470                     {
15471                       if (path)
15472                         gtk_tree_path_free (path);
15473
15474                       /* we've run out of tree, done with this func */
15475                       return FALSE;
15476                     }
15477
15478                   has_parent = gtk_tree_model_iter_parent (model,
15479                                                            iter,
15480                                                            &tmp_iter);
15481                   gtk_tree_path_up (path);
15482
15483                   /* sanity check */
15484                   TREE_VIEW_INTERNAL_ASSERT (has_parent, FALSE);
15485                 }
15486             }
15487           while (!done);
15488         }
15489     }
15490   while (1);
15491
15492   return FALSE;
15493 }
15494
15495 static void
15496 gtk_tree_view_search_init (GtkWidget   *entry,
15497                            GtkTreeView *tree_view)
15498 {
15499   gint ret;
15500   gint count = 0;
15501   const gchar *text;
15502   GtkTreeIter iter;
15503   GtkTreeModel *model;
15504   GtkTreeSelection *selection;
15505
15506   g_return_if_fail (GTK_IS_ENTRY (entry));
15507   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15508
15509   text = gtk_entry_get_text (GTK_ENTRY (entry));
15510
15511   model = gtk_tree_view_get_model (tree_view);
15512   selection = gtk_tree_view_get_selection (tree_view);
15513
15514   /* search */
15515   gtk_tree_selection_unselect_all (selection);
15516   if (tree_view->priv->typeselect_flush_timeout
15517       && !tree_view->priv->search_custom_entry_set)
15518     {
15519       g_source_remove (tree_view->priv->typeselect_flush_timeout);
15520       tree_view->priv->typeselect_flush_timeout =
15521         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
15522                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
15523                        tree_view);
15524     }
15525
15526   if (*text == '\0')
15527     return;
15528
15529   if (!gtk_tree_model_get_iter_first (model, &iter))
15530     return;
15531
15532   ret = gtk_tree_view_search_iter (model, selection,
15533                                    &iter, text,
15534                                    &count, 1);
15535
15536   if (ret)
15537     tree_view->priv->selected_iter = 1;
15538 }
15539
15540 void
15541 _gtk_tree_view_remove_editable (GtkTreeView       *tree_view,
15542                                 GtkTreeViewColumn *column,
15543                                 GtkCellEditable   *cell_editable)
15544 {
15545   if (tree_view->priv->edited_column == NULL)
15546     return;
15547
15548   g_return_if_fail (column == tree_view->priv->edited_column);
15549
15550   tree_view->priv->edited_column = NULL;
15551
15552   if (gtk_widget_has_focus (GTK_WIDGET (cell_editable)))
15553     gtk_widget_grab_focus (GTK_WIDGET (tree_view));
15554
15555   gtk_container_remove (GTK_CONTAINER (tree_view),
15556                         GTK_WIDGET (cell_editable));
15557
15558   /* FIXME should only redraw a single node */
15559   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15560 }
15561
15562 static gboolean
15563 gtk_tree_view_start_editing (GtkTreeView *tree_view,
15564                              GtkTreePath *cursor_path,
15565                              gboolean     edit_only)
15566 {
15567   GtkTreeIter iter;
15568   GdkRectangle cell_area;
15569   GtkTreeViewColumn *focus_column;
15570   guint flags = 0; /* can be 0, as the flags are primarily for rendering */
15571   gint retval = FALSE;
15572   GtkRBTree *cursor_tree;
15573   GtkRBNode *cursor_node;
15574
15575   g_assert (tree_view->priv->focus_column);
15576   focus_column = tree_view->priv->focus_column;
15577
15578   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
15579     return FALSE;
15580
15581   if (_gtk_tree_view_find_node (tree_view, cursor_path, &cursor_tree, &cursor_node) ||
15582       cursor_node == NULL)
15583     return FALSE;
15584
15585   gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path);
15586
15587   validate_row (tree_view, cursor_tree, cursor_node, &iter, cursor_path);
15588
15589   gtk_tree_view_column_cell_set_cell_data (focus_column,
15590                                            tree_view->priv->model,
15591                                            &iter,
15592                                            GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_PARENT),
15593                                            cursor_node->children ? TRUE : FALSE);
15594   gtk_tree_view_get_cell_area (tree_view,
15595                                cursor_path,
15596                                focus_column,
15597                                &cell_area);
15598
15599   if (gtk_cell_area_activate (gtk_cell_layout_get_area (GTK_CELL_LAYOUT (focus_column)),
15600                               _gtk_tree_view_column_get_context (focus_column),
15601                               GTK_WIDGET (tree_view),
15602                               &cell_area,
15603                               flags, edit_only))
15604     retval = TRUE;
15605
15606   return retval;
15607 }
15608
15609 void
15610 _gtk_tree_view_add_editable (GtkTreeView       *tree_view,
15611                              GtkTreeViewColumn *column,
15612                              GtkTreePath       *path,
15613                              GtkCellEditable   *cell_editable,
15614                              GdkRectangle      *cell_area)
15615 {
15616   gint pre_val = gtk_adjustment_get_value (tree_view->priv->vadjustment);
15617   GtkRequisition requisition;
15618
15619   tree_view->priv->edited_column = column;
15620
15621   gtk_tree_view_real_set_cursor (tree_view, path, CLAMP_NODE);
15622   cell_area->y += pre_val - (int)gtk_adjustment_get_value (tree_view->priv->vadjustment);
15623
15624   gtk_widget_get_preferred_size (GTK_WIDGET (cell_editable),
15625                                  &requisition, NULL);
15626
15627   tree_view->priv->draw_keyfocus = TRUE;
15628
15629   if (requisition.height < cell_area->height)
15630     {
15631       gint diff = cell_area->height - requisition.height;
15632       gtk_tree_view_put (tree_view,
15633                          GTK_WIDGET (cell_editable),
15634                          cell_area->x, cell_area->y + diff/2,
15635                          cell_area->width, requisition.height);
15636     }
15637   else
15638     {
15639       gtk_tree_view_put (tree_view,
15640                          GTK_WIDGET (cell_editable),
15641                          cell_area->x, cell_area->y,
15642                          cell_area->width, cell_area->height);
15643     }
15644 }
15645
15646 static void
15647 gtk_tree_view_stop_editing (GtkTreeView *tree_view,
15648                             gboolean     cancel_editing)
15649 {
15650   GtkTreeViewColumn *column;
15651
15652   if (tree_view->priv->edited_column == NULL)
15653     return;
15654
15655   /*
15656    * This is very evil. We need to do this, because
15657    * gtk_cell_editable_editing_done may trigger gtk_tree_view_row_changed
15658    * later on. If gtk_tree_view_row_changed notices
15659    * tree_view->priv->edited_column != NULL, it'll call
15660    * gtk_tree_view_stop_editing again. Bad things will happen then.
15661    *
15662    * Please read that again if you intend to modify anything here.
15663    */
15664
15665   column = tree_view->priv->edited_column;
15666   gtk_cell_area_stop_editing (gtk_cell_layout_get_area (GTK_CELL_LAYOUT (column)), cancel_editing);
15667   tree_view->priv->edited_column = NULL;
15668 }
15669
15670
15671 /**
15672  * gtk_tree_view_set_hover_selection:
15673  * @tree_view: a #GtkTreeView
15674  * @hover: %TRUE to enable hover selection mode
15675  *
15676  * Enables or disables the hover selection mode of @tree_view.
15677  * Hover selection makes the selected row follow the pointer.
15678  * Currently, this works only for the selection modes 
15679  * %GTK_SELECTION_SINGLE and %GTK_SELECTION_BROWSE.
15680  * 
15681  * Since: 2.6
15682  **/
15683 void     
15684 gtk_tree_view_set_hover_selection (GtkTreeView *tree_view,
15685                                    gboolean     hover)
15686 {
15687   hover = hover != FALSE;
15688
15689   if (hover != tree_view->priv->hover_selection)
15690     {
15691       tree_view->priv->hover_selection = hover;
15692
15693       g_object_notify (G_OBJECT (tree_view), "hover-selection");
15694     }
15695 }
15696
15697 /**
15698  * gtk_tree_view_get_hover_selection:
15699  * @tree_view: a #GtkTreeView
15700  * 
15701  * Returns whether hover selection mode is turned on for @tree_view.
15702  * 
15703  * Return value: %TRUE if @tree_view is in hover selection mode
15704  *
15705  * Since: 2.6 
15706  **/
15707 gboolean 
15708 gtk_tree_view_get_hover_selection (GtkTreeView *tree_view)
15709 {
15710   return tree_view->priv->hover_selection;
15711 }
15712
15713 /**
15714  * gtk_tree_view_set_hover_expand:
15715  * @tree_view: a #GtkTreeView
15716  * @expand: %TRUE to enable hover selection mode
15717  *
15718  * Enables or disables the hover expansion mode of @tree_view.
15719  * Hover expansion makes rows expand or collapse if the pointer 
15720  * moves over them.
15721  * 
15722  * Since: 2.6
15723  **/
15724 void     
15725 gtk_tree_view_set_hover_expand (GtkTreeView *tree_view,
15726                                 gboolean     expand)
15727 {
15728   expand = expand != FALSE;
15729
15730   if (expand != tree_view->priv->hover_expand)
15731     {
15732       tree_view->priv->hover_expand = expand;
15733
15734       g_object_notify (G_OBJECT (tree_view), "hover-expand");
15735     }
15736 }
15737
15738 /**
15739  * gtk_tree_view_get_hover_expand:
15740  * @tree_view: a #GtkTreeView
15741  * 
15742  * Returns whether hover expansion mode is turned on for @tree_view.
15743  * 
15744  * Return value: %TRUE if @tree_view is in hover expansion mode
15745  *
15746  * Since: 2.6 
15747  **/
15748 gboolean 
15749 gtk_tree_view_get_hover_expand (GtkTreeView *tree_view)
15750 {
15751   return tree_view->priv->hover_expand;
15752 }
15753
15754 /**
15755  * gtk_tree_view_set_rubber_banding:
15756  * @tree_view: a #GtkTreeView
15757  * @enable: %TRUE to enable rubber banding
15758  *
15759  * Enables or disables rubber banding in @tree_view.  If the selection mode
15760  * is #GTK_SELECTION_MULTIPLE, rubber banding will allow the user to select
15761  * multiple rows by dragging the mouse.
15762  * 
15763  * Since: 2.10
15764  **/
15765 void
15766 gtk_tree_view_set_rubber_banding (GtkTreeView *tree_view,
15767                                   gboolean     enable)
15768 {
15769   enable = enable != FALSE;
15770
15771   if (enable != tree_view->priv->rubber_banding_enable)
15772     {
15773       tree_view->priv->rubber_banding_enable = enable;
15774
15775       g_object_notify (G_OBJECT (tree_view), "rubber-banding");
15776     }
15777 }
15778
15779 /**
15780  * gtk_tree_view_get_rubber_banding:
15781  * @tree_view: a #GtkTreeView
15782  * 
15783  * Returns whether rubber banding is turned on for @tree_view.  If the
15784  * selection mode is #GTK_SELECTION_MULTIPLE, rubber banding will allow the
15785  * user to select multiple rows by dragging the mouse.
15786  * 
15787  * Return value: %TRUE if rubber banding in @tree_view is enabled.
15788  *
15789  * Since: 2.10
15790  **/
15791 gboolean
15792 gtk_tree_view_get_rubber_banding (GtkTreeView *tree_view)
15793 {
15794   return tree_view->priv->rubber_banding_enable;
15795 }
15796
15797 /**
15798  * gtk_tree_view_is_rubber_banding_active:
15799  * @tree_view: a #GtkTreeView
15800  * 
15801  * Returns whether a rubber banding operation is currently being done
15802  * in @tree_view.
15803  *
15804  * Return value: %TRUE if a rubber banding operation is currently being
15805  * done in @tree_view.
15806  *
15807  * Since: 2.12
15808  **/
15809 gboolean
15810 gtk_tree_view_is_rubber_banding_active (GtkTreeView *tree_view)
15811 {
15812   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15813
15814   if (tree_view->priv->rubber_banding_enable
15815       && tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
15816     return TRUE;
15817
15818   return FALSE;
15819 }
15820
15821 /**
15822  * gtk_tree_view_get_row_separator_func: (skip)
15823  * @tree_view: a #GtkTreeView
15824  * 
15825  * Returns the current row separator function.
15826  * 
15827  * Return value: the current row separator function.
15828  *
15829  * Since: 2.6
15830  **/
15831 GtkTreeViewRowSeparatorFunc 
15832 gtk_tree_view_get_row_separator_func (GtkTreeView *tree_view)
15833 {
15834   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
15835
15836   return tree_view->priv->row_separator_func;
15837 }
15838
15839 /**
15840  * gtk_tree_view_set_row_separator_func:
15841  * @tree_view: a #GtkTreeView
15842  * @func: (allow-none): a #GtkTreeViewRowSeparatorFunc
15843  * @data: (allow-none): user data to pass to @func, or %NULL
15844  * @destroy: (allow-none): destroy notifier for @data, or %NULL
15845  * 
15846  * Sets the row separator function, which is used to determine
15847  * whether a row should be drawn as a separator. If the row separator
15848  * function is %NULL, no separators are drawn. This is the default value.
15849  *
15850  * Since: 2.6
15851  **/
15852 void
15853 gtk_tree_view_set_row_separator_func (GtkTreeView                 *tree_view,
15854                                       GtkTreeViewRowSeparatorFunc  func,
15855                                       gpointer                     data,
15856                                       GDestroyNotify               destroy)
15857 {
15858   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15859
15860   if (tree_view->priv->row_separator_destroy)
15861     tree_view->priv->row_separator_destroy (tree_view->priv->row_separator_data);
15862
15863   tree_view->priv->row_separator_func = func;
15864   tree_view->priv->row_separator_data = data;
15865   tree_view->priv->row_separator_destroy = destroy;
15866
15867   /* Have the tree recalculate heights */
15868   _gtk_rbtree_mark_invalid (tree_view->priv->tree);
15869   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
15870 }
15871
15872   
15873 static void
15874 gtk_tree_view_grab_notify (GtkWidget *widget,
15875                            gboolean   was_grabbed)
15876 {
15877   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
15878
15879   tree_view->priv->in_grab = !was_grabbed;
15880
15881   if (!was_grabbed)
15882     {
15883       tree_view->priv->pressed_button = -1;
15884
15885       if (tree_view->priv->rubber_band_status)
15886         gtk_tree_view_stop_rubber_band (tree_view);
15887     }
15888 }
15889
15890 static void
15891 gtk_tree_view_state_flags_changed (GtkWidget     *widget,
15892                                    GtkStateFlags  previous_state)
15893 {
15894   if (gtk_widget_get_realized (widget))
15895     gtk_tree_view_ensure_background (GTK_TREE_VIEW (widget));
15896
15897   gtk_widget_queue_draw (widget);
15898 }
15899
15900 /**
15901  * gtk_tree_view_get_grid_lines:
15902  * @tree_view: a #GtkTreeView
15903  *
15904  * Returns which grid lines are enabled in @tree_view.
15905  *
15906  * Return value: a #GtkTreeViewGridLines value indicating which grid lines
15907  * are enabled.
15908  *
15909  * Since: 2.10
15910  */
15911 GtkTreeViewGridLines
15912 gtk_tree_view_get_grid_lines (GtkTreeView *tree_view)
15913 {
15914   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
15915
15916   return tree_view->priv->grid_lines;
15917 }
15918
15919 /**
15920  * gtk_tree_view_set_grid_lines:
15921  * @tree_view: a #GtkTreeView
15922  * @grid_lines: a #GtkTreeViewGridLines value indicating which grid lines to
15923  * enable.
15924  *
15925  * Sets which grid lines to draw in @tree_view.
15926  *
15927  * Since: 2.10
15928  */
15929 void
15930 gtk_tree_view_set_grid_lines (GtkTreeView           *tree_view,
15931                               GtkTreeViewGridLines   grid_lines)
15932 {
15933   GtkTreeViewPrivate *priv;
15934   GtkWidget *widget;
15935   GtkTreeViewGridLines old_grid_lines;
15936
15937   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15938
15939   priv = tree_view->priv;
15940   widget = GTK_WIDGET (tree_view);
15941
15942   old_grid_lines = priv->grid_lines;
15943   priv->grid_lines = grid_lines;
15944   
15945   if (gtk_widget_get_realized (widget))
15946     {
15947       if (grid_lines == GTK_TREE_VIEW_GRID_LINES_NONE &&
15948           priv->grid_line_width)
15949         {
15950           priv->grid_line_width = 0;
15951         }
15952       
15953       if (grid_lines != GTK_TREE_VIEW_GRID_LINES_NONE && 
15954           !priv->grid_line_width)
15955         {
15956           gint8 *dash_list;
15957
15958           gtk_widget_style_get (widget,
15959                                 "grid-line-width", &priv->grid_line_width,
15960                                 "grid-line-pattern", (gchar *)&dash_list,
15961                                 NULL);
15962       
15963           if (dash_list)
15964             {
15965               priv->grid_line_dashes[0] = dash_list[0];
15966               if (dash_list[0])
15967                 priv->grid_line_dashes[1] = dash_list[1];
15968               
15969               g_free (dash_list);
15970             }
15971           else
15972             {
15973               priv->grid_line_dashes[0] = 1;
15974               priv->grid_line_dashes[1] = 1;
15975             }
15976         }      
15977     }
15978
15979   if (old_grid_lines != grid_lines)
15980     {
15981       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15982       
15983       g_object_notify (G_OBJECT (tree_view), "enable-grid-lines");
15984     }
15985 }
15986
15987 /**
15988  * gtk_tree_view_get_enable_tree_lines:
15989  * @tree_view: a #GtkTreeView.
15990  *
15991  * Returns whether or not tree lines are drawn in @tree_view.
15992  *
15993  * Return value: %TRUE if tree lines are drawn in @tree_view, %FALSE
15994  * otherwise.
15995  *
15996  * Since: 2.10
15997  */
15998 gboolean
15999 gtk_tree_view_get_enable_tree_lines (GtkTreeView *tree_view)
16000 {
16001   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
16002
16003   return tree_view->priv->tree_lines_enabled;
16004 }
16005
16006 /**
16007  * gtk_tree_view_set_enable_tree_lines:
16008  * @tree_view: a #GtkTreeView
16009  * @enabled: %TRUE to enable tree line drawing, %FALSE otherwise.
16010  *
16011  * Sets whether to draw lines interconnecting the expanders in @tree_view.
16012  * This does not have any visible effects for lists.
16013  *
16014  * Since: 2.10
16015  */
16016 void
16017 gtk_tree_view_set_enable_tree_lines (GtkTreeView *tree_view,
16018                                      gboolean     enabled)
16019 {
16020   GtkTreeViewPrivate *priv;
16021   GtkWidget *widget;
16022   gboolean was_enabled;
16023
16024   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
16025
16026   enabled = enabled != FALSE;
16027
16028   priv = tree_view->priv;
16029   widget = GTK_WIDGET (tree_view);
16030
16031   was_enabled = priv->tree_lines_enabled;
16032
16033   priv->tree_lines_enabled = enabled;
16034
16035   if (gtk_widget_get_realized (widget))
16036     {
16037       if (!enabled && priv->tree_line_width)
16038         {
16039           priv->tree_line_width = 0;
16040         }
16041       
16042       if (enabled && !priv->tree_line_width)
16043         {
16044           gint8 *dash_list;
16045           gtk_widget_style_get (widget,
16046                                 "tree-line-width", &priv->tree_line_width,
16047                                 "tree-line-pattern", (gchar *)&dash_list,
16048                                 NULL);
16049           
16050           if (dash_list)
16051             {
16052               priv->tree_line_dashes[0] = dash_list[0];
16053               if (dash_list[0])
16054                 priv->tree_line_dashes[1] = dash_list[1];
16055               
16056               g_free (dash_list);
16057             }
16058           else
16059             {
16060               priv->tree_line_dashes[0] = 1;
16061               priv->tree_line_dashes[1] = 1;
16062             }
16063         }
16064     }
16065
16066   if (was_enabled != enabled)
16067     {
16068       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
16069
16070       g_object_notify (G_OBJECT (tree_view), "enable-tree-lines");
16071     }
16072 }
16073
16074
16075 /**
16076  * gtk_tree_view_set_show_expanders:
16077  * @tree_view: a #GtkTreeView
16078  * @enabled: %TRUE to enable expander drawing, %FALSE otherwise.
16079  *
16080  * Sets whether to draw and enable expanders and indent child rows in
16081  * @tree_view.  When disabled there will be no expanders visible in trees
16082  * and there will be no way to expand and collapse rows by default.  Also
16083  * note that hiding the expanders will disable the default indentation.  You
16084  * can set a custom indentation in this case using
16085  * gtk_tree_view_set_level_indentation().
16086  * This does not have any visible effects for lists.
16087  *
16088  * Since: 2.12
16089  */
16090 void
16091 gtk_tree_view_set_show_expanders (GtkTreeView *tree_view,
16092                                   gboolean     enabled)
16093 {
16094   gboolean was_enabled;
16095
16096   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
16097
16098   enabled = enabled != FALSE;
16099   was_enabled = tree_view->priv->show_expanders;
16100
16101   tree_view->priv->show_expanders = enabled == TRUE;
16102
16103   if (enabled != was_enabled)
16104     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
16105 }
16106
16107 /**
16108  * gtk_tree_view_get_show_expanders:
16109  * @tree_view: a #GtkTreeView.
16110  *
16111  * Returns whether or not expanders are drawn in @tree_view.
16112  *
16113  * Return value: %TRUE if expanders are drawn in @tree_view, %FALSE
16114  * otherwise.
16115  *
16116  * Since: 2.12
16117  */
16118 gboolean
16119 gtk_tree_view_get_show_expanders (GtkTreeView *tree_view)
16120 {
16121   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
16122
16123   return tree_view->priv->show_expanders;
16124 }
16125
16126 /**
16127  * gtk_tree_view_set_level_indentation:
16128  * @tree_view: a #GtkTreeView
16129  * @indentation: the amount, in pixels, of extra indentation in @tree_view.
16130  *
16131  * Sets the amount of extra indentation for child levels to use in @tree_view
16132  * in addition to the default indentation.  The value should be specified in
16133  * pixels, a value of 0 disables this feature and in this case only the default
16134  * indentation will be used.
16135  * This does not have any visible effects for lists.
16136  *
16137  * Since: 2.12
16138  */
16139 void
16140 gtk_tree_view_set_level_indentation (GtkTreeView *tree_view,
16141                                      gint         indentation)
16142 {
16143   tree_view->priv->level_indentation = indentation;
16144
16145   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
16146 }
16147
16148 /**
16149  * gtk_tree_view_get_level_indentation:
16150  * @tree_view: a #GtkTreeView.
16151  *
16152  * Returns the amount, in pixels, of extra indentation for child levels
16153  * in @tree_view.
16154  *
16155  * Return value: the amount of extra indentation for child levels in
16156  * @tree_view.  A return value of 0 means that this feature is disabled.
16157  *
16158  * Since: 2.12
16159  */
16160 gint
16161 gtk_tree_view_get_level_indentation (GtkTreeView *tree_view)
16162 {
16163   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
16164
16165   return tree_view->priv->level_indentation;
16166 }
16167
16168 /**
16169  * gtk_tree_view_set_tooltip_row:
16170  * @tree_view: a #GtkTreeView
16171  * @tooltip: a #GtkTooltip
16172  * @path: a #GtkTreePath
16173  *
16174  * Sets the tip area of @tooltip to be the area covered by the row at @path.
16175  * See also gtk_tree_view_set_tooltip_column() for a simpler alternative.
16176  * See also gtk_tooltip_set_tip_area().
16177  *
16178  * Since: 2.12
16179  */
16180 void
16181 gtk_tree_view_set_tooltip_row (GtkTreeView *tree_view,
16182                                GtkTooltip  *tooltip,
16183                                GtkTreePath *path)
16184 {
16185   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
16186   g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
16187
16188   gtk_tree_view_set_tooltip_cell (tree_view, tooltip, path, NULL, NULL);
16189 }
16190
16191 /**
16192  * gtk_tree_view_set_tooltip_cell:
16193  * @tree_view: a #GtkTreeView
16194  * @tooltip: a #GtkTooltip
16195  * @path: (allow-none): a #GtkTreePath or %NULL
16196  * @column: (allow-none): a #GtkTreeViewColumn or %NULL
16197  * @cell: (allow-none): a #GtkCellRenderer or %NULL
16198  *
16199  * Sets the tip area of @tooltip to the area @path, @column and @cell have
16200  * in common.  For example if @path is %NULL and @column is set, the tip
16201  * area will be set to the full area covered by @column.  See also
16202  * gtk_tooltip_set_tip_area().
16203  *
16204  * Note that if @path is not specified and @cell is set and part of a column
16205  * containing the expander, the tooltip might not show and hide at the correct
16206  * position.  In such cases @path must be set to the current node under the
16207  * mouse cursor for this function to operate correctly.
16208  *
16209  * See also gtk_tree_view_set_tooltip_column() for a simpler alternative.
16210  *
16211  * Since: 2.12
16212  */
16213 void
16214 gtk_tree_view_set_tooltip_cell (GtkTreeView       *tree_view,
16215                                 GtkTooltip        *tooltip,
16216                                 GtkTreePath       *path,
16217                                 GtkTreeViewColumn *column,
16218                                 GtkCellRenderer   *cell)
16219 {
16220   GtkAllocation allocation;
16221   GdkRectangle rect;
16222
16223   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
16224   g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
16225   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
16226   g_return_if_fail (cell == NULL || GTK_IS_CELL_RENDERER (cell));
16227
16228   /* Determine x values. */
16229   if (column && cell)
16230     {
16231       GdkRectangle tmp;
16232       gint start, width;
16233
16234       /* We always pass in path here, whether it is NULL or not.
16235        * For cells in expander columns path must be specified so that
16236        * we can correctly account for the indentation.  This also means
16237        * that the tooltip is constrained vertically by the "Determine y
16238        * values" code below; this is not a real problem since cells actually
16239        * don't stretch vertically in constrast to columns.
16240        */
16241       gtk_tree_view_get_cell_area (tree_view, path, column, &tmp);
16242       gtk_tree_view_column_cell_get_position (column, cell, &start, &width);
16243
16244       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
16245                                                          tmp.x + start, 0,
16246                                                          &rect.x, NULL);
16247       rect.width = width;
16248     }
16249   else if (column)
16250     {
16251       GdkRectangle tmp;
16252
16253       gtk_tree_view_get_background_area (tree_view, NULL, column, &tmp);
16254       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
16255                                                          tmp.x, 0,
16256                                                          &rect.x, NULL);
16257       rect.width = tmp.width;
16258     }
16259   else
16260     {
16261       gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
16262       rect.x = 0;
16263       rect.width = allocation.width;
16264     }
16265
16266   /* Determine y values. */
16267   if (path)
16268     {
16269       GdkRectangle tmp;
16270
16271       gtk_tree_view_get_background_area (tree_view, path, NULL, &tmp);
16272       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
16273                                                          0, tmp.y,
16274                                                          NULL, &rect.y);
16275       rect.height = tmp.height;
16276     }
16277   else
16278     {
16279       rect.y = 0;
16280       rect.height = gtk_adjustment_get_page_size (tree_view->priv->vadjustment);
16281     }
16282
16283   gtk_tooltip_set_tip_area (tooltip, &rect);
16284 }
16285
16286 /**
16287  * gtk_tree_view_get_tooltip_context:
16288  * @tree_view: a #GtkTreeView
16289  * @x: (inout): the x coordinate (relative to widget coordinates)
16290  * @y: (inout): the y coordinate (relative to widget coordinates)
16291  * @keyboard_tip: whether this is a keyboard tooltip or not
16292  * @model: (out) (allow-none) (transfer none): a pointer to receive a
16293  *         #GtkTreeModel or %NULL
16294  * @path: (out) (allow-none): a pointer to receive a #GtkTreePath or %NULL
16295  * @iter: (out) (allow-none): a pointer to receive a #GtkTreeIter or %NULL
16296  *
16297  * This function is supposed to be used in a #GtkWidget::query-tooltip
16298  * signal handler for #GtkTreeView.  The @x, @y and @keyboard_tip values
16299  * which are received in the signal handler, should be passed to this
16300  * function without modification.
16301  *
16302  * The return value indicates whether there is a tree view row at the given
16303  * coordinates (%TRUE) or not (%FALSE) for mouse tooltips.  For keyboard
16304  * tooltips the row returned will be the cursor row.  When %TRUE, then any of
16305  * @model, @path and @iter which have been provided will be set to point to
16306  * that row and the corresponding model.  @x and @y will always be converted
16307  * to be relative to @tree_view's bin_window if @keyboard_tooltip is %FALSE.
16308  *
16309  * Return value: whether or not the given tooltip context points to a row.
16310  *
16311  * Since: 2.12
16312  */
16313 gboolean
16314 gtk_tree_view_get_tooltip_context (GtkTreeView   *tree_view,
16315                                    gint          *x,
16316                                    gint          *y,
16317                                    gboolean       keyboard_tip,
16318                                    GtkTreeModel **model,
16319                                    GtkTreePath  **path,
16320                                    GtkTreeIter   *iter)
16321 {
16322   GtkTreePath *tmppath = NULL;
16323
16324   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
16325   g_return_val_if_fail (x != NULL, FALSE);
16326   g_return_val_if_fail (y != NULL, FALSE);
16327
16328   if (keyboard_tip)
16329     {
16330       gtk_tree_view_get_cursor (tree_view, &tmppath, NULL);
16331
16332       if (!tmppath)
16333         return FALSE;
16334     }
16335   else
16336     {
16337       gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, *x, *y,
16338                                                          x, y);
16339
16340       if (!gtk_tree_view_get_path_at_pos (tree_view, *x, *y,
16341                                           &tmppath, NULL, NULL, NULL))
16342         return FALSE;
16343     }
16344
16345   if (model)
16346     *model = gtk_tree_view_get_model (tree_view);
16347
16348   if (iter)
16349     gtk_tree_model_get_iter (gtk_tree_view_get_model (tree_view),
16350                              iter, tmppath);
16351
16352   if (path)
16353     *path = tmppath;
16354   else
16355     gtk_tree_path_free (tmppath);
16356
16357   return TRUE;
16358 }
16359
16360 static gboolean
16361 gtk_tree_view_set_tooltip_query_cb (GtkWidget  *widget,
16362                                     gint        x,
16363                                     gint        y,
16364                                     gboolean    keyboard_tip,
16365                                     GtkTooltip *tooltip,
16366                                     gpointer    data)
16367 {
16368   GValue value = G_VALUE_INIT;
16369   GValue transformed = G_VALUE_INIT;
16370   GtkTreeIter iter;
16371   GtkTreePath *path;
16372   GtkTreeModel *model;
16373   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
16374
16375   if (!gtk_tree_view_get_tooltip_context (GTK_TREE_VIEW (widget),
16376                                           &x, &y,
16377                                           keyboard_tip,
16378                                           &model, &path, &iter))
16379     return FALSE;
16380
16381   gtk_tree_model_get_value (model, &iter,
16382                             tree_view->priv->tooltip_column, &value);
16383
16384   g_value_init (&transformed, G_TYPE_STRING);
16385
16386   if (!g_value_transform (&value, &transformed))
16387     {
16388       g_value_unset (&value);
16389       gtk_tree_path_free (path);
16390
16391       return FALSE;
16392     }
16393
16394   g_value_unset (&value);
16395
16396   if (!g_value_get_string (&transformed))
16397     {
16398       g_value_unset (&transformed);
16399       gtk_tree_path_free (path);
16400
16401       return FALSE;
16402     }
16403
16404   gtk_tooltip_set_markup (tooltip, g_value_get_string (&transformed));
16405   gtk_tree_view_set_tooltip_row (tree_view, tooltip, path);
16406
16407   gtk_tree_path_free (path);
16408   g_value_unset (&transformed);
16409
16410   return TRUE;
16411 }
16412
16413 /**
16414  * gtk_tree_view_set_tooltip_column:
16415  * @tree_view: a #GtkTreeView
16416  * @column: an integer, which is a valid column number for @tree_view's model
16417  *
16418  * If you only plan to have simple (text-only) tooltips on full rows, you
16419  * can use this function to have #GtkTreeView handle these automatically
16420  * for you. @column should be set to the column in @tree_view's model
16421  * containing the tooltip texts, or -1 to disable this feature.
16422  *
16423  * When enabled, #GtkWidget:has-tooltip will be set to %TRUE and
16424  * @tree_view will connect a #GtkWidget::query-tooltip signal handler.
16425  *
16426  * Note that the signal handler sets the text with gtk_tooltip_set_markup(),
16427  * so &amp;, &lt;, etc have to be escaped in the text.
16428  *
16429  * Since: 2.12
16430  */
16431 void
16432 gtk_tree_view_set_tooltip_column (GtkTreeView *tree_view,
16433                                   gint         column)
16434 {
16435   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
16436
16437   if (column == tree_view->priv->tooltip_column)
16438     return;
16439
16440   if (column == -1)
16441     {
16442       g_signal_handlers_disconnect_by_func (tree_view,
16443                                             gtk_tree_view_set_tooltip_query_cb,
16444                                             NULL);
16445       gtk_widget_set_has_tooltip (GTK_WIDGET (tree_view), FALSE);
16446     }
16447   else
16448     {
16449       if (tree_view->priv->tooltip_column == -1)
16450         {
16451           g_signal_connect (tree_view, "query-tooltip",
16452                             G_CALLBACK (gtk_tree_view_set_tooltip_query_cb), NULL);
16453           gtk_widget_set_has_tooltip (GTK_WIDGET (tree_view), TRUE);
16454         }
16455     }
16456
16457   tree_view->priv->tooltip_column = column;
16458   g_object_notify (G_OBJECT (tree_view), "tooltip-column");
16459 }
16460
16461 /**
16462  * gtk_tree_view_get_tooltip_column:
16463  * @tree_view: a #GtkTreeView
16464  *
16465  * Returns the column of @tree_view's model which is being used for
16466  * displaying tooltips on @tree_view's rows.
16467  *
16468  * Return value: the index of the tooltip column that is currently being
16469  * used, or -1 if this is disabled.
16470  *
16471  * Since: 2.12
16472  */
16473 gint
16474 gtk_tree_view_get_tooltip_column (GtkTreeView *tree_view)
16475 {
16476   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
16477
16478   return tree_view->priv->tooltip_column;
16479 }