]> Pileus Git - ~andy/gtk/blob - gtk/gtktreeview.c
gtk: Don't use GDK_THREADS_ENTER/LEAVE macros internally
[~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 "gtktypebuiltins.h"
52 #include "gtkmain.h"
53 #include "gtksettings.h"
54 #include "gtkwidgetpath.h"
55 #include "a11y/gtktreeviewaccessible.h"
56
57
58 /**
59  * SECTION:gtktreeview
60  * @Short_description: A widget for displaying both trees and lists
61  * @Title: GtkTreeView
62  * @See_also: #GtkTreeViewColumn, #GtkTreeSelection, #GtkTreeDnd, #GtkTreeMode,
63  *   #GtkTreeSortable, #GtkTreeModelSort, #GtkListStore, #GtkTreeStore,
64  *   #GtkCellRenderer, #GtkCellEditable, #GtkCellRendererPixbuf,
65  *   #GtkCellRendererText, #GtkCellRendererToggle
66  *
67  * Widget that displays any object that implements the #GtkTreeModel interface.
68  *
69  * Please refer to the <link linkend="TreeWidget">tree widget conceptual
70  * overview</link> for an overview of all the objects and data types related
71  * to the tree widget and how they work together.
72  *
73  * Several different coordinate systems are exposed in the GtkTreeView API.
74  * These are:
75  *
76  * <inlinegraphic fileref="tree-view-coordinates.png" format="PNG"></inlinegraphic>
77  * <variablelist><title>Coordinate systems in GtkTreeView API</title>
78  * <varlistentry><term>Widget coordinates</term>
79  * <listitem>
80  * <para>
81  * Coordinates relative to the widget (usually <literal>widget->window</literal>).
82  * </para>
83  * </listitem>
84  * </varlistentry>
85  * <varlistentry><term>Bin window coordinates</term>
86  * <listitem>
87  * <para>
88  * Coordinates relative to the window that GtkTreeView renders to.
89  * </para>
90  * </listitem>
91  * </varlistentry>
92  * <varlistentry><term>Tree coordinates</term>
93  * <listitem>
94  * <para>
95  * Coordinates relative to the entire scrollable area of GtkTreeView. These
96  * coordinates start at (0, 0) for row 0 of the tree.
97  * </para>
98  * </listitem>
99  * </varlistentry>
100  * </variablelist>
101  *
102  * Several functions are available for converting between the different
103  * coordinate systems.  The most common translations are between widget and bin
104  * window coordinates and between bin window and tree coordinates. For the
105  * former you can use gtk_tree_view_convert_widget_to_bin_window_coords()
106  * (and vice versa), for the latter gtk_tree_view_convert_bin_window_to_tree_coords()
107  * (and vice versa).
108  *
109  * <refsect2 id="GtkTreeView-BUILDER-UI">
110  * <title>GtkTreeView as GtkBuildable</title>
111  * The GtkTreeView implementation of the GtkBuildable interface accepts
112  * #GtkTreeViewColumn objects as &lt;child&gt; elements and exposes the
113  * internal #GtkTreeSelection in UI definitions.
114  * <example>
115  * <title>A UI definition fragment with GtkTreeView</title>
116  * <programlisting><![CDATA[
117  * <object class="GtkTreeView" id="treeview">
118  *   <property name="model">liststore1</property>
119  *   <child>
120  *     <object class="GtkTreeViewColumn" id="test-column">
121  *       <property name="title">Test</property>
122  *       <child>
123  *         <object class="GtkCellRendererText" id="test-renderer"/>
124  *         <attributes>
125  *           <attribute name="text">1</attribute>
126  *         </attributes>
127  *       </child>
128  *     </object>
129  *   </child>
130  *   <child internal-child="selection">
131  *     <object class="GtkTreeSelection" id="selection">
132  *       <signal name="changed" handler="on_treeview_selection_changed"/>
133  *     </object>
134  *   </child>
135  * </object>
136  * ]]></programlisting>
137  * </example>
138  * </refsect2>
139  */
140
141 enum
142 {
143   DRAG_COLUMN_WINDOW_STATE_UNSET = 0,
144   DRAG_COLUMN_WINDOW_STATE_ORIGINAL = 1,
145   DRAG_COLUMN_WINDOW_STATE_ARROW = 2,
146   DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT = 3,
147   DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT = 4
148 };
149
150 enum
151 {
152   RUBBER_BAND_OFF = 0,
153   RUBBER_BAND_MAYBE_START = 1,
154   RUBBER_BAND_ACTIVE = 2
155 };
156
157 typedef enum {
158   CLEAR_AND_SELECT = (1 << 0),
159   CLAMP_NODE       = (1 << 1),
160   CURSOR_INVALID   = (1 << 2)
161 } SetCursorFlags;
162
163  /* This lovely little value is used to determine how far away from the title bar
164   * you can move the mouse and still have a column drag work.
165   */
166 #define TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER(tree_view) (10*gtk_tree_view_get_effective_header_height(tree_view))
167
168 #ifdef __GNUC__
169
170 #define TREE_VIEW_INTERNAL_ASSERT(expr, ret)     G_STMT_START{          \
171      if (!(expr))                                                       \
172        {                                                                \
173          g_log (G_LOG_DOMAIN,                                           \
174                 G_LOG_LEVEL_CRITICAL,                                   \
175                 "%s (%s): assertion `%s' failed.\n"                     \
176                 "There is a disparity between the internal view of the GtkTreeView,\n"    \
177                 "and the GtkTreeModel.  This generally means that the model has changed\n"\
178                 "without letting the view know.  Any display from now on is likely to\n"  \
179                 "be incorrect.\n",                                                        \
180                 G_STRLOC,                                               \
181                 G_STRFUNC,                                              \
182                 #expr);                                                 \
183          return ret;                                                    \
184        };                               }G_STMT_END
185
186 #define TREE_VIEW_INTERNAL_ASSERT_VOID(expr)     G_STMT_START{          \
187      if (!(expr))                                                       \
188        {                                                                \
189          g_log (G_LOG_DOMAIN,                                           \
190                 G_LOG_LEVEL_CRITICAL,                                   \
191                 "%s (%s): assertion `%s' failed.\n"                     \
192                 "There is a disparity between the internal view of the GtkTreeView,\n"    \
193                 "and the GtkTreeModel.  This generally means that the model has changed\n"\
194                 "without letting the view know.  Any display from now on is likely to\n"  \
195                 "be incorrect.\n",                                                        \
196                 G_STRLOC,                                               \
197                 G_STRFUNC,                                              \
198                 #expr);                                                 \
199          return;                                                        \
200        };                               }G_STMT_END
201
202 #else
203
204 #define TREE_VIEW_INTERNAL_ASSERT(expr, ret)     G_STMT_START{          \
205      if (!(expr))                                                       \
206        {                                                                \
207          g_log (G_LOG_DOMAIN,                                           \
208                 G_LOG_LEVEL_CRITICAL,                                   \
209                 "file %s: line %d: assertion `%s' failed.\n"       \
210                 "There is a disparity between the internal view of the GtkTreeView,\n"    \
211                 "and the GtkTreeModel.  This generally means that the model has changed\n"\
212                 "without letting the view know.  Any display from now on is likely to\n"  \
213                 "be incorrect.\n",                                                        \
214                 __FILE__,                                               \
215                 __LINE__,                                               \
216                 #expr);                                                 \
217          return ret;                                                    \
218        };                               }G_STMT_END
219
220 #define TREE_VIEW_INTERNAL_ASSERT_VOID(expr)     G_STMT_START{          \
221      if (!(expr))                                                       \
222        {                                                                \
223          g_log (G_LOG_DOMAIN,                                           \
224                 G_LOG_LEVEL_CRITICAL,                                   \
225                 "file %s: line %d: assertion '%s' failed.\n"            \
226                 "There is a disparity between the internal view of the GtkTreeView,\n"    \
227                 "and the GtkTreeModel.  This generally means that the model has changed\n"\
228                 "without letting the view know.  Any display from now on is likely to\n"  \
229                 "be incorrect.\n",                                                        \
230                 __FILE__,                                               \
231                 __LINE__,                                               \
232                 #expr);                                                 \
233          return;                                                        \
234        };                               }G_STMT_END
235 #endif
236
237 #define GTK_TREE_VIEW_PRIORITY_VALIDATE (GDK_PRIORITY_REDRAW + 5)
238 #define GTK_TREE_VIEW_PRIORITY_SCROLL_SYNC (GTK_TREE_VIEW_PRIORITY_VALIDATE + 2)
239 #define GTK_TREE_VIEW_TIME_MS_PER_IDLE 30
240 #define SCROLL_EDGE_SIZE 15
241 #define EXPANDER_EXTRA_PADDING 4
242 #define GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT 5000
243 #define AUTO_EXPAND_TIMEOUT 500
244
245 /* Translate from bin_window coordinates to rbtree (tree coordinates) and
246  * vice versa.
247  */
248 #define TREE_WINDOW_Y_TO_RBTREE_Y(tree_view,y) ((y) + tree_view->priv->dy)
249 #define RBTREE_Y_TO_TREE_WINDOW_Y(tree_view,y) ((y) - tree_view->priv->dy)
250
251 typedef struct _GtkTreeViewColumnReorder GtkTreeViewColumnReorder;
252 struct _GtkTreeViewColumnReorder
253 {
254   gint left_align;
255   gint right_align;
256   GtkTreeViewColumn *left_column;
257   GtkTreeViewColumn *right_column;
258 };
259
260 typedef struct _GtkTreeViewChild GtkTreeViewChild;
261 struct _GtkTreeViewChild
262 {
263   GtkWidget *widget;
264   gint x;
265   gint y;
266   gint width;
267   gint height;
268 };
269
270
271 typedef struct _TreeViewDragInfo TreeViewDragInfo;
272 struct _TreeViewDragInfo
273 {
274   GdkModifierType start_button_mask;
275   GtkTargetList *_unused_source_target_list;
276   GdkDragAction source_actions;
277
278   GtkTargetList *_unused_dest_target_list;
279
280   guint source_set : 1;
281   guint dest_set : 1;
282 };
283
284
285 struct _GtkTreeViewPrivate
286 {
287   GtkTreeModel *model;
288
289   /* tree information */
290   GtkRBTree *tree;
291
292   /* Container info */
293   GList *children;
294   gint width;
295   gint height;
296
297   /* Adjustments */
298   GtkAdjustment *hadjustment;
299   GtkAdjustment *vadjustment;
300   gint           min_display_width;
301   gint           min_display_height;
302
303   /* Sub windows */
304   GdkWindow *bin_window;
305   GdkWindow *header_window;
306
307   /* Scroll position state keeping */
308   GtkTreeRowReference *top_row;
309   gint top_row_dy;
310   /* dy == y pos of top_row + top_row_dy */
311   /* we cache it for simplicity of the code */
312   gint dy;
313
314   guint presize_handler_timer;
315   guint validate_rows_timer;
316   guint scroll_sync_timer;
317
318   /* Indentation and expander layout */
319   GtkTreeViewColumn *expander_column;
320
321   gint level_indentation;
322
323   /* Key navigation (focus), selection */
324   gint cursor_offset;
325
326   GtkTreeRowReference *anchor;
327   GtkRBNode *cursor_node;
328   GtkRBTree *cursor_tree;
329
330   GtkTreeViewColumn *focus_column;
331
332   /* Current pressed node, previously pressed, prelight */
333   GtkRBNode *button_pressed_node;
334   GtkRBTree *button_pressed_tree;
335
336   gint pressed_button;
337   gint press_start_x;
338   gint press_start_y;
339
340   gint event_last_x;
341   gint event_last_y;
342
343   guint last_button_time;
344   gint last_button_x;
345   gint last_button_y;
346
347   GtkRBNode *prelight_node;
348   GtkRBTree *prelight_tree;
349
350   /* Cell Editing */
351   GtkTreeViewColumn *edited_column;
352
353   /* The node that's currently being collapsed or expanded */
354   GtkRBNode *expanded_collapsed_node;
355   GtkRBTree *expanded_collapsed_tree;
356   guint expand_collapse_timeout;
357
358   /* Auto expand/collapse timeout in hover mode */
359   guint auto_expand_timeout;
360
361   /* Selection information */
362   GtkTreeSelection *selection;
363
364   /* Header information */
365   gint n_columns;
366   GList *columns;
367   gint header_height;
368
369   GtkTreeViewColumnDropFunc column_drop_func;
370   gpointer column_drop_func_data;
371   GDestroyNotify column_drop_func_data_destroy;
372   GList *column_drag_info;
373   GtkTreeViewColumnReorder *cur_reorder;
374
375   gint prev_width_before_expander;
376
377   /* Interactive Header reordering */
378   GdkWindow *drag_window;
379   GdkWindow *drag_highlight_window;
380   GtkTreeViewColumn *drag_column;
381   gint drag_column_x;
382
383   /* Interactive Header Resizing */
384   gint drag_pos;
385   gint x_drag;
386
387   /* Non-interactive Header Resizing, expand flag support */
388   gint prev_width;
389
390   gint last_extra_space;
391   gint last_extra_space_per_column;
392   gint last_number_of_expand_columns;
393
394   /* ATK Hack */
395   GtkTreeDestroyCountFunc destroy_count_func;
396   gpointer destroy_count_data;
397   GDestroyNotify destroy_count_destroy;
398
399   /* Scroll timeout (e.g. during dnd, rubber banding) */
400   guint scroll_timeout;
401
402   /* Row drag-and-drop */
403   GtkTreeRowReference *drag_dest_row;
404   GtkTreeViewDropPosition drag_dest_pos;
405   guint open_dest_timeout;
406
407   /* Rubber banding */
408   gint rubber_band_status;
409   gint rubber_band_x;
410   gint rubber_band_y;
411   gint rubber_band_extend;
412   gint rubber_band_modify;
413
414   GtkRBNode *rubber_band_start_node;
415   GtkRBTree *rubber_band_start_tree;
416
417   GtkRBNode *rubber_band_end_node;
418   GtkRBTree *rubber_band_end_tree;
419
420   /* fixed height */
421   gint fixed_height;
422
423   /* Scroll-to functionality when unrealized */
424   GtkTreeRowReference *scroll_to_path;
425   GtkTreeViewColumn *scroll_to_column;
426   gfloat scroll_to_row_align;
427   gfloat scroll_to_col_align;
428
429   /* Interactive search */
430   gint selected_iter;
431   gint search_column;
432   GtkTreeViewSearchPositionFunc search_position_func;
433   GtkTreeViewSearchEqualFunc search_equal_func;
434   gpointer search_user_data;
435   GDestroyNotify search_destroy;
436   gpointer search_position_user_data;
437   GDestroyNotify search_position_destroy;
438   GtkWidget *search_window;
439   GtkWidget *search_entry;
440   gulong search_entry_changed_id;
441   guint typeselect_flush_timeout;
442
443   /* Grid and tree lines */
444   GtkTreeViewGridLines grid_lines;
445   double grid_line_dashes[2];
446   int grid_line_width;
447
448   gboolean tree_lines_enabled;
449   double tree_line_dashes[2];
450   int tree_line_width;
451
452   /* Row separators */
453   GtkTreeViewRowSeparatorFunc row_separator_func;
454   gpointer row_separator_data;
455   GDestroyNotify row_separator_destroy;
456
457   /* Tooltip support */
458   gint tooltip_column;
459
460   /* Here comes the bitfield */
461   guint scroll_to_use_align : 1;
462
463   guint fixed_height_mode : 1;
464   guint fixed_height_check : 1;
465
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   guint post_validation_flag : 1;
497
498   /* Whether our key press handler is to avoid sending an unhandled binding to the search entry */
499   guint search_entry_avoid_unhandled_binding : 1;
500
501   /* GtkScrollablePolicy needs to be checked when
502    * driving the scrollable adjustment values */
503   guint hscroll_policy : 1;
504   guint vscroll_policy : 1;
505
506   /* GtkTreeView flags */
507   guint is_list : 1;
508   guint show_expanders : 1;
509   guint in_column_resize : 1;
510   guint arrow_prelit : 1;
511   guint headers_visible : 1;
512   guint draw_keyfocus : 1;
513   guint model_setup : 1;
514   guint in_column_drag : 1;
515 };
516
517
518 /* Signals */
519 enum
520 {
521   ROW_ACTIVATED,
522   TEST_EXPAND_ROW,
523   TEST_COLLAPSE_ROW,
524   ROW_EXPANDED,
525   ROW_COLLAPSED,
526   COLUMNS_CHANGED,
527   CURSOR_CHANGED,
528   MOVE_CURSOR,
529   SELECT_ALL,
530   UNSELECT_ALL,
531   SELECT_CURSOR_ROW,
532   TOGGLE_CURSOR_ROW,
533   EXPAND_COLLAPSE_CURSOR_ROW,
534   SELECT_CURSOR_PARENT,
535   START_INTERACTIVE_SEARCH,
536   LAST_SIGNAL
537 };
538
539 /* Properties */
540 enum {
541   PROP_0,
542   PROP_MODEL,
543   PROP_HADJUSTMENT,
544   PROP_VADJUSTMENT,
545   PROP_HSCROLL_POLICY,
546   PROP_VSCROLL_POLICY,
547   PROP_HEADERS_VISIBLE,
548   PROP_HEADERS_CLICKABLE,
549   PROP_EXPANDER_COLUMN,
550   PROP_REORDERABLE,
551   PROP_RULES_HINT,
552   PROP_ENABLE_SEARCH,
553   PROP_SEARCH_COLUMN,
554   PROP_FIXED_HEIGHT_MODE,
555   PROP_HOVER_SELECTION,
556   PROP_HOVER_EXPAND,
557   PROP_SHOW_EXPANDERS,
558   PROP_LEVEL_INDENTATION,
559   PROP_RUBBER_BANDING,
560   PROP_ENABLE_GRID_LINES,
561   PROP_ENABLE_TREE_LINES,
562   PROP_TOOLTIP_COLUMN
563 };
564
565 /* object signals */
566 static void     gtk_tree_view_finalize             (GObject          *object);
567 static void     gtk_tree_view_set_property         (GObject         *object,
568                                                     guint            prop_id,
569                                                     const GValue    *value,
570                                                     GParamSpec      *pspec);
571 static void     gtk_tree_view_get_property         (GObject         *object,
572                                                     guint            prop_id,
573                                                     GValue          *value,
574                                                     GParamSpec      *pspec);
575
576 /* gtkwidget signals */
577 static void     gtk_tree_view_destroy              (GtkWidget        *widget);
578 static void     gtk_tree_view_realize              (GtkWidget        *widget);
579 static void     gtk_tree_view_unrealize            (GtkWidget        *widget);
580 static void     gtk_tree_view_map                  (GtkWidget        *widget);
581 static void     gtk_tree_view_get_preferred_width  (GtkWidget        *widget,
582                                                     gint             *minimum,
583                                                     gint             *natural);
584 static void     gtk_tree_view_get_preferred_height (GtkWidget        *widget,
585                                                     gint             *minimum,
586                                                     gint             *natural);
587 static void     gtk_tree_view_size_request         (GtkWidget        *widget,
588                                                     GtkRequisition   *requisition,
589                                                     gboolean          may_validate);
590 static void     gtk_tree_view_size_allocate        (GtkWidget        *widget,
591                                                     GtkAllocation    *allocation);
592 static gboolean gtk_tree_view_draw                 (GtkWidget        *widget,
593                                                     cairo_t          *cr);
594 static gboolean gtk_tree_view_key_press            (GtkWidget        *widget,
595                                                     GdkEventKey      *event);
596 static gboolean gtk_tree_view_key_release          (GtkWidget        *widget,
597                                                     GdkEventKey      *event);
598 static gboolean gtk_tree_view_motion               (GtkWidget        *widget,
599                                                     GdkEventMotion   *event);
600 static gboolean gtk_tree_view_enter_notify         (GtkWidget        *widget,
601                                                     GdkEventCrossing *event);
602 static gboolean gtk_tree_view_leave_notify         (GtkWidget        *widget,
603                                                     GdkEventCrossing *event);
604 static gboolean gtk_tree_view_button_press         (GtkWidget        *widget,
605                                                     GdkEventButton   *event);
606 static gboolean gtk_tree_view_button_release       (GtkWidget        *widget,
607                                                     GdkEventButton   *event);
608 static gboolean gtk_tree_view_grab_broken          (GtkWidget          *widget,
609                                                     GdkEventGrabBroken *event);
610 #if 0
611 static gboolean gtk_tree_view_configure            (GtkWidget         *widget,
612                                                     GdkEventConfigure *event);
613 #endif
614
615 static GtkWidgetPath * gtk_tree_view_get_path_for_child (GtkContainer *container,
616                                                          GtkWidget    *child);
617
618 static void     gtk_tree_view_set_focus_child      (GtkContainer     *container,
619                                                     GtkWidget        *child);
620 static gint     gtk_tree_view_focus_out            (GtkWidget        *widget,
621                                                     GdkEventFocus    *event);
622 static gint     gtk_tree_view_focus                (GtkWidget        *widget,
623                                                     GtkDirectionType  direction);
624 static void     gtk_tree_view_grab_focus           (GtkWidget        *widget);
625 static void     gtk_tree_view_style_updated        (GtkWidget        *widget);
626 static void     gtk_tree_view_grab_notify          (GtkWidget        *widget,
627                                                     gboolean          was_grabbed);
628 static void     gtk_tree_view_state_flags_changed  (GtkWidget        *widget,
629                                                     GtkStateFlags     previous_state);
630
631 /* container signals */
632 static void     gtk_tree_view_remove               (GtkContainer     *container,
633                                                     GtkWidget        *widget);
634 static void     gtk_tree_view_forall               (GtkContainer     *container,
635                                                     gboolean          include_internals,
636                                                     GtkCallback       callback,
637                                                     gpointer          callback_data);
638
639 /* Source side drag signals */
640 static void gtk_tree_view_drag_begin       (GtkWidget        *widget,
641                                             GdkDragContext   *context);
642 static void gtk_tree_view_drag_end         (GtkWidget        *widget,
643                                             GdkDragContext   *context);
644 static void gtk_tree_view_drag_data_get    (GtkWidget        *widget,
645                                             GdkDragContext   *context,
646                                             GtkSelectionData *selection_data,
647                                             guint             info,
648                                             guint             time);
649 static void gtk_tree_view_drag_data_delete (GtkWidget        *widget,
650                                             GdkDragContext   *context);
651
652 /* Target side drag signals */
653 static void     gtk_tree_view_drag_leave         (GtkWidget        *widget,
654                                                   GdkDragContext   *context,
655                                                   guint             time);
656 static gboolean gtk_tree_view_drag_motion        (GtkWidget        *widget,
657                                                   GdkDragContext   *context,
658                                                   gint              x,
659                                                   gint              y,
660                                                   guint             time);
661 static gboolean gtk_tree_view_drag_drop          (GtkWidget        *widget,
662                                                   GdkDragContext   *context,
663                                                   gint              x,
664                                                   gint              y,
665                                                   guint             time);
666 static void     gtk_tree_view_drag_data_received (GtkWidget        *widget,
667                                                   GdkDragContext   *context,
668                                                   gint              x,
669                                                   gint              y,
670                                                   GtkSelectionData *selection_data,
671                                                   guint             info,
672                                                   guint             time);
673
674 /* tree_model signals */
675 static gboolean gtk_tree_view_real_move_cursor            (GtkTreeView     *tree_view,
676                                                            GtkMovementStep  step,
677                                                            gint             count);
678 static gboolean gtk_tree_view_real_select_all             (GtkTreeView     *tree_view);
679 static gboolean gtk_tree_view_real_unselect_all           (GtkTreeView     *tree_view);
680 static gboolean gtk_tree_view_real_select_cursor_row      (GtkTreeView     *tree_view,
681                                                            gboolean         start_editing);
682 static gboolean gtk_tree_view_real_toggle_cursor_row      (GtkTreeView     *tree_view);
683 static gboolean gtk_tree_view_real_expand_collapse_cursor_row (GtkTreeView     *tree_view,
684                                                                gboolean         logical,
685                                                                gboolean         expand,
686                                                                gboolean         open_all);
687 static gboolean gtk_tree_view_real_select_cursor_parent   (GtkTreeView     *tree_view);
688 static void gtk_tree_view_row_changed                     (GtkTreeModel    *model,
689                                                            GtkTreePath     *path,
690                                                            GtkTreeIter     *iter,
691                                                            gpointer         data);
692 static void gtk_tree_view_row_inserted                    (GtkTreeModel    *model,
693                                                            GtkTreePath     *path,
694                                                            GtkTreeIter     *iter,
695                                                            gpointer         data);
696 static void gtk_tree_view_row_has_child_toggled           (GtkTreeModel    *model,
697                                                            GtkTreePath     *path,
698                                                            GtkTreeIter     *iter,
699                                                            gpointer         data);
700 static void gtk_tree_view_row_deleted                     (GtkTreeModel    *model,
701                                                            GtkTreePath     *path,
702                                                            gpointer         data);
703 static void gtk_tree_view_rows_reordered                  (GtkTreeModel    *model,
704                                                            GtkTreePath     *parent,
705                                                            GtkTreeIter     *iter,
706                                                            gint            *new_order,
707                                                            gpointer         data);
708
709 /* Incremental reflow */
710 static gboolean validate_row             (GtkTreeView *tree_view,
711                                           GtkRBTree   *tree,
712                                           GtkRBNode   *node,
713                                           GtkTreeIter *iter,
714                                           GtkTreePath *path);
715 static void     validate_visible_area    (GtkTreeView *tree_view);
716 static gboolean validate_rows_handler    (GtkTreeView *tree_view);
717 static gboolean do_validate_rows         (GtkTreeView *tree_view,
718                                           gboolean     size_request);
719 static gboolean validate_rows            (GtkTreeView *tree_view);
720 static gboolean presize_handler_callback (gpointer     data);
721 static void     install_presize_handler  (GtkTreeView *tree_view);
722 static void     install_scroll_sync_handler (GtkTreeView *tree_view);
723 static void     gtk_tree_view_set_top_row   (GtkTreeView *tree_view,
724                                              GtkTreePath *path,
725                                              gint         offset);
726 static void     gtk_tree_view_dy_to_top_row (GtkTreeView *tree_view);
727 static void     gtk_tree_view_top_row_to_dy (GtkTreeView *tree_view);
728 static void     invalidate_empty_focus      (GtkTreeView *tree_view);
729
730 /* Internal functions */
731 static gboolean gtk_tree_view_is_expander_column             (GtkTreeView        *tree_view,
732                                                               GtkTreeViewColumn  *column);
733 static inline gboolean gtk_tree_view_draw_expanders          (GtkTreeView        *tree_view);
734 static void     gtk_tree_view_add_move_binding               (GtkBindingSet      *binding_set,
735                                                               guint               keyval,
736                                                               guint               modmask,
737                                                               gboolean            add_shifted_binding,
738                                                               GtkMovementStep     step,
739                                                               gint                count);
740 static gint     gtk_tree_view_unref_and_check_selection_tree (GtkTreeView        *tree_view,
741                                                               GtkRBTree          *tree);
742 static void     gtk_tree_view_queue_draw_path                (GtkTreeView        *tree_view,
743                                                               GtkTreePath        *path,
744                                                               const GdkRectangle *clip_rect);
745 static void     gtk_tree_view_queue_draw_arrow               (GtkTreeView        *tree_view,
746                                                               GtkRBTree          *tree,
747                                                               GtkRBNode          *node);
748 static void     gtk_tree_view_draw_arrow                     (GtkTreeView        *tree_view,
749                                                               cairo_t            *cr,
750                                                               GtkRBTree          *tree,
751                                                               GtkRBNode          *node);
752 static void     gtk_tree_view_get_arrow_xrange               (GtkTreeView        *tree_view,
753                                                               GtkRBTree          *tree,
754                                                               gint               *x1,
755                                                               gint               *x2);
756 static gint     gtk_tree_view_new_column_width               (GtkTreeView        *tree_view,
757                                                               gint                i,
758                                                               gint               *x);
759 static void     gtk_tree_view_adjustment_changed             (GtkAdjustment      *adjustment,
760                                                               GtkTreeView        *tree_view);
761 static void     gtk_tree_view_build_tree                     (GtkTreeView        *tree_view,
762                                                               GtkRBTree          *tree,
763                                                               GtkTreeIter        *iter,
764                                                               gint                depth,
765                                                               gboolean            recurse);
766 static void     gtk_tree_view_clamp_node_visible             (GtkTreeView        *tree_view,
767                                                               GtkRBTree          *tree,
768                                                               GtkRBNode          *node);
769 static void     gtk_tree_view_clamp_column_visible           (GtkTreeView        *tree_view,
770                                                               GtkTreeViewColumn  *column,
771                                                               gboolean            focus_to_cell);
772 static gboolean gtk_tree_view_maybe_begin_dragging_row       (GtkTreeView        *tree_view,
773                                                               GdkEventMotion     *event);
774 static void     gtk_tree_view_focus_to_cursor                (GtkTreeView        *tree_view);
775 static void     gtk_tree_view_move_cursor_up_down            (GtkTreeView        *tree_view,
776                                                               gint                count);
777 static void     gtk_tree_view_move_cursor_page_up_down       (GtkTreeView        *tree_view,
778                                                               gint                count);
779 static void     gtk_tree_view_move_cursor_left_right         (GtkTreeView        *tree_view,
780                                                               gint                count);
781 static void     gtk_tree_view_move_cursor_start_end          (GtkTreeView        *tree_view,
782                                                               gint                count);
783 static gboolean gtk_tree_view_real_collapse_row              (GtkTreeView        *tree_view,
784                                                               GtkTreePath        *path,
785                                                               GtkRBTree          *tree,
786                                                               GtkRBNode          *node,
787                                                               gboolean            animate);
788 static gboolean gtk_tree_view_real_expand_row                (GtkTreeView        *tree_view,
789                                                               GtkTreePath        *path,
790                                                               GtkRBTree          *tree,
791                                                               GtkRBNode          *node,
792                                                               gboolean            open_all,
793                                                               gboolean            animate);
794 static void     gtk_tree_view_real_set_cursor                (GtkTreeView        *tree_view,
795                                                               GtkTreePath        *path,
796                                                               SetCursorFlags      flags);
797 static gboolean gtk_tree_view_has_can_focus_cell             (GtkTreeView        *tree_view);
798 static void     column_sizing_notify                         (GObject            *object,
799                                                               GParamSpec         *pspec,
800                                                               gpointer            data);
801 static void     gtk_tree_view_stop_rubber_band               (GtkTreeView        *tree_view);
802 static void     update_prelight                              (GtkTreeView        *tree_view,
803                                                               int                 x,
804                                                               int                 y);
805
806 static inline gint gtk_tree_view_get_effective_header_height (GtkTreeView *tree_view);
807
808 static inline gint gtk_tree_view_get_cell_area_y_offset      (GtkTreeView *tree_view,
809                                                               GtkRBTree   *tree,
810                                                               GtkRBNode   *node,
811                                                               gint         vertical_separator);
812 static inline gint gtk_tree_view_get_cell_area_height        (GtkTreeView *tree_view,
813                                                               GtkRBNode   *node,
814                                                               gint         vertical_separator);
815
816 static inline gint gtk_tree_view_get_row_y_offset            (GtkTreeView *tree_view,
817                                                               GtkRBTree   *tree,
818                                                               GtkRBNode   *node);
819 static inline gint gtk_tree_view_get_row_height              (GtkTreeView *tree_view,
820                                                               GtkRBNode   *node);
821
822 /* interactive search */
823 static void     gtk_tree_view_ensure_interactive_directory (GtkTreeView *tree_view);
824 static void     gtk_tree_view_search_dialog_hide        (GtkWidget        *search_dialog,
825                                                          GtkTreeView      *tree_view,
826                                                          GdkDevice        *device);
827 static void     gtk_tree_view_search_position_func      (GtkTreeView      *tree_view,
828                                                          GtkWidget        *search_dialog,
829                                                          gpointer          user_data);
830 static void     gtk_tree_view_search_disable_popdown    (GtkEntry         *entry,
831                                                          GtkMenu          *menu,
832                                                          gpointer          data);
833 static void     gtk_tree_view_search_preedit_changed    (GtkIMContext     *im_context,
834                                                          GtkTreeView      *tree_view);
835 static void     gtk_tree_view_search_activate           (GtkEntry         *entry,
836                                                          GtkTreeView      *tree_view);
837 static gboolean gtk_tree_view_real_search_enable_popdown(gpointer          data);
838 static void     gtk_tree_view_search_enable_popdown     (GtkWidget        *widget,
839                                                          gpointer          data);
840 static gboolean gtk_tree_view_search_delete_event       (GtkWidget        *widget,
841                                                          GdkEventAny      *event,
842                                                          GtkTreeView      *tree_view);
843 static gboolean gtk_tree_view_search_button_press_event (GtkWidget        *widget,
844                                                          GdkEventButton   *event,
845                                                          GtkTreeView      *tree_view);
846 static gboolean gtk_tree_view_search_scroll_event       (GtkWidget        *entry,
847                                                          GdkEventScroll   *event,
848                                                          GtkTreeView      *tree_view);
849 static gboolean gtk_tree_view_search_key_press_event    (GtkWidget        *entry,
850                                                          GdkEventKey      *event,
851                                                          GtkTreeView      *tree_view);
852 static gboolean gtk_tree_view_search_move               (GtkWidget        *window,
853                                                          GtkTreeView      *tree_view,
854                                                          gboolean          up);
855 static gboolean gtk_tree_view_search_equal_func         (GtkTreeModel     *model,
856                                                          gint              column,
857                                                          const gchar      *key,
858                                                          GtkTreeIter      *iter,
859                                                          gpointer          search_data);
860 static gboolean gtk_tree_view_search_iter               (GtkTreeModel     *model,
861                                                          GtkTreeSelection *selection,
862                                                          GtkTreeIter      *iter,
863                                                          const gchar      *text,
864                                                          gint             *count,
865                                                          gint              n);
866 static void     gtk_tree_view_search_init               (GtkWidget        *entry,
867                                                          GtkTreeView      *tree_view);
868 static void     gtk_tree_view_put                       (GtkTreeView      *tree_view,
869                                                          GtkWidget        *child_widget,
870                                                          gint              x,
871                                                          gint              y,
872                                                          gint              width,
873                                                          gint              height);
874 static gboolean gtk_tree_view_start_editing             (GtkTreeView      *tree_view,
875                                                          GtkTreePath      *cursor_path,
876                                                          gboolean          edit_only);
877 static void gtk_tree_view_stop_editing                  (GtkTreeView *tree_view,
878                                                          gboolean     cancel_editing);
879 static gboolean gtk_tree_view_real_start_interactive_search (GtkTreeView *tree_view,
880                                                              GdkDevice   *device,
881                                                              gboolean     keybinding);
882 static gboolean gtk_tree_view_start_interactive_search      (GtkTreeView *tree_view);
883 static GtkTreeViewColumn *gtk_tree_view_get_drop_column (GtkTreeView       *tree_view,
884                                                          GtkTreeViewColumn *column,
885                                                          gint               drop_position);
886
887 /* GtkBuildable */
888 static void     gtk_tree_view_buildable_add_child          (GtkBuildable      *tree_view,
889                                                             GtkBuilder        *builder,
890                                                             GObject           *child,
891                                                             const gchar       *type);
892 static GObject *gtk_tree_view_buildable_get_internal_child (GtkBuildable      *buildable,
893                                                             GtkBuilder        *builder,
894                                                             const gchar       *childname);
895 static void     gtk_tree_view_buildable_init               (GtkBuildableIface *iface);
896
897 static GtkAdjustment *gtk_tree_view_do_get_hadjustment (GtkTreeView   *tree_view);
898 static void           gtk_tree_view_do_set_hadjustment (GtkTreeView   *tree_view,
899                                                         GtkAdjustment *adjustment);
900 static GtkAdjustment *gtk_tree_view_do_get_vadjustment (GtkTreeView   *tree_view);
901 static void           gtk_tree_view_do_set_vadjustment (GtkTreeView   *tree_view,
902                                                         GtkAdjustment *adjustment);
903
904 static gboolean scroll_row_timeout                   (gpointer     data);
905 static void     add_scroll_timeout                   (GtkTreeView *tree_view);
906 static void     remove_scroll_timeout                (GtkTreeView *tree_view);
907
908 static guint tree_view_signals [LAST_SIGNAL] = { 0 };
909
910 \f
911
912 /* GType Methods
913  */
914
915 G_DEFINE_TYPE_WITH_CODE (GtkTreeView, gtk_tree_view, GTK_TYPE_CONTAINER,
916                          G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
917                                                 gtk_tree_view_buildable_init)
918                          G_IMPLEMENT_INTERFACE (GTK_TYPE_SCROLLABLE, NULL))
919
920 static void
921 gtk_tree_view_class_init (GtkTreeViewClass *class)
922 {
923   GObjectClass *o_class;
924   GtkWidgetClass *widget_class;
925   GtkContainerClass *container_class;
926   GtkBindingSet *binding_set;
927
928   binding_set = gtk_binding_set_by_class (class);
929
930   o_class = (GObjectClass *) class;
931   widget_class = (GtkWidgetClass *) class;
932   container_class = (GtkContainerClass *) class;
933
934   /* GObject signals */
935   o_class->set_property = gtk_tree_view_set_property;
936   o_class->get_property = gtk_tree_view_get_property;
937   o_class->finalize = gtk_tree_view_finalize;
938
939   /* GtkWidget signals */
940   widget_class->destroy = gtk_tree_view_destroy;
941   widget_class->map = gtk_tree_view_map;
942   widget_class->realize = gtk_tree_view_realize;
943   widget_class->unrealize = gtk_tree_view_unrealize;
944   widget_class->get_preferred_width = gtk_tree_view_get_preferred_width;
945   widget_class->get_preferred_height = gtk_tree_view_get_preferred_height;
946   widget_class->size_allocate = gtk_tree_view_size_allocate;
947   widget_class->button_press_event = gtk_tree_view_button_press;
948   widget_class->button_release_event = gtk_tree_view_button_release;
949   widget_class->grab_broken_event = gtk_tree_view_grab_broken;
950   /*widget_class->configure_event = gtk_tree_view_configure;*/
951   widget_class->motion_notify_event = gtk_tree_view_motion;
952   widget_class->draw = gtk_tree_view_draw;
953   widget_class->key_press_event = gtk_tree_view_key_press;
954   widget_class->key_release_event = gtk_tree_view_key_release;
955   widget_class->enter_notify_event = gtk_tree_view_enter_notify;
956   widget_class->leave_notify_event = gtk_tree_view_leave_notify;
957   widget_class->focus_out_event = gtk_tree_view_focus_out;
958   widget_class->drag_begin = gtk_tree_view_drag_begin;
959   widget_class->drag_end = gtk_tree_view_drag_end;
960   widget_class->drag_data_get = gtk_tree_view_drag_data_get;
961   widget_class->drag_data_delete = gtk_tree_view_drag_data_delete;
962   widget_class->drag_leave = gtk_tree_view_drag_leave;
963   widget_class->drag_motion = gtk_tree_view_drag_motion;
964   widget_class->drag_drop = gtk_tree_view_drag_drop;
965   widget_class->drag_data_received = gtk_tree_view_drag_data_received;
966   widget_class->focus = gtk_tree_view_focus;
967   widget_class->grab_focus = gtk_tree_view_grab_focus;
968   widget_class->style_updated = gtk_tree_view_style_updated;
969   widget_class->grab_notify = gtk_tree_view_grab_notify;
970   widget_class->state_flags_changed = gtk_tree_view_state_flags_changed;
971
972   /* GtkContainer signals */
973   container_class->remove = gtk_tree_view_remove;
974   container_class->forall = gtk_tree_view_forall;
975   container_class->set_focus_child = gtk_tree_view_set_focus_child;
976   container_class->get_path_for_child = gtk_tree_view_get_path_for_child;
977
978   class->move_cursor = gtk_tree_view_real_move_cursor;
979   class->select_all = gtk_tree_view_real_select_all;
980   class->unselect_all = gtk_tree_view_real_unselect_all;
981   class->select_cursor_row = gtk_tree_view_real_select_cursor_row;
982   class->toggle_cursor_row = gtk_tree_view_real_toggle_cursor_row;
983   class->expand_collapse_cursor_row = gtk_tree_view_real_expand_collapse_cursor_row;
984   class->select_cursor_parent = gtk_tree_view_real_select_cursor_parent;
985   class->start_interactive_search = gtk_tree_view_start_interactive_search;
986
987   /* Properties */
988
989   g_object_class_install_property (o_class,
990                                    PROP_MODEL,
991                                    g_param_spec_object ("model",
992                                                         P_("TreeView Model"),
993                                                         P_("The model for the tree view"),
994                                                         GTK_TYPE_TREE_MODEL,
995                                                         GTK_PARAM_READWRITE));
996
997   g_object_class_override_property (o_class, PROP_HADJUSTMENT,    "hadjustment");
998   g_object_class_override_property (o_class, PROP_VADJUSTMENT,    "vadjustment");
999   g_object_class_override_property (o_class, PROP_HSCROLL_POLICY, "hscroll-policy");
1000   g_object_class_override_property (o_class, PROP_VSCROLL_POLICY, "vscroll-policy");
1001
1002   g_object_class_install_property (o_class,
1003                                    PROP_HEADERS_VISIBLE,
1004                                    g_param_spec_boolean ("headers-visible",
1005                                                          P_("Headers Visible"),
1006                                                          P_("Show the column header buttons"),
1007                                                          TRUE,
1008                                                          GTK_PARAM_READWRITE));
1009
1010   g_object_class_install_property (o_class,
1011                                    PROP_HEADERS_CLICKABLE,
1012                                    g_param_spec_boolean ("headers-clickable",
1013                                                          P_("Headers Clickable"),
1014                                                          P_("Column headers respond to click events"),
1015                                                          TRUE,
1016                                                          GTK_PARAM_READWRITE));
1017
1018   g_object_class_install_property (o_class,
1019                                    PROP_EXPANDER_COLUMN,
1020                                    g_param_spec_object ("expander-column",
1021                                                         P_("Expander Column"),
1022                                                         P_("Set the column for the expander column"),
1023                                                         GTK_TYPE_TREE_VIEW_COLUMN,
1024                                                         GTK_PARAM_READWRITE));
1025
1026   g_object_class_install_property (o_class,
1027                                    PROP_REORDERABLE,
1028                                    g_param_spec_boolean ("reorderable",
1029                                                          P_("Reorderable"),
1030                                                          P_("View is reorderable"),
1031                                                          FALSE,
1032                                                          GTK_PARAM_READWRITE));
1033
1034   g_object_class_install_property (o_class,
1035                                    PROP_RULES_HINT,
1036                                    g_param_spec_boolean ("rules-hint",
1037                                                          P_("Rules Hint"),
1038                                                          P_("Set a hint to the theme engine to draw rows in alternating colors"),
1039                                                          FALSE,
1040                                                          GTK_PARAM_READWRITE));
1041
1042     g_object_class_install_property (o_class,
1043                                      PROP_ENABLE_SEARCH,
1044                                      g_param_spec_boolean ("enable-search",
1045                                                            P_("Enable Search"),
1046                                                            P_("View allows user to search through columns interactively"),
1047                                                            TRUE,
1048                                                            GTK_PARAM_READWRITE));
1049
1050     g_object_class_install_property (o_class,
1051                                      PROP_SEARCH_COLUMN,
1052                                      g_param_spec_int ("search-column",
1053                                                        P_("Search Column"),
1054                                                        P_("Model column to search through during interactive search"),
1055                                                        -1,
1056                                                        G_MAXINT,
1057                                                        -1,
1058                                                        GTK_PARAM_READWRITE));
1059
1060     /**
1061      * GtkTreeView:fixed-height-mode:
1062      *
1063      * Setting the ::fixed-height-mode property to %TRUE speeds up 
1064      * #GtkTreeView by assuming that all rows have the same height. 
1065      * Only enable this option if all rows are the same height.  
1066      * Please see gtk_tree_view_set_fixed_height_mode() for more 
1067      * information on this option.
1068      *
1069      * Since: 2.4
1070      **/
1071     g_object_class_install_property (o_class,
1072                                      PROP_FIXED_HEIGHT_MODE,
1073                                      g_param_spec_boolean ("fixed-height-mode",
1074                                                            P_("Fixed Height Mode"),
1075                                                            P_("Speeds up GtkTreeView by assuming that all rows have the same height"),
1076                                                            FALSE,
1077                                                            GTK_PARAM_READWRITE));
1078     
1079     /**
1080      * GtkTreeView:hover-selection:
1081      * 
1082      * Enables or disables the hover selection mode of @tree_view.
1083      * Hover selection makes the selected row follow the pointer.
1084      * Currently, this works only for the selection modes 
1085      * %GTK_SELECTION_SINGLE and %GTK_SELECTION_BROWSE.
1086      *
1087      * This mode is primarily intended for treeviews in popups, e.g.
1088      * in #GtkComboBox or #GtkEntryCompletion.
1089      *
1090      * Since: 2.6
1091      */
1092     g_object_class_install_property (o_class,
1093                                      PROP_HOVER_SELECTION,
1094                                      g_param_spec_boolean ("hover-selection",
1095                                                            P_("Hover Selection"),
1096                                                            P_("Whether the selection should follow the pointer"),
1097                                                            FALSE,
1098                                                            GTK_PARAM_READWRITE));
1099
1100     /**
1101      * GtkTreeView:hover-expand:
1102      * 
1103      * Enables or disables the hover expansion mode of @tree_view.
1104      * Hover expansion makes rows expand or collapse if the pointer moves 
1105      * over them.
1106      *
1107      * This mode is primarily intended for treeviews in popups, e.g.
1108      * in #GtkComboBox or #GtkEntryCompletion.
1109      *
1110      * Since: 2.6
1111      */
1112     g_object_class_install_property (o_class,
1113                                      PROP_HOVER_EXPAND,
1114                                      g_param_spec_boolean ("hover-expand",
1115                                                            P_("Hover Expand"),
1116                                                            P_("Whether rows should be expanded/collapsed when the pointer moves over them"),
1117                                                            FALSE,
1118                                                            GTK_PARAM_READWRITE));
1119
1120     /**
1121      * GtkTreeView:show-expanders:
1122      *
1123      * %TRUE if the view has expanders.
1124      *
1125      * Since: 2.12
1126      */
1127     g_object_class_install_property (o_class,
1128                                      PROP_SHOW_EXPANDERS,
1129                                      g_param_spec_boolean ("show-expanders",
1130                                                            P_("Show Expanders"),
1131                                                            P_("View has expanders"),
1132                                                            TRUE,
1133                                                            GTK_PARAM_READWRITE));
1134
1135     /**
1136      * GtkTreeView:level-indentation:
1137      *
1138      * Extra indentation for each level.
1139      *
1140      * Since: 2.12
1141      */
1142     g_object_class_install_property (o_class,
1143                                      PROP_LEVEL_INDENTATION,
1144                                      g_param_spec_int ("level-indentation",
1145                                                        P_("Level Indentation"),
1146                                                        P_("Extra indentation for each level"),
1147                                                        0,
1148                                                        G_MAXINT,
1149                                                        0,
1150                                                        GTK_PARAM_READWRITE));
1151
1152     g_object_class_install_property (o_class,
1153                                      PROP_RUBBER_BANDING,
1154                                      g_param_spec_boolean ("rubber-banding",
1155                                                            P_("Rubber Banding"),
1156                                                            P_("Whether to enable selection of multiple items by dragging the mouse pointer"),
1157                                                            FALSE,
1158                                                            GTK_PARAM_READWRITE));
1159
1160     g_object_class_install_property (o_class,
1161                                      PROP_ENABLE_GRID_LINES,
1162                                      g_param_spec_enum ("enable-grid-lines",
1163                                                         P_("Enable Grid Lines"),
1164                                                         P_("Whether grid lines should be drawn in the tree view"),
1165                                                         GTK_TYPE_TREE_VIEW_GRID_LINES,
1166                                                         GTK_TREE_VIEW_GRID_LINES_NONE,
1167                                                         GTK_PARAM_READWRITE));
1168
1169     g_object_class_install_property (o_class,
1170                                      PROP_ENABLE_TREE_LINES,
1171                                      g_param_spec_boolean ("enable-tree-lines",
1172                                                            P_("Enable Tree Lines"),
1173                                                            P_("Whether tree lines should be drawn in the tree view"),
1174                                                            FALSE,
1175                                                            GTK_PARAM_READWRITE));
1176
1177     g_object_class_install_property (o_class,
1178                                      PROP_TOOLTIP_COLUMN,
1179                                      g_param_spec_int ("tooltip-column",
1180                                                        P_("Tooltip Column"),
1181                                                        P_("The column in the model containing the tooltip texts for the rows"),
1182                                                        -1,
1183                                                        G_MAXINT,
1184                                                        -1,
1185                                                        GTK_PARAM_READWRITE));
1186
1187   /* Style properties */
1188 #define _TREE_VIEW_EXPANDER_SIZE 14
1189 #define _TREE_VIEW_VERTICAL_SEPARATOR 2
1190 #define _TREE_VIEW_HORIZONTAL_SEPARATOR 2
1191
1192   gtk_widget_class_install_style_property (widget_class,
1193                                            g_param_spec_int ("expander-size",
1194                                                              P_("Expander Size"),
1195                                                              P_("Size of the expander arrow"),
1196                                                              0,
1197                                                              G_MAXINT,
1198                                                              _TREE_VIEW_EXPANDER_SIZE,
1199                                                              GTK_PARAM_READABLE));
1200
1201   gtk_widget_class_install_style_property (widget_class,
1202                                            g_param_spec_int ("vertical-separator",
1203                                                              P_("Vertical Separator Width"),
1204                                                              P_("Vertical space between cells.  Must be an even number"),
1205                                                              0,
1206                                                              G_MAXINT,
1207                                                              _TREE_VIEW_VERTICAL_SEPARATOR,
1208                                                              GTK_PARAM_READABLE));
1209
1210   gtk_widget_class_install_style_property (widget_class,
1211                                            g_param_spec_int ("horizontal-separator",
1212                                                              P_("Horizontal Separator Width"),
1213                                                              P_("Horizontal space between cells.  Must be an even number"),
1214                                                              0,
1215                                                              G_MAXINT,
1216                                                              _TREE_VIEW_HORIZONTAL_SEPARATOR,
1217                                                              GTK_PARAM_READABLE));
1218
1219   gtk_widget_class_install_style_property (widget_class,
1220                                            g_param_spec_boolean ("allow-rules",
1221                                                                  P_("Allow Rules"),
1222                                                                  P_("Allow drawing of alternating color rows"),
1223                                                                  TRUE,
1224                                                                  GTK_PARAM_READABLE));
1225
1226   gtk_widget_class_install_style_property (widget_class,
1227                                            g_param_spec_boolean ("indent-expanders",
1228                                                                  P_("Indent Expanders"),
1229                                                                  P_("Make the expanders indented"),
1230                                                                  TRUE,
1231                                                                  GTK_PARAM_READABLE));
1232
1233   gtk_widget_class_install_style_property (widget_class,
1234                                            g_param_spec_boxed ("even-row-color",
1235                                                                P_("Even Row Color"),
1236                                                                P_("Color to use for even rows"),
1237                                                                GDK_TYPE_COLOR,
1238                                                                GTK_PARAM_READABLE));
1239
1240   gtk_widget_class_install_style_property (widget_class,
1241                                            g_param_spec_boxed ("odd-row-color",
1242                                                                P_("Odd Row Color"),
1243                                                                P_("Color to use for odd rows"),
1244                                                                GDK_TYPE_COLOR,
1245                                                                GTK_PARAM_READABLE));
1246
1247   gtk_widget_class_install_style_property (widget_class,
1248                                            g_param_spec_int ("grid-line-width",
1249                                                              P_("Grid line width"),
1250                                                              P_("Width, in pixels, of the tree view grid lines"),
1251                                                              0, G_MAXINT, 1,
1252                                                              GTK_PARAM_READABLE));
1253
1254   gtk_widget_class_install_style_property (widget_class,
1255                                            g_param_spec_int ("tree-line-width",
1256                                                              P_("Tree line width"),
1257                                                              P_("Width, in pixels, of the tree view lines"),
1258                                                              0, G_MAXINT, 1,
1259                                                              GTK_PARAM_READABLE));
1260
1261   gtk_widget_class_install_style_property (widget_class,
1262                                            g_param_spec_string ("grid-line-pattern",
1263                                                                 P_("Grid line pattern"),
1264                                                                 P_("Dash pattern used to draw the tree view grid lines"),
1265                                                                 "\1\1",
1266                                                                 GTK_PARAM_READABLE));
1267
1268   gtk_widget_class_install_style_property (widget_class,
1269                                            g_param_spec_string ("tree-line-pattern",
1270                                                                 P_("Tree line pattern"),
1271                                                                 P_("Dash pattern used to draw the tree view lines"),
1272                                                                 "\1\1",
1273                                                                 GTK_PARAM_READABLE));
1274
1275   /* Signals */
1276   /**
1277    * GtkTreeView::row-activated:
1278    * @tree_view: the object on which the signal is emitted
1279    * @path: the #GtkTreePath for the activated row
1280    * @column: the #GtkTreeViewColumn in which the activation occurred
1281    *
1282    * The "row-activated" signal is emitted when the method
1283    * gtk_tree_view_row_activated() is called or the user double clicks 
1284    * a treeview row. It is also emitted when a non-editable row is 
1285    * selected and one of the keys: Space, Shift+Space, Return or 
1286    * Enter is pressed.
1287    * 
1288    * For selection handling refer to the <link linkend="TreeWidget">tree 
1289    * widget conceptual overview</link> as well as #GtkTreeSelection.
1290    */
1291   tree_view_signals[ROW_ACTIVATED] =
1292     g_signal_new (I_("row-activated"),
1293                   G_TYPE_FROM_CLASS (o_class),
1294                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1295                   G_STRUCT_OFFSET (GtkTreeViewClass, row_activated),
1296                   NULL, NULL,
1297                   _gtk_marshal_VOID__BOXED_OBJECT,
1298                   G_TYPE_NONE, 2,
1299                   GTK_TYPE_TREE_PATH,
1300                   GTK_TYPE_TREE_VIEW_COLUMN);
1301
1302   /**
1303    * GtkTreeView::test-expand-row:
1304    * @tree_view: the object on which the signal is emitted
1305    * @iter: the tree iter of the row to expand
1306    * @path: a tree path that points to the row 
1307    * 
1308    * The given row is about to be expanded (show its children nodes). Use this
1309    * signal if you need to control the expandability of individual rows.
1310    *
1311    * Returns: %FALSE to allow expansion, %TRUE to reject
1312    */
1313   tree_view_signals[TEST_EXPAND_ROW] =
1314     g_signal_new (I_("test-expand-row"),
1315                   G_TYPE_FROM_CLASS (o_class),
1316                   G_SIGNAL_RUN_LAST,
1317                   G_STRUCT_OFFSET (GtkTreeViewClass, test_expand_row),
1318                   _gtk_boolean_handled_accumulator, NULL,
1319                   _gtk_marshal_BOOLEAN__BOXED_BOXED,
1320                   G_TYPE_BOOLEAN, 2,
1321                   GTK_TYPE_TREE_ITER,
1322                   GTK_TYPE_TREE_PATH);
1323
1324   /**
1325    * GtkTreeView::test-collapse-row:
1326    * @tree_view: the object on which the signal is emitted
1327    * @iter: the tree iter of the row to collapse
1328    * @path: a tree path that points to the row 
1329    * 
1330    * The given row is about to be collapsed (hide its children nodes). Use this
1331    * signal if you need to control the collapsibility of individual rows.
1332    *
1333    * Returns: %FALSE to allow collapsing, %TRUE to reject
1334    */
1335   tree_view_signals[TEST_COLLAPSE_ROW] =
1336     g_signal_new (I_("test-collapse-row"),
1337                   G_TYPE_FROM_CLASS (o_class),
1338                   G_SIGNAL_RUN_LAST,
1339                   G_STRUCT_OFFSET (GtkTreeViewClass, test_collapse_row),
1340                   _gtk_boolean_handled_accumulator, NULL,
1341                   _gtk_marshal_BOOLEAN__BOXED_BOXED,
1342                   G_TYPE_BOOLEAN, 2,
1343                   GTK_TYPE_TREE_ITER,
1344                   GTK_TYPE_TREE_PATH);
1345
1346   /**
1347    * GtkTreeView::row-expanded:
1348    * @tree_view: the object on which the signal is emitted
1349    * @iter: the tree iter of the expanded row
1350    * @path: a tree path that points to the row 
1351    * 
1352    * The given row has been expanded (child nodes are shown).
1353    */
1354   tree_view_signals[ROW_EXPANDED] =
1355     g_signal_new (I_("row-expanded"),
1356                   G_TYPE_FROM_CLASS (o_class),
1357                   G_SIGNAL_RUN_LAST,
1358                   G_STRUCT_OFFSET (GtkTreeViewClass, row_expanded),
1359                   NULL, NULL,
1360                   _gtk_marshal_VOID__BOXED_BOXED,
1361                   G_TYPE_NONE, 2,
1362                   GTK_TYPE_TREE_ITER,
1363                   GTK_TYPE_TREE_PATH);
1364
1365   /**
1366    * GtkTreeView::row-collapsed:
1367    * @tree_view: the object on which the signal is emitted
1368    * @iter: the tree iter of the collapsed row
1369    * @path: a tree path that points to the row 
1370    * 
1371    * The given row has been collapsed (child nodes are hidden).
1372    */
1373   tree_view_signals[ROW_COLLAPSED] =
1374     g_signal_new (I_("row-collapsed"),
1375                   G_TYPE_FROM_CLASS (o_class),
1376                   G_SIGNAL_RUN_LAST,
1377                   G_STRUCT_OFFSET (GtkTreeViewClass, row_collapsed),
1378                   NULL, NULL,
1379                   _gtk_marshal_VOID__BOXED_BOXED,
1380                   G_TYPE_NONE, 2,
1381                   GTK_TYPE_TREE_ITER,
1382                   GTK_TYPE_TREE_PATH);
1383
1384   /**
1385    * GtkTreeView::columns-changed:
1386    * @tree_view: the object on which the signal is emitted 
1387    * 
1388    * The number of columns of the treeview has changed.
1389    */
1390   tree_view_signals[COLUMNS_CHANGED] =
1391     g_signal_new (I_("columns-changed"),
1392                   G_TYPE_FROM_CLASS (o_class),
1393                   G_SIGNAL_RUN_LAST,
1394                   G_STRUCT_OFFSET (GtkTreeViewClass, columns_changed),
1395                   NULL, NULL,
1396                   _gtk_marshal_VOID__VOID,
1397                   G_TYPE_NONE, 0);
1398
1399   /**
1400    * GtkTreeView::cursor-changed:
1401    * @tree_view: the object on which the signal is emitted
1402    * 
1403    * The position of the cursor (focused cell) has changed.
1404    */
1405   tree_view_signals[CURSOR_CHANGED] =
1406     g_signal_new (I_("cursor-changed"),
1407                   G_TYPE_FROM_CLASS (o_class),
1408                   G_SIGNAL_RUN_LAST,
1409                   G_STRUCT_OFFSET (GtkTreeViewClass, cursor_changed),
1410                   NULL, NULL,
1411                   _gtk_marshal_VOID__VOID,
1412                   G_TYPE_NONE, 0);
1413
1414   tree_view_signals[MOVE_CURSOR] =
1415     g_signal_new (I_("move-cursor"),
1416                   G_TYPE_FROM_CLASS (o_class),
1417                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1418                   G_STRUCT_OFFSET (GtkTreeViewClass, move_cursor),
1419                   NULL, NULL,
1420                   _gtk_marshal_BOOLEAN__ENUM_INT,
1421                   G_TYPE_BOOLEAN, 2,
1422                   GTK_TYPE_MOVEMENT_STEP,
1423                   G_TYPE_INT);
1424
1425   tree_view_signals[SELECT_ALL] =
1426     g_signal_new (I_("select-all"),
1427                   G_TYPE_FROM_CLASS (o_class),
1428                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1429                   G_STRUCT_OFFSET (GtkTreeViewClass, select_all),
1430                   NULL, NULL,
1431                   _gtk_marshal_BOOLEAN__VOID,
1432                   G_TYPE_BOOLEAN, 0);
1433
1434   tree_view_signals[UNSELECT_ALL] =
1435     g_signal_new (I_("unselect-all"),
1436                   G_TYPE_FROM_CLASS (o_class),
1437                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1438                   G_STRUCT_OFFSET (GtkTreeViewClass, unselect_all),
1439                   NULL, NULL,
1440                   _gtk_marshal_BOOLEAN__VOID,
1441                   G_TYPE_BOOLEAN, 0);
1442
1443   tree_view_signals[SELECT_CURSOR_ROW] =
1444     g_signal_new (I_("select-cursor-row"),
1445                   G_TYPE_FROM_CLASS (o_class),
1446                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1447                   G_STRUCT_OFFSET (GtkTreeViewClass, select_cursor_row),
1448                   NULL, NULL,
1449                   _gtk_marshal_BOOLEAN__BOOLEAN,
1450                   G_TYPE_BOOLEAN, 1,
1451                   G_TYPE_BOOLEAN);
1452
1453   tree_view_signals[TOGGLE_CURSOR_ROW] =
1454     g_signal_new (I_("toggle-cursor-row"),
1455                   G_TYPE_FROM_CLASS (o_class),
1456                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1457                   G_STRUCT_OFFSET (GtkTreeViewClass, toggle_cursor_row),
1458                   NULL, NULL,
1459                   _gtk_marshal_BOOLEAN__VOID,
1460                   G_TYPE_BOOLEAN, 0);
1461
1462   tree_view_signals[EXPAND_COLLAPSE_CURSOR_ROW] =
1463     g_signal_new (I_("expand-collapse-cursor-row"),
1464                   G_TYPE_FROM_CLASS (o_class),
1465                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1466                   G_STRUCT_OFFSET (GtkTreeViewClass, expand_collapse_cursor_row),
1467                   NULL, NULL,
1468                   _gtk_marshal_BOOLEAN__BOOLEAN_BOOLEAN_BOOLEAN,
1469                   G_TYPE_BOOLEAN, 3,
1470                   G_TYPE_BOOLEAN,
1471                   G_TYPE_BOOLEAN,
1472                   G_TYPE_BOOLEAN);
1473
1474   tree_view_signals[SELECT_CURSOR_PARENT] =
1475     g_signal_new (I_("select-cursor-parent"),
1476                   G_TYPE_FROM_CLASS (o_class),
1477                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1478                   G_STRUCT_OFFSET (GtkTreeViewClass, select_cursor_parent),
1479                   NULL, NULL,
1480                   _gtk_marshal_BOOLEAN__VOID,
1481                   G_TYPE_BOOLEAN, 0);
1482
1483   tree_view_signals[START_INTERACTIVE_SEARCH] =
1484     g_signal_new (I_("start-interactive-search"),
1485                   G_TYPE_FROM_CLASS (o_class),
1486                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1487                   G_STRUCT_OFFSET (GtkTreeViewClass, start_interactive_search),
1488                   NULL, NULL,
1489                   _gtk_marshal_BOOLEAN__VOID,
1490                   G_TYPE_BOOLEAN, 0);
1491
1492   /* Key bindings */
1493   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Up, 0, TRUE,
1494                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
1495   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Up, 0, TRUE,
1496                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
1497
1498   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Down, 0, TRUE,
1499                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
1500   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Down, 0, TRUE,
1501                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
1502
1503   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_p, GDK_CONTROL_MASK, FALSE,
1504                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
1505
1506   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_n, GDK_CONTROL_MASK, FALSE,
1507                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
1508
1509   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Home, 0, TRUE,
1510                                   GTK_MOVEMENT_BUFFER_ENDS, -1);
1511   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Home, 0, TRUE,
1512                                   GTK_MOVEMENT_BUFFER_ENDS, -1);
1513
1514   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_End, 0, TRUE,
1515                                   GTK_MOVEMENT_BUFFER_ENDS, 1);
1516   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_End, 0, TRUE,
1517                                   GTK_MOVEMENT_BUFFER_ENDS, 1);
1518
1519   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Page_Up, 0, TRUE,
1520                                   GTK_MOVEMENT_PAGES, -1);
1521   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Page_Up, 0, TRUE,
1522                                   GTK_MOVEMENT_PAGES, -1);
1523
1524   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Page_Down, 0, TRUE,
1525                                   GTK_MOVEMENT_PAGES, 1);
1526   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Page_Down, 0, TRUE,
1527                                   GTK_MOVEMENT_PAGES, 1);
1528
1529
1530   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Right, 0, "move-cursor", 2,
1531                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1532                                 G_TYPE_INT, 1);
1533
1534   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Left, 0, "move-cursor", 2,
1535                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1536                                 G_TYPE_INT, -1);
1537
1538   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Right, 0, "move-cursor", 2,
1539                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1540                                 G_TYPE_INT, 1);
1541
1542   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Left, 0, "move-cursor", 2,
1543                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1544                                 G_TYPE_INT, -1);
1545
1546   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Right, GDK_CONTROL_MASK,
1547                                 "move-cursor", 2,
1548                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1549                                 G_TYPE_INT, 1);
1550
1551   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Left, GDK_CONTROL_MASK,
1552                                 "move-cursor", 2,
1553                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1554                                 G_TYPE_INT, -1);
1555
1556   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Right, GDK_CONTROL_MASK,
1557                                 "move-cursor", 2,
1558                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1559                                 G_TYPE_INT, 1);
1560
1561   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Left, GDK_CONTROL_MASK,
1562                                 "move-cursor", 2,
1563                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1564                                 G_TYPE_INT, -1);
1565
1566   gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, GDK_CONTROL_MASK, "toggle-cursor-row", 0);
1567   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Space, GDK_CONTROL_MASK, "toggle-cursor-row", 0);
1568
1569   gtk_binding_entry_add_signal (binding_set, GDK_KEY_a, GDK_CONTROL_MASK, "select-all", 0);
1570   gtk_binding_entry_add_signal (binding_set, GDK_KEY_slash, GDK_CONTROL_MASK, "select-all", 0);
1571
1572   gtk_binding_entry_add_signal (binding_set, GDK_KEY_A, GDK_CONTROL_MASK | GDK_SHIFT_MASK, "unselect-all", 0);
1573   gtk_binding_entry_add_signal (binding_set, GDK_KEY_backslash, GDK_CONTROL_MASK, "unselect-all", 0);
1574
1575   gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, GDK_SHIFT_MASK, "select-cursor-row", 1,
1576                                 G_TYPE_BOOLEAN, TRUE);
1577   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Space, GDK_SHIFT_MASK, "select-cursor-row", 1,
1578                                 G_TYPE_BOOLEAN, TRUE);
1579
1580   gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, 0, "select-cursor-row", 1,
1581                                 G_TYPE_BOOLEAN, TRUE);
1582   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Space, 0, "select-cursor-row", 1,
1583                                 G_TYPE_BOOLEAN, TRUE);
1584   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Return, 0, "select-cursor-row", 1,
1585                                 G_TYPE_BOOLEAN, TRUE);
1586   gtk_binding_entry_add_signal (binding_set, GDK_KEY_ISO_Enter, 0, "select-cursor-row", 1,
1587                                 G_TYPE_BOOLEAN, TRUE);
1588   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Enter, 0, "select-cursor-row", 1,
1589                                 G_TYPE_BOOLEAN, TRUE);
1590
1591   /* expand and collapse rows */
1592   gtk_binding_entry_add_signal (binding_set, GDK_KEY_plus, 0, "expand-collapse-cursor-row", 3,
1593                                 G_TYPE_BOOLEAN, TRUE,
1594                                 G_TYPE_BOOLEAN, TRUE,
1595                                 G_TYPE_BOOLEAN, FALSE);
1596
1597   gtk_binding_entry_add_signal (binding_set, GDK_KEY_asterisk, 0,
1598                                 "expand-collapse-cursor-row", 3,
1599                                 G_TYPE_BOOLEAN, TRUE,
1600                                 G_TYPE_BOOLEAN, TRUE,
1601                                 G_TYPE_BOOLEAN, TRUE);
1602   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Multiply, 0,
1603                                 "expand-collapse-cursor-row", 3,
1604                                 G_TYPE_BOOLEAN, TRUE,
1605                                 G_TYPE_BOOLEAN, TRUE,
1606                                 G_TYPE_BOOLEAN, TRUE);
1607
1608   gtk_binding_entry_add_signal (binding_set, GDK_KEY_slash, 0,
1609                                 "expand-collapse-cursor-row", 3,
1610                                 G_TYPE_BOOLEAN, TRUE,
1611                                 G_TYPE_BOOLEAN, FALSE,
1612                                 G_TYPE_BOOLEAN, FALSE);
1613   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Divide, 0,
1614                                 "expand-collapse-cursor-row", 3,
1615                                 G_TYPE_BOOLEAN, TRUE,
1616                                 G_TYPE_BOOLEAN, FALSE,
1617                                 G_TYPE_BOOLEAN, FALSE);
1618
1619   /* Not doable on US keyboards */
1620   gtk_binding_entry_add_signal (binding_set, GDK_KEY_plus, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1621                                 G_TYPE_BOOLEAN, TRUE,
1622                                 G_TYPE_BOOLEAN, TRUE,
1623                                 G_TYPE_BOOLEAN, TRUE);
1624   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Add, 0, "expand-collapse-cursor-row", 3,
1625                                 G_TYPE_BOOLEAN, TRUE,
1626                                 G_TYPE_BOOLEAN, TRUE,
1627                                 G_TYPE_BOOLEAN, FALSE);
1628   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Add, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1629                                 G_TYPE_BOOLEAN, TRUE,
1630                                 G_TYPE_BOOLEAN, TRUE,
1631                                 G_TYPE_BOOLEAN, TRUE);
1632   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Add, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1633                                 G_TYPE_BOOLEAN, TRUE,
1634                                 G_TYPE_BOOLEAN, TRUE,
1635                                 G_TYPE_BOOLEAN, TRUE);
1636   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Right, GDK_SHIFT_MASK,
1637                                 "expand-collapse-cursor-row", 3,
1638                                 G_TYPE_BOOLEAN, FALSE,
1639                                 G_TYPE_BOOLEAN, TRUE,
1640                                 G_TYPE_BOOLEAN, TRUE);
1641   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Right, GDK_SHIFT_MASK,
1642                                 "expand-collapse-cursor-row", 3,
1643                                 G_TYPE_BOOLEAN, FALSE,
1644                                 G_TYPE_BOOLEAN, TRUE,
1645                                 G_TYPE_BOOLEAN, TRUE);
1646   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Right,
1647                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1648                                 "expand-collapse-cursor-row", 3,
1649                                 G_TYPE_BOOLEAN, FALSE,
1650                                 G_TYPE_BOOLEAN, TRUE,
1651                                 G_TYPE_BOOLEAN, TRUE);
1652   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Right,
1653                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1654                                 "expand-collapse-cursor-row", 3,
1655                                 G_TYPE_BOOLEAN, FALSE,
1656                                 G_TYPE_BOOLEAN, TRUE,
1657                                 G_TYPE_BOOLEAN, TRUE);
1658
1659   gtk_binding_entry_add_signal (binding_set, GDK_KEY_minus, 0, "expand-collapse-cursor-row", 3,
1660                                 G_TYPE_BOOLEAN, TRUE,
1661                                 G_TYPE_BOOLEAN, FALSE,
1662                                 G_TYPE_BOOLEAN, FALSE);
1663   gtk_binding_entry_add_signal (binding_set, GDK_KEY_minus, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1664                                 G_TYPE_BOOLEAN, TRUE,
1665                                 G_TYPE_BOOLEAN, FALSE,
1666                                 G_TYPE_BOOLEAN, TRUE);
1667   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Subtract, 0, "expand-collapse-cursor-row", 3,
1668                                 G_TYPE_BOOLEAN, TRUE,
1669                                 G_TYPE_BOOLEAN, FALSE,
1670                                 G_TYPE_BOOLEAN, FALSE);
1671   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Subtract, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1672                                 G_TYPE_BOOLEAN, TRUE,
1673                                 G_TYPE_BOOLEAN, FALSE,
1674                                 G_TYPE_BOOLEAN, TRUE);
1675   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Left, GDK_SHIFT_MASK,
1676                                 "expand-collapse-cursor-row", 3,
1677                                 G_TYPE_BOOLEAN, FALSE,
1678                                 G_TYPE_BOOLEAN, FALSE,
1679                                 G_TYPE_BOOLEAN, TRUE);
1680   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Left, GDK_SHIFT_MASK,
1681                                 "expand-collapse-cursor-row", 3,
1682                                 G_TYPE_BOOLEAN, FALSE,
1683                                 G_TYPE_BOOLEAN, FALSE,
1684                                 G_TYPE_BOOLEAN, TRUE);
1685   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Left,
1686                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1687                                 "expand-collapse-cursor-row", 3,
1688                                 G_TYPE_BOOLEAN, FALSE,
1689                                 G_TYPE_BOOLEAN, FALSE,
1690                                 G_TYPE_BOOLEAN, TRUE);
1691   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Left,
1692                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1693                                 "expand-collapse-cursor-row", 3,
1694                                 G_TYPE_BOOLEAN, FALSE,
1695                                 G_TYPE_BOOLEAN, FALSE,
1696                                 G_TYPE_BOOLEAN, TRUE);
1697
1698   gtk_binding_entry_add_signal (binding_set, GDK_KEY_BackSpace, 0, "select-cursor-parent", 0);
1699   gtk_binding_entry_add_signal (binding_set, GDK_KEY_BackSpace, GDK_CONTROL_MASK, "select-cursor-parent", 0);
1700
1701   gtk_binding_entry_add_signal (binding_set, GDK_KEY_f, GDK_CONTROL_MASK, "start-interactive-search", 0);
1702
1703   gtk_binding_entry_add_signal (binding_set, GDK_KEY_F, GDK_CONTROL_MASK, "start-interactive-search", 0);
1704
1705   g_type_class_add_private (o_class, sizeof (GtkTreeViewPrivate));
1706
1707   gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_TREE_VIEW_ACCESSIBLE);
1708 }
1709
1710 static void
1711 gtk_tree_view_init (GtkTreeView *tree_view)
1712 {
1713   tree_view->priv = G_TYPE_INSTANCE_GET_PRIVATE (tree_view, GTK_TYPE_TREE_VIEW, GtkTreeViewPrivate);
1714
1715   gtk_widget_set_can_focus (GTK_WIDGET (tree_view), TRUE);
1716   gtk_widget_set_redraw_on_allocate (GTK_WIDGET (tree_view), FALSE);
1717
1718   tree_view->priv->show_expanders = TRUE;
1719   tree_view->priv->draw_keyfocus = TRUE;
1720   tree_view->priv->headers_visible = TRUE;
1721
1722   /* We need some padding */
1723   tree_view->priv->dy = 0;
1724   tree_view->priv->cursor_offset = 0;
1725   tree_view->priv->n_columns = 0;
1726   tree_view->priv->header_height = 1;
1727   tree_view->priv->x_drag = 0;
1728   tree_view->priv->drag_pos = -1;
1729   tree_view->priv->header_has_focus = FALSE;
1730   tree_view->priv->pressed_button = -1;
1731   tree_view->priv->press_start_x = -1;
1732   tree_view->priv->press_start_y = -1;
1733   tree_view->priv->reorderable = FALSE;
1734   tree_view->priv->presize_handler_timer = 0;
1735   tree_view->priv->scroll_sync_timer = 0;
1736   tree_view->priv->fixed_height = -1;
1737   tree_view->priv->fixed_height_mode = FALSE;
1738   tree_view->priv->fixed_height_check = 0;
1739   tree_view->priv->selection = _gtk_tree_selection_new_with_tree_view (tree_view);
1740   tree_view->priv->enable_search = TRUE;
1741   tree_view->priv->search_column = -1;
1742   tree_view->priv->search_position_func = gtk_tree_view_search_position_func;
1743   tree_view->priv->search_equal_func = gtk_tree_view_search_equal_func;
1744   tree_view->priv->search_custom_entry_set = FALSE;
1745   tree_view->priv->typeselect_flush_timeout = 0;
1746   tree_view->priv->init_hadjust_value = TRUE;    
1747   tree_view->priv->width = 0;
1748           
1749   tree_view->priv->hover_selection = FALSE;
1750   tree_view->priv->hover_expand = FALSE;
1751
1752   tree_view->priv->level_indentation = 0;
1753
1754   tree_view->priv->rubber_banding_enable = FALSE;
1755
1756   tree_view->priv->grid_lines = GTK_TREE_VIEW_GRID_LINES_NONE;
1757   tree_view->priv->tree_lines_enabled = FALSE;
1758
1759   tree_view->priv->tooltip_column = -1;
1760
1761   tree_view->priv->post_validation_flag = FALSE;
1762
1763   tree_view->priv->last_button_x = -1;
1764   tree_view->priv->last_button_y = -1;
1765
1766   tree_view->priv->event_last_x = -10000;
1767   tree_view->priv->event_last_y = -10000;
1768
1769   gtk_tree_view_do_set_vadjustment (tree_view, NULL);
1770   gtk_tree_view_do_set_hadjustment (tree_view, NULL);
1771 }
1772
1773 \f
1774
1775 /* GObject Methods
1776  */
1777
1778 static void
1779 gtk_tree_view_set_property (GObject         *object,
1780                             guint            prop_id,
1781                             const GValue    *value,
1782                             GParamSpec      *pspec)
1783 {
1784   GtkTreeView *tree_view;
1785
1786   tree_view = GTK_TREE_VIEW (object);
1787
1788   switch (prop_id)
1789     {
1790     case PROP_MODEL:
1791       gtk_tree_view_set_model (tree_view, g_value_get_object (value));
1792       break;
1793     case PROP_HADJUSTMENT:
1794       gtk_tree_view_do_set_hadjustment (tree_view, g_value_get_object (value));
1795       break;
1796     case PROP_VADJUSTMENT:
1797       gtk_tree_view_do_set_vadjustment (tree_view, g_value_get_object (value));
1798       break;
1799     case PROP_HSCROLL_POLICY:
1800       tree_view->priv->hscroll_policy = g_value_get_enum (value);
1801       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
1802       break;
1803     case PROP_VSCROLL_POLICY:
1804       tree_view->priv->vscroll_policy = g_value_get_enum (value);
1805       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
1806       break;
1807     case PROP_HEADERS_VISIBLE:
1808       gtk_tree_view_set_headers_visible (tree_view, g_value_get_boolean (value));
1809       break;
1810     case PROP_HEADERS_CLICKABLE:
1811       gtk_tree_view_set_headers_clickable (tree_view, g_value_get_boolean (value));
1812       break;
1813     case PROP_EXPANDER_COLUMN:
1814       gtk_tree_view_set_expander_column (tree_view, g_value_get_object (value));
1815       break;
1816     case PROP_REORDERABLE:
1817       gtk_tree_view_set_reorderable (tree_view, g_value_get_boolean (value));
1818       break;
1819     case PROP_RULES_HINT:
1820       gtk_tree_view_set_rules_hint (tree_view, g_value_get_boolean (value));
1821       break;
1822     case PROP_ENABLE_SEARCH:
1823       gtk_tree_view_set_enable_search (tree_view, g_value_get_boolean (value));
1824       break;
1825     case PROP_SEARCH_COLUMN:
1826       gtk_tree_view_set_search_column (tree_view, g_value_get_int (value));
1827       break;
1828     case PROP_FIXED_HEIGHT_MODE:
1829       gtk_tree_view_set_fixed_height_mode (tree_view, g_value_get_boolean (value));
1830       break;
1831     case PROP_HOVER_SELECTION:
1832       tree_view->priv->hover_selection = g_value_get_boolean (value);
1833       break;
1834     case PROP_HOVER_EXPAND:
1835       tree_view->priv->hover_expand = g_value_get_boolean (value);
1836       break;
1837     case PROP_SHOW_EXPANDERS:
1838       gtk_tree_view_set_show_expanders (tree_view, g_value_get_boolean (value));
1839       break;
1840     case PROP_LEVEL_INDENTATION:
1841       tree_view->priv->level_indentation = g_value_get_int (value);
1842       break;
1843     case PROP_RUBBER_BANDING:
1844       tree_view->priv->rubber_banding_enable = g_value_get_boolean (value);
1845       break;
1846     case PROP_ENABLE_GRID_LINES:
1847       gtk_tree_view_set_grid_lines (tree_view, g_value_get_enum (value));
1848       break;
1849     case PROP_ENABLE_TREE_LINES:
1850       gtk_tree_view_set_enable_tree_lines (tree_view, g_value_get_boolean (value));
1851       break;
1852     case PROP_TOOLTIP_COLUMN:
1853       gtk_tree_view_set_tooltip_column (tree_view, g_value_get_int (value));
1854       break;
1855     default:
1856       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1857       break;
1858     }
1859 }
1860
1861 static void
1862 gtk_tree_view_get_property (GObject    *object,
1863                             guint       prop_id,
1864                             GValue     *value,
1865                             GParamSpec *pspec)
1866 {
1867   GtkTreeView *tree_view;
1868
1869   tree_view = GTK_TREE_VIEW (object);
1870
1871   switch (prop_id)
1872     {
1873     case PROP_MODEL:
1874       g_value_set_object (value, tree_view->priv->model);
1875       break;
1876     case PROP_HADJUSTMENT:
1877       g_value_set_object (value, tree_view->priv->hadjustment);
1878       break;
1879     case PROP_VADJUSTMENT:
1880       g_value_set_object (value, tree_view->priv->vadjustment);
1881       break;
1882     case PROP_HSCROLL_POLICY:
1883       g_value_set_enum (value, tree_view->priv->hscroll_policy);
1884       break;
1885     case PROP_VSCROLL_POLICY:
1886       g_value_set_enum (value, tree_view->priv->vscroll_policy);
1887       break;
1888     case PROP_HEADERS_VISIBLE:
1889       g_value_set_boolean (value, gtk_tree_view_get_headers_visible (tree_view));
1890       break;
1891     case PROP_HEADERS_CLICKABLE:
1892       g_value_set_boolean (value, gtk_tree_view_get_headers_clickable (tree_view));
1893       break;
1894     case PROP_EXPANDER_COLUMN:
1895       g_value_set_object (value, tree_view->priv->expander_column);
1896       break;
1897     case PROP_REORDERABLE:
1898       g_value_set_boolean (value, tree_view->priv->reorderable);
1899       break;
1900     case PROP_RULES_HINT:
1901       g_value_set_boolean (value, tree_view->priv->has_rules);
1902       break;
1903     case PROP_ENABLE_SEARCH:
1904       g_value_set_boolean (value, tree_view->priv->enable_search);
1905       break;
1906     case PROP_SEARCH_COLUMN:
1907       g_value_set_int (value, tree_view->priv->search_column);
1908       break;
1909     case PROP_FIXED_HEIGHT_MODE:
1910       g_value_set_boolean (value, tree_view->priv->fixed_height_mode);
1911       break;
1912     case PROP_HOVER_SELECTION:
1913       g_value_set_boolean (value, tree_view->priv->hover_selection);
1914       break;
1915     case PROP_HOVER_EXPAND:
1916       g_value_set_boolean (value, tree_view->priv->hover_expand);
1917       break;
1918     case PROP_SHOW_EXPANDERS:
1919       g_value_set_boolean (value, tree_view->priv->show_expanders);
1920       break;
1921     case PROP_LEVEL_INDENTATION:
1922       g_value_set_int (value, tree_view->priv->level_indentation);
1923       break;
1924     case PROP_RUBBER_BANDING:
1925       g_value_set_boolean (value, tree_view->priv->rubber_banding_enable);
1926       break;
1927     case PROP_ENABLE_GRID_LINES:
1928       g_value_set_enum (value, tree_view->priv->grid_lines);
1929       break;
1930     case PROP_ENABLE_TREE_LINES:
1931       g_value_set_boolean (value, tree_view->priv->tree_lines_enabled);
1932       break;
1933     case PROP_TOOLTIP_COLUMN:
1934       g_value_set_int (value, tree_view->priv->tooltip_column);
1935       break;
1936     default:
1937       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1938       break;
1939     }
1940 }
1941
1942 static void
1943 gtk_tree_view_finalize (GObject *object)
1944 {
1945   G_OBJECT_CLASS (gtk_tree_view_parent_class)->finalize (object);
1946 }
1947
1948
1949 static GtkBuildableIface *parent_buildable_iface;
1950
1951 static void
1952 gtk_tree_view_buildable_init (GtkBuildableIface *iface)
1953 {
1954   parent_buildable_iface = g_type_interface_peek_parent (iface);
1955   iface->add_child = gtk_tree_view_buildable_add_child;
1956   iface->get_internal_child = gtk_tree_view_buildable_get_internal_child;
1957 }
1958
1959 static void
1960 gtk_tree_view_buildable_add_child (GtkBuildable *tree_view,
1961                                    GtkBuilder  *builder,
1962                                    GObject     *child,
1963                                    const gchar *type)
1964 {
1965   gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), GTK_TREE_VIEW_COLUMN (child));
1966 }
1967
1968 static GObject *
1969 gtk_tree_view_buildable_get_internal_child (GtkBuildable      *buildable,
1970                                             GtkBuilder        *builder,
1971                                             const gchar       *childname)
1972 {
1973     if (strcmp (childname, "selection") == 0)
1974       return G_OBJECT (GTK_TREE_VIEW (buildable)->priv->selection);
1975     
1976     return parent_buildable_iface->get_internal_child (buildable,
1977                                                        builder,
1978                                                        childname);
1979 }
1980
1981 /* GtkWidget Methods
1982  */
1983
1984 static void
1985 gtk_tree_view_free_rbtree (GtkTreeView *tree_view)
1986 {
1987   _gtk_rbtree_free (tree_view->priv->tree);
1988   
1989   tree_view->priv->tree = NULL;
1990   tree_view->priv->button_pressed_node = NULL;
1991   tree_view->priv->button_pressed_tree = NULL;
1992   tree_view->priv->prelight_tree = NULL;
1993   tree_view->priv->prelight_node = NULL;
1994   tree_view->priv->expanded_collapsed_node = NULL;
1995   tree_view->priv->expanded_collapsed_tree = NULL;
1996 }
1997
1998 static void
1999 gtk_tree_view_destroy (GtkWidget *widget)
2000 {
2001   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2002   GList *list;
2003
2004   gtk_tree_view_stop_editing (tree_view, TRUE);
2005
2006   if (tree_view->priv->columns != NULL)
2007     {
2008       list = tree_view->priv->columns;
2009       while (list)
2010         {
2011           GtkTreeViewColumn *column;
2012           column = GTK_TREE_VIEW_COLUMN (list->data);
2013           list = list->next;
2014           gtk_tree_view_remove_column (tree_view, column);
2015         }
2016       tree_view->priv->columns = NULL;
2017     }
2018
2019   if (tree_view->priv->tree != NULL)
2020     {
2021       gtk_tree_view_unref_and_check_selection_tree (tree_view, tree_view->priv->tree);
2022
2023       gtk_tree_view_free_rbtree (tree_view);
2024     }
2025
2026   if (tree_view->priv->selection != NULL)
2027     {
2028       _gtk_tree_selection_set_tree_view (tree_view->priv->selection, NULL);
2029       g_object_unref (tree_view->priv->selection);
2030       tree_view->priv->selection = NULL;
2031     }
2032
2033   if (tree_view->priv->scroll_to_path != NULL)
2034     {
2035       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
2036       tree_view->priv->scroll_to_path = NULL;
2037     }
2038
2039   if (tree_view->priv->drag_dest_row != NULL)
2040     {
2041       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
2042       tree_view->priv->drag_dest_row = NULL;
2043     }
2044
2045   if (tree_view->priv->top_row != NULL)
2046     {
2047       gtk_tree_row_reference_free (tree_view->priv->top_row);
2048       tree_view->priv->top_row = NULL;
2049     }
2050
2051   if (tree_view->priv->column_drop_func_data &&
2052       tree_view->priv->column_drop_func_data_destroy)
2053     {
2054       tree_view->priv->column_drop_func_data_destroy (tree_view->priv->column_drop_func_data);
2055       tree_view->priv->column_drop_func_data = NULL;
2056     }
2057
2058   if (tree_view->priv->destroy_count_destroy &&
2059       tree_view->priv->destroy_count_data)
2060     {
2061       tree_view->priv->destroy_count_destroy (tree_view->priv->destroy_count_data);
2062       tree_view->priv->destroy_count_data = NULL;
2063     }
2064
2065   gtk_tree_row_reference_free (tree_view->priv->anchor);
2066   tree_view->priv->anchor = NULL;
2067
2068   /* destroy interactive search dialog */
2069   if (tree_view->priv->search_window)
2070     {
2071       gtk_widget_destroy (tree_view->priv->search_window);
2072       tree_view->priv->search_window = NULL;
2073       tree_view->priv->search_entry = NULL;
2074       if (tree_view->priv->typeselect_flush_timeout)
2075         {
2076           g_source_remove (tree_view->priv->typeselect_flush_timeout);
2077           tree_view->priv->typeselect_flush_timeout = 0;
2078         }
2079     }
2080
2081   if (tree_view->priv->search_destroy && tree_view->priv->search_user_data)
2082     {
2083       tree_view->priv->search_destroy (tree_view->priv->search_user_data);
2084       tree_view->priv->search_user_data = NULL;
2085     }
2086
2087   if (tree_view->priv->search_position_destroy && tree_view->priv->search_position_user_data)
2088     {
2089       tree_view->priv->search_position_destroy (tree_view->priv->search_position_user_data);
2090       tree_view->priv->search_position_user_data = NULL;
2091     }
2092
2093   if (tree_view->priv->row_separator_destroy && tree_view->priv->row_separator_data)
2094     {
2095       tree_view->priv->row_separator_destroy (tree_view->priv->row_separator_data);
2096       tree_view->priv->row_separator_data = NULL;
2097     }
2098   
2099   gtk_tree_view_set_model (tree_view, NULL);
2100
2101   if (tree_view->priv->hadjustment)
2102     {
2103       g_object_unref (tree_view->priv->hadjustment);
2104       tree_view->priv->hadjustment = NULL;
2105     }
2106   if (tree_view->priv->vadjustment)
2107     {
2108       g_object_unref (tree_view->priv->vadjustment);
2109       tree_view->priv->vadjustment = NULL;
2110     }
2111
2112   GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->destroy (widget);
2113 }
2114
2115 /* GtkWidget::map helper */
2116 static void
2117 gtk_tree_view_map_buttons (GtkTreeView *tree_view)
2118 {
2119   GList *list;
2120
2121   g_return_if_fail (gtk_widget_get_mapped (GTK_WIDGET (tree_view)));
2122
2123   if (tree_view->priv->headers_visible)
2124     {
2125       GtkTreeViewColumn *column;
2126       GtkWidget         *button;
2127       GdkWindow         *window;
2128
2129       for (list = tree_view->priv->columns; list; list = list->next)
2130         {
2131           column = list->data;
2132           button = gtk_tree_view_column_get_button (column);
2133
2134           if (gtk_tree_view_column_get_visible (column) && button)
2135             gtk_widget_show_now (button);
2136
2137           if (gtk_widget_get_visible (button) &&
2138               !gtk_widget_get_mapped (button))
2139             gtk_widget_map (button);
2140         }
2141       for (list = tree_view->priv->columns; list; list = list->next)
2142         {
2143           column = list->data;
2144           if (gtk_tree_view_column_get_visible (column) == FALSE)
2145             continue;
2146
2147           window = _gtk_tree_view_column_get_window (column);
2148           if (gtk_tree_view_column_get_resizable (column))
2149             {
2150               gdk_window_raise (window);
2151               gdk_window_show (window);
2152             }
2153           else
2154             gdk_window_hide (window);
2155         }
2156       gdk_window_show (tree_view->priv->header_window);
2157     }
2158 }
2159
2160 static void
2161 gtk_tree_view_map (GtkWidget *widget)
2162 {
2163   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2164   GList *tmp_list;
2165
2166   gtk_widget_set_mapped (widget, TRUE);
2167
2168   tmp_list = tree_view->priv->children;
2169   while (tmp_list)
2170     {
2171       GtkTreeViewChild *child = tmp_list->data;
2172       tmp_list = tmp_list->next;
2173
2174       if (gtk_widget_get_visible (child->widget))
2175         {
2176           if (!gtk_widget_get_mapped (child->widget))
2177             gtk_widget_map (child->widget);
2178         }
2179     }
2180   gdk_window_show (tree_view->priv->bin_window);
2181
2182   gtk_tree_view_map_buttons (tree_view);
2183
2184   gdk_window_show (gtk_widget_get_window (widget));
2185 }
2186
2187 static void
2188 gtk_tree_view_ensure_background (GtkTreeView *tree_view)
2189 {
2190   GtkStyleContext *context;
2191
2192   context = gtk_widget_get_style_context (GTK_WIDGET (tree_view));
2193
2194   gtk_style_context_save (context);
2195   gtk_style_context_add_class (context, GTK_STYLE_CLASS_VIEW);
2196   gtk_style_context_set_background (context, tree_view->priv->bin_window);
2197   gtk_style_context_set_background (context, gtk_widget_get_window (GTK_WIDGET (tree_view)));
2198   gtk_style_context_restore (context);
2199
2200   gtk_style_context_set_background (context, tree_view->priv->header_window);
2201 }
2202
2203 static void
2204 gtk_tree_view_realize (GtkWidget *widget)
2205 {
2206   GtkAllocation allocation;
2207   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2208   GdkWindow *window;
2209   GdkWindowAttr attributes;
2210   GList *tmp_list;
2211   gint attributes_mask;
2212
2213   gtk_widget_set_realized (widget, TRUE);
2214
2215   gtk_widget_get_allocation (widget, &allocation);
2216
2217   /* Make the main, clipping window */
2218   attributes.window_type = GDK_WINDOW_CHILD;
2219   attributes.x = allocation.x;
2220   attributes.y = allocation.y;
2221   attributes.width = allocation.width;
2222   attributes.height = allocation.height;
2223   attributes.wclass = GDK_INPUT_OUTPUT;
2224   attributes.visual = gtk_widget_get_visual (widget);
2225   attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK;
2226
2227   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
2228
2229   window = gdk_window_new (gtk_widget_get_parent_window (widget),
2230                            &attributes, attributes_mask);
2231   gtk_widget_set_window (widget, window);
2232   gdk_window_set_user_data (window, widget);
2233
2234   gtk_widget_get_allocation (widget, &allocation);
2235
2236   /* Make the window for the tree */
2237   attributes.x = 0;
2238   attributes.y = gtk_tree_view_get_effective_header_height (tree_view);
2239   attributes.width = MAX (tree_view->priv->width, allocation.width);
2240   attributes.height = allocation.height;
2241   attributes.event_mask = (GDK_EXPOSURE_MASK |
2242                            GDK_SCROLL_MASK |
2243                            GDK_SMOOTH_SCROLL_MASK |
2244                            GDK_POINTER_MOTION_MASK |
2245                            GDK_ENTER_NOTIFY_MASK |
2246                            GDK_LEAVE_NOTIFY_MASK |
2247                            GDK_BUTTON_PRESS_MASK |
2248                            GDK_BUTTON_RELEASE_MASK |
2249                            gtk_widget_get_events (widget));
2250
2251   tree_view->priv->bin_window = gdk_window_new (window,
2252                                                 &attributes, attributes_mask);
2253   gdk_window_set_user_data (tree_view->priv->bin_window, widget);
2254
2255   gtk_widget_get_allocation (widget, &allocation);
2256
2257   /* Make the column header window */
2258   attributes.x = 0;
2259   attributes.y = 0;
2260   attributes.width = MAX (tree_view->priv->width, allocation.width);
2261   attributes.height = tree_view->priv->header_height;
2262   attributes.event_mask = (GDK_EXPOSURE_MASK |
2263                            GDK_SCROLL_MASK |
2264                            GDK_ENTER_NOTIFY_MASK |
2265                            GDK_LEAVE_NOTIFY_MASK |
2266                            GDK_BUTTON_PRESS_MASK |
2267                            GDK_BUTTON_RELEASE_MASK |
2268                            GDK_KEY_PRESS_MASK |
2269                            GDK_KEY_RELEASE_MASK |
2270                            gtk_widget_get_events (widget));
2271
2272   tree_view->priv->header_window = gdk_window_new (window,
2273                                                    &attributes, attributes_mask);
2274   gdk_window_set_user_data (tree_view->priv->header_window, widget);
2275
2276   gtk_tree_view_ensure_background (tree_view);
2277
2278   tmp_list = tree_view->priv->children;
2279   while (tmp_list)
2280     {
2281       GtkTreeViewChild *child = tmp_list->data;
2282       tmp_list = tmp_list->next;
2283
2284       gtk_widget_set_parent_window (child->widget, tree_view->priv->bin_window);
2285     }
2286
2287   for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
2288     _gtk_tree_view_column_realize_button (GTK_TREE_VIEW_COLUMN (tmp_list->data));
2289
2290   /* Need to call those here, since they create GCs */
2291   gtk_tree_view_set_grid_lines (tree_view, tree_view->priv->grid_lines);
2292   gtk_tree_view_set_enable_tree_lines (tree_view, tree_view->priv->tree_lines_enabled);
2293
2294   install_presize_handler (tree_view); 
2295 }
2296
2297 static void
2298 gtk_tree_view_unrealize (GtkWidget *widget)
2299 {
2300   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2301   GtkTreeViewPrivate *priv = tree_view->priv;
2302   GList *list;
2303
2304   if (priv->scroll_timeout != 0)
2305     {
2306       g_source_remove (priv->scroll_timeout);
2307       priv->scroll_timeout = 0;
2308     }
2309
2310   if (priv->auto_expand_timeout != 0)
2311     {
2312       g_source_remove (priv->auto_expand_timeout);
2313       priv->auto_expand_timeout = 0;
2314     }
2315
2316   if (priv->open_dest_timeout != 0)
2317     {
2318       g_source_remove (priv->open_dest_timeout);
2319       priv->open_dest_timeout = 0;
2320     }
2321
2322   if (priv->presize_handler_timer != 0)
2323     {
2324       g_source_remove (priv->presize_handler_timer);
2325       priv->presize_handler_timer = 0;
2326     }
2327
2328   if (priv->validate_rows_timer != 0)
2329     {
2330       g_source_remove (priv->validate_rows_timer);
2331       priv->validate_rows_timer = 0;
2332     }
2333
2334   if (priv->scroll_sync_timer != 0)
2335     {
2336       g_source_remove (priv->scroll_sync_timer);
2337       priv->scroll_sync_timer = 0;
2338     }
2339
2340   if (priv->typeselect_flush_timeout)
2341     {
2342       g_source_remove (priv->typeselect_flush_timeout);
2343       priv->typeselect_flush_timeout = 0;
2344     }
2345   
2346   for (list = priv->columns; list; list = list->next)
2347     _gtk_tree_view_column_unrealize_button (GTK_TREE_VIEW_COLUMN (list->data));
2348
2349   gdk_window_set_user_data (priv->bin_window, NULL);
2350   gdk_window_destroy (priv->bin_window);
2351   priv->bin_window = NULL;
2352
2353   gdk_window_set_user_data (priv->header_window, NULL);
2354   gdk_window_destroy (priv->header_window);
2355   priv->header_window = NULL;
2356
2357   if (priv->drag_window)
2358     {
2359       gdk_window_set_user_data (priv->drag_window, NULL);
2360       gdk_window_destroy (priv->drag_window);
2361       priv->drag_window = NULL;
2362     }
2363
2364   if (priv->drag_highlight_window)
2365     {
2366       gdk_window_set_user_data (priv->drag_highlight_window, NULL);
2367       gdk_window_destroy (priv->drag_highlight_window);
2368       priv->drag_highlight_window = NULL;
2369     }
2370
2371   GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->unrealize (widget);
2372 }
2373
2374 /* GtkWidget::size_request helper */
2375 static void
2376 gtk_tree_view_size_request_columns (GtkTreeView *tree_view)
2377 {
2378   GList *list;
2379
2380   tree_view->priv->header_height = 0;
2381
2382   for (list = tree_view->priv->columns; list; list = list->next)
2383     {
2384       GtkRequisition     requisition;
2385       GtkTreeViewColumn *column = list->data;
2386       GtkWidget         *button = gtk_tree_view_column_get_button (column);
2387
2388       if (button == NULL)
2389         continue;
2390
2391       gtk_widget_get_preferred_size (button, &requisition, NULL);
2392       tree_view->priv->header_height = MAX (tree_view->priv->header_height, requisition.height);
2393     }
2394 }
2395
2396
2397 /* Called only by ::size_request */
2398 static void
2399 gtk_tree_view_update_size (GtkTreeView *tree_view)
2400 {
2401   GList *list;
2402   GtkTreeViewColumn *column;
2403   gint i;
2404
2405   if (tree_view->priv->model == NULL)
2406     {
2407       tree_view->priv->width = 0;
2408       tree_view->priv->prev_width = 0;                   
2409       tree_view->priv->height = 0;
2410       return;
2411     }
2412
2413   tree_view->priv->prev_width = tree_view->priv->width;  
2414   tree_view->priv->width = 0;
2415
2416   /* keep this in sync with size_allocate below */
2417   for (list = tree_view->priv->columns, i = 0; list; list = list->next, i++)
2418     {
2419       column = list->data;
2420       if (!gtk_tree_view_column_get_visible (column))
2421         continue;
2422
2423       tree_view->priv->width += _gtk_tree_view_column_request_width (column);
2424     }
2425
2426   if (tree_view->priv->tree == NULL)
2427     tree_view->priv->height = 0;
2428   else
2429     tree_view->priv->height = tree_view->priv->tree->root->offset;
2430 }
2431
2432 static void
2433 gtk_tree_view_size_request (GtkWidget      *widget,
2434                             GtkRequisition *requisition,
2435                             gboolean        may_validate)
2436 {
2437   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2438
2439   if (may_validate)
2440     {
2441       /* we validate some rows initially just to make sure we have some size.
2442        * In practice, with a lot of static lists, this should get a good width.
2443        */
2444       do_validate_rows (tree_view, FALSE);
2445     }
2446
2447   gtk_tree_view_size_request_columns (tree_view);
2448   gtk_tree_view_update_size (GTK_TREE_VIEW (widget));
2449
2450   requisition->width = tree_view->priv->width;
2451   requisition->height = tree_view->priv->height + gtk_tree_view_get_effective_header_height (tree_view);
2452 }
2453
2454 static void
2455 gtk_tree_view_get_preferred_width (GtkWidget *widget,
2456                                    gint      *minimum,
2457                                    gint      *natural)
2458 {
2459   GtkRequisition requisition;
2460
2461   gtk_tree_view_size_request (widget, &requisition, TRUE);
2462
2463   *minimum = *natural = requisition.width;
2464 }
2465
2466 static void
2467 gtk_tree_view_get_preferred_height (GtkWidget *widget,
2468                                     gint      *minimum,
2469                                     gint      *natural)
2470 {
2471   GtkRequisition requisition;
2472
2473   gtk_tree_view_size_request (widget, &requisition, TRUE);
2474
2475   *minimum = *natural = requisition.height;
2476 }
2477
2478 static int
2479 gtk_tree_view_calculate_width_before_expander (GtkTreeView *tree_view)
2480 {
2481   int width = 0;
2482   GList *list;
2483   gboolean rtl;
2484
2485   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2486   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
2487        list->data != tree_view->priv->expander_column;
2488        list = (rtl ? list->prev : list->next))
2489     {
2490       GtkTreeViewColumn *column = list->data;
2491
2492       width += gtk_tree_view_column_get_width (column);
2493     }
2494
2495   return width;
2496 }
2497
2498 /* GtkWidget::size_allocate helper */
2499 static void
2500 gtk_tree_view_size_allocate_columns (GtkWidget *widget,
2501                                      gboolean  *width_changed)
2502 {
2503   GtkTreeView *tree_view;
2504   GList *list, *first_column, *last_column;
2505   GtkTreeViewColumn *column;
2506   GtkAllocation widget_allocation;
2507   gint width = 0;
2508   gint extra, extra_per_column, extra_for_last;
2509   gint full_requested_width = 0;
2510   gint number_of_expand_columns = 0;
2511   gboolean rtl;
2512   gboolean update_expand;
2513   
2514   tree_view = GTK_TREE_VIEW (widget);
2515
2516   for (last_column = g_list_last (tree_view->priv->columns);
2517        last_column &&
2518        !(gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (last_column->data)));
2519        last_column = last_column->prev)
2520     ;
2521   if (last_column == NULL)
2522     return;
2523
2524   for (first_column = g_list_first (tree_view->priv->columns);
2525        first_column &&
2526        !(gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (first_column->data)));
2527        first_column = first_column->next)
2528     ;
2529
2530   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
2531
2532   /* find out how many extra space and expandable columns we have */
2533   for (list = tree_view->priv->columns; list != last_column->next; list = list->next)
2534     {
2535       column = (GtkTreeViewColumn *)list->data;
2536
2537       if (!gtk_tree_view_column_get_visible (column))
2538         continue;
2539
2540       full_requested_width += _gtk_tree_view_column_request_width (column);
2541
2542       if (gtk_tree_view_column_get_expand (column))
2543         number_of_expand_columns++;
2544     }
2545
2546   /* Only update the expand value if the width of the widget has changed,
2547    * or the number of expand columns has changed, or if there are no expand
2548    * columns, or if we didn't have an size-allocation yet after the
2549    * last validated node.
2550    */
2551   update_expand = (width_changed && *width_changed == TRUE)
2552       || number_of_expand_columns != tree_view->priv->last_number_of_expand_columns
2553       || number_of_expand_columns == 0
2554       || tree_view->priv->post_validation_flag == TRUE;
2555
2556   tree_view->priv->post_validation_flag = FALSE;
2557
2558   gtk_widget_get_allocation (widget, &widget_allocation);
2559   if (!update_expand)
2560     {
2561       extra = tree_view->priv->last_extra_space;
2562       extra_for_last = MAX (widget_allocation.width - full_requested_width - extra, 0);
2563     }
2564   else
2565     {
2566       extra = MAX (widget_allocation.width - full_requested_width, 0);
2567       extra_for_last = 0;
2568
2569       tree_view->priv->last_extra_space = extra;
2570     }
2571
2572   if (number_of_expand_columns > 0)
2573     extra_per_column = extra/number_of_expand_columns;
2574   else
2575     extra_per_column = 0;
2576
2577   if (update_expand)
2578     {
2579       tree_view->priv->last_extra_space_per_column = extra_per_column;
2580       tree_view->priv->last_number_of_expand_columns = number_of_expand_columns;
2581     }
2582
2583   for (list = (rtl ? last_column : first_column); 
2584        list != (rtl ? first_column->prev : last_column->next);
2585        list = (rtl ? list->prev : list->next)) 
2586     {
2587       gint column_width;
2588
2589       column = list->data;
2590
2591       if (!gtk_tree_view_column_get_visible (column))
2592         continue;
2593
2594       /* We need to handle the dragged button specially.
2595        */
2596       if (column == tree_view->priv->drag_column)
2597         {
2598           GtkAllocation drag_allocation;
2599           GtkWidget    *button;
2600
2601           button = gtk_tree_view_column_get_button (tree_view->priv->drag_column);
2602
2603           drag_allocation.x = 0;
2604           drag_allocation.y = 0;
2605           drag_allocation.width = gdk_window_get_width (tree_view->priv->drag_window);
2606           drag_allocation.height = gdk_window_get_height (tree_view->priv->drag_window);
2607           gtk_widget_size_allocate (button, &drag_allocation);
2608           width += drag_allocation.width;
2609           continue;
2610         }
2611
2612       column_width = _gtk_tree_view_column_request_width (column);
2613
2614       if (gtk_tree_view_column_get_expand (column))
2615         {
2616           if (number_of_expand_columns == 1)
2617             {
2618               /* We add the remander to the last column as
2619                * */
2620               column_width += extra;
2621             }
2622           else
2623             {
2624               column_width += extra_per_column;
2625               extra -= extra_per_column;
2626               number_of_expand_columns --;
2627             }
2628         }
2629       else if (number_of_expand_columns == 0 &&
2630                list == last_column)
2631         {
2632           column_width += extra;
2633         }
2634
2635       /* In addition to expand, the last column can get even more
2636        * extra space so all available space is filled up.
2637        */
2638       if (extra_for_last > 0 && list == last_column)
2639         column_width += extra_for_last;
2640
2641       _gtk_tree_view_column_allocate (column, width, column_width);
2642
2643       width += column_width;
2644     }
2645
2646   /* We change the width here.  The user might have been resizing columns,
2647    * which changes the total width of the tree view.  This is of
2648    * importance for getting the horizontal scroll bar right.
2649    */
2650   if (tree_view->priv->width != width)
2651     {
2652       tree_view->priv->width = width;
2653       if (width_changed)
2654         *width_changed = TRUE;
2655     }
2656 }
2657
2658
2659 static void
2660 gtk_tree_view_size_allocate (GtkWidget     *widget,
2661                              GtkAllocation *allocation)
2662 {
2663   GtkAllocation widget_allocation;
2664   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2665   GList *tmp_list;
2666   gboolean width_changed = FALSE;
2667   gint old_width;
2668
2669   gtk_widget_get_allocation (widget, &widget_allocation);
2670   old_width = widget_allocation.width;
2671   if (allocation->width != widget_allocation.width)
2672     width_changed = TRUE;
2673
2674   gtk_widget_set_allocation (widget, allocation);
2675
2676   tmp_list = tree_view->priv->children;
2677
2678   while (tmp_list)
2679     {
2680       GtkAllocation allocation;
2681
2682       GtkTreeViewChild *child = tmp_list->data;
2683       tmp_list = tmp_list->next;
2684
2685       /* totally ignore our child's requisition */
2686       allocation.x = child->x;
2687       allocation.y = child->y;
2688       allocation.width = child->width;
2689       allocation.height = child->height;
2690       gtk_widget_size_allocate (child->widget, &allocation);
2691     }
2692
2693   /* We size-allocate the columns first because the width of the
2694    * tree view (used in updating the adjustments below) might change.
2695    */
2696   gtk_tree_view_size_allocate_columns (widget, &width_changed);
2697
2698   g_object_freeze_notify (G_OBJECT (tree_view->priv->hadjustment));
2699   gtk_adjustment_set_page_size (tree_view->priv->hadjustment,
2700                                 allocation->width);
2701   gtk_adjustment_set_page_increment (tree_view->priv->hadjustment,
2702                                      allocation->width * 0.9);
2703   gtk_adjustment_set_step_increment (tree_view->priv->hadjustment,
2704                                      allocation->width * 0.1);
2705   gtk_adjustment_set_lower (tree_view->priv->hadjustment, 0);
2706   gtk_adjustment_set_upper (tree_view->priv->hadjustment,
2707                             MAX (gtk_adjustment_get_page_size (tree_view->priv->hadjustment),
2708                                  tree_view->priv->width));
2709   g_object_thaw_notify (G_OBJECT (tree_view->priv->hadjustment));
2710
2711   if (gtk_widget_get_direction(widget) == GTK_TEXT_DIR_RTL)   
2712     {
2713       if (allocation->width < tree_view->priv->width)
2714         {
2715           if (tree_view->priv->init_hadjust_value)
2716             {
2717               gtk_adjustment_set_value (tree_view->priv->hadjustment,
2718                                         MAX (tree_view->priv->width -
2719                                              allocation->width, 0));
2720               tree_view->priv->init_hadjust_value = FALSE;
2721             }
2722           else if (allocation->width != old_width)
2723             {
2724               gtk_adjustment_set_value (tree_view->priv->hadjustment,
2725                                         CLAMP (gtk_adjustment_get_value (tree_view->priv->hadjustment) - allocation->width + old_width,
2726                                                0,
2727                                                tree_view->priv->width - allocation->width));
2728             }
2729           else
2730             gtk_adjustment_set_value (tree_view->priv->hadjustment,
2731                                       CLAMP (tree_view->priv->width - (tree_view->priv->prev_width - gtk_adjustment_get_value (tree_view->priv->hadjustment)),
2732                                              0,
2733                                              tree_view->priv->width - allocation->width));
2734         }
2735       else
2736         {
2737           gtk_adjustment_set_value (tree_view->priv->hadjustment, 0);
2738           tree_view->priv->init_hadjust_value = TRUE;
2739         }
2740     }
2741   else
2742     if (gtk_adjustment_get_value (tree_view->priv->hadjustment) + allocation->width > tree_view->priv->width)
2743       gtk_adjustment_set_value (tree_view->priv->hadjustment,
2744                                 MAX (tree_view->priv->width -
2745                                      allocation->width, 0));
2746
2747   g_object_freeze_notify (G_OBJECT (tree_view->priv->vadjustment));
2748   gtk_adjustment_set_page_size (tree_view->priv->vadjustment,
2749                                 allocation->height -
2750                                 gtk_tree_view_get_effective_header_height (tree_view));
2751   gtk_adjustment_set_step_increment (tree_view->priv->vadjustment,
2752                                      gtk_adjustment_get_page_size (tree_view->priv->vadjustment) * 0.1);
2753   gtk_adjustment_set_page_increment (tree_view->priv->vadjustment,
2754                                      gtk_adjustment_get_page_size (tree_view->priv->vadjustment) * 0.9);
2755   gtk_adjustment_set_lower (tree_view->priv->vadjustment, 0);
2756   gtk_adjustment_set_upper (tree_view->priv->vadjustment,
2757                             MAX (gtk_adjustment_get_page_size (tree_view->priv->vadjustment),
2758                                  tree_view->priv->height));
2759   g_object_thaw_notify (G_OBJECT (tree_view->priv->vadjustment));
2760
2761   /* now the adjustments and window sizes are in sync, we can sync toprow/dy again */
2762   if (tree_view->priv->height <= gtk_adjustment_get_page_size (tree_view->priv->vadjustment))
2763     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
2764   else if (gtk_adjustment_get_value (tree_view->priv->vadjustment) + gtk_adjustment_get_page_size (tree_view->priv->vadjustment) > tree_view->priv->height)
2765     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment),
2766                               tree_view->priv->height - gtk_adjustment_get_page_size (tree_view->priv->vadjustment));
2767   else if (gtk_tree_row_reference_valid (tree_view->priv->top_row))
2768     gtk_tree_view_top_row_to_dy (tree_view);
2769   else
2770     gtk_tree_view_dy_to_top_row (tree_view);
2771   
2772   if (gtk_widget_get_realized (widget))
2773     {
2774       gdk_window_move_resize (gtk_widget_get_window (widget),
2775                               allocation->x, allocation->y,
2776                               allocation->width, allocation->height);
2777       gdk_window_move_resize (tree_view->priv->header_window,
2778                               - (gint) gtk_adjustment_get_value (tree_view->priv->hadjustment),
2779                               0,
2780                               MAX (tree_view->priv->width, allocation->width),
2781                               tree_view->priv->header_height);
2782       gdk_window_move_resize (tree_view->priv->bin_window,
2783                               - (gint) gtk_adjustment_get_value (tree_view->priv->hadjustment),
2784                               gtk_tree_view_get_effective_header_height (tree_view),
2785                               MAX (tree_view->priv->width, allocation->width),
2786                               allocation->height - gtk_tree_view_get_effective_header_height (tree_view));
2787
2788       if (tree_view->priv->tree == NULL)
2789         invalidate_empty_focus (tree_view);
2790
2791       if (width_changed && tree_view->priv->expander_column)
2792         {
2793           /* Might seem awkward, but is the best heuristic I could come up
2794            * with.  Only if the width of the columns before the expander
2795            * changes, we will update the prelight status.  It is this
2796            * width that makes the expander move vertically.  Always updating
2797            * prelight status causes trouble with hover selections.
2798            */
2799           gint width_before_expander;
2800
2801           width_before_expander = gtk_tree_view_calculate_width_before_expander (tree_view);
2802
2803           if (tree_view->priv->prev_width_before_expander
2804               != width_before_expander)
2805               update_prelight (tree_view,
2806                                tree_view->priv->event_last_x,
2807                                tree_view->priv->event_last_y);
2808
2809           tree_view->priv->prev_width_before_expander = width_before_expander;
2810         }
2811     }
2812 }
2813
2814 /* Grabs the focus and unsets the GTK_TREE_VIEW_DRAW_KEYFOCUS flag */
2815 static void
2816 grab_focus_and_unset_draw_keyfocus (GtkTreeView *tree_view)
2817 {
2818   GtkWidget *widget = GTK_WIDGET (tree_view);
2819
2820   if (gtk_widget_get_can_focus (widget) && !gtk_widget_has_focus (widget))
2821     gtk_widget_grab_focus (widget);
2822   tree_view->priv->draw_keyfocus = 0;
2823 }
2824
2825 static inline gboolean
2826 row_is_separator (GtkTreeView *tree_view,
2827                   GtkTreeIter *iter,
2828                   GtkTreePath *path)
2829 {
2830   gboolean is_separator = FALSE;
2831
2832   if (tree_view->priv->row_separator_func)
2833     {
2834       GtkTreeIter tmpiter;
2835
2836       if (iter)
2837         tmpiter = *iter;
2838       else
2839         {
2840           if (!gtk_tree_model_get_iter (tree_view->priv->model, &tmpiter, path))
2841             return FALSE;
2842         }
2843
2844       is_separator = tree_view->priv->row_separator_func (tree_view->priv->model,
2845                                                           &tmpiter,
2846                                                           tree_view->priv->row_separator_data);
2847     }
2848
2849   return is_separator;
2850 }
2851
2852 static int
2853 gtk_tree_view_get_expander_size (GtkTreeView *tree_view)
2854 {
2855   gint expander_size;
2856
2857   gtk_widget_style_get (GTK_WIDGET (tree_view),
2858                         "expander-size", &expander_size,
2859                         NULL);
2860   expander_size += EXPANDER_EXTRA_PADDING;
2861
2862   return expander_size;
2863 }
2864
2865 static gboolean
2866 gtk_tree_view_button_press (GtkWidget      *widget,
2867                             GdkEventButton *event)
2868 {
2869   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2870   GList *list;
2871   GtkTreeViewColumn *column = NULL;
2872   gint i;
2873   GdkRectangle background_area;
2874   GdkRectangle cell_area;
2875   gint vertical_separator;
2876   gint horizontal_separator;
2877   gboolean path_is_selectable;
2878   gboolean rtl;
2879
2880   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
2881   gtk_tree_view_stop_editing (tree_view, FALSE);
2882   gtk_widget_style_get (widget,
2883                         "vertical-separator", &vertical_separator,
2884                         "horizontal-separator", &horizontal_separator,
2885                         NULL);
2886
2887   /* Don't handle extra mouse buttons events, let them bubble up */
2888   if (event->button > 5)
2889     return FALSE;
2890  
2891   /* Because grab_focus can cause reentrancy, we delay grab_focus until after
2892    * we're done handling the button press.
2893    */
2894
2895   if (event->window == tree_view->priv->bin_window)
2896     {
2897       GtkRBNode *node;
2898       GtkRBTree *tree;
2899       GtkTreePath *path;
2900       gint depth;
2901       gint new_y;
2902       gint y_offset;
2903       gint dval;
2904       gint pre_val, aft_val;
2905       GtkTreeViewColumn *column = NULL;
2906       gint column_handled_click = FALSE;
2907       gboolean row_double_click = FALSE;
2908       gboolean rtl;
2909       gboolean node_selected;
2910       GdkModifierType extend_mod_mask;
2911       GdkModifierType modify_mod_mask;
2912
2913       /* Empty tree? */
2914       if (tree_view->priv->tree == NULL)
2915         {
2916           grab_focus_and_unset_draw_keyfocus (tree_view);
2917           return TRUE;
2918         }
2919
2920       /* are we in an arrow? */
2921       if (tree_view->priv->prelight_node &&
2922           tree_view->priv->arrow_prelit &&
2923           gtk_tree_view_draw_expanders (tree_view))
2924         {
2925           if (event->button == GDK_BUTTON_PRIMARY)
2926             {
2927               gtk_grab_add (widget);
2928               tree_view->priv->button_pressed_node = tree_view->priv->prelight_node;
2929               tree_view->priv->button_pressed_tree = tree_view->priv->prelight_tree;
2930               gtk_tree_view_queue_draw_arrow (GTK_TREE_VIEW (widget),
2931                                               tree_view->priv->prelight_tree,
2932                                               tree_view->priv->prelight_node);
2933             }
2934
2935           grab_focus_and_unset_draw_keyfocus (tree_view);
2936           return TRUE;
2937         }
2938
2939       /* find the node that was clicked */
2940       new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
2941       if (new_y < 0)
2942         new_y = 0;
2943       y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
2944
2945       if (node == NULL)
2946         {
2947           /* We clicked in dead space */
2948           grab_focus_and_unset_draw_keyfocus (tree_view);
2949           return TRUE;
2950         }
2951
2952       /* Get the path and the node */
2953       path = _gtk_tree_path_new_from_rbtree (tree, node);
2954       path_is_selectable = !row_is_separator (tree_view, NULL, path);
2955
2956       if (!path_is_selectable)
2957         {
2958           gtk_tree_path_free (path);
2959           grab_focus_and_unset_draw_keyfocus (tree_view);
2960           return TRUE;
2961         }
2962
2963       depth = gtk_tree_path_get_depth (path);
2964       background_area.y = y_offset + event->y;
2965       background_area.height = gtk_tree_view_get_row_height (tree_view, node);
2966       background_area.x = 0;
2967
2968
2969       /* Let the column have a chance at selecting it. */
2970       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2971       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
2972            list; list = (rtl ? list->prev : list->next))
2973         {
2974           GtkTreeViewColumn *candidate = list->data;
2975
2976           if (!gtk_tree_view_column_get_visible (candidate))
2977             continue;
2978
2979           background_area.width = gtk_tree_view_column_get_width (candidate);
2980           if ((background_area.x > (gint) event->x) ||
2981               (background_area.x + background_area.width <= (gint) event->x))
2982             {
2983               background_area.x += background_area.width;
2984               continue;
2985             }
2986
2987           /* we found the focus column */
2988           column = candidate;
2989           cell_area = background_area;
2990           cell_area.width -= horizontal_separator;
2991           cell_area.height -= vertical_separator;
2992           cell_area.x += horizontal_separator/2;
2993           cell_area.y += vertical_separator/2;
2994           if (gtk_tree_view_is_expander_column (tree_view, column))
2995             {
2996               if (!rtl)
2997                 cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
2998               cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
2999
3000               if (gtk_tree_view_draw_expanders (tree_view))
3001                 {
3002                   gint expander_size = gtk_tree_view_get_expander_size (tree_view);
3003                   if (!rtl)
3004                     cell_area.x += depth * expander_size;
3005                   cell_area.width -= depth * expander_size;
3006                 }
3007             }
3008           break;
3009         }
3010
3011       if (column == NULL)
3012         {
3013           gtk_tree_path_free (path);
3014           grab_focus_and_unset_draw_keyfocus (tree_view);
3015           return FALSE;
3016         }
3017
3018       _gtk_tree_view_set_focus_column (tree_view, column);
3019
3020       /* decide if we edit */
3021       if (event->type == GDK_BUTTON_PRESS && event->button == GDK_BUTTON_PRIMARY &&
3022           !(event->state & gtk_accelerator_get_default_mod_mask ()))
3023         {
3024           GtkTreePath *anchor;
3025           GtkTreeIter iter;
3026
3027           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
3028           gtk_tree_view_column_cell_set_cell_data (column,
3029                                                    tree_view->priv->model,
3030                                                    &iter,
3031                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
3032                                                    node->children?TRUE:FALSE);
3033
3034           if (tree_view->priv->anchor)
3035             anchor = gtk_tree_row_reference_get_path (tree_view->priv->anchor);
3036           else
3037             anchor = NULL;
3038
3039           if ((anchor && !gtk_tree_path_compare (anchor, path))
3040               || !_gtk_tree_view_column_has_editable_cell (column))
3041             {
3042               GtkCellEditable *cell_editable = NULL;
3043
3044               /* FIXME: get the right flags */
3045               guint flags = 0;
3046
3047               if (_gtk_tree_view_column_cell_event (column,
3048                                                     (GdkEvent *)event,
3049                                                     &cell_area, flags))
3050                 {
3051                   GtkCellArea *area = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (column));
3052                   cell_editable = gtk_cell_area_get_edit_widget (area);
3053
3054                   if (cell_editable != NULL)
3055                     {
3056                       gtk_tree_path_free (path);
3057                       gtk_tree_path_free (anchor);
3058                       return TRUE;
3059                     }
3060                   column_handled_click = TRUE;
3061                 }
3062             }
3063           if (anchor)
3064             gtk_tree_path_free (anchor);
3065         }
3066
3067       extend_mod_mask =
3068         gtk_widget_get_modifier_mask (widget, GDK_MODIFIER_INTENT_EXTEND_SELECTION);
3069
3070       modify_mod_mask =
3071         gtk_widget_get_modifier_mask (widget, GDK_MODIFIER_INTENT_MODIFY_SELECTION);
3072
3073       /* select */
3074       node_selected = GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED);
3075       pre_val = gtk_adjustment_get_value (tree_view->priv->vadjustment);
3076
3077       /* we only handle selection modifications on the first button press
3078        */
3079       if (event->type == GDK_BUTTON_PRESS)
3080         {
3081           GtkCellRenderer *focus_cell;
3082
3083           if ((event->state & modify_mod_mask) == modify_mod_mask)
3084             tree_view->priv->modify_selection_pressed = TRUE;
3085           if ((event->state & extend_mod_mask) == extend_mod_mask)
3086             tree_view->priv->extend_selection_pressed = TRUE;
3087
3088           /* We update the focus cell here, this is also needed if the
3089            * column does not contain an editable cell.  In this case,
3090            * GtkCellArea did not receive the event for processing (and
3091            * could not update the focus cell).
3092            */
3093           focus_cell = _gtk_tree_view_column_get_cell_at_pos (column,
3094                                                               &cell_area,
3095                                                               &background_area,
3096                                                               event->x,
3097                                                               event->y);
3098
3099           if (focus_cell)
3100             gtk_tree_view_column_focus_cell (column, focus_cell);
3101
3102           if (event->state & modify_mod_mask)
3103             {
3104               gtk_tree_view_real_set_cursor (tree_view, path, CLAMP_NODE);
3105               gtk_tree_view_real_toggle_cursor_row (tree_view);
3106             }
3107           else if (event->state & extend_mod_mask)
3108             {
3109               gtk_tree_view_real_set_cursor (tree_view, path, CLAMP_NODE);
3110               gtk_tree_view_real_select_cursor_row (tree_view, FALSE);
3111             }
3112           else
3113             {
3114               gtk_tree_view_real_set_cursor (tree_view, path, CLEAR_AND_SELECT | CLAMP_NODE);
3115             }
3116
3117           tree_view->priv->modify_selection_pressed = FALSE;
3118           tree_view->priv->extend_selection_pressed = FALSE;
3119         }
3120
3121       /* the treeview may have been scrolled because of _set_cursor,
3122        * correct here
3123        */
3124
3125       aft_val = gtk_adjustment_get_value (tree_view->priv->vadjustment);
3126       dval = pre_val - aft_val;
3127
3128       cell_area.y += dval;
3129       background_area.y += dval;
3130
3131       /* Save press to possibly begin a drag
3132        */
3133       if (!column_handled_click &&
3134           !tree_view->priv->in_grab &&
3135           tree_view->priv->pressed_button < 0)
3136         {
3137           tree_view->priv->pressed_button = event->button;
3138           tree_view->priv->press_start_x = event->x;
3139           tree_view->priv->press_start_y = event->y;
3140
3141           if (tree_view->priv->rubber_banding_enable
3142               && !node_selected
3143               && gtk_tree_selection_get_mode (tree_view->priv->selection) == GTK_SELECTION_MULTIPLE)
3144             {
3145               tree_view->priv->press_start_y += tree_view->priv->dy;
3146               tree_view->priv->rubber_band_x = event->x;
3147               tree_view->priv->rubber_band_y = event->y + tree_view->priv->dy;
3148               tree_view->priv->rubber_band_status = RUBBER_BAND_MAYBE_START;
3149
3150               if ((event->state & modify_mod_mask) == modify_mod_mask)
3151                 tree_view->priv->rubber_band_modify = TRUE;
3152               if ((event->state & extend_mod_mask) == extend_mod_mask)
3153                 tree_view->priv->rubber_band_extend = TRUE;
3154             }
3155         }
3156
3157       /* Test if a double click happened on the same row. */
3158       if (event->button == GDK_BUTTON_PRIMARY && event->type == GDK_BUTTON_PRESS)
3159         {
3160           int double_click_time, double_click_distance;
3161
3162           g_object_get (gtk_settings_get_default (),
3163                         "gtk-double-click-time", &double_click_time,
3164                         "gtk-double-click-distance", &double_click_distance,
3165                         NULL);
3166
3167           /* Same conditions as _gdk_event_button_generate */
3168           if (tree_view->priv->last_button_x != -1 &&
3169               (event->time < tree_view->priv->last_button_time + double_click_time) &&
3170               (ABS (event->x - tree_view->priv->last_button_x) <= double_click_distance) &&
3171               (ABS (event->y - tree_view->priv->last_button_y) <= double_click_distance))
3172             {
3173               /* We do no longer compare paths of this row and the
3174                * row clicked previously.  We use the double click
3175                * distance to decide whether this is a valid click,
3176                * allowing the mouse to slightly move over another row.
3177                */
3178               row_double_click = TRUE;
3179
3180               tree_view->priv->last_button_time = 0;
3181               tree_view->priv->last_button_x = -1;
3182               tree_view->priv->last_button_y = -1;
3183             }
3184           else
3185             {
3186               tree_view->priv->last_button_time = event->time;
3187               tree_view->priv->last_button_x = event->x;
3188               tree_view->priv->last_button_y = event->y;
3189             }
3190         }
3191
3192       if (row_double_click)
3193         {
3194           gtk_grab_remove (widget);
3195           gtk_tree_view_row_activated (tree_view, path, column);
3196
3197           if (tree_view->priv->pressed_button == event->button)
3198             tree_view->priv->pressed_button = -1;
3199         }
3200
3201       gtk_tree_path_free (path);
3202
3203       /* If we activated the row through a double click we don't want to grab
3204        * focus back, as moving focus to another widget is pretty common.
3205        */
3206       if (!row_double_click)
3207         grab_focus_and_unset_draw_keyfocus (tree_view);
3208
3209       return TRUE;
3210     }
3211
3212   /* We didn't click in the window.  Let's check to see if we clicked on a column resize window.
3213    */
3214   for (i = 0, list = tree_view->priv->columns; list; list = list->next, i++)
3215     {
3216       column = list->data;
3217       if (event->window == _gtk_tree_view_column_get_window (column) &&
3218           gtk_tree_view_column_get_resizable (column) &&
3219           _gtk_tree_view_column_get_window (column))
3220         {
3221           gpointer drag_data;
3222
3223           if (event->type == GDK_2BUTTON_PRESS &&
3224               gtk_tree_view_column_get_sizing (column) != GTK_TREE_VIEW_COLUMN_AUTOSIZE)
3225             {
3226               _gtk_tree_view_column_set_use_resized_width (column, FALSE);
3227               _gtk_tree_view_column_autosize (tree_view, column);
3228               return TRUE;
3229             }
3230
3231           if (gdk_device_grab (gdk_event_get_device ((GdkEvent*)event),
3232                                _gtk_tree_view_column_get_window (column),
3233                                GDK_OWNERSHIP_NONE,
3234                                FALSE,
3235                                GDK_POINTER_MOTION_HINT_MASK
3236                                 | GDK_BUTTON1_MOTION_MASK
3237                                 | GDK_BUTTON_RELEASE_MASK,
3238                                NULL,
3239                                event->time) != GDK_GRAB_SUCCESS)
3240             return FALSE;
3241
3242           gtk_grab_add (widget);
3243           tree_view->priv->in_column_resize = TRUE;
3244
3245           _gtk_tree_view_column_set_resized_width (column, gtk_tree_view_column_get_width (column) -
3246                                                    tree_view->priv->last_extra_space_per_column);
3247
3248           /* block attached dnd signal handler */
3249           drag_data = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
3250           if (drag_data)
3251             g_signal_handlers_block_matched (widget,
3252                                              G_SIGNAL_MATCH_DATA,
3253                                              0, 0, NULL, NULL,
3254                                              drag_data);
3255
3256           tree_view->priv->drag_pos = i;
3257           tree_view->priv->x_drag = gtk_tree_view_column_get_x_offset (column) + (rtl ? 0 : gtk_tree_view_column_get_width (column));
3258
3259           if (!gtk_widget_has_focus (widget))
3260             gtk_widget_grab_focus (widget);
3261
3262           return TRUE;
3263         }
3264     }
3265   return FALSE;
3266 }
3267
3268 /* GtkWidget::button_release_event helper */
3269 static gboolean
3270 gtk_tree_view_button_release_drag_column (GtkWidget      *widget,
3271                                           GdkEventButton *event)
3272 {
3273   GtkTreeView *tree_view;
3274   GtkWidget *button;
3275   GList *l;
3276   gboolean rtl;
3277   GdkDevice *device, *other;
3278
3279   tree_view = GTK_TREE_VIEW (widget);
3280
3281   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
3282   device = gdk_event_get_device ((GdkEvent*)event);
3283   other = gdk_device_get_associated_device (device);
3284   gdk_device_ungrab (device, event->time);
3285   gdk_device_ungrab (other, event->time);
3286
3287   /* Move the button back */
3288   button = gtk_tree_view_column_get_button (tree_view->priv->drag_column);
3289   g_object_ref (button);
3290   gtk_container_remove (GTK_CONTAINER (tree_view), button);
3291   gtk_widget_set_parent_window (button, tree_view->priv->header_window);
3292   gtk_widget_set_parent (button, GTK_WIDGET (tree_view));
3293   g_object_unref (button);
3294   gtk_widget_queue_resize (widget);
3295   if (gtk_tree_view_column_get_resizable (tree_view->priv->drag_column))
3296     {
3297       gdk_window_raise (_gtk_tree_view_column_get_window (tree_view->priv->drag_column));
3298       gdk_window_show (_gtk_tree_view_column_get_window (tree_view->priv->drag_column));
3299     }
3300   else
3301     gdk_window_hide (_gtk_tree_view_column_get_window (tree_view->priv->drag_column));
3302
3303   gtk_widget_grab_focus (button);
3304
3305   if (rtl)
3306     {
3307       if (tree_view->priv->cur_reorder &&
3308           tree_view->priv->cur_reorder->right_column != tree_view->priv->drag_column)
3309         gtk_tree_view_move_column_after (tree_view, tree_view->priv->drag_column,
3310                                          tree_view->priv->cur_reorder->right_column);
3311     }
3312   else
3313     {
3314       if (tree_view->priv->cur_reorder &&
3315           tree_view->priv->cur_reorder->left_column != tree_view->priv->drag_column)
3316         gtk_tree_view_move_column_after (tree_view, tree_view->priv->drag_column,
3317                                          tree_view->priv->cur_reorder->left_column);
3318     }
3319   tree_view->priv->drag_column = NULL;
3320   gdk_window_hide (tree_view->priv->drag_window);
3321
3322   for (l = tree_view->priv->column_drag_info; l != NULL; l = l->next)
3323     g_slice_free (GtkTreeViewColumnReorder, l->data);
3324   g_list_free (tree_view->priv->column_drag_info);
3325   tree_view->priv->column_drag_info = NULL;
3326   tree_view->priv->cur_reorder = NULL;
3327
3328   if (tree_view->priv->drag_highlight_window)
3329     gdk_window_hide (tree_view->priv->drag_highlight_window);
3330
3331   /* Reset our flags */
3332   tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_UNSET;
3333   tree_view->priv->in_column_drag = FALSE;
3334
3335   return TRUE;
3336 }
3337
3338 /* GtkWidget::button_release_event helper */
3339 static gboolean
3340 gtk_tree_view_button_release_column_resize (GtkWidget      *widget,
3341                                             GdkEventButton *event)
3342 {
3343   GtkTreeView *tree_view;
3344   gpointer drag_data;
3345
3346   tree_view = GTK_TREE_VIEW (widget);
3347
3348   tree_view->priv->drag_pos = -1;
3349
3350   /* unblock attached dnd signal handler */
3351   drag_data = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
3352   if (drag_data)
3353     g_signal_handlers_unblock_matched (widget,
3354                                        G_SIGNAL_MATCH_DATA,
3355                                        0, 0, NULL, NULL,
3356                                        drag_data);
3357
3358   tree_view->priv->in_column_resize = FALSE;
3359   gtk_grab_remove (widget);
3360   gdk_device_ungrab (gdk_event_get_device ((GdkEvent*)event), event->time);
3361   return TRUE;
3362 }
3363
3364 static gboolean
3365 gtk_tree_view_button_release (GtkWidget      *widget,
3366                               GdkEventButton *event)
3367 {
3368   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
3369
3370   if (tree_view->priv->in_column_drag)
3371     return gtk_tree_view_button_release_drag_column (widget, event);
3372
3373   if (tree_view->priv->rubber_band_status)
3374     gtk_tree_view_stop_rubber_band (tree_view);
3375
3376   if (tree_view->priv->pressed_button == event->button)
3377     tree_view->priv->pressed_button = -1;
3378
3379   if (tree_view->priv->in_column_resize)
3380     return gtk_tree_view_button_release_column_resize (widget, event);
3381
3382   if (tree_view->priv->button_pressed_node == NULL)
3383     return FALSE;
3384
3385   if (event->button == GDK_BUTTON_PRIMARY)
3386     {
3387       if (tree_view->priv->button_pressed_node == tree_view->priv->prelight_node &&
3388           tree_view->priv->arrow_prelit)
3389         {
3390           GtkTreePath *path = NULL;
3391
3392           path = _gtk_tree_path_new_from_rbtree (tree_view->priv->button_pressed_tree,
3393                                                  tree_view->priv->button_pressed_node);
3394           /* Actually activate the node */
3395           if (tree_view->priv->button_pressed_node->children == NULL)
3396             gtk_tree_view_real_expand_row (tree_view, path,
3397                                            tree_view->priv->button_pressed_tree,
3398                                            tree_view->priv->button_pressed_node,
3399                                            FALSE, TRUE);
3400           else
3401             gtk_tree_view_real_collapse_row (GTK_TREE_VIEW (widget), path,
3402                                              tree_view->priv->button_pressed_tree,
3403                                              tree_view->priv->button_pressed_node, TRUE);
3404           gtk_tree_path_free (path);
3405         }
3406
3407       gtk_grab_remove (widget);
3408       tree_view->priv->button_pressed_tree = NULL;
3409       tree_view->priv->button_pressed_node = NULL;
3410     }
3411
3412   return TRUE;
3413 }
3414
3415 static gboolean
3416 gtk_tree_view_grab_broken (GtkWidget          *widget,
3417                            GdkEventGrabBroken *event)
3418 {
3419   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
3420
3421   if (tree_view->priv->in_column_drag)
3422     gtk_tree_view_button_release_drag_column (widget, (GdkEventButton *)event);
3423
3424   if (tree_view->priv->in_column_resize)
3425     gtk_tree_view_button_release_column_resize (widget, (GdkEventButton *)event);
3426
3427   return TRUE;
3428 }
3429
3430 #if 0
3431 static gboolean
3432 gtk_tree_view_configure (GtkWidget *widget,
3433                          GdkEventConfigure *event)
3434 {
3435   GtkTreeView *tree_view;
3436
3437   tree_view = GTK_TREE_VIEW (widget);
3438   tree_view->priv->search_position_func (tree_view, tree_view->priv->search_window);
3439
3440   return FALSE;
3441 }
3442 #endif
3443
3444 /* GtkWidget::motion_event function set.
3445  */
3446
3447 static gboolean
3448 coords_are_over_arrow (GtkTreeView *tree_view,
3449                        GtkRBTree   *tree,
3450                        GtkRBNode   *node,
3451                        /* these are in bin window coords */
3452                        gint         x,
3453                        gint         y)
3454 {
3455   GdkRectangle arrow;
3456   gint x2;
3457
3458   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
3459     return FALSE;
3460
3461   if ((node->flags & GTK_RBNODE_IS_PARENT) == 0)
3462     return FALSE;
3463
3464   arrow.y = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
3465   arrow.height = gtk_tree_view_get_row_height (tree_view, node);
3466
3467   gtk_tree_view_get_arrow_xrange (tree_view, tree, &arrow.x, &x2);
3468
3469   arrow.width = x2 - arrow.x;
3470
3471   return (x >= arrow.x &&
3472           x < (arrow.x + arrow.width) &&
3473           y >= arrow.y &&
3474           y < (arrow.y + arrow.height));
3475 }
3476
3477 static gboolean
3478 auto_expand_timeout (gpointer data)
3479 {
3480   GtkTreeView *tree_view = GTK_TREE_VIEW (data);
3481   GtkTreePath *path;
3482
3483   if (tree_view->priv->prelight_node)
3484     {
3485       path = _gtk_tree_path_new_from_rbtree (tree_view->priv->prelight_tree,
3486                                              tree_view->priv->prelight_node);
3487
3488       if (tree_view->priv->prelight_node->children)
3489         gtk_tree_view_collapse_row (tree_view, path);
3490       else
3491         gtk_tree_view_expand_row (tree_view, path, FALSE);
3492
3493       gtk_tree_path_free (path);
3494     }
3495
3496   tree_view->priv->auto_expand_timeout = 0;
3497
3498   return FALSE;
3499 }
3500
3501 static void
3502 remove_auto_expand_timeout (GtkTreeView *tree_view)
3503 {
3504   if (tree_view->priv->auto_expand_timeout != 0)
3505     {
3506       g_source_remove (tree_view->priv->auto_expand_timeout);
3507       tree_view->priv->auto_expand_timeout = 0;
3508     }
3509 }
3510
3511 static void
3512 do_prelight (GtkTreeView *tree_view,
3513              GtkRBTree   *tree,
3514              GtkRBNode   *node,
3515              /* these are in bin_window coords */
3516              gint         x,
3517              gint         y)
3518 {
3519   if (tree_view->priv->prelight_tree == tree &&
3520       tree_view->priv->prelight_node == node)
3521     {
3522       /*  We are still on the same node,
3523           but we might need to take care of the arrow  */
3524
3525       if (tree && node && gtk_tree_view_draw_expanders (tree_view))
3526         {
3527           gboolean over_arrow;
3528
3529           over_arrow = coords_are_over_arrow (tree_view, tree, node, x, y);
3530
3531           if (over_arrow != tree_view->priv->arrow_prelit)
3532             {
3533               if (over_arrow)
3534                 tree_view->priv->arrow_prelit = TRUE;
3535               else
3536                 tree_view->priv->arrow_prelit = FALSE;
3537
3538               gtk_tree_view_queue_draw_arrow (tree_view, tree, node);
3539             }
3540         }
3541
3542       return;
3543     }
3544
3545   if (tree_view->priv->prelight_tree && tree_view->priv->prelight_node)
3546     {
3547       /*  Unprelight the old node and arrow  */
3548
3549       GTK_RBNODE_UNSET_FLAG (tree_view->priv->prelight_node,
3550                              GTK_RBNODE_IS_PRELIT);
3551
3552       if (tree_view->priv->arrow_prelit
3553           && gtk_tree_view_draw_expanders (tree_view))
3554         {
3555           tree_view->priv->arrow_prelit = FALSE;
3556           
3557           gtk_tree_view_queue_draw_arrow (tree_view,
3558                                           tree_view->priv->prelight_tree,
3559                                           tree_view->priv->prelight_node);
3560         }
3561
3562       _gtk_tree_view_queue_draw_node (tree_view,
3563                                       tree_view->priv->prelight_tree,
3564                                       tree_view->priv->prelight_node,
3565                                       NULL);
3566     }
3567
3568
3569   if (tree_view->priv->hover_expand)
3570     remove_auto_expand_timeout (tree_view);
3571
3572   /*  Set the new prelight values  */
3573   tree_view->priv->prelight_node = node;
3574   tree_view->priv->prelight_tree = tree;
3575
3576   if (!node || !tree)
3577     return;
3578
3579   /*  Prelight the new node and arrow  */
3580
3581   if (gtk_tree_view_draw_expanders (tree_view)
3582       && coords_are_over_arrow (tree_view, tree, node, x, y))
3583     {
3584       tree_view->priv->arrow_prelit = TRUE;
3585
3586       gtk_tree_view_queue_draw_arrow (tree_view, tree, node);
3587     }
3588
3589   GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_PRELIT);
3590
3591   _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
3592
3593   if (tree_view->priv->hover_expand)
3594     {
3595       tree_view->priv->auto_expand_timeout = 
3596         gdk_threads_add_timeout (AUTO_EXPAND_TIMEOUT, auto_expand_timeout, tree_view);
3597     }
3598 }
3599
3600 static void
3601 prelight_or_select (GtkTreeView *tree_view,
3602                     GtkRBTree   *tree,
3603                     GtkRBNode   *node,
3604                     /* these are in bin_window coords */
3605                     gint         x,
3606                     gint         y)
3607 {
3608   GtkSelectionMode mode = gtk_tree_selection_get_mode (tree_view->priv->selection);
3609   
3610   if (tree_view->priv->hover_selection &&
3611       (mode == GTK_SELECTION_SINGLE || mode == GTK_SELECTION_BROWSE) &&
3612       !(tree_view->priv->edited_column &&
3613         gtk_cell_area_get_edit_widget 
3614         (gtk_cell_layout_get_area (GTK_CELL_LAYOUT (tree_view->priv->edited_column)))))
3615     {
3616       if (node)
3617         {
3618           if (!GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
3619             {
3620               GtkTreePath *path;
3621               
3622               path = _gtk_tree_path_new_from_rbtree (tree, node);
3623               gtk_tree_selection_select_path (tree_view->priv->selection, path);
3624               if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
3625                 {
3626                   tree_view->priv->draw_keyfocus = FALSE;
3627                   gtk_tree_view_real_set_cursor (tree_view, path, 0);
3628                 }
3629               gtk_tree_path_free (path);
3630             }
3631         }
3632
3633       else if (mode == GTK_SELECTION_SINGLE)
3634         gtk_tree_selection_unselect_all (tree_view->priv->selection);
3635     }
3636
3637     do_prelight (tree_view, tree, node, x, y);
3638 }
3639
3640 static void
3641 ensure_unprelighted (GtkTreeView *tree_view)
3642 {
3643   do_prelight (tree_view,
3644                NULL, NULL,
3645                -1000, -1000); /* coords not possibly over an arrow */
3646
3647   g_assert (tree_view->priv->prelight_node == NULL);
3648 }
3649
3650 static void
3651 update_prelight (GtkTreeView *tree_view,
3652                  gint         x,
3653                  gint         y)
3654 {
3655   int new_y;
3656   GtkRBTree *tree;
3657   GtkRBNode *node;
3658
3659   if (tree_view->priv->tree == NULL)
3660     return;
3661
3662   if (x == -10000)
3663     {
3664       ensure_unprelighted (tree_view);
3665       return;
3666     }
3667
3668   new_y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, y);
3669   if (new_y < 0)
3670     new_y = 0;
3671
3672   _gtk_rbtree_find_offset (tree_view->priv->tree,
3673                            new_y, &tree, &node);
3674
3675   if (node)
3676     prelight_or_select (tree_view, tree, node, x, y);
3677 }
3678
3679
3680
3681
3682 /* Our motion arrow is either a box (in the case of the original spot)
3683  * or an arrow.  It is expander_size wide.
3684  */
3685 /*
3686  * 11111111111111
3687  * 01111111111110
3688  * 00111111111100
3689  * 00011111111000
3690  * 00001111110000
3691  * 00000111100000
3692  * 00000111100000
3693  * 00000111100000
3694  * ~ ~ ~ ~ ~ ~ ~
3695  * 00000111100000
3696  * 00000111100000
3697  * 00000111100000
3698  * 00001111110000
3699  * 00011111111000
3700  * 00111111111100
3701  * 01111111111110
3702  * 11111111111111
3703  */
3704
3705 static void
3706 gtk_tree_view_motion_draw_column_motion_arrow (GtkTreeView *tree_view)
3707 {
3708   GtkTreeViewColumnReorder *reorder = tree_view->priv->cur_reorder;
3709   GtkWidget *widget = GTK_WIDGET (tree_view);
3710   cairo_surface_t *mask_image;
3711   cairo_region_t *mask_region;
3712   gint x;
3713   gint y;
3714   gint width;
3715   gint height;
3716   gint arrow_type = DRAG_COLUMN_WINDOW_STATE_UNSET;
3717   GdkWindowAttr attributes;
3718   guint attributes_mask;
3719   cairo_t *cr;
3720
3721   if (!reorder ||
3722       reorder->left_column == tree_view->priv->drag_column ||
3723       reorder->right_column == tree_view->priv->drag_column)
3724     arrow_type = DRAG_COLUMN_WINDOW_STATE_ORIGINAL;
3725   else if (reorder->left_column || reorder->right_column)
3726     {
3727       GtkAllocation left_allocation, right_allocation;
3728       GdkRectangle visible_rect;
3729       GtkWidget *button;
3730
3731       gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
3732       if (reorder->left_column)
3733         {
3734           button = gtk_tree_view_column_get_button (reorder->left_column);
3735           gtk_widget_get_allocation (button, &left_allocation);
3736           x = left_allocation.x + left_allocation.width;
3737         }
3738       else
3739         {
3740           button = gtk_tree_view_column_get_button (reorder->right_column);
3741           gtk_widget_get_allocation (button, &right_allocation);
3742           x = right_allocation.x;
3743         }
3744
3745       if (x < visible_rect.x)
3746         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT;
3747       else if (x > visible_rect.x + visible_rect.width)
3748         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT;
3749       else
3750         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW;
3751     }
3752
3753   /* We want to draw the rectangle over the initial location. */
3754   if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ORIGINAL)
3755     {
3756       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ORIGINAL)
3757         {
3758           GtkAllocation drag_allocation;
3759           GtkWidget    *button;
3760
3761           if (tree_view->priv->drag_highlight_window)
3762             {
3763               gdk_window_set_user_data (tree_view->priv->drag_highlight_window,
3764                                         NULL);
3765               gdk_window_destroy (tree_view->priv->drag_highlight_window);
3766             }
3767
3768           button = gtk_tree_view_column_get_button (tree_view->priv->drag_column);
3769           attributes.window_type = GDK_WINDOW_CHILD;
3770           attributes.wclass = GDK_INPUT_OUTPUT;
3771           attributes.x = tree_view->priv->drag_column_x;
3772           attributes.y = 0;
3773           gtk_widget_get_allocation (button, &drag_allocation);
3774           width = attributes.width = drag_allocation.width;
3775           height = attributes.height = drag_allocation.height;
3776           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
3777           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3778           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
3779           tree_view->priv->drag_highlight_window = gdk_window_new (tree_view->priv->header_window, &attributes, attributes_mask);
3780           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
3781
3782           mask_image = cairo_image_surface_create (CAIRO_FORMAT_A1, width, height);
3783           cr = cairo_create (mask_image);
3784
3785           cairo_rectangle (cr, 1, 1, width - 2, height - 2);
3786           cairo_stroke (cr);
3787           cairo_destroy (cr);
3788
3789           mask_region = gdk_cairo_region_create_from_surface (mask_image);
3790           gdk_window_shape_combine_region (tree_view->priv->drag_highlight_window,
3791                                            mask_region, 0, 0);
3792
3793           cairo_region_destroy (mask_region);
3794           cairo_surface_destroy (mask_image);
3795
3796           tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_ORIGINAL;
3797         }
3798     }
3799   else if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW)
3800     {
3801       GtkAllocation button_allocation;
3802       GtkWidget    *button;
3803
3804       width = gtk_tree_view_get_expander_size (tree_view);
3805
3806       /* Get x, y, width, height of arrow */
3807       gdk_window_get_origin (tree_view->priv->header_window, &x, &y);
3808       if (reorder->left_column)
3809         {
3810           button = gtk_tree_view_column_get_button (reorder->left_column);
3811           gtk_widget_get_allocation (button, &button_allocation);
3812           x += button_allocation.x + button_allocation.width - width/2;
3813           height = button_allocation.height;
3814         }
3815       else
3816         {
3817           button = gtk_tree_view_column_get_button (reorder->right_column);
3818           gtk_widget_get_allocation (button, &button_allocation);
3819           x += button_allocation.x - width/2;
3820           height = button_allocation.height;
3821         }
3822       y -= width/2; /* The arrow takes up only half the space */
3823       height += width;
3824
3825       /* Create the new window */
3826       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW)
3827         {
3828           if (tree_view->priv->drag_highlight_window)
3829             {
3830               gdk_window_set_user_data (tree_view->priv->drag_highlight_window,
3831                                         NULL);
3832               gdk_window_destroy (tree_view->priv->drag_highlight_window);
3833             }
3834
3835           attributes.window_type = GDK_WINDOW_TEMP;
3836           attributes.wclass = GDK_INPUT_OUTPUT;
3837           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
3838           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3839           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
3840           attributes.x = x;
3841           attributes.y = y;
3842           attributes.width = width;
3843           attributes.height = height;
3844           tree_view->priv->drag_highlight_window = gdk_window_new (gtk_widget_get_root_window (widget),
3845                                                                    &attributes, attributes_mask);
3846           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
3847
3848           mask_image = cairo_image_surface_create (CAIRO_FORMAT_A1, width, height);
3849
3850           cr = cairo_create (mask_image);
3851           cairo_move_to (cr, 0, 0);
3852           cairo_line_to (cr, width, 0);
3853           cairo_line_to (cr, width / 2., width / 2);
3854           cairo_move_to (cr, 0, height);
3855           cairo_line_to (cr, width, height);
3856           cairo_line_to (cr, width / 2., height - width / 2.);
3857           cairo_fill (cr);
3858           cairo_destroy (cr);
3859
3860           mask_region = gdk_cairo_region_create_from_surface (mask_image);
3861           gdk_window_shape_combine_region (tree_view->priv->drag_highlight_window,
3862                                            mask_region, 0, 0);
3863
3864           cairo_region_destroy (mask_region);
3865           cairo_surface_destroy (mask_image);
3866         }
3867
3868       tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_ARROW;
3869       gdk_window_move (tree_view->priv->drag_highlight_window, x, y);
3870     }
3871   else if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT ||
3872            arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
3873     {
3874       GtkAllocation allocation;
3875       GtkWidget    *button;
3876       gint          expander_size;
3877
3878       expander_size = gtk_tree_view_get_expander_size (tree_view);
3879
3880       /* Get x, y, width, height of arrow */
3881       width = expander_size/2; /* remember, the arrow only takes half the available width */
3882       gdk_window_get_origin (gtk_widget_get_window (widget),
3883                              &x, &y);
3884       if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
3885         {
3886           gtk_widget_get_allocation (widget, &allocation);
3887           x += allocation.width - width;
3888         }
3889
3890       if (reorder->left_column)
3891         {
3892           button = gtk_tree_view_column_get_button (reorder->left_column);
3893           gtk_widget_get_allocation (button, &allocation);
3894           height = allocation.height;
3895         }
3896       else
3897         {
3898           button = gtk_tree_view_column_get_button (reorder->right_column);
3899           gtk_widget_get_allocation (button, &allocation);
3900           height = allocation.height;
3901         }
3902
3903       y -= expander_size;
3904       height += 2 * expander_size;
3905
3906       /* Create the new window */
3907       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT &&
3908           tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
3909         {
3910           if (tree_view->priv->drag_highlight_window)
3911             {
3912               gdk_window_set_user_data (tree_view->priv->drag_highlight_window,
3913                                         NULL);
3914               gdk_window_destroy (tree_view->priv->drag_highlight_window);
3915             }
3916
3917           attributes.window_type = GDK_WINDOW_TEMP;
3918           attributes.wclass = GDK_INPUT_OUTPUT;
3919           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
3920           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3921           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
3922           attributes.x = x;
3923           attributes.y = y;
3924           attributes.width = width;
3925           attributes.height = height;
3926           tree_view->priv->drag_highlight_window = gdk_window_new (NULL, &attributes, attributes_mask);
3927           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
3928
3929           mask_image = cairo_image_surface_create (CAIRO_FORMAT_A1, width, height);
3930
3931           cr = cairo_create (mask_image);
3932           /* mirror if we're on the left */
3933           if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT)
3934             {
3935               cairo_translate (cr, width, 0);
3936               cairo_scale (cr, -1, 1);
3937             }
3938           cairo_move_to (cr, 0, 0);
3939           cairo_line_to (cr, width, width);
3940           cairo_line_to (cr, 0, expander_size);
3941           cairo_move_to (cr, 0, height);
3942           cairo_line_to (cr, width, height - width);
3943           cairo_line_to (cr, 0, height - expander_size);
3944           cairo_fill (cr);
3945           cairo_destroy (cr);
3946
3947           mask_region = gdk_cairo_region_create_from_surface (mask_image);
3948           gdk_window_shape_combine_region (tree_view->priv->drag_highlight_window,
3949                                            mask_region, 0, 0);
3950
3951           cairo_region_destroy (mask_region);
3952           cairo_surface_destroy (mask_image);
3953         }
3954
3955       tree_view->priv->drag_column_window_state = arrow_type;
3956       gdk_window_move (tree_view->priv->drag_highlight_window, x, y);
3957    }
3958   else
3959     {
3960       g_warning (G_STRLOC"Invalid GtkTreeViewColumnReorder struct");
3961       gdk_window_hide (tree_view->priv->drag_highlight_window);
3962       return;
3963     }
3964
3965   gdk_window_show (tree_view->priv->drag_highlight_window);
3966   gdk_window_raise (tree_view->priv->drag_highlight_window);
3967 }
3968
3969 static gboolean
3970 gtk_tree_view_motion_resize_column (GtkWidget      *widget,
3971                                     GdkEventMotion *event)
3972 {
3973   gint x;
3974   gint new_width;
3975   GtkTreeViewColumn *column;
3976   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
3977
3978   column = gtk_tree_view_get_column (tree_view, tree_view->priv->drag_pos);
3979
3980   if (event->is_hint || event->window != gtk_widget_get_window (widget))
3981     gdk_window_get_device_position (gtk_widget_get_window (widget),
3982                                     gdk_event_get_device ((GdkEvent *) event),
3983                                     &x, NULL, NULL);
3984   else
3985     x = event->x;
3986
3987   if (tree_view->priv->hadjustment)
3988     x += gtk_adjustment_get_value (tree_view->priv->hadjustment);
3989
3990   new_width = gtk_tree_view_new_column_width (tree_view,
3991                                               tree_view->priv->drag_pos, &x);
3992   if (x != tree_view->priv->x_drag &&
3993       (new_width != gtk_tree_view_column_get_fixed_width (column)))
3994     {
3995       _gtk_tree_view_column_set_use_resized_width (column, TRUE);
3996
3997       if (gtk_tree_view_column_get_expand (column))
3998         new_width -= tree_view->priv->last_extra_space_per_column;
3999
4000       _gtk_tree_view_column_set_resized_width (column, new_width);
4001
4002
4003       gtk_widget_queue_resize (widget);
4004     }
4005
4006   return FALSE;
4007 }
4008
4009
4010 static void
4011 gtk_tree_view_update_current_reorder (GtkTreeView *tree_view,
4012                                       GdkEvent    *event)
4013 {
4014   GtkTreeViewColumnReorder *reorder = NULL;
4015   GList *list;
4016   gint mouse_x;
4017
4018   gdk_window_get_device_position (tree_view->priv->header_window,
4019                                   gdk_event_get_device (event),
4020                                   &mouse_x, NULL, NULL);
4021   for (list = tree_view->priv->column_drag_info; list; list = list->next)
4022     {
4023       reorder = (GtkTreeViewColumnReorder *) list->data;
4024       if (mouse_x >= reorder->left_align && mouse_x < reorder->right_align)
4025         break;
4026       reorder = NULL;
4027     }
4028
4029   /*  if (reorder && reorder == tree_view->priv->cur_reorder)
4030       return;*/
4031
4032   tree_view->priv->cur_reorder = reorder;
4033   gtk_tree_view_motion_draw_column_motion_arrow (tree_view);
4034 }
4035
4036 static void
4037 gtk_tree_view_vertical_autoscroll (GtkTreeView *tree_view)
4038 {
4039   GdkRectangle visible_rect;
4040   gint y;
4041   gint offset;
4042
4043   gdk_window_get_device_position (tree_view->priv->bin_window,
4044                                   gdk_device_manager_get_client_pointer (
4045                                     gdk_display_get_device_manager (
4046                                       gtk_widget_get_display (GTK_WIDGET (tree_view)))),
4047                                   NULL, &y, NULL);
4048   y += tree_view->priv->dy;
4049
4050   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
4051
4052   /* see if we are near the edge. */
4053   offset = y - (visible_rect.y + 2 * SCROLL_EDGE_SIZE);
4054   if (offset > 0)
4055     {
4056       offset = y - (visible_rect.y + visible_rect.height - 2 * SCROLL_EDGE_SIZE);
4057       if (offset < 0)
4058         return;
4059     }
4060
4061   gtk_adjustment_set_value (tree_view->priv->vadjustment,
4062                             MAX (gtk_adjustment_get_value (tree_view->priv->vadjustment) + offset, 0.0));
4063 }
4064
4065 static gboolean
4066 gtk_tree_view_horizontal_autoscroll (GtkTreeView *tree_view,
4067                                      GdkEvent    *event)
4068 {
4069   GdkRectangle visible_rect;
4070   gint x;
4071   gint offset;
4072
4073   gdk_window_get_device_position (tree_view->priv->bin_window,
4074                                   gdk_event_get_device (event),
4075                                   &x, NULL, NULL);
4076
4077   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
4078
4079   /* See if we are near the edge. */
4080   offset = x - (visible_rect.x + SCROLL_EDGE_SIZE);
4081   if (offset > 0)
4082     {
4083       offset = x - (visible_rect.x + visible_rect.width - SCROLL_EDGE_SIZE);
4084       if (offset < 0)
4085         return TRUE;
4086     }
4087   offset = offset/3;
4088
4089   gtk_adjustment_set_value (tree_view->priv->hadjustment,
4090                             MAX (gtk_adjustment_get_value (tree_view->priv->hadjustment) + offset, 0.0));
4091
4092   return TRUE;
4093
4094 }
4095
4096 static gboolean
4097 gtk_tree_view_motion_drag_column (GtkWidget      *widget,
4098                                   GdkEventMotion *event)
4099 {
4100   GtkAllocation allocation, button_allocation;
4101   GtkTreeView *tree_view = (GtkTreeView *) widget;
4102   GtkTreeViewColumn *column = tree_view->priv->drag_column;
4103   GtkWidget *button;
4104   gint x, y;
4105
4106   /* Sanity Check */
4107   if ((column == NULL) ||
4108       (event->window != tree_view->priv->drag_window))
4109     return FALSE;
4110
4111   button = gtk_tree_view_column_get_button (column);
4112
4113   /* Handle moving the header */
4114   gdk_window_get_position (tree_view->priv->drag_window, &x, &y);
4115   gtk_widget_get_allocation (widget, &allocation);
4116   gtk_widget_get_allocation (button, &button_allocation);
4117   x = CLAMP (x + (gint)event->x - _gtk_tree_view_column_get_drag_x (column), 0,
4118              MAX (tree_view->priv->width, allocation.width) - button_allocation.width);
4119   gdk_window_move (tree_view->priv->drag_window, x, y);
4120   
4121   /* autoscroll, if needed */
4122   gtk_tree_view_horizontal_autoscroll (tree_view, (GdkEvent *) event);
4123   /* Update the current reorder position and arrow; */
4124   gtk_tree_view_update_current_reorder (tree_view, (GdkEvent *) event);
4125
4126   return TRUE;
4127 }
4128
4129 static void
4130 gtk_tree_view_stop_rubber_band (GtkTreeView *tree_view)
4131 {
4132   remove_scroll_timeout (tree_view);
4133   gtk_grab_remove (GTK_WIDGET (tree_view));
4134
4135   if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
4136     {
4137       GtkTreePath *tmp_path;
4138
4139       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
4140
4141       /* The anchor path should be set to the start path */
4142       tmp_path = _gtk_tree_path_new_from_rbtree (tree_view->priv->rubber_band_start_tree,
4143                                                  tree_view->priv->rubber_band_start_node);
4144
4145       if (tree_view->priv->anchor)
4146         gtk_tree_row_reference_free (tree_view->priv->anchor);
4147
4148       tree_view->priv->anchor =
4149         gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
4150                                           tree_view->priv->model,
4151                                           tmp_path);
4152
4153       gtk_tree_path_free (tmp_path);
4154
4155       /* ... and the cursor to the end path */
4156       tmp_path = _gtk_tree_path_new_from_rbtree (tree_view->priv->rubber_band_end_tree,
4157                                                  tree_view->priv->rubber_band_end_node);
4158       gtk_tree_view_real_set_cursor (GTK_TREE_VIEW (tree_view), tmp_path, 0);
4159       gtk_tree_path_free (tmp_path);
4160
4161       _gtk_tree_selection_emit_changed (tree_view->priv->selection);
4162     }
4163
4164   /* Clear status variables */
4165   tree_view->priv->rubber_band_status = RUBBER_BAND_OFF;
4166   tree_view->priv->rubber_band_extend = FALSE;
4167   tree_view->priv->rubber_band_modify = FALSE;
4168
4169   tree_view->priv->rubber_band_start_node = NULL;
4170   tree_view->priv->rubber_band_start_tree = NULL;
4171   tree_view->priv->rubber_band_end_node = NULL;
4172   tree_view->priv->rubber_band_end_tree = NULL;
4173 }
4174
4175 static void
4176 gtk_tree_view_update_rubber_band_selection_range (GtkTreeView *tree_view,
4177                                                  GtkRBTree   *start_tree,
4178                                                  GtkRBNode   *start_node,
4179                                                  GtkRBTree   *end_tree,
4180                                                  GtkRBNode   *end_node,
4181                                                  gboolean     select,
4182                                                  gboolean     skip_start,
4183                                                  gboolean     skip_end)
4184 {
4185   if (start_node == end_node)
4186     return;
4187
4188   /* We skip the first node and jump inside the loop */
4189   if (skip_start)
4190     goto skip_first;
4191
4192   do
4193     {
4194       /* Small optimization by assuming insensitive nodes are never
4195        * selected.
4196        */
4197       if (!GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
4198         {
4199           GtkTreePath *path;
4200           gboolean selectable;
4201
4202           path = _gtk_tree_path_new_from_rbtree (start_tree, start_node);
4203           selectable = _gtk_tree_selection_row_is_selectable (tree_view->priv->selection, start_node, path);
4204           gtk_tree_path_free (path);
4205
4206           if (!selectable)
4207             goto node_not_selectable;
4208         }
4209
4210       if (select)
4211         {
4212           if (tree_view->priv->rubber_band_extend)
4213             GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4214           else if (tree_view->priv->rubber_band_modify)
4215             {
4216               /* Toggle the selection state */
4217               if (GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
4218                 GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4219               else
4220                 GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4221             }
4222           else
4223             GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4224         }
4225       else
4226         {
4227           /* Mirror the above */
4228           if (tree_view->priv->rubber_band_extend)
4229             GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4230           else if (tree_view->priv->rubber_band_modify)
4231             {
4232               /* Toggle the selection state */
4233               if (GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
4234                 GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4235               else
4236                 GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4237             }
4238           else
4239             GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4240         }
4241
4242       _gtk_tree_view_queue_draw_node (tree_view, start_tree, start_node, NULL);
4243
4244 node_not_selectable:
4245       if (start_node == end_node)
4246         break;
4247
4248 skip_first:
4249
4250       if (start_node->children)
4251         {
4252           start_tree = start_node->children;
4253           start_node = _gtk_rbtree_first (start_tree);
4254         }
4255       else
4256         {
4257           _gtk_rbtree_next_full (start_tree, start_node, &start_tree, &start_node);
4258
4259           if (!start_tree)
4260             /* Ran out of tree */
4261             break;
4262         }
4263
4264       if (skip_end && start_node == end_node)
4265         break;
4266     }
4267   while (TRUE);
4268 }
4269
4270 static void
4271 gtk_tree_view_update_rubber_band_selection (GtkTreeView *tree_view)
4272 {
4273   GtkRBTree *start_tree, *end_tree;
4274   GtkRBNode *start_node, *end_node;
4275
4276   _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);
4277   _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);
4278
4279   /* Handle the start area first */
4280   if (!tree_view->priv->rubber_band_start_node)
4281     {
4282       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4283                                                        start_tree,
4284                                                        start_node,
4285                                                        end_tree,
4286                                                        end_node,
4287                                                        TRUE,
4288                                                        FALSE,
4289                                                        FALSE);
4290     }
4291   else if (_gtk_rbtree_node_find_offset (start_tree, start_node) <
4292            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_start_tree, tree_view->priv->rubber_band_start_node))
4293     {
4294       /* New node is above the old one; selection became bigger */
4295       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4296                                                        start_tree,
4297                                                        start_node,
4298                                                        tree_view->priv->rubber_band_start_tree,
4299                                                        tree_view->priv->rubber_band_start_node,
4300                                                        TRUE,
4301                                                        FALSE,
4302                                                        TRUE);
4303     }
4304   else if (_gtk_rbtree_node_find_offset (start_tree, start_node) >
4305            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_start_tree, tree_view->priv->rubber_band_start_node))
4306     {
4307       /* New node is below the old one; selection became smaller */
4308       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4309                                                        tree_view->priv->rubber_band_start_tree,
4310                                                        tree_view->priv->rubber_band_start_node,
4311                                                        start_tree,
4312                                                        start_node,
4313                                                        FALSE,
4314                                                        FALSE,
4315                                                        TRUE);
4316     }
4317
4318   tree_view->priv->rubber_band_start_tree = start_tree;
4319   tree_view->priv->rubber_band_start_node = start_node;
4320
4321   /* Next, handle the end area */
4322   if (!tree_view->priv->rubber_band_end_node)
4323     {
4324       /* In the event this happens, start_node was also NULL; this case is
4325        * handled above.
4326        */
4327     }
4328   else if (!end_node)
4329     {
4330       /* Find the last node in the tree */
4331       _gtk_rbtree_find_offset (tree_view->priv->tree, tree_view->priv->height - 1,
4332                                &end_tree, &end_node);
4333
4334       /* Selection reached end of the tree */
4335       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4336                                                        tree_view->priv->rubber_band_end_tree,
4337                                                        tree_view->priv->rubber_band_end_node,
4338                                                        end_tree,
4339                                                        end_node,
4340                                                        TRUE,
4341                                                        TRUE,
4342                                                        FALSE);
4343     }
4344   else if (_gtk_rbtree_node_find_offset (end_tree, end_node) >
4345            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_end_tree, tree_view->priv->rubber_band_end_node))
4346     {
4347       /* New node is below the old one; selection became bigger */
4348       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4349                                                        tree_view->priv->rubber_band_end_tree,
4350                                                        tree_view->priv->rubber_band_end_node,
4351                                                        end_tree,
4352                                                        end_node,
4353                                                        TRUE,
4354                                                        TRUE,
4355                                                        FALSE);
4356     }
4357   else if (_gtk_rbtree_node_find_offset (end_tree, end_node) <
4358            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_end_tree, tree_view->priv->rubber_band_end_node))
4359     {
4360       /* New node is above the old one; selection became smaller */
4361       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4362                                                        end_tree,
4363                                                        end_node,
4364                                                        tree_view->priv->rubber_band_end_tree,
4365                                                        tree_view->priv->rubber_band_end_node,
4366                                                        FALSE,
4367                                                        TRUE,
4368                                                        FALSE);
4369     }
4370
4371   tree_view->priv->rubber_band_end_tree = end_tree;
4372   tree_view->priv->rubber_band_end_node = end_node;
4373 }
4374
4375 static void
4376 gtk_tree_view_update_rubber_band (GtkTreeView *tree_view)
4377 {
4378   gint x, y;
4379   GdkRectangle old_area;
4380   GdkRectangle new_area;
4381   GdkRectangle common;
4382   cairo_region_t *invalid_region;
4383
4384   old_area.x = MIN (tree_view->priv->press_start_x, tree_view->priv->rubber_band_x);
4385   old_area.y = MIN (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y) - tree_view->priv->dy;
4386   old_area.width = ABS (tree_view->priv->rubber_band_x - tree_view->priv->press_start_x) + 1;
4387   old_area.height = ABS (tree_view->priv->rubber_band_y - tree_view->priv->press_start_y) + 1;
4388
4389   gdk_window_get_device_position (tree_view->priv->bin_window,
4390                                   gdk_device_manager_get_client_pointer (
4391                                     gdk_display_get_device_manager (
4392                                       gtk_widget_get_display (GTK_WIDGET (tree_view)))),
4393                                   &x, &y, NULL);
4394
4395   x = MAX (x, 0);
4396   y = MAX (y, 0) + tree_view->priv->dy;
4397
4398   new_area.x = MIN (tree_view->priv->press_start_x, x);
4399   new_area.y = MIN (tree_view->priv->press_start_y, y) - tree_view->priv->dy;
4400   new_area.width = ABS (x - tree_view->priv->press_start_x) + 1;
4401   new_area.height = ABS (y - tree_view->priv->press_start_y) + 1;
4402
4403   invalid_region = cairo_region_create_rectangle (&old_area);
4404   cairo_region_union_rectangle (invalid_region, &new_area);
4405
4406   gdk_rectangle_intersect (&old_area, &new_area, &common);
4407   if (common.width > 2 && common.height > 2)
4408     {
4409       cairo_region_t *common_region;
4410
4411       /* make sure the border is invalidated */
4412       common.x += 1;
4413       common.y += 1;
4414       common.width -= 2;
4415       common.height -= 2;
4416
4417       common_region = cairo_region_create_rectangle (&common);
4418
4419       cairo_region_subtract (invalid_region, common_region);
4420       cairo_region_destroy (common_region);
4421     }
4422
4423   gdk_window_invalidate_region (tree_view->priv->bin_window, invalid_region, TRUE);
4424
4425   cairo_region_destroy (invalid_region);
4426
4427   tree_view->priv->rubber_band_x = x;
4428   tree_view->priv->rubber_band_y = y;
4429
4430   gtk_tree_view_update_rubber_band_selection (tree_view);
4431 }
4432
4433 static void
4434 gtk_tree_view_paint_rubber_band (GtkTreeView  *tree_view,
4435                                  cairo_t      *cr)
4436 {
4437   GdkRectangle rect;
4438   GtkStyleContext *context;
4439
4440   cairo_save (cr);
4441
4442   context = gtk_widget_get_style_context (GTK_WIDGET (tree_view));
4443
4444   gtk_style_context_save (context);
4445   gtk_style_context_add_class (context, GTK_STYLE_CLASS_RUBBERBAND);
4446
4447   rect.x = MIN (tree_view->priv->press_start_x, tree_view->priv->rubber_band_x);
4448   rect.y = MIN (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y) - tree_view->priv->dy;
4449   rect.width = ABS (tree_view->priv->press_start_x - tree_view->priv->rubber_band_x) + 1;
4450   rect.height = ABS (tree_view->priv->press_start_y - tree_view->priv->rubber_band_y) + 1;
4451
4452   gdk_cairo_rectangle (cr, &rect);
4453   cairo_clip (cr);
4454
4455   gtk_render_background (context, cr,
4456                          rect.x, rect.y,
4457                          rect.width, rect.height);
4458   gtk_render_frame (context, cr,
4459                     rect.x, rect.y,
4460                     rect.width, rect.height);
4461
4462   gtk_style_context_restore (context);
4463   cairo_restore (cr);
4464 }
4465
4466 static gboolean
4467 gtk_tree_view_motion_bin_window (GtkWidget      *widget,
4468                                  GdkEventMotion *event)
4469 {
4470   GtkTreeView *tree_view;
4471   GtkRBTree *tree;
4472   GtkRBNode *node;
4473   gint new_y;
4474
4475   tree_view = (GtkTreeView *) widget;
4476
4477   if (tree_view->priv->tree == NULL)
4478     return FALSE;
4479
4480   if (tree_view->priv->rubber_band_status == RUBBER_BAND_MAYBE_START)
4481     {
4482       gtk_grab_add (GTK_WIDGET (tree_view));
4483       gtk_tree_view_update_rubber_band (tree_view);
4484
4485       tree_view->priv->rubber_band_status = RUBBER_BAND_ACTIVE;
4486     }
4487   else if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
4488     {
4489       gtk_tree_view_update_rubber_band (tree_view);
4490
4491       add_scroll_timeout (tree_view);
4492     }
4493
4494   /* only check for an initiated drag when a button is pressed */
4495   if (tree_view->priv->pressed_button >= 0
4496       && !tree_view->priv->rubber_band_status)
4497     gtk_tree_view_maybe_begin_dragging_row (tree_view, event);
4498
4499   new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
4500   if (new_y < 0)
4501     new_y = 0;
4502
4503   _gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
4504
4505   /* If we are currently pressing down a button, we don't want to prelight anything else. */
4506   if ((tree_view->priv->button_pressed_node != NULL) &&
4507       (tree_view->priv->button_pressed_node != node))
4508     node = NULL;
4509
4510   tree_view->priv->event_last_x = event->x;
4511   tree_view->priv->event_last_y = event->y;
4512
4513   prelight_or_select (tree_view, tree, node, event->x, event->y);
4514
4515   return TRUE;
4516 }
4517
4518 static gboolean
4519 gtk_tree_view_motion (GtkWidget      *widget,
4520                       GdkEventMotion *event)
4521 {
4522   GtkTreeView *tree_view;
4523
4524   tree_view = (GtkTreeView *) widget;
4525
4526   /* Resizing a column */
4527   if (tree_view->priv->in_column_resize)
4528     return gtk_tree_view_motion_resize_column (widget, event);
4529
4530   /* Drag column */
4531   if (tree_view->priv->in_column_drag)
4532     return gtk_tree_view_motion_drag_column (widget, event);
4533
4534   /* Sanity check it */
4535   if (event->window == tree_view->priv->bin_window)
4536     return gtk_tree_view_motion_bin_window (widget, event);
4537
4538   return FALSE;
4539 }
4540
4541 /* Invalidate the focus rectangle near the edge of the bin_window; used when
4542  * the tree is empty.
4543  */
4544 static void
4545 invalidate_empty_focus (GtkTreeView *tree_view)
4546 {
4547   GdkRectangle area;
4548
4549   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
4550     return;
4551
4552   area.x = 0;
4553   area.y = 0;
4554   area.width = gdk_window_get_width (tree_view->priv->bin_window);
4555   area.height = gdk_window_get_height (tree_view->priv->bin_window);
4556   gdk_window_invalidate_rect (tree_view->priv->bin_window, &area, FALSE);
4557 }
4558
4559 /* Draws a focus rectangle near the edge of the bin_window; used when the tree
4560  * is empty.
4561  */
4562 static void
4563 draw_empty_focus (GtkTreeView *tree_view, cairo_t *cr)
4564 {
4565   GtkWidget *widget = GTK_WIDGET (tree_view);
4566   gint w, h;
4567
4568   if (!gtk_widget_has_visible_focus (widget))
4569     return;
4570
4571   w = gdk_window_get_width (tree_view->priv->bin_window) - 2;
4572   h = gdk_window_get_height (tree_view->priv->bin_window) - 2;
4573
4574   if (w > 0 && h > 0)
4575     {
4576       GtkStyleContext *context;
4577
4578       context = gtk_widget_get_style_context (widget);
4579
4580       gtk_render_focus (context, cr, 1, 1, w, h);
4581     }
4582 }
4583
4584 typedef enum {
4585   GTK_TREE_VIEW_GRID_LINE,
4586   GTK_TREE_VIEW_TREE_LINE,
4587   GTK_TREE_VIEW_FOREGROUND_LINE
4588 } GtkTreeViewLineType;
4589
4590 static void
4591 gtk_tree_view_draw_line (GtkTreeView         *tree_view,
4592                          cairo_t             *cr,
4593                          GtkTreeViewLineType  type,
4594                          int                  x1,
4595                          int                  y1,
4596                          int                  x2,
4597                          int                  y2)
4598 {
4599   cairo_save (cr);
4600
4601   switch (type)
4602     {
4603     case GTK_TREE_VIEW_TREE_LINE:
4604       cairo_set_source_rgb (cr, 0, 0, 0);
4605       cairo_set_line_width (cr, tree_view->priv->tree_line_width);
4606       if (tree_view->priv->tree_line_dashes[0])
4607         cairo_set_dash (cr, 
4608                         tree_view->priv->tree_line_dashes,
4609                         2, 0.5);
4610       break;
4611     case GTK_TREE_VIEW_GRID_LINE:
4612       cairo_set_source_rgb (cr, 0, 0, 0);
4613       cairo_set_line_width (cr, tree_view->priv->grid_line_width);
4614       if (tree_view->priv->grid_line_dashes[0])
4615         cairo_set_dash (cr, 
4616                         tree_view->priv->grid_line_dashes,
4617                         2, 0.5);
4618       break;
4619     default:
4620       g_assert_not_reached ();
4621       /* fall through */
4622     case GTK_TREE_VIEW_FOREGROUND_LINE:
4623       {
4624         GtkStyleContext *context;
4625         GtkStateFlags state;
4626         GdkRGBA color;
4627
4628         context = gtk_widget_get_style_context (GTK_WIDGET (tree_view));
4629         state = gtk_widget_get_state_flags (GTK_WIDGET (tree_view));
4630
4631         cairo_set_line_width (cr, 1.0);
4632         gtk_style_context_get_color (context, state, &color);
4633         gdk_cairo_set_source_rgba (cr, &color);
4634       }
4635
4636       break;
4637     }
4638
4639   cairo_move_to (cr, x1 + 0.5, y1 + 0.5);
4640   cairo_line_to (cr, x2 + 0.5, y2 + 0.5);
4641   cairo_stroke (cr);
4642
4643   cairo_restore (cr);
4644 }
4645                          
4646 static void
4647 gtk_tree_view_draw_grid_lines (GtkTreeView    *tree_view,
4648                                cairo_t        *cr,
4649                                gint            n_visible_columns)
4650 {
4651   GList *list = tree_view->priv->columns;
4652   gint i = 0;
4653   gint current_x = 0;
4654
4655   if (tree_view->priv->grid_lines != GTK_TREE_VIEW_GRID_LINES_VERTICAL
4656       && tree_view->priv->grid_lines != GTK_TREE_VIEW_GRID_LINES_BOTH)
4657     return;
4658
4659   /* Only draw the lines for visible rows and columns */
4660   for (list = tree_view->priv->columns; list; list = list->next, i++)
4661     {
4662       GtkTreeViewColumn *column = list->data;
4663
4664       /* We don't want a line for the last column */
4665       if (i == n_visible_columns - 1)
4666         break;
4667
4668       if (!gtk_tree_view_column_get_visible (column))
4669         continue;
4670
4671       current_x += gtk_tree_view_column_get_width (column);
4672
4673       gtk_tree_view_draw_line (tree_view, cr,
4674                                GTK_TREE_VIEW_GRID_LINE,
4675                                current_x - 1, 0,
4676                                current_x - 1, tree_view->priv->height);
4677     }
4678 }
4679
4680 /* Warning: Very scary function.
4681  * Modify at your own risk
4682  *
4683  * KEEP IN SYNC WITH gtk_tree_view_create_row_drag_icon()!
4684  * FIXME: It's not...
4685  */
4686 static gboolean
4687 gtk_tree_view_bin_draw (GtkWidget      *widget,
4688                         cairo_t        *cr)
4689 {
4690   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
4691   GtkTreePath *path;
4692   GtkRBTree *tree;
4693   GList *list;
4694   GtkRBNode *node;
4695   GtkRBNode *drag_highlight = NULL;
4696   GtkRBTree *drag_highlight_tree = NULL;
4697   GtkTreeIter iter;
4698   gint new_y;
4699   gint y_offset, cell_offset;
4700   gint max_height;
4701   gint depth;
4702   GdkRectangle background_area;
4703   GdkRectangle cell_area;
4704   GdkRectangle clip;
4705   guint flags;
4706   gint highlight_x;
4707   gint expander_cell_width;
4708   gint bin_window_width;
4709   gint bin_window_height;
4710   GtkTreePath *drag_dest_path;
4711   GList *first_column, *last_column;
4712   gint vertical_separator;
4713   gint horizontal_separator;
4714   gboolean allow_rules;
4715   gboolean has_can_focus_cell;
4716   gboolean rtl;
4717   gint n_visible_columns;
4718   gint grid_line_width;
4719   gint expander_size;
4720   gboolean draw_vgrid_lines, draw_hgrid_lines;
4721   GtkStyleContext *context;
4722   gboolean parity;
4723
4724   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
4725   context = gtk_widget_get_style_context (widget);
4726
4727   gtk_widget_style_get (widget,
4728                         "horizontal-separator", &horizontal_separator,
4729                         "vertical-separator", &vertical_separator,
4730                         "allow-rules", &allow_rules,
4731                         NULL);
4732
4733   if (tree_view->priv->tree == NULL)
4734     {
4735       draw_empty_focus (tree_view, cr);
4736       return TRUE;
4737     }
4738
4739   bin_window_width = gdk_window_get_width (tree_view->priv->bin_window);
4740   bin_window_height = gdk_window_get_height (tree_view->priv->bin_window);
4741   cairo_rectangle (cr, 0, 0, bin_window_width, bin_window_height);
4742   cairo_clip (cr);
4743   if (!gdk_cairo_get_clip_rectangle (cr, &clip))
4744     return TRUE;
4745
4746   new_y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, clip.y);
4747
4748   if (new_y < 0)
4749     new_y = 0;
4750   y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
4751
4752   if (tree_view->priv->height < bin_window_height)
4753     {
4754       gtk_style_context_save (context);
4755       gtk_style_context_add_class (context, GTK_STYLE_CLASS_CELL);
4756
4757       gtk_render_background (context, cr,
4758                              0, tree_view->priv->height,
4759                              bin_window_width,
4760                              bin_window_height - tree_view->priv->height);
4761
4762       gtk_style_context_restore (context);
4763     }
4764
4765   if (node == NULL)
4766     return TRUE;
4767
4768   /* find the path for the node */
4769   path = _gtk_tree_path_new_from_rbtree (tree, node);
4770   gtk_tree_model_get_iter (tree_view->priv->model,
4771                            &iter,
4772                            path);
4773   depth = gtk_tree_path_get_depth (path);
4774   gtk_tree_path_free (path);
4775   
4776   drag_dest_path = NULL;
4777
4778   if (tree_view->priv->drag_dest_row)
4779     drag_dest_path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
4780
4781   if (drag_dest_path)
4782     _gtk_tree_view_find_node (tree_view, drag_dest_path,
4783                               &drag_highlight_tree, &drag_highlight);
4784
4785   draw_vgrid_lines =
4786     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_VERTICAL
4787     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
4788   draw_hgrid_lines =
4789     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_HORIZONTAL
4790     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
4791   expander_size = gtk_tree_view_get_expander_size (tree_view);
4792
4793   if (draw_vgrid_lines || draw_hgrid_lines)
4794     gtk_widget_style_get (widget, "grid-line-width", &grid_line_width, NULL);
4795   
4796   n_visible_columns = 0;
4797   for (list = tree_view->priv->columns; list; list = list->next)
4798     {
4799       if (!gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (list->data)))
4800         continue;
4801       n_visible_columns ++;
4802     }
4803
4804   /* Find the last column */
4805   for (last_column = g_list_last (tree_view->priv->columns);
4806        last_column &&
4807        !(gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (last_column->data)));
4808        last_column = last_column->prev)
4809     ;
4810
4811   /* and the first */
4812   for (first_column = g_list_first (tree_view->priv->columns);
4813        first_column &&
4814        !(gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (first_column->data)));
4815        first_column = first_column->next)
4816     ;
4817
4818   /* Actually process the expose event.  To do this, we want to
4819    * start at the first node of the event, and walk the tree in
4820    * order, drawing each successive node.
4821    */
4822   
4823   parity = !(_gtk_rbtree_node_get_index (tree, node) % 2);
4824
4825   do
4826     {
4827       gboolean is_separator = FALSE;
4828       gboolean is_first = FALSE;
4829       gboolean is_last = FALSE;
4830       gint n_col = 0;
4831
4832       parity = !parity;
4833       is_separator = row_is_separator (tree_view, &iter, NULL);
4834
4835       max_height = gtk_tree_view_get_row_height (tree_view, node);
4836
4837       cell_offset = 0;
4838       highlight_x = 0; /* should match x coord of first cell */
4839       expander_cell_width = 0;
4840
4841       background_area.y = y_offset + clip.y;
4842       background_area.height = max_height;
4843
4844       flags = 0;
4845
4846       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PRELIT))
4847         flags |= GTK_CELL_RENDERER_PRELIT;
4848
4849       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
4850         flags |= GTK_CELL_RENDERER_SELECTED;
4851
4852       /* we *need* to set cell data on all cells before the call
4853        * to _has_can_focus_cell, else _has_can_focus_cell() does not
4854        * return a correct value.
4855        */
4856       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
4857            list;
4858            list = (rtl ? list->prev : list->next))
4859         {
4860           GtkTreeViewColumn *column = list->data;
4861           gtk_tree_view_column_cell_set_cell_data (column,
4862                                                    tree_view->priv->model,
4863                                                    &iter,
4864                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
4865                                                    node->children?TRUE:FALSE);
4866         }
4867
4868       has_can_focus_cell = gtk_tree_view_has_can_focus_cell (tree_view);
4869
4870       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
4871            list;
4872            list = (rtl ? list->prev : list->next))
4873         {
4874           GtkTreeViewColumn *column = list->data;
4875           GtkRegionFlags row_flags = 0, column_flags = 0;
4876           GtkStateFlags state = 0;
4877           gint width;
4878           gboolean draw_focus;
4879
4880           if (!gtk_tree_view_column_get_visible (column))
4881             continue;
4882
4883           n_col++;
4884           width = gtk_tree_view_column_get_width (column);
4885
4886           if (cell_offset > clip.x + clip.width ||
4887               cell_offset + width < clip.x)
4888             {
4889               cell_offset += width;
4890               continue;
4891             }
4892
4893           if (gtk_tree_view_column_get_sort_indicator (column))
4894             flags |= GTK_CELL_RENDERER_SORTED;
4895           else
4896             flags &= ~GTK_CELL_RENDERER_SORTED;
4897
4898           if (tree_view->priv->cursor_node == node)
4899             flags |= GTK_CELL_RENDERER_FOCUSED;
4900           else
4901             flags &= ~GTK_CELL_RENDERER_FOCUSED;
4902
4903           if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
4904             flags |= GTK_CELL_RENDERER_EXPANDABLE;
4905           else
4906             flags &= ~GTK_CELL_RENDERER_EXPANDABLE;
4907
4908           if (node->children)
4909             flags |= GTK_CELL_RENDERER_EXPANDED;
4910           else
4911             flags &= ~GTK_CELL_RENDERER_EXPANDED;
4912
4913           background_area.x = cell_offset;
4914           background_area.width = width;
4915
4916           cell_area = background_area;
4917           cell_area.y += vertical_separator / 2;
4918           cell_area.x += horizontal_separator / 2;
4919           cell_area.height -= vertical_separator;
4920           cell_area.width -= horizontal_separator;
4921
4922           if (draw_vgrid_lines)
4923             {
4924               if (list == first_column)
4925                 {
4926                   cell_area.width -= grid_line_width / 2;
4927                 }
4928               else if (list == last_column)
4929                 {
4930                   cell_area.x += grid_line_width / 2;
4931                   cell_area.width -= grid_line_width / 2;
4932                 }
4933               else
4934                 {
4935                   cell_area.x += grid_line_width / 2;
4936                   cell_area.width -= grid_line_width;
4937                 }
4938             }
4939
4940           if (draw_hgrid_lines)
4941             {
4942               cell_area.y += grid_line_width / 2;
4943               cell_area.height -= grid_line_width;
4944             }
4945
4946           if (!gdk_rectangle_intersect (&clip, &background_area, NULL))
4947             {
4948               cell_offset += gtk_tree_view_column_get_width (column);
4949               continue;
4950             }
4951
4952           gtk_tree_view_column_cell_set_cell_data (column,
4953                                                    tree_view->priv->model,
4954                                                    &iter,
4955                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
4956                                                    node->children?TRUE:FALSE);
4957
4958           /* Select the detail for drawing the cell.  relevant
4959            * factors are parity, sortedness, and whether to
4960            * display rules.
4961            */
4962           if (allow_rules && tree_view->priv->has_rules)
4963             {
4964               if (parity)
4965                 row_flags |= GTK_REGION_ODD;
4966               else
4967                 row_flags |= GTK_REGION_EVEN;
4968             }
4969
4970           if ((flags & GTK_CELL_RENDERER_SORTED) &&
4971               n_visible_columns >= 3)
4972             column_flags |= GTK_REGION_SORTED;
4973
4974           is_first = (rtl ? !list->next : !list->prev);
4975           is_last = (rtl ? !list->prev : !list->next);
4976
4977           if (is_first)
4978             column_flags |= GTK_REGION_FIRST;
4979
4980           if (is_last)
4981             column_flags |= GTK_REGION_LAST;
4982
4983           if ((n_col % 2) == 0)
4984             column_flags |= GTK_REGION_EVEN;
4985           else
4986             column_flags |= GTK_REGION_ODD;
4987
4988           gtk_style_context_save (context);
4989
4990           state = gtk_cell_renderer_get_state (NULL, widget, flags);
4991           gtk_style_context_set_state (context, state);
4992
4993           gtk_style_context_add_class (context, GTK_STYLE_CLASS_CELL);
4994           gtk_style_context_add_region (context, GTK_STYLE_REGION_ROW, row_flags);
4995           gtk_style_context_add_region (context, GTK_STYLE_REGION_COLUMN, column_flags);
4996
4997           if (node == tree_view->priv->cursor_node && has_can_focus_cell
4998               && ((column == tree_view->priv->focus_column
4999                    && tree_view->priv->draw_keyfocus &&
5000                    gtk_widget_has_visible_focus (widget))
5001                   || (column == tree_view->priv->edited_column)))
5002             draw_focus = TRUE;
5003           else
5004             draw_focus = FALSE;
5005
5006           /* Draw background */
5007           gtk_render_background (context, cr,
5008                                  background_area.x,
5009                                  background_area.y,
5010                                  background_area.width,
5011                                  background_area.height);
5012
5013           /* Draw frame */
5014           gtk_render_frame (context, cr,
5015                             background_area.x,
5016                             background_area.y,
5017                             background_area.width,
5018                             background_area.height);
5019
5020           if (gtk_tree_view_is_expander_column (tree_view, column))
5021             {
5022               if (!rtl)
5023                 cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
5024               cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
5025
5026               if (gtk_tree_view_draw_expanders (tree_view))
5027                 {
5028                   int expander_size = gtk_tree_view_get_expander_size (tree_view);
5029                   if (!rtl)
5030                     cell_area.x += depth * expander_size;
5031                   cell_area.width -= depth * expander_size;
5032                 }
5033
5034               /* If we have an expander column, the highlight underline
5035                * starts with that column, so that it indicates which
5036                * level of the tree we're dropping at.
5037                */
5038               highlight_x = cell_area.x;
5039               expander_cell_width = cell_area.width;
5040
5041               if (is_separator)
5042                 {
5043                   gtk_style_context_save (context);
5044                   gtk_style_context_add_class (context, GTK_STYLE_CLASS_SEPARATOR);
5045
5046                   gtk_render_line (context, cr,
5047                                    cell_area.x,
5048                                    cell_area.y + cell_area.height / 2,
5049                                    cell_area.x + cell_area.width,
5050                                    cell_area.y + cell_area.height / 2);
5051
5052                   gtk_style_context_restore (context);
5053                 }
5054               else
5055                 {
5056                   _gtk_tree_view_column_cell_render (column,
5057                                                      cr,
5058                                                      &background_area,
5059                                                      &cell_area,
5060                                                      flags,
5061                                                      draw_focus);
5062                 }
5063
5064               if (gtk_tree_view_draw_expanders (tree_view)
5065                   && (node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT)
5066                 {
5067                   gtk_tree_view_draw_arrow (GTK_TREE_VIEW (widget),
5068                                             cr,
5069                                             tree,
5070                                             node);
5071                 }
5072             }
5073           else
5074             {
5075               if (is_separator)
5076                 {
5077                   gtk_style_context_save (context);
5078                   gtk_style_context_add_class (context, GTK_STYLE_CLASS_SEPARATOR);
5079
5080                   gtk_render_line (context, cr,
5081                                    cell_area.x,
5082                                    cell_area.y + cell_area.height / 2,
5083                                    cell_area.x + cell_area.width,
5084                                    cell_area.y + cell_area.height / 2);
5085
5086                   gtk_style_context_restore (context);
5087                 }
5088               else
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 (draw_hgrid_lines)
5098             {
5099               if (background_area.y > 0)
5100                 gtk_tree_view_draw_line (tree_view, cr,
5101                                          GTK_TREE_VIEW_GRID_LINE,
5102                                          background_area.x, background_area.y,
5103                                          background_area.x + background_area.width,
5104                                          background_area.y);
5105
5106               if (y_offset + max_height >= clip.height)
5107                 gtk_tree_view_draw_line (tree_view, cr,
5108                                          GTK_TREE_VIEW_GRID_LINE,
5109                                          background_area.x, background_area.y + max_height,
5110                                          background_area.x + background_area.width,
5111                                          background_area.y + max_height);
5112             }
5113
5114           if (gtk_tree_view_is_expander_column (tree_view, column) &&
5115               tree_view->priv->tree_lines_enabled)
5116             {
5117               gint x = background_area.x;
5118               gint mult = rtl ? -1 : 1;
5119               gint y0 = background_area.y;
5120               gint y1 = background_area.y + background_area.height/2;
5121               gint y2 = background_area.y + background_area.height;
5122
5123               if (rtl)
5124                 x += background_area.width - 1;
5125
5126               if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT
5127                   && depth > 1)
5128                 {
5129                   gtk_tree_view_draw_line (tree_view, cr,
5130                                            GTK_TREE_VIEW_TREE_LINE,
5131                                            x + expander_size * (depth - 1.5) * mult,
5132                                            y1,
5133                                            x + expander_size * (depth - 1.1) * mult,
5134                                            y1);
5135                 }
5136               else if (depth > 1)
5137                 {
5138                   gtk_tree_view_draw_line (tree_view, cr,
5139                                            GTK_TREE_VIEW_TREE_LINE,
5140                                            x + expander_size * (depth - 1.5) * mult,
5141                                            y1,
5142                                            x + expander_size * (depth - 0.5) * mult,
5143                                            y1);
5144                 }
5145
5146               if (depth > 1)
5147                 {
5148                   gint i;
5149                   GtkRBNode *tmp_node;
5150                   GtkRBTree *tmp_tree;
5151
5152                   if (!_gtk_rbtree_next (tree, node))
5153                     gtk_tree_view_draw_line (tree_view, cr,
5154                                              GTK_TREE_VIEW_TREE_LINE,
5155                                              x + expander_size * (depth - 1.5) * mult,
5156                                              y0,
5157                                              x + expander_size * (depth - 1.5) * mult,
5158                                              y1);
5159                   else
5160                     gtk_tree_view_draw_line (tree_view, cr,
5161                                              GTK_TREE_VIEW_TREE_LINE,
5162                                              x + expander_size * (depth - 1.5) * mult,
5163                                              y0,
5164                                              x + expander_size * (depth - 1.5) * mult,
5165                                              y2);
5166
5167                   tmp_node = tree->parent_node;
5168                   tmp_tree = tree->parent_tree;
5169
5170                   for (i = depth - 2; i > 0; i--)
5171                     {
5172                       if (_gtk_rbtree_next (tmp_tree, tmp_node))
5173                         gtk_tree_view_draw_line (tree_view, cr,
5174                                                  GTK_TREE_VIEW_TREE_LINE,
5175                                                  x + expander_size * (i - 0.5) * mult,
5176                                                  y0,
5177                                                  x + expander_size * (i - 0.5) * mult,
5178                                                  y2);
5179
5180                       tmp_node = tmp_tree->parent_node;
5181                       tmp_tree = tmp_tree->parent_tree;
5182                     }
5183                 }
5184             }
5185
5186           gtk_style_context_restore (context);
5187           cell_offset += gtk_tree_view_column_get_width (column);
5188         }
5189
5190       if (node == drag_highlight)
5191         {
5192           /* Draw indicator for the drop
5193            */
5194           gint highlight_y = -1;
5195           GtkRBTree *tree = NULL;
5196           GtkRBNode *node = NULL;
5197
5198           gtk_style_context_save (context);
5199           gtk_style_context_add_class (context, GTK_STYLE_CLASS_DND);
5200
5201           switch (tree_view->priv->drag_dest_pos)
5202             {
5203             case GTK_TREE_VIEW_DROP_BEFORE:
5204               highlight_y = background_area.y - 1;
5205               if (highlight_y < 0)
5206                       highlight_y = 0;
5207               break;
5208
5209             case GTK_TREE_VIEW_DROP_AFTER:
5210               highlight_y = background_area.y + background_area.height - 1;
5211               break;
5212
5213             case GTK_TREE_VIEW_DROP_INTO_OR_BEFORE:
5214             case GTK_TREE_VIEW_DROP_INTO_OR_AFTER:
5215               _gtk_tree_view_find_node (tree_view, drag_dest_path, &tree, &node);
5216
5217               if (tree == NULL)
5218                 break;
5219
5220               gtk_render_frame (context, cr,
5221                                 0, gtk_tree_view_get_row_y_offset (tree_view, tree, node),
5222                                 gdk_window_get_width (tree_view->priv->bin_window),
5223                                 gtk_tree_view_get_row_height (tree_view, node));
5224               break;
5225             }
5226
5227           if (highlight_y >= 0)
5228             {
5229               gtk_tree_view_draw_line (tree_view, cr,
5230                                        GTK_TREE_VIEW_FOREGROUND_LINE,
5231                                        rtl ? highlight_x + expander_cell_width : highlight_x,
5232                                        highlight_y,
5233                                        rtl ? 0 : bin_window_width,
5234                                        highlight_y);
5235             }
5236
5237           gtk_style_context_restore (context);
5238         }
5239
5240       /* draw the big row-spanning focus rectangle, if needed */
5241       if (!has_can_focus_cell && node == tree_view->priv->cursor_node &&
5242           tree_view->priv->draw_keyfocus &&
5243           gtk_widget_has_visible_focus (widget))
5244         {
5245           gint tmp_y, tmp_height;
5246           GtkStateFlags focus_rect_state = 0;
5247
5248           gtk_style_context_save (context);
5249
5250           focus_rect_state = gtk_cell_renderer_get_state (NULL, widget, flags);
5251           gtk_style_context_set_state (context, focus_rect_state);
5252
5253           if (draw_hgrid_lines)
5254             {
5255               tmp_y = gtk_tree_view_get_row_y_offset (tree_view, tree, node) + grid_line_width / 2;
5256               tmp_height = gtk_tree_view_get_row_height (tree_view, node) - grid_line_width;
5257             }
5258           else
5259             {
5260               tmp_y = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
5261               tmp_height = gtk_tree_view_get_row_height (tree_view, node);
5262             }
5263
5264           gtk_render_focus (context, cr,
5265                             0, tmp_y,
5266                             gdk_window_get_width (tree_view->priv->bin_window),
5267                             tmp_height);
5268
5269           gtk_style_context_restore (context);
5270         }
5271
5272       y_offset += max_height;
5273       if (node->children)
5274         {
5275           GtkTreeIter parent = iter;
5276           gboolean has_child;
5277
5278           tree = node->children;
5279           node = _gtk_rbtree_first (tree);
5280
5281           has_child = gtk_tree_model_iter_children (tree_view->priv->model,
5282                                                     &iter,
5283                                                     &parent);
5284           depth++;
5285
5286           /* Sanity Check! */
5287           TREE_VIEW_INTERNAL_ASSERT (has_child, FALSE);
5288         }
5289       else
5290         {
5291           gboolean done = FALSE;
5292
5293           do
5294             {
5295               node = _gtk_rbtree_next (tree, node);
5296               if (node != NULL)
5297                 {
5298                   gboolean has_next = gtk_tree_model_iter_next (tree_view->priv->model, &iter);
5299                   done = TRUE;
5300
5301                   /* Sanity Check! */
5302                   TREE_VIEW_INTERNAL_ASSERT (has_next, FALSE);
5303                 }
5304               else
5305                 {
5306                   GtkTreeIter parent_iter = iter;
5307                   gboolean has_parent;
5308
5309                   node = tree->parent_node;
5310                   tree = tree->parent_tree;
5311                   if (tree == NULL)
5312                     /* we should go to done to free some memory */
5313                     goto done;
5314                   has_parent = gtk_tree_model_iter_parent (tree_view->priv->model,
5315                                                            &iter,
5316                                                            &parent_iter);
5317                   depth--;
5318
5319                   /* Sanity check */
5320                   TREE_VIEW_INTERNAL_ASSERT (has_parent, FALSE);
5321                 }
5322             }
5323           while (!done);
5324         }
5325     }
5326   while (y_offset < clip.height);
5327
5328 done:
5329   gtk_tree_view_draw_grid_lines (tree_view, cr, n_visible_columns);
5330
5331   if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
5332     gtk_tree_view_paint_rubber_band (tree_view, cr);
5333
5334   if (drag_dest_path)
5335     gtk_tree_path_free (drag_dest_path);
5336
5337   return FALSE;
5338 }
5339
5340 static gboolean
5341 gtk_tree_view_draw (GtkWidget *widget,
5342                     cairo_t   *cr)
5343 {
5344   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
5345   GtkWidget   *button;
5346
5347   if (gtk_cairo_should_draw_window (cr, tree_view->priv->bin_window))
5348     {
5349       GtkStyleContext *context;
5350       GList *tmp_list;
5351
5352       context = gtk_widget_get_style_context (widget);
5353
5354       cairo_save (cr);
5355
5356       gtk_style_context_save (context);
5357       gtk_style_context_add_class (context, GTK_STYLE_CLASS_VIEW);
5358
5359       gtk_cairo_transform_to_window (cr, widget, tree_view->priv->bin_window);
5360
5361       gtk_tree_view_bin_draw (widget, cr);
5362
5363       gtk_style_context_restore (context);
5364       cairo_restore (cr);
5365
5366       /* We can't just chain up to Container::draw as it will try to send the
5367        * event to the headers, so we handle propagating it to our children
5368        * (eg. widgets being edited) ourselves.
5369        */
5370       tmp_list = tree_view->priv->children;
5371       while (tmp_list)
5372         {
5373           GtkTreeViewChild *child = tmp_list->data;
5374           tmp_list = tmp_list->next;
5375
5376           gtk_container_propagate_draw (GTK_CONTAINER (tree_view), child->widget, cr);
5377         }
5378     }
5379
5380   if (gtk_cairo_should_draw_window (cr, tree_view->priv->header_window))
5381     {
5382       GList *list;
5383       
5384       for (list = tree_view->priv->columns; list != NULL; list = list->next)
5385         {
5386           GtkTreeViewColumn *column = list->data;
5387
5388           if (column == tree_view->priv->drag_column)
5389             continue;
5390
5391           if (gtk_tree_view_column_get_visible (column))
5392             {
5393               button = gtk_tree_view_column_get_button (column);
5394               gtk_container_propagate_draw (GTK_CONTAINER (tree_view),
5395                                             button, cr);
5396             }
5397         }
5398     }
5399   
5400   if (tree_view->priv->drag_window &&
5401       gtk_cairo_should_draw_window (cr, tree_view->priv->drag_window))
5402     {
5403       button = gtk_tree_view_column_get_button (tree_view->priv->drag_column);
5404       gtk_container_propagate_draw (GTK_CONTAINER (tree_view),
5405                                     button, cr);
5406     }
5407
5408   return FALSE;
5409 }
5410
5411 enum
5412 {
5413   DROP_HOME,
5414   DROP_RIGHT,
5415   DROP_LEFT,
5416   DROP_END
5417 };
5418
5419 /* returns 0x1 when no column has been found -- yes it's hackish */
5420 static GtkTreeViewColumn *
5421 gtk_tree_view_get_drop_column (GtkTreeView       *tree_view,
5422                                GtkTreeViewColumn *column,
5423                                gint               drop_position)
5424 {
5425   GtkTreeViewColumn *left_column = NULL;
5426   GtkTreeViewColumn *cur_column = NULL;
5427   GList *tmp_list;
5428
5429   if (!gtk_tree_view_column_get_reorderable (column))
5430     return (GtkTreeViewColumn *)0x1;
5431
5432   switch (drop_position)
5433     {
5434       case DROP_HOME:
5435         /* find first column where we can drop */
5436         tmp_list = tree_view->priv->columns;
5437         if (column == GTK_TREE_VIEW_COLUMN (tmp_list->data))
5438           return (GtkTreeViewColumn *)0x1;
5439
5440         while (tmp_list)
5441           {
5442             g_assert (tmp_list);
5443
5444             cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5445             tmp_list = tmp_list->next;
5446
5447             if (left_column &&
5448                 gtk_tree_view_column_get_visible (left_column) == FALSE)
5449               continue;
5450
5451             if (!tree_view->priv->column_drop_func)
5452               return left_column;
5453
5454             if (!tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5455               {
5456                 left_column = cur_column;
5457                 continue;
5458               }
5459
5460             return left_column;
5461           }
5462
5463         if (!tree_view->priv->column_drop_func)
5464           return left_column;
5465
5466         if (tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data))
5467           return left_column;
5468         else
5469           return (GtkTreeViewColumn *)0x1;
5470         break;
5471
5472       case DROP_RIGHT:
5473         /* find first column after column where we can drop */
5474         tmp_list = tree_view->priv->columns;
5475
5476         for (; tmp_list; tmp_list = tmp_list->next)
5477           if (GTK_TREE_VIEW_COLUMN (tmp_list->data) == column)
5478             break;
5479
5480         if (!tmp_list || !tmp_list->next)
5481           return (GtkTreeViewColumn *)0x1;
5482
5483         tmp_list = tmp_list->next;
5484         left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5485         tmp_list = tmp_list->next;
5486
5487         while (tmp_list)
5488           {
5489             g_assert (tmp_list);
5490
5491             cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5492             tmp_list = tmp_list->next;
5493
5494             if (left_column &&
5495                 gtk_tree_view_column_get_visible (left_column) == FALSE)
5496               {
5497                 left_column = cur_column;
5498                 if (tmp_list)
5499                   tmp_list = tmp_list->next;
5500                 continue;
5501               }
5502
5503             if (!tree_view->priv->column_drop_func)
5504               return left_column;
5505
5506             if (!tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5507               {
5508                 left_column = cur_column;
5509                 continue;
5510               }
5511
5512             return left_column;
5513           }
5514
5515         if (!tree_view->priv->column_drop_func)
5516           return left_column;
5517
5518         if (tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data))
5519           return left_column;
5520         else
5521           return (GtkTreeViewColumn *)0x1;
5522         break;
5523
5524       case DROP_LEFT:
5525         /* find first column before column where we can drop */
5526         tmp_list = tree_view->priv->columns;
5527
5528         for (; tmp_list; tmp_list = tmp_list->next)
5529           if (GTK_TREE_VIEW_COLUMN (tmp_list->data) == column)
5530             break;
5531
5532         if (!tmp_list || !tmp_list->prev)
5533           return (GtkTreeViewColumn *)0x1;
5534
5535         tmp_list = tmp_list->prev;
5536         cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5537         tmp_list = tmp_list->prev;
5538
5539         while (tmp_list)
5540           {
5541             g_assert (tmp_list);
5542
5543             left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5544
5545             if (left_column &&
5546                 gtk_tree_view_column_get_visible (left_column) == FALSE)
5547               {
5548                 /*if (!tmp_list->prev)
5549                   return (GtkTreeViewColumn *)0x1;
5550                   */
5551 /*
5552                 cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->prev->data);
5553                 tmp_list = tmp_list->prev->prev;
5554                 continue;*/
5555
5556                 cur_column = left_column;
5557                 if (tmp_list)
5558                   tmp_list = tmp_list->prev;
5559                 continue;
5560               }
5561
5562             if (!tree_view->priv->column_drop_func)
5563               return left_column;
5564
5565             if (tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5566               return left_column;
5567
5568             cur_column = left_column;
5569             tmp_list = tmp_list->prev;
5570           }
5571
5572         if (!tree_view->priv->column_drop_func)
5573           return NULL;
5574
5575         if (tree_view->priv->column_drop_func (tree_view, column, NULL, cur_column, tree_view->priv->column_drop_func_data))
5576           return NULL;
5577         else
5578           return (GtkTreeViewColumn *)0x1;
5579         break;
5580
5581       case DROP_END:
5582         /* same as DROP_HOME case, but doing it backwards */
5583         tmp_list = g_list_last (tree_view->priv->columns);
5584         cur_column = NULL;
5585
5586         if (column == GTK_TREE_VIEW_COLUMN (tmp_list->data))
5587           return (GtkTreeViewColumn *)0x1;
5588
5589         while (tmp_list)
5590           {
5591             g_assert (tmp_list);
5592
5593             left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5594
5595             if (left_column &&
5596                 gtk_tree_view_column_get_visible (left_column) == FALSE)
5597               {
5598                 cur_column = left_column;
5599                 tmp_list = tmp_list->prev;
5600               }
5601
5602             if (!tree_view->priv->column_drop_func)
5603               return left_column;
5604
5605             if (tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5606               return left_column;
5607
5608             cur_column = left_column;
5609             tmp_list = tmp_list->prev;
5610           }
5611
5612         if (!tree_view->priv->column_drop_func)
5613           return NULL;
5614
5615         if (tree_view->priv->column_drop_func (tree_view, column, NULL, cur_column, tree_view->priv->column_drop_func_data))
5616           return NULL;
5617         else
5618           return (GtkTreeViewColumn *)0x1;
5619         break;
5620     }
5621
5622   return (GtkTreeViewColumn *)0x1;
5623 }
5624
5625 static gboolean
5626 gtk_tree_view_key_press (GtkWidget   *widget,
5627                          GdkEventKey *event)
5628 {
5629   GtkTreeView *tree_view = (GtkTreeView *) widget;
5630   GtkWidget   *button;
5631
5632   if (tree_view->priv->rubber_band_status)
5633     {
5634       if (event->keyval == GDK_KEY_Escape)
5635         gtk_tree_view_stop_rubber_band (tree_view);
5636
5637       return TRUE;
5638     }
5639
5640   if (tree_view->priv->in_column_drag)
5641     {
5642       if (event->keyval == GDK_KEY_Escape)
5643         {
5644           tree_view->priv->cur_reorder = NULL;
5645           gtk_tree_view_button_release_drag_column (widget, NULL);
5646         }
5647       return TRUE;
5648     }
5649
5650   if (tree_view->priv->headers_visible)
5651     {
5652       GList *focus_column;
5653       gboolean rtl;
5654
5655       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
5656
5657       for (focus_column = tree_view->priv->columns;
5658            focus_column;
5659            focus_column = focus_column->next)
5660         {
5661           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
5662           
5663           button = gtk_tree_view_column_get_button (column);
5664           if (gtk_widget_has_focus (button))
5665             break;
5666         }
5667
5668       if (focus_column &&
5669           (event->state & GDK_SHIFT_MASK) && (event->state & GDK_MOD1_MASK) &&
5670           (event->keyval == GDK_KEY_Left || event->keyval == GDK_KEY_KP_Left
5671            || event->keyval == GDK_KEY_Right || event->keyval == GDK_KEY_KP_Right))
5672         {
5673           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
5674           gint max_width, min_width;
5675
5676           if (!gtk_tree_view_column_get_resizable (column))
5677             {
5678               gtk_widget_error_bell (widget);
5679               return TRUE;
5680             }
5681
5682           if (event->keyval == (rtl ? GDK_KEY_Right : GDK_KEY_Left)
5683               || event->keyval == (rtl ? GDK_KEY_KP_Right : GDK_KEY_KP_Left))
5684             {
5685               GtkRequisition button_req;
5686               gint old_width = _gtk_tree_view_column_get_resized_width (column);
5687               gint new_width;
5688
5689               button = gtk_tree_view_column_get_button (column);
5690
5691               gtk_widget_get_preferred_size (button, &button_req, NULL);
5692
5693               new_width = MAX (old_width, gtk_tree_view_column_get_width (column));
5694               new_width -= 2;
5695               if (new_width < 0)
5696                 new_width = 0;
5697
5698               _gtk_tree_view_column_set_resized_width (column, new_width);
5699
5700               min_width = gtk_tree_view_column_get_min_width (column);
5701               if (min_width == -1)
5702                 new_width = MAX (button_req.width, new_width);
5703               else
5704                 {
5705                   new_width = MAX (min_width, new_width);
5706                 }
5707
5708               max_width = gtk_tree_view_column_get_max_width (column);
5709               if (max_width != -1)
5710                 new_width = MIN (new_width, max_width);
5711
5712               _gtk_tree_view_column_set_use_resized_width (column, TRUE);
5713
5714               if (new_width != old_width)
5715                 {
5716                   _gtk_tree_view_column_set_resized_width (column, new_width);
5717                   gtk_widget_queue_resize (widget);
5718                 }
5719               else
5720                 gtk_widget_error_bell (widget);
5721             }
5722           else if (event->keyval == (rtl ? GDK_KEY_Left : GDK_KEY_Right)
5723                    || event->keyval == (rtl ? GDK_KEY_KP_Left : GDK_KEY_KP_Right))
5724             {
5725               gint old_width = _gtk_tree_view_column_get_resized_width (column);
5726               gint new_width;
5727
5728               new_width = MAX (old_width, gtk_tree_view_column_get_width (column));
5729               new_width += 2;
5730
5731               max_width = gtk_tree_view_column_get_max_width (column);
5732               if (max_width != -1)
5733                 new_width = MIN (new_width, max_width);
5734
5735               _gtk_tree_view_column_set_use_resized_width (column, TRUE);
5736
5737               if (new_width != old_width)
5738                 {
5739                   _gtk_tree_view_column_set_resized_width (column, new_width);
5740                   gtk_widget_queue_resize (widget);
5741                 }
5742               else
5743                 gtk_widget_error_bell (widget);
5744             }
5745
5746           return TRUE;
5747         }
5748
5749       if (focus_column &&
5750           (event->state & GDK_MOD1_MASK) &&
5751           (event->keyval == GDK_KEY_Left || event->keyval == GDK_KEY_KP_Left
5752            || event->keyval == GDK_KEY_Right || event->keyval == GDK_KEY_KP_Right
5753            || event->keyval == GDK_KEY_Home || event->keyval == GDK_KEY_KP_Home
5754            || event->keyval == GDK_KEY_End || event->keyval == GDK_KEY_KP_End))
5755         {
5756           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
5757
5758           if (event->keyval == (rtl ? GDK_KEY_Right : GDK_KEY_Left)
5759               || event->keyval == (rtl ? GDK_KEY_KP_Right : GDK_KEY_KP_Left))
5760             {
5761               GtkTreeViewColumn *col;
5762               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_LEFT);
5763               if (col != (GtkTreeViewColumn *)0x1)
5764                 gtk_tree_view_move_column_after (tree_view, column, col);
5765               else
5766                 gtk_widget_error_bell (widget);
5767             }
5768           else if (event->keyval == (rtl ? GDK_KEY_Left : GDK_KEY_Right)
5769                    || event->keyval == (rtl ? GDK_KEY_KP_Left : GDK_KEY_KP_Right))
5770             {
5771               GtkTreeViewColumn *col;
5772               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_RIGHT);
5773               if (col != (GtkTreeViewColumn *)0x1)
5774                 gtk_tree_view_move_column_after (tree_view, column, col);
5775               else
5776                 gtk_widget_error_bell (widget);
5777             }
5778           else if (event->keyval == GDK_KEY_Home || event->keyval == GDK_KEY_KP_Home)
5779             {
5780               GtkTreeViewColumn *col;
5781               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_HOME);
5782               if (col != (GtkTreeViewColumn *)0x1)
5783                 gtk_tree_view_move_column_after (tree_view, column, col);
5784               else
5785                 gtk_widget_error_bell (widget);
5786             }
5787           else if (event->keyval == GDK_KEY_End || event->keyval == GDK_KEY_KP_End)
5788             {
5789               GtkTreeViewColumn *col;
5790               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_END);
5791               if (col != (GtkTreeViewColumn *)0x1)
5792                 gtk_tree_view_move_column_after (tree_view, column, col);
5793               else
5794                 gtk_widget_error_bell (widget);
5795             }
5796
5797           return TRUE;
5798         }
5799     }
5800
5801   /* Chain up to the parent class.  It handles the keybindings. */
5802   if (GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->key_press_event (widget, event))
5803     return TRUE;
5804
5805   if (tree_view->priv->search_entry_avoid_unhandled_binding)
5806     {
5807       tree_view->priv->search_entry_avoid_unhandled_binding = FALSE;
5808       return FALSE;
5809     }
5810
5811   /* We pass the event to the search_entry.  If its text changes, then we start
5812    * the typeahead find capabilities. */
5813   if (gtk_widget_has_focus (GTK_WIDGET (tree_view))
5814       && tree_view->priv->enable_search
5815       && !tree_view->priv->search_custom_entry_set)
5816     {
5817       GdkEvent *new_event;
5818       char *old_text;
5819       const char *new_text;
5820       gboolean retval;
5821       GdkScreen *screen;
5822       gboolean text_modified;
5823       gulong popup_menu_id;
5824
5825       gtk_tree_view_ensure_interactive_directory (tree_view);
5826
5827       /* Make a copy of the current text */
5828       old_text = g_strdup (gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry)));
5829       new_event = gdk_event_copy ((GdkEvent *) event);
5830       g_object_unref (((GdkEventKey *) new_event)->window);
5831       ((GdkEventKey *) new_event)->window = g_object_ref (gtk_widget_get_window (tree_view->priv->search_window));
5832       gtk_widget_realize (tree_view->priv->search_window);
5833
5834       popup_menu_id = g_signal_connect (tree_view->priv->search_entry, 
5835                                         "popup-menu", G_CALLBACK (gtk_true),
5836                                         NULL);
5837
5838       /* Move the entry off screen */
5839       screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
5840       gtk_window_move (GTK_WINDOW (tree_view->priv->search_window),
5841                        gdk_screen_get_width (screen) + 1,
5842                        gdk_screen_get_height (screen) + 1);
5843       gtk_widget_show (tree_view->priv->search_window);
5844
5845       /* Send the event to the window.  If the preedit_changed signal is emitted
5846        * during this event, we will set priv->imcontext_changed  */
5847       tree_view->priv->imcontext_changed = FALSE;
5848       retval = gtk_widget_event (tree_view->priv->search_window, new_event);
5849       gdk_event_free (new_event);
5850       gtk_widget_hide (tree_view->priv->search_window);
5851
5852       g_signal_handler_disconnect (tree_view->priv->search_entry, 
5853                                    popup_menu_id);
5854
5855       /* We check to make sure that the entry tried to handle the text, and that
5856        * the text has changed.
5857        */
5858       new_text = gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry));
5859       text_modified = strcmp (old_text, new_text) != 0;
5860       g_free (old_text);
5861       if (tree_view->priv->imcontext_changed ||    /* we're in a preedit */
5862           (retval && text_modified))               /* ...or the text was modified */
5863         {
5864           if (gtk_tree_view_real_start_interactive_search (tree_view,
5865                                                            gdk_event_get_device ((GdkEvent *) event),
5866                                                            FALSE))
5867             {
5868               gtk_widget_grab_focus (GTK_WIDGET (tree_view));
5869               return TRUE;
5870             }
5871           else
5872             {
5873               gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
5874               return FALSE;
5875             }
5876         }
5877     }
5878
5879   return FALSE;
5880 }
5881
5882 static gboolean
5883 gtk_tree_view_key_release (GtkWidget   *widget,
5884                            GdkEventKey *event)
5885 {
5886   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
5887
5888   if (tree_view->priv->rubber_band_status)
5889     return TRUE;
5890
5891   return GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->key_release_event (widget, event);
5892 }
5893
5894 /* FIXME Is this function necessary? Can I get an enter_notify event
5895  * w/o either an expose event or a mouse motion event?
5896  */
5897 static gboolean
5898 gtk_tree_view_enter_notify (GtkWidget        *widget,
5899                             GdkEventCrossing *event)
5900 {
5901   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
5902   GtkRBTree *tree;
5903   GtkRBNode *node;
5904   gint new_y;
5905
5906   /* Sanity check it */
5907   if (event->window != tree_view->priv->bin_window)
5908     return FALSE;
5909
5910   if (tree_view->priv->tree == NULL)
5911     return FALSE;
5912
5913   if (event->mode == GDK_CROSSING_GRAB ||
5914       event->mode == GDK_CROSSING_GTK_GRAB ||
5915       event->mode == GDK_CROSSING_GTK_UNGRAB ||
5916       event->mode == GDK_CROSSING_STATE_CHANGED)
5917     return TRUE;
5918
5919   /* find the node internally */
5920   new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
5921   if (new_y < 0)
5922     new_y = 0;
5923   _gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
5924
5925   tree_view->priv->event_last_x = event->x;
5926   tree_view->priv->event_last_y = event->y;
5927
5928   if ((tree_view->priv->button_pressed_node == NULL) ||
5929       (tree_view->priv->button_pressed_node == node))
5930     prelight_or_select (tree_view, tree, node, event->x, event->y);
5931
5932   return TRUE;
5933 }
5934
5935 static gboolean
5936 gtk_tree_view_leave_notify (GtkWidget        *widget,
5937                             GdkEventCrossing *event)
5938 {
5939   GtkTreeView *tree_view;
5940
5941   if (event->mode == GDK_CROSSING_GRAB ||
5942       event->mode == GDK_CROSSING_GTK_GRAB ||
5943       event->mode == GDK_CROSSING_GTK_UNGRAB)
5944     return TRUE;
5945
5946   tree_view = GTK_TREE_VIEW (widget);
5947
5948   if (tree_view->priv->prelight_node)
5949     _gtk_tree_view_queue_draw_node (tree_view,
5950                                    tree_view->priv->prelight_tree,
5951                                    tree_view->priv->prelight_node,
5952                                    NULL);
5953
5954   tree_view->priv->event_last_x = -10000;
5955   tree_view->priv->event_last_y = -10000;
5956
5957   prelight_or_select (tree_view,
5958                       NULL, NULL,
5959                       -1000, -1000); /* coords not possibly over an arrow */
5960
5961   return TRUE;
5962 }
5963
5964
5965 static gint
5966 gtk_tree_view_focus_out (GtkWidget     *widget,
5967                          GdkEventFocus *event)
5968 {
5969   GtkTreeView *tree_view;
5970
5971   tree_view = GTK_TREE_VIEW (widget);
5972
5973   gtk_widget_queue_draw (widget);
5974
5975   /* destroy interactive search dialog */
5976   if (tree_view->priv->search_window)
5977     gtk_tree_view_search_dialog_hide (tree_view->priv->search_window, tree_view,
5978                                       gdk_event_get_device ((GdkEvent *) event));
5979
5980   return FALSE;
5981 }
5982
5983
5984 /* Incremental Reflow
5985  */
5986
5987 static void
5988 gtk_tree_view_node_queue_redraw (GtkTreeView *tree_view,
5989                                  GtkRBTree   *tree,
5990                                  GtkRBNode   *node)
5991 {
5992   GtkAllocation allocation;
5993   gint y;
5994
5995   y = _gtk_rbtree_node_find_offset (tree, node)
5996     - gtk_adjustment_get_value (tree_view->priv->vadjustment)
5997     + gtk_tree_view_get_effective_header_height (tree_view);
5998
5999   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
6000   gtk_widget_queue_draw_area (GTK_WIDGET (tree_view),
6001                               0, y,
6002                               allocation.width,
6003                               GTK_RBNODE_GET_HEIGHT (node));
6004 }
6005
6006 static gboolean
6007 node_is_visible (GtkTreeView *tree_view,
6008                  GtkRBTree   *tree,
6009                  GtkRBNode   *node)
6010 {
6011   int y;
6012   int height;
6013
6014   y = _gtk_rbtree_node_find_offset (tree, node);
6015   height = gtk_tree_view_get_row_height (tree_view, node);
6016
6017   if (y >= gtk_adjustment_get_value (tree_view->priv->vadjustment) &&
6018       y + height <= (gtk_adjustment_get_value (tree_view->priv->vadjustment)
6019                      + gtk_adjustment_get_page_size (tree_view->priv->vadjustment)))
6020     return TRUE;
6021
6022   return FALSE;
6023 }
6024
6025 /* Returns TRUE if it updated the size
6026  */
6027 static gboolean
6028 validate_row (GtkTreeView *tree_view,
6029               GtkRBTree   *tree,
6030               GtkRBNode   *node,
6031               GtkTreeIter *iter,
6032               GtkTreePath *path)
6033 {
6034   GtkTreeViewColumn *column;
6035   GList *list, *first_column, *last_column;
6036   gint height = 0;
6037   gint horizontal_separator;
6038   gint vertical_separator;
6039   gint depth = gtk_tree_path_get_depth (path);
6040   gboolean retval = FALSE;
6041   gboolean is_separator = FALSE;
6042   gboolean draw_vgrid_lines, draw_hgrid_lines;
6043   gint focus_pad;
6044   gint grid_line_width;
6045   gboolean wide_separators;
6046   gint separator_height;
6047   gint expander_size;
6048
6049   /* double check the row needs validating */
6050   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) &&
6051       ! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6052     return FALSE;
6053
6054   is_separator = row_is_separator (tree_view, iter, NULL);
6055
6056   gtk_widget_style_get (GTK_WIDGET (tree_view),
6057                         "focus-padding", &focus_pad,
6058                         "horizontal-separator", &horizontal_separator,
6059                         "vertical-separator", &vertical_separator,
6060                         "grid-line-width", &grid_line_width,
6061                         "wide-separators",  &wide_separators,
6062                         "separator-height", &separator_height,
6063                         NULL);
6064   
6065   draw_vgrid_lines =
6066     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_VERTICAL
6067     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
6068   draw_hgrid_lines =
6069     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_HORIZONTAL
6070     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
6071   expander_size = gtk_tree_view_get_expander_size (tree_view);
6072
6073   for (last_column = g_list_last (tree_view->priv->columns);
6074        last_column &&
6075        !(gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (last_column->data)));
6076        last_column = last_column->prev)
6077     ;
6078
6079   for (first_column = g_list_first (tree_view->priv->columns);
6080        first_column &&
6081        !(gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (first_column->data)));
6082        first_column = first_column->next)
6083     ;
6084
6085   for (list = tree_view->priv->columns; list; list = list->next)
6086     {
6087       gint padding = 0;
6088       gint original_width;
6089       gint new_width;
6090       gint row_height;
6091
6092       column = list->data;
6093
6094       if (!gtk_tree_view_column_get_visible (column))
6095         continue;
6096
6097       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID) && 
6098           !_gtk_tree_view_column_cell_get_dirty (column))
6099         continue;
6100
6101       original_width = _gtk_tree_view_column_get_requested_width (column);
6102
6103       gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, iter,
6104                                                GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
6105                                                node->children?TRUE:FALSE);
6106       gtk_tree_view_column_cell_get_size (column,
6107                                           NULL, NULL, NULL,
6108                                           NULL, &row_height);
6109
6110       if (!is_separator)
6111         {
6112           row_height += vertical_separator;
6113           height = MAX (height, row_height);
6114           height = MAX (height, expander_size);
6115         }
6116       else
6117         {
6118           if (wide_separators)
6119             height = separator_height + 2 * focus_pad;
6120           else
6121             height = 2 + 2 * focus_pad;
6122         }
6123
6124       if (gtk_tree_view_is_expander_column (tree_view, column))
6125         {
6126           padding += horizontal_separator + (depth - 1) * tree_view->priv->level_indentation;
6127
6128           if (gtk_tree_view_draw_expanders (tree_view))
6129             padding += depth * expander_size;
6130         }
6131       else
6132         padding += horizontal_separator;
6133
6134       if (draw_vgrid_lines)
6135         {
6136           if (list->data == first_column || list->data == last_column)
6137             padding += grid_line_width / 2.0;
6138           else
6139             padding += grid_line_width;
6140         }
6141
6142       /* Update the padding for the column */
6143       _gtk_tree_view_column_push_padding (column, padding);
6144       new_width = _gtk_tree_view_column_get_requested_width (column);
6145
6146       if (new_width > original_width)
6147         retval = TRUE;
6148     }
6149
6150   if (draw_hgrid_lines)
6151     height += grid_line_width;
6152
6153   if (height != GTK_RBNODE_GET_HEIGHT (node))
6154     {
6155       retval = TRUE;
6156       _gtk_rbtree_node_set_height (tree, node, height);
6157     }
6158   _gtk_rbtree_node_mark_valid (tree, node);
6159   tree_view->priv->post_validation_flag = TRUE;
6160
6161   return retval;
6162 }
6163
6164
6165 static void
6166 validate_visible_area (GtkTreeView *tree_view)
6167 {
6168   GtkAllocation allocation;
6169   GtkTreePath *path = NULL;
6170   GtkTreePath *above_path = NULL;
6171   GtkTreeIter iter;
6172   GtkRBTree *tree = NULL;
6173   GtkRBNode *node = NULL;
6174   gboolean need_redraw = FALSE;
6175   gboolean size_changed = FALSE;
6176   gint total_height;
6177   gint area_above = 0;
6178   gint area_below = 0;
6179
6180   if (tree_view->priv->tree == NULL)
6181     return;
6182
6183   if (! GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID) &&
6184       tree_view->priv->scroll_to_path == NULL)
6185     return;
6186
6187   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
6188   total_height = allocation.height - gtk_tree_view_get_effective_header_height (tree_view);
6189
6190   if (total_height == 0)
6191     return;
6192
6193   /* First, we check to see if we need to scroll anywhere
6194    */
6195   if (tree_view->priv->scroll_to_path)
6196     {
6197       path = gtk_tree_row_reference_get_path (tree_view->priv->scroll_to_path);
6198       if (path && !_gtk_tree_view_find_node (tree_view, path, &tree, &node))
6199         {
6200           /* we are going to scroll, and will update dy */
6201           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6202           if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6203               GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6204             {
6205               _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
6206               if (validate_row (tree_view, tree, node, &iter, path))
6207                 size_changed = TRUE;
6208             }
6209
6210           if (tree_view->priv->scroll_to_use_align)
6211             {
6212               gint height = gtk_tree_view_get_row_height (tree_view, node);
6213               area_above = (total_height - height) *
6214                 tree_view->priv->scroll_to_row_align;
6215               area_below = total_height - area_above - height;
6216               area_above = MAX (area_above, 0);
6217               area_below = MAX (area_below, 0);
6218             }
6219           else
6220             {
6221               /* two cases:
6222                * 1) row not visible
6223                * 2) row visible
6224                */
6225               gint dy;
6226               gint height = gtk_tree_view_get_row_height (tree_view, node);
6227
6228               dy = _gtk_rbtree_node_find_offset (tree, node);
6229
6230               if (dy >= gtk_adjustment_get_value (tree_view->priv->vadjustment) &&
6231                   dy + height <= (gtk_adjustment_get_value (tree_view->priv->vadjustment)
6232                                   + gtk_adjustment_get_page_size (tree_view->priv->vadjustment)))
6233                 {
6234                   /* row visible: keep the row at the same position */
6235                   area_above = dy - gtk_adjustment_get_value (tree_view->priv->vadjustment);
6236                   area_below = (gtk_adjustment_get_value (tree_view->priv->vadjustment) +
6237                                 gtk_adjustment_get_page_size (tree_view->priv->vadjustment))
6238                                - dy - height;
6239                 }
6240               else
6241                 {
6242                   /* row not visible */
6243                   if (dy >= 0
6244                       && dy + height <= gtk_adjustment_get_page_size (tree_view->priv->vadjustment))
6245                     {
6246                       /* row at the beginning -- fixed */
6247                       area_above = dy;
6248                       area_below = gtk_adjustment_get_page_size (tree_view->priv->vadjustment)
6249                                    - area_above - height;
6250                     }
6251                   else if (dy >= (gtk_adjustment_get_upper (tree_view->priv->vadjustment) -
6252                                   gtk_adjustment_get_page_size (tree_view->priv->vadjustment)))
6253                     {
6254                       /* row at the end -- fixed */
6255                       area_above = dy - (gtk_adjustment_get_upper (tree_view->priv->vadjustment) -
6256                                    gtk_adjustment_get_page_size (tree_view->priv->vadjustment));
6257                       area_below = gtk_adjustment_get_page_size (tree_view->priv->vadjustment) -
6258                                    area_above - height;
6259
6260                       if (area_below < 0)
6261                         {
6262                           area_above = gtk_adjustment_get_page_size (tree_view->priv->vadjustment) - height;
6263                           area_below = 0;
6264                         }
6265                     }
6266                   else
6267                     {
6268                       /* row somewhere in the middle, bring it to the top
6269                        * of the view
6270                        */
6271                       area_above = 0;
6272                       area_below = total_height - height;
6273                     }
6274                 }
6275             }
6276         }
6277       else
6278         /* the scroll to isn't valid; ignore it.
6279          */
6280         {
6281           if (tree_view->priv->scroll_to_path && !path)
6282             {
6283               gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
6284               tree_view->priv->scroll_to_path = NULL;
6285             }
6286           if (path)
6287             gtk_tree_path_free (path);
6288           path = NULL;
6289         }      
6290     }
6291
6292   /* We didn't have a scroll_to set, so we just handle things normally
6293    */
6294   if (path == NULL)
6295     {
6296       gint offset;
6297
6298       offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
6299                                         TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, 0),
6300                                         &tree, &node);
6301       if (node == NULL)
6302         {
6303           /* In this case, nothing has been validated */
6304           path = gtk_tree_path_new_first ();
6305           _gtk_tree_view_find_node (tree_view, path, &tree, &node);
6306         }
6307       else
6308         {
6309           path = _gtk_tree_path_new_from_rbtree (tree, node);
6310           total_height += offset;
6311         }
6312
6313       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6314
6315       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6316           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6317         {
6318           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
6319           if (validate_row (tree_view, tree, node, &iter, path))
6320             size_changed = TRUE;
6321         }
6322       area_above = 0;
6323       area_below = total_height - gtk_tree_view_get_row_height (tree_view, node);
6324     }
6325
6326   above_path = gtk_tree_path_copy (path);
6327
6328   /* if we do not validate any row above the new top_row, we will make sure
6329    * that the row immediately above top_row has been validated. (if we do not
6330    * do this, _gtk_rbtree_find_offset will find the row above top_row, because
6331    * when invalidated that row's height will be zero. and this will mess up
6332    * scrolling).
6333    */
6334   if (area_above == 0)
6335     {
6336       GtkRBTree *tmptree;
6337       GtkRBNode *tmpnode;
6338
6339       _gtk_tree_view_find_node (tree_view, above_path, &tmptree, &tmpnode);
6340       _gtk_rbtree_prev_full (tmptree, tmpnode, &tmptree, &tmpnode);
6341
6342       if (tmpnode)
6343         {
6344           GtkTreePath *tmppath;
6345           GtkTreeIter tmpiter;
6346
6347           tmppath = _gtk_tree_path_new_from_rbtree (tmptree, tmpnode);
6348           gtk_tree_model_get_iter (tree_view->priv->model, &tmpiter, tmppath);
6349
6350           if (GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_INVALID) ||
6351               GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_COLUMN_INVALID))
6352             {
6353               _gtk_tree_view_queue_draw_node (tree_view, tmptree, tmpnode, NULL);
6354               if (validate_row (tree_view, tmptree, tmpnode, &tmpiter, tmppath))
6355                 size_changed = TRUE;
6356             }
6357
6358           gtk_tree_path_free (tmppath);
6359         }
6360     }
6361
6362   /* Now, we walk forwards and backwards, measuring rows. Unfortunately,
6363    * backwards is much slower then forward, as there is no iter_prev function.
6364    * We go forwards first in case we run out of tree.  Then we go backwards to
6365    * fill out the top.
6366    */
6367   while (node && area_below > 0)
6368     {
6369       if (node->children)
6370         {
6371           GtkTreeIter parent = iter;
6372           gboolean has_child;
6373
6374           tree = node->children;
6375           node = _gtk_rbtree_first (tree);
6376
6377           has_child = gtk_tree_model_iter_children (tree_view->priv->model,
6378                                                     &iter,
6379                                                     &parent);
6380           TREE_VIEW_INTERNAL_ASSERT_VOID (has_child);
6381           gtk_tree_path_down (path);
6382         }
6383       else
6384         {
6385           gboolean done = FALSE;
6386           do
6387             {
6388               node = _gtk_rbtree_next (tree, node);
6389               if (node != NULL)
6390                 {
6391                   gboolean has_next = gtk_tree_model_iter_next (tree_view->priv->model, &iter);
6392                   done = TRUE;
6393                   gtk_tree_path_next (path);
6394
6395                   /* Sanity Check! */
6396                   TREE_VIEW_INTERNAL_ASSERT_VOID (has_next);
6397                 }
6398               else
6399                 {
6400                   GtkTreeIter parent_iter = iter;
6401                   gboolean has_parent;
6402
6403                   node = tree->parent_node;
6404                   tree = tree->parent_tree;
6405                   if (tree == NULL)
6406                     break;
6407                   has_parent = gtk_tree_model_iter_parent (tree_view->priv->model,
6408                                                            &iter,
6409                                                            &parent_iter);
6410                   gtk_tree_path_up (path);
6411
6412                   /* Sanity check */
6413                   TREE_VIEW_INTERNAL_ASSERT_VOID (has_parent);
6414                 }
6415             }
6416           while (!done);
6417         }
6418
6419       if (!node)
6420         break;
6421
6422       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6423           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6424         {
6425           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
6426           if (validate_row (tree_view, tree, node, &iter, path))
6427               size_changed = TRUE;
6428         }
6429
6430       area_below -= gtk_tree_view_get_row_height (tree_view, node);
6431     }
6432   gtk_tree_path_free (path);
6433
6434   /* If we ran out of tree, and have extra area_below left, we need to add it
6435    * to area_above */
6436   if (area_below > 0)
6437     area_above += area_below;
6438
6439   _gtk_tree_view_find_node (tree_view, above_path, &tree, &node);
6440
6441   /* We walk backwards */
6442   while (area_above > 0)
6443     {
6444       _gtk_rbtree_prev_full (tree, node, &tree, &node);
6445
6446       /* Always find the new path in the tree.  We cannot just assume
6447        * a gtk_tree_path_prev() is enough here, as there might be children
6448        * in between this node and the previous sibling node.  If this
6449        * appears to be a performance hotspot in profiles, we can look into
6450        * intrigate logic for keeping path, node and iter in sync like
6451        * we do for forward walks.  (Which will be hard because of the lacking
6452        * iter_prev).
6453        */
6454
6455       if (node == NULL)
6456         break;
6457
6458       gtk_tree_path_free (above_path);
6459       above_path = _gtk_tree_path_new_from_rbtree (tree, node);
6460
6461       gtk_tree_model_get_iter (tree_view->priv->model, &iter, above_path);
6462
6463       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6464           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6465         {
6466           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
6467           if (validate_row (tree_view, tree, node, &iter, above_path))
6468             size_changed = TRUE;
6469         }
6470       area_above -= gtk_tree_view_get_row_height (tree_view, node);
6471     }
6472
6473   /* if we scrolled to a path, we need to set the dy here,
6474    * and sync the top row accordingly
6475    */
6476   if (tree_view->priv->scroll_to_path)
6477     {
6478       gtk_tree_view_set_top_row (tree_view, above_path, -area_above);
6479       gtk_tree_view_top_row_to_dy (tree_view);
6480
6481       need_redraw = TRUE;
6482     }
6483   else if (tree_view->priv->height <= gtk_adjustment_get_page_size (tree_view->priv->vadjustment))
6484     {
6485       /* when we are not scrolling, we should never set dy to something
6486        * else than zero. we update top_row to be in sync with dy = 0.
6487        */
6488       gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
6489       gtk_tree_view_dy_to_top_row (tree_view);
6490     }
6491   else if (gtk_adjustment_get_value (tree_view->priv->vadjustment) + gtk_adjustment_get_page_size (tree_view->priv->vadjustment) > tree_view->priv->height)
6492     {
6493       gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), tree_view->priv->height - gtk_adjustment_get_page_size (tree_view->priv->vadjustment));
6494       gtk_tree_view_dy_to_top_row (tree_view);
6495     }
6496   else
6497     gtk_tree_view_top_row_to_dy (tree_view);
6498
6499   /* update width/height and queue a resize */
6500   if (size_changed)
6501     {
6502       GtkRequisition requisition;
6503
6504       /* We temporarily guess a size, under the assumption that it will be the
6505        * same when we get our next size_allocate.  If we don't do this, we'll be
6506        * in an inconsistent state if we call top_row_to_dy. */
6507
6508       gtk_widget_get_preferred_size (GTK_WIDGET (tree_view),
6509                                      &requisition, NULL);
6510       gtk_adjustment_set_upper (tree_view->priv->hadjustment,
6511                                 MAX (gtk_adjustment_get_upper (tree_view->priv->hadjustment), requisition.width));
6512       gtk_adjustment_set_upper (tree_view->priv->vadjustment,
6513                                 MAX (gtk_adjustment_get_upper (tree_view->priv->vadjustment), requisition.height));
6514       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6515     }
6516
6517   if (tree_view->priv->scroll_to_path)
6518     {
6519       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
6520       tree_view->priv->scroll_to_path = NULL;
6521     }
6522
6523   if (above_path)
6524     gtk_tree_path_free (above_path);
6525
6526   if (tree_view->priv->scroll_to_column)
6527     {
6528       tree_view->priv->scroll_to_column = NULL;
6529     }
6530   if (need_redraw)
6531     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
6532 }
6533
6534 static void
6535 initialize_fixed_height_mode (GtkTreeView *tree_view)
6536 {
6537   if (!tree_view->priv->tree)
6538     return;
6539
6540   if (tree_view->priv->fixed_height < 0)
6541     {
6542       GtkTreeIter iter;
6543       GtkTreePath *path;
6544
6545       GtkRBTree *tree = NULL;
6546       GtkRBNode *node = NULL;
6547
6548       tree = tree_view->priv->tree;
6549       node = tree->root;
6550
6551       path = _gtk_tree_path_new_from_rbtree (tree, node);
6552       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6553
6554       validate_row (tree_view, tree, node, &iter, path);
6555
6556       gtk_tree_path_free (path);
6557
6558       tree_view->priv->fixed_height = gtk_tree_view_get_row_height (tree_view, node);
6559     }
6560
6561    _gtk_rbtree_set_fixed_height (tree_view->priv->tree,
6562                                  tree_view->priv->fixed_height, TRUE);
6563 }
6564
6565 /* Our strategy for finding nodes to validate is a little convoluted.  We find
6566  * the left-most uninvalidated node.  We then try walking right, validating
6567  * nodes.  Once we find a valid node, we repeat the previous process of finding
6568  * the first invalid node.
6569  */
6570
6571 static gboolean
6572 do_validate_rows (GtkTreeView *tree_view, gboolean queue_resize)
6573 {
6574   GtkRBTree *tree = NULL;
6575   GtkRBNode *node = NULL;
6576   gboolean validated_area = FALSE;
6577   gint retval = TRUE;
6578   GtkTreePath *path = NULL;
6579   GtkTreeIter iter;
6580   GTimer *timer;
6581   gint i = 0;
6582
6583   gint y = -1;
6584   gint prev_height = -1;
6585   gboolean fixed_height = TRUE;
6586
6587   g_assert (tree_view);
6588
6589   if (tree_view->priv->tree == NULL)
6590       return FALSE;
6591
6592   if (tree_view->priv->fixed_height_mode)
6593     {
6594       if (tree_view->priv->fixed_height < 0)
6595         initialize_fixed_height_mode (tree_view);
6596
6597       return FALSE;
6598     }
6599
6600   timer = g_timer_new ();
6601   g_timer_start (timer);
6602
6603   do
6604     {
6605       gboolean changed = FALSE;
6606
6607       if (! GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID))
6608         {
6609           retval = FALSE;
6610           goto done;
6611         }
6612
6613       if (path != NULL)
6614         {
6615           node = _gtk_rbtree_next (tree, node);
6616           if (node != NULL)
6617             {
6618               TREE_VIEW_INTERNAL_ASSERT (gtk_tree_model_iter_next (tree_view->priv->model, &iter), FALSE);
6619               gtk_tree_path_next (path);
6620             }
6621           else
6622             {
6623               gtk_tree_path_free (path);
6624               path = NULL;
6625             }
6626         }
6627
6628       if (path == NULL)
6629         {
6630           tree = tree_view->priv->tree;
6631           node = tree_view->priv->tree->root;
6632
6633           g_assert (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_DESCENDANTS_INVALID));
6634
6635           do
6636             {
6637               if (!_gtk_rbtree_is_nil (node->left) &&
6638                   GTK_RBNODE_FLAG_SET (node->left, GTK_RBNODE_DESCENDANTS_INVALID))
6639                 {
6640                   node = node->left;
6641                 }
6642               else if (!_gtk_rbtree_is_nil (node->right) &&
6643                        GTK_RBNODE_FLAG_SET (node->right, GTK_RBNODE_DESCENDANTS_INVALID))
6644                 {
6645                   node = node->right;
6646                 }
6647               else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6648                        GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6649                 {
6650                   break;
6651                 }
6652               else if (node->children != NULL)
6653                 {
6654                   tree = node->children;
6655                   node = tree->root;
6656                 }
6657               else
6658                 /* RBTree corruption!  All bad */
6659                 g_assert_not_reached ();
6660             }
6661           while (TRUE);
6662           path = _gtk_tree_path_new_from_rbtree (tree, node);
6663           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6664         }
6665
6666       changed = validate_row (tree_view, tree, node, &iter, path);
6667       validated_area = changed || validated_area;
6668
6669       if (changed)
6670         {
6671           gint offset = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
6672
6673           if (y == -1 || y > offset)
6674             y = offset;
6675         }
6676
6677       if (!tree_view->priv->fixed_height_check)
6678         {
6679           gint height;
6680
6681           height = gtk_tree_view_get_row_height (tree_view, node);
6682           if (prev_height < 0)
6683             prev_height = height;
6684           else if (prev_height != height)
6685             fixed_height = FALSE;
6686         }
6687
6688       i++;
6689     }
6690   while (g_timer_elapsed (timer, NULL) < GTK_TREE_VIEW_TIME_MS_PER_IDLE / 1000.);
6691
6692   if (!tree_view->priv->fixed_height_check)
6693    {
6694      if (fixed_height)
6695        _gtk_rbtree_set_fixed_height (tree_view->priv->tree, prev_height, FALSE);
6696
6697      tree_view->priv->fixed_height_check = 1;
6698    }
6699   
6700  done:
6701   if (validated_area)
6702     {
6703       GtkRequisition requisition;
6704
6705       /* We temporarily guess a size, under the assumption that it will be the
6706        * same when we get our next size_allocate.  If we don't do this, we'll be
6707        * in an inconsistent state when we call top_row_to_dy. */
6708
6709       /* FIXME: This is called from size_request, for some reason it is not infinitely
6710        * recursing, we cannot call gtk_widget_get_preferred_size() here because that's
6711        * not allowed (from inside ->get_preferred_width/height() implementations, one
6712        * should call the vfuncs directly). However what is desired here is the full
6713        * size including any margins and limited by any alignment (i.e. after 
6714        * GtkWidget:adjust_size_request() is called).
6715        *
6716        * Currently bypassing this but the real solution is to not update the scroll adjustments
6717        * untill we've recieved an allocation (never update scroll adjustments from size-requests).
6718        */
6719       gtk_tree_view_size_request (GTK_WIDGET (tree_view), &requisition, FALSE);
6720
6721       /* If rows above the current position have changed height, this has
6722        * affected the current view and thus needs a redraw.
6723        */
6724       if (y != -1 && y < gtk_adjustment_get_value (tree_view->priv->vadjustment))
6725         gtk_widget_queue_draw (GTK_WIDGET (tree_view));
6726
6727       gtk_adjustment_set_upper (tree_view->priv->hadjustment,
6728                                 MAX (gtk_adjustment_get_upper (tree_view->priv->hadjustment), requisition.width));
6729       gtk_adjustment_set_upper (tree_view->priv->vadjustment,
6730                                 MAX (gtk_adjustment_get_upper (tree_view->priv->vadjustment), requisition.height));
6731
6732       if (queue_resize)
6733         gtk_widget_queue_resize_no_redraw (GTK_WIDGET (tree_view));
6734     }
6735
6736   if (path) gtk_tree_path_free (path);
6737   g_timer_destroy (timer);
6738
6739   return retval;
6740 }
6741
6742 static gboolean
6743 validate_rows (GtkTreeView *tree_view)
6744 {
6745   gboolean retval;
6746   
6747   retval = do_validate_rows (tree_view, TRUE);
6748   
6749   if (! retval && tree_view->priv->validate_rows_timer)
6750     {
6751       g_source_remove (tree_view->priv->validate_rows_timer);
6752       tree_view->priv->validate_rows_timer = 0;
6753     }
6754
6755   return retval;
6756 }
6757
6758 static gboolean
6759 validate_rows_handler (GtkTreeView *tree_view)
6760 {
6761   gboolean retval;
6762
6763   retval = do_validate_rows (tree_view, TRUE);
6764   if (! retval && tree_view->priv->validate_rows_timer)
6765     {
6766       g_source_remove (tree_view->priv->validate_rows_timer);
6767       tree_view->priv->validate_rows_timer = 0;
6768     }
6769
6770   return retval;
6771 }
6772
6773 static gboolean
6774 do_presize_handler (GtkTreeView *tree_view)
6775 {
6776   if (tree_view->priv->mark_rows_col_dirty)
6777     {
6778       if (tree_view->priv->tree)
6779         _gtk_rbtree_column_invalid (tree_view->priv->tree);
6780       tree_view->priv->mark_rows_col_dirty = FALSE;
6781     }
6782   validate_visible_area (tree_view);
6783   tree_view->priv->presize_handler_timer = 0;
6784
6785   if (tree_view->priv->fixed_height_mode)
6786     {
6787       GtkRequisition requisition;
6788
6789       gtk_widget_get_preferred_size (GTK_WIDGET (tree_view),
6790                                      &requisition, NULL);
6791
6792       gtk_adjustment_set_upper (tree_view->priv->hadjustment,
6793                                 MAX (gtk_adjustment_get_upper (tree_view->priv->hadjustment), requisition.width));
6794       gtk_adjustment_set_upper (tree_view->priv->vadjustment,
6795                                 MAX (gtk_adjustment_get_upper (tree_view->priv->vadjustment), requisition.height));
6796       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6797     }
6798                    
6799   return FALSE;
6800 }
6801
6802 static gboolean
6803 presize_handler_callback (gpointer data)
6804 {
6805   do_presize_handler (GTK_TREE_VIEW (data));
6806                    
6807   return FALSE;
6808 }
6809
6810 static void
6811 install_presize_handler (GtkTreeView *tree_view)
6812 {
6813   if (! gtk_widget_get_realized (GTK_WIDGET (tree_view)))
6814     return;
6815
6816   if (! tree_view->priv->presize_handler_timer)
6817     {
6818       tree_view->priv->presize_handler_timer =
6819         gdk_threads_add_idle_full (GTK_PRIORITY_RESIZE - 2, presize_handler_callback, tree_view, NULL);
6820     }
6821   if (! tree_view->priv->validate_rows_timer)
6822     {
6823       tree_view->priv->validate_rows_timer =
6824         gdk_threads_add_idle_full (GTK_TREE_VIEW_PRIORITY_VALIDATE, (GSourceFunc) validate_rows_handler, tree_view, NULL);
6825     }
6826 }
6827
6828 static gboolean
6829 scroll_sync_handler (GtkTreeView *tree_view)
6830 {
6831   if (tree_view->priv->height <= gtk_adjustment_get_page_size (tree_view->priv->vadjustment))
6832     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
6833   else if (gtk_tree_row_reference_valid (tree_view->priv->top_row))
6834     gtk_tree_view_top_row_to_dy (tree_view);
6835   else
6836     gtk_tree_view_dy_to_top_row (tree_view);
6837
6838   tree_view->priv->scroll_sync_timer = 0;
6839
6840   return FALSE;
6841 }
6842
6843 static void
6844 install_scroll_sync_handler (GtkTreeView *tree_view)
6845 {
6846   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
6847     return;
6848
6849   if (!tree_view->priv->scroll_sync_timer)
6850     {
6851       tree_view->priv->scroll_sync_timer =
6852         gdk_threads_add_idle_full (GTK_TREE_VIEW_PRIORITY_SCROLL_SYNC, (GSourceFunc) scroll_sync_handler, tree_view, NULL);
6853     }
6854 }
6855
6856 static void
6857 gtk_tree_view_set_top_row (GtkTreeView *tree_view,
6858                            GtkTreePath *path,
6859                            gint         offset)
6860 {
6861   gtk_tree_row_reference_free (tree_view->priv->top_row);
6862
6863   if (!path)
6864     {
6865       tree_view->priv->top_row = NULL;
6866       tree_view->priv->top_row_dy = 0;
6867     }
6868   else
6869     {
6870       tree_view->priv->top_row = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
6871       tree_view->priv->top_row_dy = offset;
6872     }
6873 }
6874
6875 /* Always call this iff dy is in the visible range.  If the tree is empty, then
6876  * it's set to be NULL, and top_row_dy is 0;
6877  */
6878 static void
6879 gtk_tree_view_dy_to_top_row (GtkTreeView *tree_view)
6880 {
6881   gint offset;
6882   GtkTreePath *path;
6883   GtkRBTree *tree;
6884   GtkRBNode *node;
6885
6886   if (tree_view->priv->tree == NULL)
6887     {
6888       gtk_tree_view_set_top_row (tree_view, NULL, 0);
6889     }
6890   else
6891     {
6892       offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
6893                                         tree_view->priv->dy,
6894                                         &tree, &node);
6895
6896       if (tree == NULL)
6897         {
6898           gtk_tree_view_set_top_row (tree_view, NULL, 0);
6899         }
6900       else
6901         {
6902           path = _gtk_tree_path_new_from_rbtree (tree, node);
6903           gtk_tree_view_set_top_row (tree_view, path, offset);
6904           gtk_tree_path_free (path);
6905         }
6906     }
6907 }
6908
6909 static void
6910 gtk_tree_view_top_row_to_dy (GtkTreeView *tree_view)
6911 {
6912   GtkTreePath *path;
6913   GtkRBTree *tree;
6914   GtkRBNode *node;
6915   int new_dy;
6916
6917   /* Avoid recursive calls */
6918   if (tree_view->priv->in_top_row_to_dy)
6919     return;
6920
6921   if (tree_view->priv->top_row)
6922     path = gtk_tree_row_reference_get_path (tree_view->priv->top_row);
6923   else
6924     path = NULL;
6925
6926   if (!path)
6927     tree = NULL;
6928   else
6929     _gtk_tree_view_find_node (tree_view, path, &tree, &node);
6930
6931   if (path)
6932     gtk_tree_path_free (path);
6933
6934   if (tree == NULL)
6935     {
6936       /* keep dy and set new toprow */
6937       gtk_tree_row_reference_free (tree_view->priv->top_row);
6938       tree_view->priv->top_row = NULL;
6939       tree_view->priv->top_row_dy = 0;
6940       /* DO NOT install the idle handler */
6941       gtk_tree_view_dy_to_top_row (tree_view);
6942       return;
6943     }
6944
6945   if (gtk_tree_view_get_row_height (tree_view, node)
6946       < tree_view->priv->top_row_dy)
6947     {
6948       /* new top row -- do NOT install the idle handler */
6949       gtk_tree_view_dy_to_top_row (tree_view);
6950       return;
6951     }
6952
6953   new_dy = _gtk_rbtree_node_find_offset (tree, node);
6954   new_dy += tree_view->priv->top_row_dy;
6955
6956   if (new_dy + gtk_adjustment_get_page_size (tree_view->priv->vadjustment) > tree_view->priv->height)
6957     new_dy = tree_view->priv->height - gtk_adjustment_get_page_size (tree_view->priv->vadjustment);
6958
6959   new_dy = MAX (0, new_dy);
6960
6961   tree_view->priv->in_top_row_to_dy = TRUE;
6962   gtk_adjustment_set_value (tree_view->priv->vadjustment, (gdouble)new_dy);
6963   tree_view->priv->in_top_row_to_dy = FALSE;
6964 }
6965
6966
6967 void
6968 _gtk_tree_view_install_mark_rows_col_dirty (GtkTreeView *tree_view,
6969                                             gboolean     install_handler)
6970 {
6971   tree_view->priv->mark_rows_col_dirty = TRUE;
6972
6973   if (install_handler)
6974     install_presize_handler (tree_view);
6975 }
6976
6977 /*
6978  * This function works synchronously (due to the while (validate_rows...)
6979  * loop).
6980  *
6981  * There was a check for column_type != GTK_TREE_VIEW_COLUMN_AUTOSIZE
6982  * here. You now need to check that yourself.
6983  */
6984 void
6985 _gtk_tree_view_column_autosize (GtkTreeView *tree_view,
6986                                 GtkTreeViewColumn *column)
6987 {
6988   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
6989   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (column));
6990
6991   _gtk_tree_view_column_cell_set_dirty (column, FALSE);
6992
6993   do_presize_handler (tree_view);
6994   while (validate_rows (tree_view));
6995
6996   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6997 }
6998
6999 /* Drag-and-drop */
7000
7001 static void
7002 set_source_row (GdkDragContext *context,
7003                 GtkTreeModel   *model,
7004                 GtkTreePath    *source_row)
7005 {
7006   g_object_set_data_full (G_OBJECT (context),
7007                           I_("gtk-tree-view-source-row"),
7008                           source_row ? gtk_tree_row_reference_new (model, source_row) : NULL,
7009                           (GDestroyNotify) (source_row ? gtk_tree_row_reference_free : NULL));
7010 }
7011
7012 static GtkTreePath*
7013 get_source_row (GdkDragContext *context)
7014 {
7015   GtkTreeRowReference *ref =
7016     g_object_get_data (G_OBJECT (context), "gtk-tree-view-source-row");
7017
7018   if (ref)
7019     return gtk_tree_row_reference_get_path (ref);
7020   else
7021     return NULL;
7022 }
7023
7024 typedef struct
7025 {
7026   GtkTreeRowReference *dest_row;
7027   guint                path_down_mode   : 1;
7028   guint                empty_view_drop  : 1;
7029   guint                drop_append_mode : 1;
7030 }
7031 DestRow;
7032
7033 static void
7034 dest_row_free (gpointer data)
7035 {
7036   DestRow *dr = (DestRow *)data;
7037
7038   gtk_tree_row_reference_free (dr->dest_row);
7039   g_slice_free (DestRow, dr);
7040 }
7041
7042 static void
7043 set_dest_row (GdkDragContext *context,
7044               GtkTreeModel   *model,
7045               GtkTreePath    *dest_row,
7046               gboolean        path_down_mode,
7047               gboolean        empty_view_drop,
7048               gboolean        drop_append_mode)
7049 {
7050   DestRow *dr;
7051
7052   if (!dest_row)
7053     {
7054       g_object_set_data_full (G_OBJECT (context), I_("gtk-tree-view-dest-row"),
7055                               NULL, NULL);
7056       return;
7057     }
7058
7059   dr = g_slice_new (DestRow);
7060
7061   dr->dest_row = gtk_tree_row_reference_new (model, dest_row);
7062   dr->path_down_mode = path_down_mode != FALSE;
7063   dr->empty_view_drop = empty_view_drop != FALSE;
7064   dr->drop_append_mode = drop_append_mode != FALSE;
7065
7066   g_object_set_data_full (G_OBJECT (context), I_("gtk-tree-view-dest-row"),
7067                           dr, (GDestroyNotify) dest_row_free);
7068 }
7069
7070 static GtkTreePath*
7071 get_dest_row (GdkDragContext *context,
7072               gboolean       *path_down_mode)
7073 {
7074   DestRow *dr =
7075     g_object_get_data (G_OBJECT (context), "gtk-tree-view-dest-row");
7076
7077   if (dr)
7078     {
7079       GtkTreePath *path = NULL;
7080
7081       if (path_down_mode)
7082         *path_down_mode = dr->path_down_mode;
7083
7084       if (dr->dest_row)
7085         path = gtk_tree_row_reference_get_path (dr->dest_row);
7086       else if (dr->empty_view_drop)
7087         path = gtk_tree_path_new_from_indices (0, -1);
7088       else
7089         path = NULL;
7090
7091       if (path && dr->drop_append_mode)
7092         gtk_tree_path_next (path);
7093
7094       return path;
7095     }
7096   else
7097     return NULL;
7098 }
7099
7100 /* Get/set whether drag_motion requested the drag data and
7101  * drag_data_received should thus not actually insert the data,
7102  * since the data doesn't result from a drop.
7103  */
7104 static void
7105 set_status_pending (GdkDragContext *context,
7106                     GdkDragAction   suggested_action)
7107 {
7108   g_object_set_data (G_OBJECT (context),
7109                      I_("gtk-tree-view-status-pending"),
7110                      GINT_TO_POINTER (suggested_action));
7111 }
7112
7113 static GdkDragAction
7114 get_status_pending (GdkDragContext *context)
7115 {
7116   return GPOINTER_TO_INT (g_object_get_data (G_OBJECT (context),
7117                                              "gtk-tree-view-status-pending"));
7118 }
7119
7120 static TreeViewDragInfo*
7121 get_info (GtkTreeView *tree_view)
7122 {
7123   return g_object_get_data (G_OBJECT (tree_view), "gtk-tree-view-drag-info");
7124 }
7125
7126 static void
7127 destroy_info (TreeViewDragInfo *di)
7128 {
7129   g_slice_free (TreeViewDragInfo, di);
7130 }
7131
7132 static TreeViewDragInfo*
7133 ensure_info (GtkTreeView *tree_view)
7134 {
7135   TreeViewDragInfo *di;
7136
7137   di = get_info (tree_view);
7138
7139   if (di == NULL)
7140     {
7141       di = g_slice_new0 (TreeViewDragInfo);
7142
7143       g_object_set_data_full (G_OBJECT (tree_view),
7144                               I_("gtk-tree-view-drag-info"),
7145                               di,
7146                               (GDestroyNotify) destroy_info);
7147     }
7148
7149   return di;
7150 }
7151
7152 static void
7153 remove_info (GtkTreeView *tree_view)
7154 {
7155   g_object_set_data (G_OBJECT (tree_view), I_("gtk-tree-view-drag-info"), NULL);
7156 }
7157
7158 #if 0
7159 static gint
7160 drag_scan_timeout (gpointer data)
7161 {
7162   GtkTreeView *tree_view;
7163   gint x, y;
7164   GdkModifierType state;
7165   GtkTreePath *path = NULL;
7166   GtkTreeViewColumn *column = NULL;
7167   GdkRectangle visible_rect;
7168
7169   gdk_threads_enter ();
7170
7171   tree_view = GTK_TREE_VIEW (data);
7172
7173   gdk_window_get_device_position (tree_view->priv->bin_window,
7174                                   gdk_device_manager_get_client_pointer (
7175                                     gdk_display_get_device_manager (
7176                                       gtk_widget_get_display (GTK_WIDGET (tree_view)))),
7177                                   &x, &y, &state);
7178
7179   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
7180
7181   /* See if we are near the edge. */
7182   if ((x - visible_rect.x) < SCROLL_EDGE_SIZE ||
7183       (visible_rect.x + visible_rect.width - x) < SCROLL_EDGE_SIZE ||
7184       (y - visible_rect.y) < SCROLL_EDGE_SIZE ||
7185       (visible_rect.y + visible_rect.height - y) < SCROLL_EDGE_SIZE)
7186     {
7187       gtk_tree_view_get_path_at_pos (tree_view,
7188                                      tree_view->priv->bin_window,
7189                                      x, y,
7190                                      &path,
7191                                      &column,
7192                                      NULL,
7193                                      NULL);
7194
7195       if (path != NULL)
7196         {
7197           gtk_tree_view_scroll_to_cell (tree_view,
7198                                         path,
7199                                         column,
7200                                         TRUE,
7201                                         0.5, 0.5);
7202
7203           gtk_tree_path_free (path);
7204         }
7205     }
7206
7207   gdk_threads_leave ();
7208
7209   return TRUE;
7210 }
7211 #endif /* 0 */
7212
7213 static void
7214 add_scroll_timeout (GtkTreeView *tree_view)
7215 {
7216   if (tree_view->priv->scroll_timeout == 0)
7217     {
7218       tree_view->priv->scroll_timeout =
7219         gdk_threads_add_timeout (150, scroll_row_timeout, tree_view);
7220     }
7221 }
7222
7223 static void
7224 remove_scroll_timeout (GtkTreeView *tree_view)
7225 {
7226   if (tree_view->priv->scroll_timeout != 0)
7227     {
7228       g_source_remove (tree_view->priv->scroll_timeout);
7229       tree_view->priv->scroll_timeout = 0;
7230     }
7231 }
7232
7233 static gboolean
7234 check_model_dnd (GtkTreeModel *model,
7235                  GType         required_iface,
7236                  const gchar  *signal)
7237 {
7238   if (model == NULL || !G_TYPE_CHECK_INSTANCE_TYPE ((model), required_iface))
7239     {
7240       g_warning ("You must override the default '%s' handler "
7241                  "on GtkTreeView when using models that don't support "
7242                  "the %s interface and enabling drag-and-drop. The simplest way to do this "
7243                  "is to connect to '%s' and call "
7244                  "g_signal_stop_emission_by_name() in your signal handler to prevent "
7245                  "the default handler from running. Look at the source code "
7246                  "for the default handler in gtktreeview.c to get an idea what "
7247                  "your handler should do. (gtktreeview.c is in the GTK source "
7248                  "code.) If you're using GTK from a language other than C, "
7249                  "there may be a more natural way to override default handlers, e.g. via derivation.",
7250                  signal, g_type_name (required_iface), signal);
7251       return FALSE;
7252     }
7253   else
7254     return TRUE;
7255 }
7256
7257 static void
7258 remove_open_timeout (GtkTreeView *tree_view)
7259 {
7260   if (tree_view->priv->open_dest_timeout != 0)
7261     {
7262       g_source_remove (tree_view->priv->open_dest_timeout);
7263       tree_view->priv->open_dest_timeout = 0;
7264     }
7265 }
7266
7267
7268 static gint
7269 open_row_timeout (gpointer data)
7270 {
7271   GtkTreeView *tree_view = data;
7272   GtkTreePath *dest_path = NULL;
7273   GtkTreeViewDropPosition pos;
7274   gboolean result = FALSE;
7275
7276   gtk_tree_view_get_drag_dest_row (tree_view,
7277                                    &dest_path,
7278                                    &pos);
7279
7280   if (dest_path &&
7281       (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
7282        pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
7283     {
7284       gtk_tree_view_expand_row (tree_view, dest_path, FALSE);
7285       tree_view->priv->open_dest_timeout = 0;
7286
7287       gtk_tree_path_free (dest_path);
7288     }
7289   else
7290     {
7291       if (dest_path)
7292         gtk_tree_path_free (dest_path);
7293
7294       result = TRUE;
7295     }
7296
7297   return result;
7298 }
7299
7300 static gboolean
7301 scroll_row_timeout (gpointer data)
7302 {
7303   GtkTreeView *tree_view = data;
7304
7305   gtk_tree_view_vertical_autoscroll (tree_view);
7306
7307   if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
7308     gtk_tree_view_update_rubber_band (tree_view);
7309
7310   return TRUE;
7311 }
7312
7313 /* Returns TRUE if event should not be propagated to parent widgets */
7314 static gboolean
7315 set_destination_row (GtkTreeView    *tree_view,
7316                      GdkDragContext *context,
7317                      /* coordinates relative to the widget */
7318                      gint            x,
7319                      gint            y,
7320                      GdkDragAction  *suggested_action,
7321                      GdkAtom        *target)
7322 {
7323   GtkTreePath *path = NULL;
7324   GtkTreeViewDropPosition pos;
7325   GtkTreeViewDropPosition old_pos;
7326   TreeViewDragInfo *di;
7327   GtkWidget *widget;
7328   GtkTreePath *old_dest_path = NULL;
7329   gboolean can_drop = FALSE;
7330
7331   *suggested_action = 0;
7332   *target = GDK_NONE;
7333
7334   widget = GTK_WIDGET (tree_view);
7335
7336   di = get_info (tree_view);
7337
7338   if (di == NULL || y - gtk_tree_view_get_effective_header_height (tree_view) < 0)
7339     {
7340       /* someone unset us as a drag dest, note that if
7341        * we return FALSE drag_leave isn't called
7342        */
7343
7344       gtk_tree_view_set_drag_dest_row (tree_view,
7345                                        NULL,
7346                                        GTK_TREE_VIEW_DROP_BEFORE);
7347
7348       remove_scroll_timeout (GTK_TREE_VIEW (widget));
7349       remove_open_timeout (GTK_TREE_VIEW (widget));
7350
7351       return FALSE; /* no longer a drop site */
7352     }
7353
7354   *target = gtk_drag_dest_find_target (widget, context,
7355                                        gtk_drag_dest_get_target_list (widget));
7356   if (*target == GDK_NONE)
7357     {
7358       return FALSE;
7359     }
7360
7361   if (!gtk_tree_view_get_dest_row_at_pos (tree_view,
7362                                           x, y,
7363                                           &path,
7364                                           &pos))
7365     {
7366       gint n_children;
7367       GtkTreeModel *model;
7368
7369       remove_open_timeout (tree_view);
7370
7371       /* the row got dropped on empty space, let's setup a special case
7372        */
7373
7374       if (path)
7375         gtk_tree_path_free (path);
7376
7377       model = gtk_tree_view_get_model (tree_view);
7378
7379       n_children = gtk_tree_model_iter_n_children (model, NULL);
7380       if (n_children)
7381         {
7382           pos = GTK_TREE_VIEW_DROP_AFTER;
7383           path = gtk_tree_path_new_from_indices (n_children - 1, -1);
7384         }
7385       else
7386         {
7387           pos = GTK_TREE_VIEW_DROP_BEFORE;
7388           path = gtk_tree_path_new_from_indices (0, -1);
7389         }
7390
7391       can_drop = TRUE;
7392
7393       goto out;
7394     }
7395
7396   g_assert (path);
7397
7398   /* If we left the current row's "open" zone, unset the timeout for
7399    * opening the row
7400    */
7401   gtk_tree_view_get_drag_dest_row (tree_view,
7402                                    &old_dest_path,
7403                                    &old_pos);
7404
7405   if (old_dest_path &&
7406       (gtk_tree_path_compare (path, old_dest_path) != 0 ||
7407        !(pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
7408          pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE)))
7409     remove_open_timeout (tree_view);
7410
7411   if (old_dest_path)
7412     gtk_tree_path_free (old_dest_path);
7413
7414   if (TRUE /* FIXME if the location droppable predicate */)
7415     {
7416       can_drop = TRUE;
7417     }
7418
7419 out:
7420   if (can_drop)
7421     {
7422       GtkWidget *source_widget;
7423
7424       *suggested_action = gdk_drag_context_get_suggested_action (context);
7425       source_widget = gtk_drag_get_source_widget (context);
7426
7427       if (source_widget == widget)
7428         {
7429           /* Default to MOVE, unless the user has
7430            * pressed ctrl or shift to affect available actions
7431            */
7432           if ((gdk_drag_context_get_actions (context) & GDK_ACTION_MOVE) != 0)
7433             *suggested_action = GDK_ACTION_MOVE;
7434         }
7435
7436       gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7437                                        path, pos);
7438     }
7439   else
7440     {
7441       /* can't drop here */
7442       remove_open_timeout (tree_view);
7443
7444       gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7445                                        NULL,
7446                                        GTK_TREE_VIEW_DROP_BEFORE);
7447     }
7448
7449   if (path)
7450     gtk_tree_path_free (path);
7451
7452   return TRUE;
7453 }
7454
7455 static GtkTreePath*
7456 get_logical_dest_row (GtkTreeView *tree_view,
7457                       gboolean    *path_down_mode,
7458                       gboolean    *drop_append_mode)
7459 {
7460   /* adjust path to point to the row the drop goes in front of */
7461   GtkTreePath *path = NULL;
7462   GtkTreeViewDropPosition pos;
7463
7464   g_return_val_if_fail (path_down_mode != NULL, NULL);
7465   g_return_val_if_fail (drop_append_mode != NULL, NULL);
7466
7467   *path_down_mode = FALSE;
7468   *drop_append_mode = 0;
7469
7470   gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
7471
7472   if (path == NULL)
7473     return NULL;
7474
7475   if (pos == GTK_TREE_VIEW_DROP_BEFORE)
7476     ; /* do nothing */
7477   else if (pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE ||
7478            pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER)
7479     *path_down_mode = TRUE;
7480   else
7481     {
7482       GtkTreeIter iter;
7483       GtkTreeModel *model = gtk_tree_view_get_model (tree_view);
7484
7485       g_assert (pos == GTK_TREE_VIEW_DROP_AFTER);
7486
7487       if (!gtk_tree_model_get_iter (model, &iter, path) ||
7488           !gtk_tree_model_iter_next (model, &iter))
7489         *drop_append_mode = 1;
7490       else
7491         {
7492           *drop_append_mode = 0;
7493           gtk_tree_path_next (path);
7494         }
7495     }
7496
7497   return path;
7498 }
7499
7500 static gboolean
7501 gtk_tree_view_maybe_begin_dragging_row (GtkTreeView      *tree_view,
7502                                         GdkEventMotion   *event)
7503 {
7504   GtkWidget *widget = GTK_WIDGET (tree_view);
7505   GdkDragContext *context;
7506   TreeViewDragInfo *di;
7507   GtkTreePath *path = NULL;
7508   gint button;
7509   gint cell_x, cell_y;
7510   GtkTreeModel *model;
7511   gboolean retval = FALSE;
7512
7513   di = get_info (tree_view);
7514
7515   if (di == NULL || !di->source_set)
7516     goto out;
7517
7518   if (tree_view->priv->pressed_button < 0)
7519     goto out;
7520
7521   if (!gtk_drag_check_threshold (widget,
7522                                  tree_view->priv->press_start_x,
7523                                  tree_view->priv->press_start_y,
7524                                  event->x, event->y))
7525     goto out;
7526
7527   model = gtk_tree_view_get_model (tree_view);
7528
7529   if (model == NULL)
7530     goto out;
7531
7532   button = tree_view->priv->pressed_button;
7533   tree_view->priv->pressed_button = -1;
7534
7535   gtk_tree_view_get_path_at_pos (tree_view,
7536                                  tree_view->priv->press_start_x,
7537                                  tree_view->priv->press_start_y,
7538                                  &path,
7539                                  NULL,
7540                                  &cell_x,
7541                                  &cell_y);
7542
7543   if (path == NULL)
7544     goto out;
7545
7546   if (!GTK_IS_TREE_DRAG_SOURCE (model) ||
7547       !gtk_tree_drag_source_row_draggable (GTK_TREE_DRAG_SOURCE (model),
7548                                            path))
7549     goto out;
7550
7551   if (!(GDK_BUTTON1_MASK << (button - 1) & di->start_button_mask))
7552     goto out;
7553
7554   /* Now we can begin the drag */
7555
7556   retval = TRUE;
7557
7558   context = gtk_drag_begin (widget,
7559                             gtk_drag_source_get_target_list (widget),
7560                             di->source_actions,
7561                             button,
7562                             (GdkEvent*)event);
7563
7564   set_source_row (context, model, path);
7565
7566  out:
7567   if (path)
7568     gtk_tree_path_free (path);
7569
7570   return retval;
7571 }
7572
7573
7574 static void
7575 gtk_tree_view_drag_begin (GtkWidget      *widget,
7576                           GdkDragContext *context)
7577 {
7578   GtkTreeView *tree_view;
7579   GtkTreePath *path = NULL;
7580   gint cell_x, cell_y;
7581   cairo_surface_t *row_pix;
7582   TreeViewDragInfo *di;
7583
7584   tree_view = GTK_TREE_VIEW (widget);
7585
7586   /* if the user uses a custom DND source impl, we don't set the icon here */
7587   di = get_info (tree_view);
7588
7589   if (di == NULL || !di->source_set)
7590     return;
7591
7592   gtk_tree_view_get_path_at_pos (tree_view,
7593                                  tree_view->priv->press_start_x,
7594                                  tree_view->priv->press_start_y,
7595                                  &path,
7596                                  NULL,
7597                                  &cell_x,
7598                                  &cell_y);
7599
7600   /* If path is NULL, there's nothing we can drag.  For now, we silently
7601    * bail out.  Actually, dragging should not be possible from an empty
7602    * tree view, but there's no way we can cancel that from here.
7603    * Automatically unsetting the tree view as drag source for empty models
7604    * is something that would likely break other people's code ...
7605    */
7606   if (!path)
7607     return;
7608
7609   row_pix = gtk_tree_view_create_row_drag_icon (tree_view,
7610                                                 path);
7611   cairo_surface_set_device_offset (row_pix,
7612                                    /* the + 1 is for the black border in the icon */
7613                                    - (tree_view->priv->press_start_x + 1),
7614                                    - (cell_y + 1));
7615
7616   gtk_drag_set_icon_surface (context, row_pix);
7617
7618   cairo_surface_destroy (row_pix);
7619   gtk_tree_path_free (path);
7620 }
7621
7622 static void
7623 gtk_tree_view_drag_end (GtkWidget      *widget,
7624                         GdkDragContext *context)
7625 {
7626   /* do nothing */
7627 }
7628
7629 /* Default signal implementations for the drag signals */
7630 static void
7631 gtk_tree_view_drag_data_get (GtkWidget        *widget,
7632                              GdkDragContext   *context,
7633                              GtkSelectionData *selection_data,
7634                              guint             info,
7635                              guint             time)
7636 {
7637   GtkTreeView *tree_view;
7638   GtkTreeModel *model;
7639   TreeViewDragInfo *di;
7640   GtkTreePath *source_row;
7641
7642   tree_view = GTK_TREE_VIEW (widget);
7643
7644   model = gtk_tree_view_get_model (tree_view);
7645
7646   if (model == NULL)
7647     return;
7648
7649   di = get_info (GTK_TREE_VIEW (widget));
7650
7651   if (di == NULL)
7652     return;
7653
7654   source_row = get_source_row (context);
7655
7656   if (source_row == NULL)
7657     return;
7658
7659   /* We can implement the GTK_TREE_MODEL_ROW target generically for
7660    * any model; for DragSource models there are some other targets
7661    * we also support.
7662    */
7663
7664   if (GTK_IS_TREE_DRAG_SOURCE (model) &&
7665       gtk_tree_drag_source_drag_data_get (GTK_TREE_DRAG_SOURCE (model),
7666                                           source_row,
7667                                           selection_data))
7668     goto done;
7669
7670   /* If drag_data_get does nothing, try providing row data. */
7671   if (gtk_selection_data_get_target (selection_data) == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
7672     {
7673       gtk_tree_set_row_drag_data (selection_data,
7674                                   model,
7675                                   source_row);
7676     }
7677
7678  done:
7679   gtk_tree_path_free (source_row);
7680 }
7681
7682
7683 static void
7684 gtk_tree_view_drag_data_delete (GtkWidget      *widget,
7685                                 GdkDragContext *context)
7686 {
7687   TreeViewDragInfo *di;
7688   GtkTreeModel *model;
7689   GtkTreeView *tree_view;
7690   GtkTreePath *source_row;
7691
7692   tree_view = GTK_TREE_VIEW (widget);
7693   model = gtk_tree_view_get_model (tree_view);
7694
7695   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_SOURCE, "drag_data_delete"))
7696     return;
7697
7698   di = get_info (tree_view);
7699
7700   if (di == NULL)
7701     return;
7702
7703   source_row = get_source_row (context);
7704
7705   if (source_row == NULL)
7706     return;
7707
7708   gtk_tree_drag_source_drag_data_delete (GTK_TREE_DRAG_SOURCE (model),
7709                                          source_row);
7710
7711   gtk_tree_path_free (source_row);
7712
7713   set_source_row (context, NULL, NULL);
7714 }
7715
7716 static void
7717 gtk_tree_view_drag_leave (GtkWidget      *widget,
7718                           GdkDragContext *context,
7719                           guint             time)
7720 {
7721   /* unset any highlight row */
7722   gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7723                                    NULL,
7724                                    GTK_TREE_VIEW_DROP_BEFORE);
7725
7726   remove_scroll_timeout (GTK_TREE_VIEW (widget));
7727   remove_open_timeout (GTK_TREE_VIEW (widget));
7728 }
7729
7730
7731 static gboolean
7732 gtk_tree_view_drag_motion (GtkWidget        *widget,
7733                            GdkDragContext   *context,
7734                            /* coordinates relative to the widget */
7735                            gint              x,
7736                            gint              y,
7737                            guint             time)
7738 {
7739   gboolean empty;
7740   GtkTreePath *path = NULL;
7741   GtkTreeViewDropPosition pos;
7742   GtkTreeView *tree_view;
7743   GdkDragAction suggested_action = 0;
7744   GdkAtom target;
7745
7746   tree_view = GTK_TREE_VIEW (widget);
7747
7748   if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
7749     return FALSE;
7750
7751   gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
7752
7753   /* we only know this *after* set_desination_row */
7754   empty = tree_view->priv->empty_view_drop;
7755
7756   if (path == NULL && !empty)
7757     {
7758       /* Can't drop here. */
7759       gdk_drag_status (context, 0, time);
7760     }
7761   else
7762     {
7763       if (tree_view->priv->open_dest_timeout == 0 &&
7764           (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
7765            pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
7766         {
7767           tree_view->priv->open_dest_timeout =
7768             gdk_threads_add_timeout (AUTO_EXPAND_TIMEOUT, open_row_timeout, tree_view);
7769         }
7770       else
7771         {
7772           add_scroll_timeout (tree_view);
7773         }
7774
7775       if (target == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
7776         {
7777           /* Request data so we can use the source row when
7778            * determining whether to accept the drop
7779            */
7780           set_status_pending (context, suggested_action);
7781           gtk_drag_get_data (widget, context, target, time);
7782         }
7783       else
7784         {
7785           set_status_pending (context, 0);
7786           gdk_drag_status (context, suggested_action, time);
7787         }
7788     }
7789
7790   if (path)
7791     gtk_tree_path_free (path);
7792
7793   return TRUE;
7794 }
7795
7796
7797 static gboolean
7798 gtk_tree_view_drag_drop (GtkWidget        *widget,
7799                          GdkDragContext   *context,
7800                          /* coordinates relative to the widget */
7801                          gint              x,
7802                          gint              y,
7803                          guint             time)
7804 {
7805   GtkTreeView *tree_view;
7806   GtkTreePath *path;
7807   GdkDragAction suggested_action = 0;
7808   GdkAtom target = GDK_NONE;
7809   TreeViewDragInfo *di;
7810   GtkTreeModel *model;
7811   gboolean path_down_mode;
7812   gboolean drop_append_mode;
7813
7814   tree_view = GTK_TREE_VIEW (widget);
7815
7816   model = gtk_tree_view_get_model (tree_view);
7817
7818   remove_scroll_timeout (GTK_TREE_VIEW (widget));
7819   remove_open_timeout (GTK_TREE_VIEW (widget));
7820
7821   di = get_info (tree_view);
7822
7823   if (di == NULL)
7824     return FALSE;
7825
7826   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_drop"))
7827     return FALSE;
7828
7829   if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
7830     return FALSE;
7831
7832   path = get_logical_dest_row (tree_view, &path_down_mode, &drop_append_mode);
7833
7834   if (target != GDK_NONE && path != NULL)
7835     {
7836       /* in case a motion had requested drag data, change things so we
7837        * treat drag data receives as a drop.
7838        */
7839       set_status_pending (context, 0);
7840       set_dest_row (context, model, path,
7841                     path_down_mode, tree_view->priv->empty_view_drop,
7842                     drop_append_mode);
7843     }
7844
7845   if (path)
7846     gtk_tree_path_free (path);
7847
7848   /* Unset this thing */
7849   gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7850                                    NULL,
7851                                    GTK_TREE_VIEW_DROP_BEFORE);
7852
7853   if (target != GDK_NONE)
7854     {
7855       gtk_drag_get_data (widget, context, target, time);
7856       return TRUE;
7857     }
7858   else
7859     return FALSE;
7860 }
7861
7862 static void
7863 gtk_tree_view_drag_data_received (GtkWidget        *widget,
7864                                   GdkDragContext   *context,
7865                                   /* coordinates relative to the widget */
7866                                   gint              x,
7867                                   gint              y,
7868                                   GtkSelectionData *selection_data,
7869                                   guint             info,
7870                                   guint             time)
7871 {
7872   GtkTreePath *path;
7873   TreeViewDragInfo *di;
7874   gboolean accepted = FALSE;
7875   GtkTreeModel *model;
7876   GtkTreeView *tree_view;
7877   GtkTreePath *dest_row;
7878   GdkDragAction suggested_action;
7879   gboolean path_down_mode;
7880   gboolean drop_append_mode;
7881
7882   tree_view = GTK_TREE_VIEW (widget);
7883
7884   model = gtk_tree_view_get_model (tree_view);
7885
7886   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_data_received"))
7887     return;
7888
7889   di = get_info (tree_view);
7890
7891   if (di == NULL)
7892     return;
7893
7894   suggested_action = get_status_pending (context);
7895
7896   if (suggested_action)
7897     {
7898       /* We are getting this data due to a request in drag_motion,
7899        * rather than due to a request in drag_drop, so we are just
7900        * supposed to call drag_status, not actually paste in the
7901        * data.
7902        */
7903       path = get_logical_dest_row (tree_view, &path_down_mode,
7904                                    &drop_append_mode);
7905
7906       if (path == NULL)
7907         suggested_action = 0;
7908       else if (path_down_mode)
7909         gtk_tree_path_down (path);
7910
7911       if (suggested_action)
7912         {
7913           if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
7914                                                      path,
7915                                                      selection_data))
7916             {
7917               if (path_down_mode)
7918                 {
7919                   path_down_mode = FALSE;
7920                   gtk_tree_path_up (path);
7921
7922                   if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
7923                                                              path,
7924                                                              selection_data))
7925                     suggested_action = 0;
7926                 }
7927               else
7928                 suggested_action = 0;
7929             }
7930         }
7931
7932       gdk_drag_status (context, suggested_action, time);
7933
7934       if (path)
7935         gtk_tree_path_free (path);
7936
7937       /* If you can't drop, remove user drop indicator until the next motion */
7938       if (suggested_action == 0)
7939         gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7940                                          NULL,
7941                                          GTK_TREE_VIEW_DROP_BEFORE);
7942
7943       return;
7944     }
7945
7946   dest_row = get_dest_row (context, &path_down_mode);
7947
7948   if (dest_row == NULL)
7949     return;
7950
7951   if (gtk_selection_data_get_length (selection_data) >= 0)
7952     {
7953       if (path_down_mode)
7954         {
7955           gtk_tree_path_down (dest_row);
7956           if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
7957                                                      dest_row, selection_data))
7958             gtk_tree_path_up (dest_row);
7959         }
7960     }
7961
7962   if (gtk_selection_data_get_length (selection_data) >= 0)
7963     {
7964       if (gtk_tree_drag_dest_drag_data_received (GTK_TREE_DRAG_DEST (model),
7965                                                  dest_row,
7966                                                  selection_data))
7967         accepted = TRUE;
7968     }
7969
7970   gtk_drag_finish (context,
7971                    accepted,
7972                    (gdk_drag_context_get_selected_action (context) == GDK_ACTION_MOVE),
7973                    time);
7974
7975   if (gtk_tree_path_get_depth (dest_row) == 1 &&
7976       gtk_tree_path_get_indices (dest_row)[0] == 0 &&
7977       gtk_tree_model_iter_n_children (tree_view->priv->model, NULL) != 0)
7978     {
7979       /* special special case drag to "0", scroll to first item */
7980       if (!tree_view->priv->scroll_to_path)
7981         gtk_tree_view_scroll_to_cell (tree_view, dest_row, NULL, FALSE, 0.0, 0.0);
7982     }
7983
7984   gtk_tree_path_free (dest_row);
7985
7986   /* drop dest_row */
7987   set_dest_row (context, NULL, NULL, FALSE, FALSE, FALSE);
7988 }
7989
7990
7991
7992 /* GtkContainer Methods
7993  */
7994
7995
7996 static void
7997 gtk_tree_view_remove (GtkContainer *container,
7998                       GtkWidget    *widget)
7999 {
8000   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
8001   GtkTreeViewChild *child = NULL;
8002   GList *tmp_list;
8003
8004   tmp_list = tree_view->priv->children;
8005   while (tmp_list)
8006     {
8007       child = tmp_list->data;
8008       if (child->widget == widget)
8009         {
8010           gtk_widget_unparent (widget);
8011
8012           tree_view->priv->children = g_list_remove_link (tree_view->priv->children, tmp_list);
8013           g_list_free_1 (tmp_list);
8014           g_slice_free (GtkTreeViewChild, child);
8015           return;
8016         }
8017
8018       tmp_list = tmp_list->next;
8019     }
8020
8021   tmp_list = tree_view->priv->columns;
8022
8023   while (tmp_list)
8024     {
8025       GtkTreeViewColumn *column;
8026       GtkWidget         *button;
8027
8028       column = tmp_list->data;
8029       button = gtk_tree_view_column_get_button (column);
8030
8031       if (button == widget)
8032         {
8033           gtk_widget_unparent (widget);
8034           return;
8035         }
8036       tmp_list = tmp_list->next;
8037     }
8038 }
8039
8040 static void
8041 gtk_tree_view_forall (GtkContainer *container,
8042                       gboolean      include_internals,
8043                       GtkCallback   callback,
8044                       gpointer      callback_data)
8045 {
8046   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
8047   GtkTreeViewChild *child = NULL;
8048   GtkTreeViewColumn *column;
8049   GtkWidget *button;
8050   GList *tmp_list;
8051
8052   tmp_list = tree_view->priv->children;
8053   while (tmp_list)
8054     {
8055       child = tmp_list->data;
8056       tmp_list = tmp_list->next;
8057
8058       (* callback) (child->widget, callback_data);
8059     }
8060   if (include_internals == FALSE)
8061     return;
8062
8063   for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
8064     {
8065       column = tmp_list->data;
8066       button = gtk_tree_view_column_get_button (column);
8067
8068       if (button)
8069         (* callback) (button, callback_data);
8070     }
8071 }
8072
8073 /* Returns TRUE is any of the columns contains a cell that can-focus.
8074  * If this is not the case, a column-spanning focus rectangle will be
8075  * drawn.
8076  */
8077 static gboolean
8078 gtk_tree_view_has_can_focus_cell (GtkTreeView *tree_view)
8079 {
8080   GList *list;
8081
8082   for (list = tree_view->priv->columns; list; list = list->next)
8083     {
8084       GtkTreeViewColumn *column = list->data;
8085
8086       if (!gtk_tree_view_column_get_visible (column))
8087         continue;
8088       if (gtk_cell_area_is_activatable (gtk_cell_layout_get_area (GTK_CELL_LAYOUT (column))))
8089         return TRUE;
8090     }
8091
8092   return FALSE;
8093 }
8094
8095 static void
8096 column_sizing_notify (GObject    *object,
8097                       GParamSpec *pspec,
8098                       gpointer    data)
8099 {
8100   GtkTreeViewColumn *c = GTK_TREE_VIEW_COLUMN (object);
8101
8102   if (gtk_tree_view_column_get_sizing (c) != GTK_TREE_VIEW_COLUMN_FIXED)
8103     /* disable fixed height mode */
8104     g_object_set (data, "fixed-height-mode", FALSE, NULL);
8105 }
8106
8107 /**
8108  * gtk_tree_view_set_fixed_height_mode:
8109  * @tree_view: a #GtkTreeView 
8110  * @enable: %TRUE to enable fixed height mode
8111  * 
8112  * Enables or disables the fixed height mode of @tree_view. 
8113  * Fixed height mode speeds up #GtkTreeView by assuming that all 
8114  * rows have the same height. 
8115  * Only enable this option if all rows are the same height and all
8116  * columns are of type %GTK_TREE_VIEW_COLUMN_FIXED.
8117  *
8118  * Since: 2.6 
8119  **/
8120 void
8121 gtk_tree_view_set_fixed_height_mode (GtkTreeView *tree_view,
8122                                      gboolean     enable)
8123 {
8124   GList *l;
8125   
8126   enable = enable != FALSE;
8127
8128   if (enable == tree_view->priv->fixed_height_mode)
8129     return;
8130
8131   if (!enable)
8132     {
8133       tree_view->priv->fixed_height_mode = 0;
8134       tree_view->priv->fixed_height = -1;
8135
8136       /* force a revalidation */
8137       install_presize_handler (tree_view);
8138     }
8139   else 
8140     {
8141       /* make sure all columns are of type FIXED */
8142       for (l = tree_view->priv->columns; l; l = l->next)
8143         {
8144           GtkTreeViewColumn *c = l->data;
8145           
8146           g_return_if_fail (gtk_tree_view_column_get_sizing (c) == GTK_TREE_VIEW_COLUMN_FIXED);
8147         }
8148       
8149       /* yes, we really have to do this is in a separate loop */
8150       for (l = tree_view->priv->columns; l; l = l->next)
8151         g_signal_connect (l->data, "notify::sizing",
8152                           G_CALLBACK (column_sizing_notify), tree_view);
8153       
8154       tree_view->priv->fixed_height_mode = 1;
8155       tree_view->priv->fixed_height = -1;
8156       
8157       if (tree_view->priv->tree)
8158         initialize_fixed_height_mode (tree_view);
8159     }
8160
8161   g_object_notify (G_OBJECT (tree_view), "fixed-height-mode");
8162 }
8163
8164 /**
8165  * gtk_tree_view_get_fixed_height_mode:
8166  * @tree_view: a #GtkTreeView
8167  * 
8168  * Returns whether fixed height mode is turned on for @tree_view.
8169  * 
8170  * Return value: %TRUE if @tree_view is in fixed height mode
8171  * 
8172  * Since: 2.6
8173  **/
8174 gboolean
8175 gtk_tree_view_get_fixed_height_mode (GtkTreeView *tree_view)
8176 {
8177   return tree_view->priv->fixed_height_mode;
8178 }
8179
8180 /* Returns TRUE if the focus is within the headers, after the focus operation is
8181  * done
8182  */
8183 static gboolean
8184 gtk_tree_view_header_focus (GtkTreeView      *tree_view,
8185                             GtkDirectionType  dir,
8186                             gboolean          clamp_column_visible)
8187 {
8188   GtkTreeViewColumn *column;
8189   GtkWidget *focus_child;
8190   GtkWidget *button;
8191   GList *last_column, *first_column;
8192   GList *tmp_list;
8193   gboolean rtl;
8194
8195   if (! tree_view->priv->headers_visible)
8196     return FALSE;
8197
8198   focus_child = gtk_container_get_focus_child (GTK_CONTAINER (tree_view));
8199
8200   first_column = tree_view->priv->columns;
8201   while (first_column)
8202     {
8203       column = GTK_TREE_VIEW_COLUMN (first_column->data);
8204       button = gtk_tree_view_column_get_button (column);
8205
8206       if (gtk_widget_get_can_focus (button) &&
8207           gtk_tree_view_column_get_visible (column) &&
8208           (gtk_tree_view_column_get_clickable (column) ||
8209            gtk_tree_view_column_get_reorderable (column)))
8210         break;
8211       first_column = first_column->next;
8212     }
8213
8214   /* No headers are visible, or are focusable.  We can't focus in or out.
8215    */
8216   if (first_column == NULL)
8217     return FALSE;
8218
8219   last_column = g_list_last (tree_view->priv->columns);
8220   while (last_column)
8221     {
8222       column = GTK_TREE_VIEW_COLUMN (last_column->data);
8223       button = gtk_tree_view_column_get_button (column);
8224
8225       if (gtk_widget_get_can_focus (button) &&
8226           gtk_tree_view_column_get_visible (column) &&
8227           (gtk_tree_view_column_get_clickable (column) ||
8228            gtk_tree_view_column_get_reorderable (column)))
8229         break;
8230       last_column = last_column->prev;
8231     }
8232
8233
8234   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
8235
8236   switch (dir)
8237     {
8238     case GTK_DIR_TAB_BACKWARD:
8239     case GTK_DIR_TAB_FORWARD:
8240     case GTK_DIR_UP:
8241     case GTK_DIR_DOWN:
8242       if (focus_child == NULL)
8243         {
8244           if (tree_view->priv->focus_column != NULL)
8245             button = gtk_tree_view_column_get_button (tree_view->priv->focus_column);
8246           else 
8247             button = NULL;
8248
8249           if (button && gtk_widget_get_can_focus (button))
8250             focus_child = button;
8251           else
8252             focus_child = gtk_tree_view_column_get_button (GTK_TREE_VIEW_COLUMN (first_column->data));
8253
8254           gtk_widget_grab_focus (focus_child);
8255           break;
8256         }
8257       return FALSE;
8258
8259     case GTK_DIR_LEFT:
8260     case GTK_DIR_RIGHT:
8261       if (focus_child == NULL)
8262         {
8263           if (tree_view->priv->focus_column != NULL)
8264             focus_child = gtk_tree_view_column_get_button (tree_view->priv->focus_column);
8265           else if (dir == GTK_DIR_LEFT)
8266             focus_child = gtk_tree_view_column_get_button (GTK_TREE_VIEW_COLUMN (last_column->data));
8267           else
8268             focus_child = gtk_tree_view_column_get_button (GTK_TREE_VIEW_COLUMN (first_column->data));
8269
8270           gtk_widget_grab_focus (focus_child);
8271           break;
8272         }
8273
8274       if (gtk_widget_child_focus (focus_child, dir))
8275         {
8276           /* The focus moves inside the button. */
8277           /* This is probably a great example of bad UI */
8278           break;
8279         }
8280
8281       /* We need to move the focus among the row of buttons. */
8282       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
8283         if (gtk_tree_view_column_get_button (GTK_TREE_VIEW_COLUMN (tmp_list->data)) == focus_child)
8284           break;
8285
8286       if ((tmp_list == first_column && dir == (rtl ? GTK_DIR_RIGHT : GTK_DIR_LEFT))
8287           || (tmp_list == last_column && dir == (rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT)))
8288         {
8289           gtk_widget_error_bell (GTK_WIDGET (tree_view));
8290           break;
8291         }
8292
8293       while (tmp_list)
8294         {
8295           GtkTreeViewColumn *column;
8296           GtkWidget         *button;
8297
8298           if (dir == (rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT))
8299             tmp_list = tmp_list->next;
8300           else
8301             tmp_list = tmp_list->prev;
8302
8303           if (tmp_list == NULL)
8304             {
8305               g_warning ("Internal button not found");
8306               break;
8307             }
8308           column = tmp_list->data;
8309           button = gtk_tree_view_column_get_button (column);
8310           if (button &&
8311               gtk_tree_view_column_get_visible (column) &&
8312               gtk_widget_get_can_focus (button))
8313             {
8314               focus_child = button;
8315               gtk_widget_grab_focus (button);
8316               break;
8317             }
8318         }
8319       break;
8320     default:
8321       g_assert_not_reached ();
8322       break;
8323     }
8324
8325   /* if focus child is non-null, we assume it's been set to the current focus child
8326    */
8327   if (focus_child)
8328     {
8329       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
8330         if (gtk_tree_view_column_get_button (GTK_TREE_VIEW_COLUMN (tmp_list->data)) == focus_child)
8331           {
8332             _gtk_tree_view_set_focus_column (tree_view, GTK_TREE_VIEW_COLUMN (tmp_list->data));
8333             break;
8334           }
8335
8336       if (clamp_column_visible)
8337         {
8338           gtk_tree_view_clamp_column_visible (tree_view,
8339                                               tree_view->priv->focus_column,
8340                                               FALSE);
8341         }
8342     }
8343
8344   return (focus_child != NULL);
8345 }
8346
8347 /* This function returns in 'path' the first focusable path, if the given path
8348  * is already focusable, it's the returned one.
8349  */
8350 static gboolean
8351 search_first_focusable_path (GtkTreeView  *tree_view,
8352                              GtkTreePath **path,
8353                              gboolean      search_forward,
8354                              GtkRBTree   **new_tree,
8355                              GtkRBNode   **new_node)
8356 {
8357   GtkRBTree *tree = NULL;
8358   GtkRBNode *node = NULL;
8359
8360   if (!path || !*path)
8361     return FALSE;
8362
8363   _gtk_tree_view_find_node (tree_view, *path, &tree, &node);
8364
8365   if (!tree || !node)
8366     return FALSE;
8367
8368   while (node && row_is_separator (tree_view, NULL, *path))
8369     {
8370       if (search_forward)
8371         _gtk_rbtree_next_full (tree, node, &tree, &node);
8372       else
8373         _gtk_rbtree_prev_full (tree, node, &tree, &node);
8374
8375       if (*path)
8376         gtk_tree_path_free (*path);
8377
8378       if (node)
8379         *path = _gtk_tree_path_new_from_rbtree (tree, node);
8380       else
8381         *path = NULL;
8382     }
8383
8384   if (new_tree)
8385     *new_tree = tree;
8386
8387   if (new_node)
8388     *new_node = node;
8389
8390   return (*path != NULL);
8391 }
8392
8393 static gint
8394 gtk_tree_view_focus (GtkWidget        *widget,
8395                      GtkDirectionType  direction)
8396 {
8397   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
8398   GtkContainer *container = GTK_CONTAINER (widget);
8399   GtkWidget *focus_child;
8400
8401   if (!gtk_widget_is_sensitive (widget) || !gtk_widget_get_can_focus (widget))
8402     return FALSE;
8403
8404   focus_child = gtk_container_get_focus_child (container);
8405
8406   gtk_tree_view_stop_editing (GTK_TREE_VIEW (widget), FALSE);
8407   /* Case 1.  Headers currently have focus. */
8408   if (focus_child)
8409     {
8410       switch (direction)
8411         {
8412         case GTK_DIR_LEFT:
8413         case GTK_DIR_RIGHT:
8414           gtk_tree_view_header_focus (tree_view, direction, TRUE);
8415           return TRUE;
8416         case GTK_DIR_TAB_BACKWARD:
8417         case GTK_DIR_UP:
8418           return FALSE;
8419         case GTK_DIR_TAB_FORWARD:
8420         case GTK_DIR_DOWN:
8421           gtk_widget_grab_focus (widget);
8422           return TRUE;
8423         default:
8424           g_assert_not_reached ();
8425           return FALSE;
8426         }
8427     }
8428
8429   /* Case 2. We don't have focus at all. */
8430   if (!gtk_widget_has_focus (widget))
8431     {
8432       gtk_widget_grab_focus (widget);
8433       return TRUE;
8434     }
8435
8436   /* Case 3. We have focus already. */
8437   if (direction == GTK_DIR_TAB_BACKWARD)
8438     return (gtk_tree_view_header_focus (tree_view, direction, FALSE));
8439   else if (direction == GTK_DIR_TAB_FORWARD)
8440     return FALSE;
8441
8442   /* Other directions caught by the keybindings */
8443   gtk_widget_grab_focus (widget);
8444   return TRUE;
8445 }
8446
8447 static void
8448 gtk_tree_view_grab_focus (GtkWidget *widget)
8449 {
8450   GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->grab_focus (widget);
8451
8452   gtk_tree_view_focus_to_cursor (GTK_TREE_VIEW (widget));
8453 }
8454
8455 static void
8456 gtk_tree_view_style_updated (GtkWidget *widget)
8457 {
8458   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
8459   GList *list;
8460   GtkTreeViewColumn *column;
8461
8462   GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->style_updated (widget);
8463
8464   if (gtk_widget_get_realized (widget))
8465     {
8466       gtk_tree_view_ensure_background (tree_view);
8467
8468       gtk_tree_view_set_grid_lines (tree_view, tree_view->priv->grid_lines);
8469       gtk_tree_view_set_enable_tree_lines (tree_view, tree_view->priv->tree_lines_enabled);
8470     }
8471
8472   for (list = tree_view->priv->columns; list; list = list->next)
8473     {
8474       column = list->data;
8475       _gtk_tree_view_column_cell_set_dirty (column, TRUE);
8476     }
8477
8478   tree_view->priv->fixed_height = -1;
8479   _gtk_rbtree_mark_invalid (tree_view->priv->tree);
8480
8481   gtk_widget_queue_resize (widget);
8482 }
8483
8484
8485 static void
8486 gtk_tree_view_set_focus_child (GtkContainer *container,
8487                                GtkWidget    *child)
8488 {
8489   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
8490   GList *list;
8491
8492   for (list = tree_view->priv->columns; list; list = list->next)
8493     {
8494       if (gtk_tree_view_column_get_button (GTK_TREE_VIEW_COLUMN (list->data)) == child)
8495         {
8496           _gtk_tree_view_set_focus_column (tree_view, GTK_TREE_VIEW_COLUMN (list->data));
8497           break;
8498         }
8499     }
8500
8501   GTK_CONTAINER_CLASS (gtk_tree_view_parent_class)->set_focus_child (container, child);
8502 }
8503
8504 static GtkWidgetPath *
8505 gtk_tree_view_get_path_for_child (GtkContainer *container,
8506                                   GtkWidget    *child)
8507 {
8508   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
8509   GtkWidgetPath *path;
8510   gboolean rtl;
8511   GList *list, *visible_columns = NULL;
8512   gint n_col = 0;
8513
8514   path = GTK_CONTAINER_CLASS (gtk_tree_view_parent_class)->get_path_for_child (container, child);
8515   rtl = (gtk_widget_get_direction (GTK_WIDGET (container)) == GTK_TEXT_DIR_RTL);
8516
8517   for (list = tree_view->priv->columns; list; list = list->next)
8518     {
8519       GtkTreeViewColumn *column = list->data;
8520
8521       if (gtk_tree_view_column_get_visible (column))
8522         visible_columns = g_list_prepend (visible_columns, column);
8523     }
8524
8525   if (!rtl)
8526     visible_columns = g_list_reverse (visible_columns);
8527
8528   for (list = visible_columns; list != NULL; list = list->next)
8529     {
8530       GtkTreeViewColumn *column = list->data;
8531       GtkRegionFlags flags = 0;
8532
8533       n_col++;
8534
8535       if (gtk_tree_view_column_get_widget (column) != child &&
8536           gtk_tree_view_column_get_button (column) != child)
8537         continue;
8538
8539       if ((n_col % 2) == 0)
8540         flags |= GTK_REGION_EVEN;
8541       else
8542         flags |= GTK_REGION_ODD;
8543
8544       if (n_col == 1)
8545         flags |= GTK_REGION_FIRST;
8546
8547       if (!list->next)
8548         flags |= GTK_REGION_LAST;
8549
8550       gtk_widget_path_iter_add_region (path, -1, GTK_STYLE_REGION_COLUMN_HEADER, flags);
8551       break;
8552     }
8553   g_list_free (visible_columns);
8554
8555   gtk_widget_path_append_for_widget (path, child);
8556
8557   return path;
8558 }
8559
8560 static gboolean
8561 gtk_tree_view_real_move_cursor (GtkTreeView       *tree_view,
8562                                 GtkMovementStep    step,
8563                                 gint               count)
8564 {
8565   GdkModifierType state;
8566
8567   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
8568   g_return_val_if_fail (step == GTK_MOVEMENT_LOGICAL_POSITIONS ||
8569                         step == GTK_MOVEMENT_VISUAL_POSITIONS ||
8570                         step == GTK_MOVEMENT_DISPLAY_LINES ||
8571                         step == GTK_MOVEMENT_PAGES ||
8572                         step == GTK_MOVEMENT_BUFFER_ENDS, FALSE);
8573
8574   if (tree_view->priv->tree == NULL)
8575     return FALSE;
8576   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
8577     return FALSE;
8578
8579   gtk_tree_view_stop_editing (tree_view, FALSE);
8580   tree_view->priv->draw_keyfocus = TRUE;
8581   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
8582
8583   if (gtk_get_current_event_state (&state))
8584     {
8585       GdkModifierType extend_mod_mask;
8586       GdkModifierType modify_mod_mask;
8587
8588       extend_mod_mask =
8589         gtk_widget_get_modifier_mask (GTK_WIDGET (tree_view),
8590                                       GDK_MODIFIER_INTENT_EXTEND_SELECTION);
8591
8592       modify_mod_mask =
8593         gtk_widget_get_modifier_mask (GTK_WIDGET (tree_view),
8594                                       GDK_MODIFIER_INTENT_MODIFY_SELECTION);
8595
8596       if ((state & modify_mod_mask) == modify_mod_mask)
8597         tree_view->priv->modify_selection_pressed = TRUE;
8598       if ((state & extend_mod_mask) == extend_mod_mask)
8599         tree_view->priv->extend_selection_pressed = TRUE;
8600     }
8601   /* else we assume not pressed */
8602
8603   switch (step)
8604     {
8605       /* currently we make no distinction.  When we go bi-di, we need to */
8606     case GTK_MOVEMENT_LOGICAL_POSITIONS:
8607     case GTK_MOVEMENT_VISUAL_POSITIONS:
8608       gtk_tree_view_move_cursor_left_right (tree_view, count);
8609       break;
8610     case GTK_MOVEMENT_DISPLAY_LINES:
8611       gtk_tree_view_move_cursor_up_down (tree_view, count);
8612       break;
8613     case GTK_MOVEMENT_PAGES:
8614       gtk_tree_view_move_cursor_page_up_down (tree_view, count);
8615       break;
8616     case GTK_MOVEMENT_BUFFER_ENDS:
8617       gtk_tree_view_move_cursor_start_end (tree_view, count);
8618       break;
8619     default:
8620       g_assert_not_reached ();
8621     }
8622
8623   tree_view->priv->modify_selection_pressed = FALSE;
8624   tree_view->priv->extend_selection_pressed = FALSE;
8625
8626   return TRUE;
8627 }
8628
8629 static void
8630 gtk_tree_view_put (GtkTreeView *tree_view,
8631                    GtkWidget   *child_widget,
8632                    /* in bin_window coordinates */
8633                    gint         x,
8634                    gint         y,
8635                    gint         width,
8636                    gint         height)
8637 {
8638   GtkTreeViewChild *child;
8639   
8640   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8641   g_return_if_fail (GTK_IS_WIDGET (child_widget));
8642
8643   child = g_slice_new (GtkTreeViewChild);
8644
8645   child->widget = child_widget;
8646   child->x = x;
8647   child->y = y;
8648   child->width = width;
8649   child->height = height;
8650
8651   tree_view->priv->children = g_list_append (tree_view->priv->children, child);
8652
8653   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
8654     gtk_widget_set_parent_window (child->widget, tree_view->priv->bin_window);
8655   
8656   gtk_widget_set_parent (child_widget, GTK_WIDGET (tree_view));
8657 }
8658
8659 void
8660 _gtk_tree_view_child_move_resize (GtkTreeView *tree_view,
8661                                   GtkWidget   *widget,
8662                                   /* in tree coordinates */
8663                                   gint         x,
8664                                   gint         y,
8665                                   gint         width,
8666                                   gint         height)
8667 {
8668   GtkTreeViewChild *child = NULL;
8669   GList *list;
8670   GdkRectangle allocation;
8671
8672   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8673   g_return_if_fail (GTK_IS_WIDGET (widget));
8674
8675   for (list = tree_view->priv->children; list; list = list->next)
8676     {
8677       if (((GtkTreeViewChild *)list->data)->widget == widget)
8678         {
8679           child = list->data;
8680           break;
8681         }
8682     }
8683   if (child == NULL)
8684     return;
8685
8686   allocation.x = child->x = x;
8687   allocation.y = child->y = y;
8688   allocation.width = child->width = width;
8689   allocation.height = child->height = height;
8690
8691   if (gtk_widget_get_realized (widget))
8692     gtk_widget_size_allocate (widget, &allocation);
8693 }
8694
8695
8696 /* TreeModel Callbacks
8697  */
8698
8699 static void
8700 gtk_tree_view_row_changed (GtkTreeModel *model,
8701                            GtkTreePath  *path,
8702                            GtkTreeIter  *iter,
8703                            gpointer      data)
8704 {
8705   GtkTreeView *tree_view = (GtkTreeView *)data;
8706   GtkRBTree *tree;
8707   GtkRBNode *node;
8708   gboolean free_path = FALSE;
8709   GList *list;
8710   GtkTreePath *cursor_path;
8711
8712   g_return_if_fail (path != NULL || iter != NULL);
8713
8714   if (tree_view->priv->cursor_node != NULL)
8715     cursor_path = _gtk_tree_path_new_from_rbtree (tree_view->priv->cursor_tree,
8716                                                   tree_view->priv->cursor_node);
8717   else
8718     cursor_path = NULL;
8719
8720   if (tree_view->priv->edited_column &&
8721       (cursor_path == NULL || gtk_tree_path_compare (cursor_path, path) == 0))
8722     gtk_tree_view_stop_editing (tree_view, TRUE);
8723
8724   if (cursor_path != NULL)
8725     gtk_tree_path_free (cursor_path);
8726
8727   if (path == NULL)
8728     {
8729       path = gtk_tree_model_get_path (model, iter);
8730       free_path = TRUE;
8731     }
8732   else if (iter == NULL)
8733     gtk_tree_model_get_iter (model, iter, path);
8734
8735   if (_gtk_tree_view_find_node (tree_view,
8736                                 path,
8737                                 &tree,
8738                                 &node))
8739     /* We aren't actually showing the node */
8740     goto done;
8741
8742   if (tree == NULL)
8743     goto done;
8744
8745   _gtk_tree_view_accessible_changed (tree_view, tree, node);
8746
8747   if (tree_view->priv->fixed_height_mode
8748       && tree_view->priv->fixed_height >= 0)
8749     {
8750       _gtk_rbtree_node_set_height (tree, node, tree_view->priv->fixed_height);
8751       if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
8752         gtk_tree_view_node_queue_redraw (tree_view, tree, node);
8753     }
8754   else
8755     {
8756       _gtk_rbtree_node_mark_invalid (tree, node);
8757       for (list = tree_view->priv->columns; list; list = list->next)
8758         {
8759           GtkTreeViewColumn *column;
8760
8761           column = list->data;
8762           if (!gtk_tree_view_column_get_visible (column))
8763             continue;
8764
8765           if (gtk_tree_view_column_get_sizing (column) == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
8766             {
8767               _gtk_tree_view_column_cell_set_dirty (column, TRUE);
8768             }
8769         }
8770     }
8771
8772  done:
8773   if (!tree_view->priv->fixed_height_mode &&
8774       gtk_widget_get_realized (GTK_WIDGET (tree_view)))
8775     install_presize_handler (tree_view);
8776   if (free_path)
8777     gtk_tree_path_free (path);
8778 }
8779
8780 static void
8781 gtk_tree_view_row_inserted (GtkTreeModel *model,
8782                             GtkTreePath  *path,
8783                             GtkTreeIter  *iter,
8784                             gpointer      data)
8785 {
8786   GtkTreeView *tree_view = (GtkTreeView *) data;
8787   gint *indices;
8788   GtkRBTree *tree;
8789   GtkRBNode *tmpnode = NULL;
8790   gint depth;
8791   gint i = 0;
8792   gint height;
8793   gboolean free_path = FALSE;
8794   gboolean node_visible = TRUE;
8795
8796   g_return_if_fail (path != NULL || iter != NULL);
8797
8798   if (tree_view->priv->fixed_height_mode
8799       && tree_view->priv->fixed_height >= 0)
8800     height = tree_view->priv->fixed_height;
8801   else
8802     height = 0;
8803
8804   if (path == NULL)
8805     {
8806       path = gtk_tree_model_get_path (model, iter);
8807       free_path = TRUE;
8808     }
8809   else if (iter == NULL)
8810     gtk_tree_model_get_iter (model, iter, path);
8811
8812   if (tree_view->priv->tree == NULL)
8813     tree_view->priv->tree = _gtk_rbtree_new ();
8814
8815   tree = tree_view->priv->tree;
8816
8817   /* Update all row-references */
8818   gtk_tree_row_reference_inserted (G_OBJECT (data), path);
8819   depth = gtk_tree_path_get_depth (path);
8820   indices = gtk_tree_path_get_indices (path);
8821
8822   /* First, find the parent tree */
8823   while (i < depth - 1)
8824     {
8825       if (tree == NULL)
8826         {
8827           /* We aren't showing the node */
8828           node_visible = FALSE;
8829           goto done;
8830         }
8831
8832       tmpnode = _gtk_rbtree_find_count (tree, indices[i] + 1);
8833       if (tmpnode == NULL)
8834         {
8835           g_warning ("A node was inserted with a parent that's not in the tree.\n" \
8836                      "This possibly means that a GtkTreeModel inserted a child node\n" \
8837                      "before the parent was inserted.");
8838           goto done;
8839         }
8840       else if (!GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_IS_PARENT))
8841         {
8842           /* FIXME enforce correct behavior on model, probably */
8843           /* In theory, the model should have emitted has_child_toggled here.  We
8844            * try to catch it anyway, just to be safe, in case the model hasn't.
8845            */
8846           GtkTreePath *tmppath = _gtk_tree_path_new_from_rbtree (tree, tmpnode);
8847           gtk_tree_view_row_has_child_toggled (model, tmppath, NULL, data);
8848           gtk_tree_path_free (tmppath);
8849           goto done;
8850         }
8851
8852       tree = tmpnode->children;
8853       i++;
8854     }
8855
8856   if (tree == NULL)
8857     {
8858       node_visible = FALSE;
8859       goto done;
8860     }
8861
8862   /* ref the node */
8863   gtk_tree_model_ref_node (tree_view->priv->model, iter);
8864   if (indices[depth - 1] == 0)
8865     {
8866       tmpnode = _gtk_rbtree_find_count (tree, 1);
8867       tmpnode = _gtk_rbtree_insert_before (tree, tmpnode, height, FALSE);
8868     }
8869   else
8870     {
8871       tmpnode = _gtk_rbtree_find_count (tree, indices[depth - 1]);
8872       tmpnode = _gtk_rbtree_insert_after (tree, tmpnode, height, FALSE);
8873     }
8874
8875   _gtk_tree_view_accessible_add (tree_view, tree, tmpnode);
8876
8877  done:
8878   if (height > 0)
8879     {
8880       if (tree)
8881         _gtk_rbtree_node_mark_valid (tree, tmpnode);
8882
8883       if (node_visible && node_is_visible (tree_view, tree, tmpnode))
8884         gtk_widget_queue_resize (GTK_WIDGET (tree_view));
8885       else
8886         gtk_widget_queue_resize_no_redraw (GTK_WIDGET (tree_view));
8887     }
8888   else
8889     install_presize_handler (tree_view);
8890   if (free_path)
8891     gtk_tree_path_free (path);
8892 }
8893
8894 static void
8895 gtk_tree_view_row_has_child_toggled (GtkTreeModel *model,
8896                                      GtkTreePath  *path,
8897                                      GtkTreeIter  *iter,
8898                                      gpointer      data)
8899 {
8900   GtkTreeView *tree_view = (GtkTreeView *)data;
8901   GtkTreeIter real_iter;
8902   gboolean has_child;
8903   GtkRBTree *tree;
8904   GtkRBNode *node;
8905   gboolean free_path = FALSE;
8906
8907   g_return_if_fail (path != NULL || iter != NULL);
8908
8909   if (iter)
8910     real_iter = *iter;
8911
8912   if (path == NULL)
8913     {
8914       path = gtk_tree_model_get_path (model, iter);
8915       free_path = TRUE;
8916     }
8917   else if (iter == NULL)
8918     gtk_tree_model_get_iter (model, &real_iter, path);
8919
8920   if (_gtk_tree_view_find_node (tree_view,
8921                                 path,
8922                                 &tree,
8923                                 &node))
8924     /* We aren't actually showing the node */
8925     goto done;
8926
8927   if (tree == NULL)
8928     goto done;
8929
8930   has_child = gtk_tree_model_iter_has_child (model, &real_iter);
8931   /* Sanity check.
8932    */
8933   if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT) == has_child)
8934     goto done;
8935
8936   if (has_child)
8937     {
8938       GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_PARENT);
8939       _gtk_tree_view_accessible_add_state (tree_view, tree, node, GTK_CELL_RENDERER_EXPANDABLE);
8940     }
8941   else
8942     {
8943       GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_PARENT);
8944       _gtk_tree_view_accessible_remove_state (tree_view, tree, node, GTK_CELL_RENDERER_EXPANDABLE);
8945     }
8946
8947   if (has_child && tree_view->priv->is_list)
8948     {
8949       tree_view->priv->is_list = FALSE;
8950       if (tree_view->priv->show_expanders)
8951         {
8952           GList *list;
8953
8954           for (list = tree_view->priv->columns; list; list = list->next)
8955             if (gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (list->data)))
8956               {
8957                 _gtk_tree_view_column_cell_set_dirty (GTK_TREE_VIEW_COLUMN (list->data), TRUE);
8958                 break;
8959               }
8960         }
8961       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
8962     }
8963   else
8964     {
8965       _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
8966     }
8967
8968  done:
8969   if (free_path)
8970     gtk_tree_path_free (path);
8971 }
8972
8973 static void
8974 count_children_helper (GtkRBTree *tree,
8975                        GtkRBNode *node,
8976                        gpointer   data)
8977 {
8978   if (node->children)
8979     _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, data);
8980   (*((gint *)data))++;
8981 }
8982
8983 static void
8984 check_selection_helper (GtkRBTree *tree,
8985                         GtkRBNode *node,
8986                         gpointer   data)
8987 {
8988   gint *value = (gint *)data;
8989
8990   *value |= GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED);
8991
8992   if (node->children && !*value)
8993     _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, check_selection_helper, data);
8994 }
8995
8996 static void
8997 gtk_tree_view_row_deleted (GtkTreeModel *model,
8998                            GtkTreePath  *path,
8999                            gpointer      data)
9000 {
9001   GtkTreeView *tree_view = (GtkTreeView *)data;
9002   GtkRBTree *tree;
9003   GtkRBNode *node;
9004   GList *list;
9005   gboolean selection_changed = FALSE, cursor_changed = FALSE;
9006   GtkRBTree *cursor_tree = NULL;
9007   GtkRBNode *cursor_node = NULL;
9008
9009   g_return_if_fail (path != NULL);
9010
9011   gtk_tree_row_reference_deleted (G_OBJECT (data), path);
9012
9013   if (_gtk_tree_view_find_node (tree_view, path, &tree, &node))
9014     return;
9015
9016   if (tree == NULL)
9017     return;
9018
9019   /* check if the selection has been changed */
9020   _gtk_rbtree_traverse (tree, node, G_POST_ORDER,
9021                         check_selection_helper, &selection_changed);
9022
9023   for (list = tree_view->priv->columns; list; list = list->next)
9024     if (gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (list->data)) &&
9025         gtk_tree_view_column_get_sizing (GTK_TREE_VIEW_COLUMN (list->data)) == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
9026       _gtk_tree_view_column_cell_set_dirty ((GtkTreeViewColumn *)list->data, TRUE);
9027
9028   /* Ensure we don't have a dangling pointer to a dead node */
9029   ensure_unprelighted (tree_view);
9030
9031   /* Cancel editting if we've started */
9032   gtk_tree_view_stop_editing (tree_view, TRUE);
9033
9034   /* If the cursor row got deleted, move the cursor to the next row */
9035   if (tree_view->priv->cursor_node &&
9036       (tree_view->priv->cursor_node == node ||
9037        (node->children && (tree_view->priv->cursor_tree == node->children ||
9038                            _gtk_rbtree_contains (node->children, tree_view->priv->cursor_tree)))))
9039     {
9040       GtkTreePath *cursor_path;
9041
9042       cursor_tree = tree;
9043       cursor_node = _gtk_rbtree_next (tree, node);
9044       /* find the first node that is not going to be deleted */
9045       while (cursor_node == NULL && cursor_tree->parent_tree)
9046         {
9047           cursor_node = _gtk_rbtree_next (cursor_tree->parent_tree,
9048                                           cursor_tree->parent_node);
9049           cursor_tree = cursor_tree->parent_tree;
9050         }
9051
9052       if (cursor_node != NULL)
9053         cursor_path = _gtk_tree_path_new_from_rbtree (cursor_tree, cursor_node);
9054       else
9055         cursor_path = NULL;
9056
9057       if (cursor_path == NULL ||
9058           ! search_first_focusable_path (tree_view, &cursor_path, TRUE, 
9059                                          &cursor_tree, &cursor_node))
9060         {
9061           /* It looks like we reached the end of the view without finding
9062            * a focusable row.  We will step backwards to find the last
9063            * focusable row.
9064            */
9065           _gtk_rbtree_prev_full (tree, node, &cursor_tree, &cursor_node);
9066           if (cursor_node)
9067             {
9068               cursor_path = _gtk_tree_path_new_from_rbtree (cursor_tree, cursor_node);
9069               if (! search_first_focusable_path (tree_view, &cursor_path, FALSE,
9070                                                  &cursor_tree, &cursor_node))
9071                 cursor_node = NULL;
9072               gtk_tree_path_free (cursor_path);
9073             }
9074         }
9075       else if (cursor_path)
9076         gtk_tree_path_free (cursor_path);
9077
9078       cursor_changed = TRUE;
9079     }
9080
9081   if (tree_view->priv->destroy_count_func)
9082     {
9083       gint child_count = 0;
9084       if (node->children)
9085         _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, &child_count);
9086       tree_view->priv->destroy_count_func (tree_view, path, child_count, tree_view->priv->destroy_count_data);
9087     }
9088
9089   if (tree->root->count == 1)
9090     {
9091       if (tree_view->priv->tree == tree)
9092         tree_view->priv->tree = NULL;
9093
9094       _gtk_tree_view_accessible_remove_state (tree_view,
9095                                               tree->parent_tree, tree->parent_node,
9096                                               GTK_CELL_RENDERER_EXPANDED);
9097       _gtk_tree_view_accessible_remove (tree_view, tree, NULL);
9098       _gtk_rbtree_remove (tree);
9099     }
9100   else
9101     {
9102       _gtk_tree_view_accessible_remove (tree_view, tree, node);
9103       _gtk_rbtree_remove_node (tree, node);
9104     }
9105
9106   if (! gtk_tree_row_reference_valid (tree_view->priv->top_row))
9107     {
9108       gtk_tree_row_reference_free (tree_view->priv->top_row);
9109       tree_view->priv->top_row = NULL;
9110     }
9111
9112   install_scroll_sync_handler (tree_view);
9113
9114   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
9115
9116   if (cursor_changed)
9117     {
9118       if (cursor_node)
9119         {
9120           GtkTreePath *cursor_path = _gtk_tree_path_new_from_rbtree (cursor_tree, cursor_node);
9121           gtk_tree_view_real_set_cursor (tree_view, cursor_path, CLEAR_AND_SELECT | CURSOR_INVALID);
9122           gtk_tree_path_free (cursor_path);
9123         }
9124       else
9125         gtk_tree_view_real_set_cursor (tree_view, NULL, CLEAR_AND_SELECT | CURSOR_INVALID);
9126     }
9127   if (selection_changed)
9128     g_signal_emit_by_name (tree_view->priv->selection, "changed");
9129 }
9130
9131 static void
9132 gtk_tree_view_rows_reordered (GtkTreeModel *model,
9133                               GtkTreePath  *parent,
9134                               GtkTreeIter  *iter,
9135                               gint         *new_order,
9136                               gpointer      data)
9137 {
9138   GtkTreeView *tree_view = GTK_TREE_VIEW (data);
9139   GtkRBTree *tree;
9140   GtkRBNode *node;
9141   gint len;
9142
9143   len = gtk_tree_model_iter_n_children (model, iter);
9144
9145   if (len < 2)
9146     return;
9147
9148   gtk_tree_row_reference_reordered (G_OBJECT (data),
9149                                     parent,
9150                                     iter,
9151                                     new_order);
9152
9153   if (_gtk_tree_view_find_node (tree_view,
9154                                 parent,
9155                                 &tree,
9156                                 &node))
9157     return;
9158
9159   /* We need to special case the parent path */
9160   if (tree == NULL)
9161     tree = tree_view->priv->tree;
9162   else
9163     tree = node->children;
9164
9165   if (tree == NULL)
9166     return;
9167
9168   if (tree_view->priv->edited_column)
9169     gtk_tree_view_stop_editing (tree_view, TRUE);
9170
9171   /* we need to be unprelighted */
9172   ensure_unprelighted (tree_view);
9173
9174   _gtk_rbtree_reorder (tree, new_order, len);
9175
9176   _gtk_tree_view_accessible_reorder (tree_view);
9177
9178   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
9179
9180   gtk_tree_view_dy_to_top_row (tree_view);
9181 }
9182
9183
9184 /* Internal tree functions
9185  */
9186
9187
9188 static void
9189 gtk_tree_view_get_background_xrange (GtkTreeView       *tree_view,
9190                                      GtkRBTree         *tree,
9191                                      GtkTreeViewColumn *column,
9192                                      gint              *x1,
9193                                      gint              *x2)
9194 {
9195   GtkTreeViewColumn *tmp_column = NULL;
9196   gint total_width;
9197   GList *list;
9198   gboolean rtl;
9199
9200   if (x1)
9201     *x1 = 0;
9202
9203   if (x2)
9204     *x2 = 0;
9205
9206   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
9207
9208   total_width = 0;
9209   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
9210        list;
9211        list = (rtl ? list->prev : list->next))
9212     {
9213       tmp_column = list->data;
9214
9215       if (tmp_column == column)
9216         break;
9217
9218       if (gtk_tree_view_column_get_visible (tmp_column))
9219         total_width += gtk_tree_view_column_get_width (tmp_column);
9220     }
9221
9222   if (tmp_column != column)
9223     {
9224       g_warning (G_STRLOC": passed-in column isn't in the tree");
9225       return;
9226     }
9227
9228   if (x1)
9229     *x1 = total_width;
9230
9231   if (x2)
9232     {
9233       if (gtk_tree_view_column_get_visible (column))
9234         *x2 = total_width + gtk_tree_view_column_get_width (column);
9235       else
9236         *x2 = total_width; /* width of 0 */
9237     }
9238 }
9239
9240 static void
9241 gtk_tree_view_get_arrow_xrange (GtkTreeView *tree_view,
9242                                 GtkRBTree   *tree,
9243                                 gint        *x1,
9244                                 gint        *x2)
9245 {
9246   gint x_offset = 0;
9247   GList *list;
9248   GtkTreeViewColumn *tmp_column = NULL;
9249   gint total_width;
9250   gint expander_size;
9251   gboolean indent_expanders;
9252   gboolean rtl;
9253
9254   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
9255   expander_size = gtk_tree_view_get_expander_size (tree_view);
9256
9257   total_width = 0;
9258   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
9259        list;
9260        list = (rtl ? list->prev : list->next))
9261     {
9262       tmp_column = list->data;
9263
9264       if (gtk_tree_view_is_expander_column (tree_view, tmp_column))
9265         {
9266           if (rtl)
9267             x_offset = total_width + gtk_tree_view_column_get_width (tmp_column) - expander_size;
9268           else
9269             x_offset = total_width;
9270           break;
9271         }
9272
9273       if (gtk_tree_view_column_get_visible (tmp_column))
9274         total_width += gtk_tree_view_column_get_width (tmp_column);
9275     }
9276
9277   gtk_widget_style_get (GTK_WIDGET (tree_view),
9278                         "indent-expanders", &indent_expanders,
9279                         NULL);
9280
9281   if (indent_expanders)
9282     {
9283       if (rtl)
9284         x_offset -= expander_size * _gtk_rbtree_get_depth (tree);
9285       else
9286         x_offset += expander_size * _gtk_rbtree_get_depth (tree);
9287     }
9288
9289   *x1 = x_offset;
9290
9291   if (tmp_column &&
9292       gtk_tree_view_column_get_visible (tmp_column))
9293     /* +1 because x2 isn't included in the range. */
9294     *x2 = *x1 + expander_size + 1;
9295   else
9296     *x2 = *x1;
9297 }
9298
9299 static void
9300 gtk_tree_view_build_tree (GtkTreeView *tree_view,
9301                           GtkRBTree   *tree,
9302                           GtkTreeIter *iter,
9303                           gint         depth,
9304                           gboolean     recurse)
9305 {
9306   GtkRBNode *temp = NULL;
9307   GtkTreePath *path = NULL;
9308
9309   do
9310     {
9311       gtk_tree_model_ref_node (tree_view->priv->model, iter);
9312       temp = _gtk_rbtree_insert_after (tree, temp, 0, FALSE);
9313
9314       if (tree_view->priv->fixed_height > 0)
9315         {
9316           if (GTK_RBNODE_FLAG_SET (temp, GTK_RBNODE_INVALID))
9317             {
9318               _gtk_rbtree_node_set_height (tree, temp, tree_view->priv->fixed_height);
9319               _gtk_rbtree_node_mark_valid (tree, temp);
9320             }
9321         }
9322
9323       if (tree_view->priv->is_list)
9324         continue;
9325
9326       if (recurse)
9327         {
9328           GtkTreeIter child;
9329
9330           if (!path)
9331             path = gtk_tree_model_get_path (tree_view->priv->model, iter);
9332           else
9333             gtk_tree_path_next (path);
9334
9335           if (gtk_tree_model_iter_children (tree_view->priv->model, &child, iter))
9336             {
9337               gboolean expand;
9338
9339               g_signal_emit (tree_view, tree_view_signals[TEST_EXPAND_ROW], 0, iter, path, &expand);
9340
9341               if (gtk_tree_model_iter_has_child (tree_view->priv->model, iter)
9342                   && !expand)
9343                 {
9344                   temp->children = _gtk_rbtree_new ();
9345                   temp->children->parent_tree = tree;
9346                   temp->children->parent_node = temp;
9347                   gtk_tree_view_build_tree (tree_view, temp->children, &child, depth + 1, recurse);
9348                 }
9349             }
9350         }
9351
9352       if (gtk_tree_model_iter_has_child (tree_view->priv->model, iter))
9353         {
9354           if ((temp->flags&GTK_RBNODE_IS_PARENT) != GTK_RBNODE_IS_PARENT)
9355             temp->flags ^= GTK_RBNODE_IS_PARENT;
9356         }
9357     }
9358   while (gtk_tree_model_iter_next (tree_view->priv->model, iter));
9359
9360   if (path)
9361     gtk_tree_path_free (path);
9362 }
9363
9364 /* Make sure the node is visible vertically */
9365 static void
9366 gtk_tree_view_clamp_node_visible (GtkTreeView *tree_view,
9367                                   GtkRBTree   *tree,
9368                                   GtkRBNode   *node)
9369 {
9370   gint node_dy, height;
9371   GtkTreePath *path = NULL;
9372
9373   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
9374     return;
9375
9376   /* just return if the node is visible, avoiding a costly expose */
9377   node_dy = _gtk_rbtree_node_find_offset (tree, node);
9378   height = gtk_tree_view_get_row_height (tree_view, node);
9379   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID)
9380       && node_dy >= gtk_adjustment_get_value (tree_view->priv->vadjustment)
9381       && node_dy + height <= (gtk_adjustment_get_value (tree_view->priv->vadjustment)
9382                               + gtk_adjustment_get_page_size (tree_view->priv->vadjustment)))
9383     return;
9384
9385   path = _gtk_tree_path_new_from_rbtree (tree, node);
9386   if (path)
9387     {
9388       gtk_tree_view_scroll_to_cell (tree_view, path, NULL, FALSE, 0.0, 0.0);
9389       gtk_tree_path_free (path);
9390     }
9391 }
9392
9393 static void
9394 gtk_tree_view_clamp_column_visible (GtkTreeView       *tree_view,
9395                                     GtkTreeViewColumn *column,
9396                                     gboolean           focus_to_cell)
9397 {
9398   GtkAllocation allocation;
9399   gint x, width;
9400
9401   if (column == NULL)
9402     return;
9403
9404   gtk_widget_get_allocation (gtk_tree_view_column_get_button (column), &allocation);
9405   x = allocation.x;
9406   width = allocation.width;
9407
9408   if (width > gtk_adjustment_get_page_size (tree_view->priv->hadjustment))
9409     {
9410       /* The column is larger than the horizontal page size.  If the
9411        * column has cells which can be focussed individually, then we make
9412        * sure the cell which gets focus is fully visible (if even the
9413        * focus cell is bigger than the page size, we make sure the
9414        * left-hand side of the cell is visible).
9415        *
9416        * If the column does not have an activatable cell, we
9417        * make sure the left-hand side of the column is visible.
9418        */
9419
9420       if (focus_to_cell && gtk_tree_view_has_can_focus_cell (tree_view))
9421         {
9422           GtkCellArea *cell_area;
9423           GtkCellRenderer *focus_cell;
9424
9425           cell_area = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (column));
9426           focus_cell = gtk_cell_area_get_focus_cell (cell_area);
9427
9428           if (gtk_tree_view_column_cell_get_position (column, focus_cell,
9429                                                       &x, &width))
9430             {
9431               if (width < gtk_adjustment_get_page_size (tree_view->priv->hadjustment))
9432                 {
9433                   if (gtk_adjustment_get_value (tree_view->priv->hadjustment) + gtk_adjustment_get_page_size (tree_view->priv->hadjustment) < x + width)
9434                     gtk_adjustment_set_value (tree_view->priv->hadjustment,
9435                                               x + width - gtk_adjustment_get_page_size (tree_view->priv->hadjustment));
9436                   else if (gtk_adjustment_get_value (tree_view->priv->hadjustment) > x)
9437                     gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
9438                 }
9439             }
9440         }
9441
9442       gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
9443     }
9444   else
9445     {
9446       if ((gtk_adjustment_get_value (tree_view->priv->hadjustment) + gtk_adjustment_get_page_size (tree_view->priv->hadjustment)) < (x + width))
9447           gtk_adjustment_set_value (tree_view->priv->hadjustment,
9448                                     x + width - gtk_adjustment_get_page_size (tree_view->priv->hadjustment));
9449       else if (gtk_adjustment_get_value (tree_view->priv->hadjustment) > x)
9450         gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
9451   }
9452 }
9453
9454 /* This function could be more efficient.  I'll optimize it if profiling seems
9455  * to imply that it is important */
9456 GtkTreePath *
9457 _gtk_tree_path_new_from_rbtree (GtkRBTree   *tree,
9458                                 GtkRBNode   *node)
9459 {
9460   GtkTreePath *path;
9461   GtkRBTree *tmp_tree;
9462   GtkRBNode *tmp_node, *last;
9463   gint count;
9464
9465   path = gtk_tree_path_new ();
9466
9467   g_return_val_if_fail (node != NULL, path);
9468
9469   count = 1 + node->left->count;
9470
9471   last = node;
9472   tmp_node = node->parent;
9473   tmp_tree = tree;
9474   while (tmp_tree)
9475     {
9476       while (!_gtk_rbtree_is_nil (tmp_node))
9477         {
9478           if (tmp_node->right == last)
9479             count += 1 + tmp_node->left->count;
9480           last = tmp_node;
9481           tmp_node = tmp_node->parent;
9482         }
9483       gtk_tree_path_prepend_index (path, count - 1);
9484       last = tmp_tree->parent_node;
9485       tmp_tree = tmp_tree->parent_tree;
9486       if (last)
9487         {
9488           count = 1 + last->left->count;
9489           tmp_node = last->parent;
9490         }
9491     }
9492   return path;
9493 }
9494
9495 /* Returns TRUE if we ran out of tree before finding the path.  If the path is
9496  * invalid (ie. points to a node that's not in the tree), *tree and *node are
9497  * both set to NULL.
9498  */
9499 gboolean
9500 _gtk_tree_view_find_node (GtkTreeView  *tree_view,
9501                           GtkTreePath  *path,
9502                           GtkRBTree   **tree,
9503                           GtkRBNode   **node)
9504 {
9505   GtkRBNode *tmpnode = NULL;
9506   GtkRBTree *tmptree = tree_view->priv->tree;
9507   gint *indices = gtk_tree_path_get_indices (path);
9508   gint depth = gtk_tree_path_get_depth (path);
9509   gint i = 0;
9510
9511   *node = NULL;
9512   *tree = NULL;
9513
9514   if (depth == 0 || tmptree == NULL)
9515     return FALSE;
9516   do
9517     {
9518       tmpnode = _gtk_rbtree_find_count (tmptree, indices[i] + 1);
9519       ++i;
9520       if (tmpnode == NULL)
9521         {
9522           *tree = NULL;
9523           *node = NULL;
9524           return FALSE;
9525         }
9526       if (i >= depth)
9527         {
9528           *tree = tmptree;
9529           *node = tmpnode;
9530           return FALSE;
9531         }
9532       *tree = tmptree;
9533       *node = tmpnode;
9534       tmptree = tmpnode->children;
9535       if (tmptree == NULL)
9536         return TRUE;
9537     }
9538   while (1);
9539 }
9540
9541 static gboolean
9542 gtk_tree_view_is_expander_column (GtkTreeView       *tree_view,
9543                                   GtkTreeViewColumn *column)
9544 {
9545   GList *list;
9546
9547   if (tree_view->priv->is_list)
9548     return FALSE;
9549
9550   if (tree_view->priv->expander_column != NULL)
9551     {
9552       if (tree_view->priv->expander_column == column)
9553         return TRUE;
9554       return FALSE;
9555     }
9556   else
9557     {
9558       for (list = tree_view->priv->columns;
9559            list;
9560            list = list->next)
9561         if (gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (list->data)))
9562           break;
9563       if (list && list->data == column)
9564         return TRUE;
9565     }
9566   return FALSE;
9567 }
9568
9569 static inline gboolean
9570 gtk_tree_view_draw_expanders (GtkTreeView *tree_view)
9571 {
9572   if (!tree_view->priv->is_list && tree_view->priv->show_expanders)
9573     return TRUE;
9574   /* else */
9575   return FALSE;
9576 }
9577
9578 static void
9579 gtk_tree_view_add_move_binding (GtkBindingSet  *binding_set,
9580                                 guint           keyval,
9581                                 guint           modmask,
9582                                 gboolean        add_shifted_binding,
9583                                 GtkMovementStep step,
9584                                 gint            count)
9585 {
9586   
9587   gtk_binding_entry_add_signal (binding_set, keyval, modmask,
9588                                 "move-cursor", 2,
9589                                 G_TYPE_ENUM, step,
9590                                 G_TYPE_INT, count);
9591
9592   if (add_shifted_binding)
9593     gtk_binding_entry_add_signal (binding_set, keyval, GDK_SHIFT_MASK,
9594                                   "move-cursor", 2,
9595                                   G_TYPE_ENUM, step,
9596                                   G_TYPE_INT, count);
9597
9598   if ((modmask & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
9599    return;
9600
9601   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK | GDK_SHIFT_MASK,
9602                                 "move-cursor", 2,
9603                                 G_TYPE_ENUM, step,
9604                                 G_TYPE_INT, count);
9605
9606   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK,
9607                                 "move-cursor", 2,
9608                                 G_TYPE_ENUM, step,
9609                                 G_TYPE_INT, count);
9610 }
9611
9612 static gint
9613 gtk_tree_view_unref_tree_helper (GtkTreeModel *model,
9614                                  GtkTreeIter  *iter,
9615                                  GtkRBTree    *tree,
9616                                  GtkRBNode    *node)
9617 {
9618   gint retval = FALSE;
9619   do
9620     {
9621       g_return_val_if_fail (node != NULL, FALSE);
9622
9623       if (node->children)
9624         {
9625           GtkTreeIter child;
9626           GtkRBTree *new_tree;
9627           GtkRBNode *new_node;
9628
9629           new_tree = node->children;
9630           new_node = _gtk_rbtree_first (new_tree);
9631
9632           if (!gtk_tree_model_iter_children (model, &child, iter))
9633             return FALSE;
9634
9635           retval = gtk_tree_view_unref_tree_helper (model, &child, new_tree, new_node) | retval;
9636         }
9637
9638       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
9639         retval = TRUE;
9640       gtk_tree_model_unref_node (model, iter);
9641       node = _gtk_rbtree_next (tree, node);
9642     }
9643   while (gtk_tree_model_iter_next (model, iter));
9644
9645   return retval;
9646 }
9647
9648 static gint
9649 gtk_tree_view_unref_and_check_selection_tree (GtkTreeView *tree_view,
9650                                               GtkRBTree   *tree)
9651 {
9652   GtkTreeIter iter;
9653   GtkTreePath *path;
9654   GtkRBNode *node;
9655   gint retval;
9656
9657   if (!tree)
9658     return FALSE;
9659
9660   node = _gtk_rbtree_first (tree);
9661
9662   g_return_val_if_fail (node != NULL, FALSE);
9663   path = _gtk_tree_path_new_from_rbtree (tree, node);
9664   gtk_tree_model_get_iter (GTK_TREE_MODEL (tree_view->priv->model),
9665                            &iter, path);
9666   retval = gtk_tree_view_unref_tree_helper (GTK_TREE_MODEL (tree_view->priv->model), &iter, tree, node);
9667   gtk_tree_path_free (path);
9668
9669   return retval;
9670 }
9671
9672 static void
9673 gtk_tree_view_set_column_drag_info (GtkTreeView       *tree_view,
9674                                     GtkTreeViewColumn *column)
9675 {
9676   GtkTreeViewColumn *left_column;
9677   GtkTreeViewColumn *cur_column = NULL;
9678   GtkTreeViewColumnReorder *reorder;
9679   gboolean rtl;
9680   GList *tmp_list;
9681   gint left;
9682
9683   /* We want to precalculate the motion list such that we know what column slots
9684    * are available.
9685    */
9686   left_column = NULL;
9687   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
9688
9689   /* First, identify all possible drop spots */
9690   if (rtl)
9691     tmp_list = g_list_last (tree_view->priv->columns);
9692   else
9693     tmp_list = g_list_first (tree_view->priv->columns);
9694
9695   while (tmp_list)
9696     {
9697       cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
9698       tmp_list = rtl?g_list_previous (tmp_list):g_list_next (tmp_list);
9699
9700       if (gtk_tree_view_column_get_visible (cur_column) == FALSE)
9701         continue;
9702
9703       /* If it's not the column moving and func tells us to skip over the column, we continue. */
9704       if (left_column != column && cur_column != column &&
9705           tree_view->priv->column_drop_func &&
9706           ! tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
9707         {
9708           left_column = cur_column;
9709           continue;
9710         }
9711       reorder = g_slice_new0 (GtkTreeViewColumnReorder);
9712       reorder->left_column = left_column;
9713       left_column = reorder->right_column = cur_column;
9714
9715       tree_view->priv->column_drag_info = g_list_append (tree_view->priv->column_drag_info, reorder);
9716     }
9717
9718   /* Add the last one */
9719   if (tree_view->priv->column_drop_func == NULL ||
9720       ((left_column != column) &&
9721        tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data)))
9722     {
9723       reorder = g_slice_new0 (GtkTreeViewColumnReorder);
9724       reorder->left_column = left_column;
9725       reorder->right_column = NULL;
9726       tree_view->priv->column_drag_info = g_list_append (tree_view->priv->column_drag_info, reorder);
9727     }
9728
9729   /* We quickly check to see if it even makes sense to reorder columns. */
9730   /* If there is nothing that can be moved, then we return */
9731
9732   if (tree_view->priv->column_drag_info == NULL)
9733     return;
9734
9735   /* We know there are always 2 slots possbile, as you can always return column. */
9736   /* If that's all there is, return */
9737   if (tree_view->priv->column_drag_info->next == NULL || 
9738       (tree_view->priv->column_drag_info->next->next == NULL &&
9739        ((GtkTreeViewColumnReorder *)tree_view->priv->column_drag_info->data)->right_column == column &&
9740        ((GtkTreeViewColumnReorder *)tree_view->priv->column_drag_info->next->data)->left_column == column))
9741     {
9742       for (tmp_list = tree_view->priv->column_drag_info; tmp_list; tmp_list = tmp_list->next)
9743         g_slice_free (GtkTreeViewColumnReorder, tmp_list->data);
9744       g_list_free (tree_view->priv->column_drag_info);
9745       tree_view->priv->column_drag_info = NULL;
9746       return;
9747     }
9748   /* We fill in the ranges for the columns, now that we've isolated them */
9749   left = - TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER (tree_view);
9750
9751   for (tmp_list = tree_view->priv->column_drag_info; tmp_list; tmp_list = tmp_list->next)
9752     {
9753       reorder = (GtkTreeViewColumnReorder *) tmp_list->data;
9754
9755       reorder->left_align = left;
9756       if (tmp_list->next != NULL)
9757         {
9758           GtkAllocation right_allocation, left_allocation;
9759           GtkWidget    *left_button, *right_button;
9760
9761           g_assert (tmp_list->next->data);
9762
9763           right_button = gtk_tree_view_column_get_button (reorder->right_column);
9764           left_button  = gtk_tree_view_column_get_button
9765             (((GtkTreeViewColumnReorder *)tmp_list->next->data)->left_column);
9766
9767           gtk_widget_get_allocation (right_button, &right_allocation);
9768           gtk_widget_get_allocation (left_button, &left_allocation);
9769           left = reorder->right_align = (right_allocation.x + right_allocation.width + left_allocation.x) / 2;
9770         }
9771       else
9772         {
9773           reorder->right_align = gdk_window_get_width (tree_view->priv->header_window)
9774                                  + TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER (tree_view);
9775         }
9776     }
9777 }
9778
9779 void
9780 _gtk_tree_view_column_start_drag (GtkTreeView       *tree_view,
9781                                   GtkTreeViewColumn *column,
9782                                   GdkDevice         *device)
9783 {
9784   GdkEvent *send_event;
9785   GtkAllocation allocation;
9786   GtkAllocation button_allocation;
9787   GdkScreen *screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
9788   GtkWidget *button;
9789   GdkDevice *pointer, *keyboard;
9790
9791   g_return_if_fail (tree_view->priv->column_drag_info == NULL);
9792   g_return_if_fail (tree_view->priv->cur_reorder == NULL);
9793
9794   gtk_tree_view_set_column_drag_info (tree_view, column);
9795
9796   if (tree_view->priv->column_drag_info == NULL)
9797     return;
9798
9799   button = gtk_tree_view_column_get_button (column);
9800
9801   if (tree_view->priv->drag_window == NULL)
9802     {
9803       GdkWindowAttr attributes;
9804       guint attributes_mask;
9805
9806       gtk_widget_get_allocation (button, &button_allocation);
9807
9808       attributes.window_type = GDK_WINDOW_CHILD;
9809       attributes.wclass = GDK_INPUT_OUTPUT;
9810       attributes.x = button_allocation.x;
9811       attributes.y = 0;
9812       attributes.width = button_allocation.width;
9813       attributes.height = button_allocation.height;
9814       attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
9815       attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
9816       attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
9817
9818       tree_view->priv->drag_window = gdk_window_new (tree_view->priv->bin_window,
9819                                                      &attributes,
9820                                                      attributes_mask);
9821       gdk_window_set_user_data (tree_view->priv->drag_window, GTK_WIDGET (tree_view));
9822     }
9823
9824   if (gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD)
9825     {
9826       keyboard = device;
9827       pointer = gdk_device_get_associated_device (device);
9828     }
9829   else
9830     {
9831       pointer = device;
9832       keyboard = gdk_device_get_associated_device (device);
9833     }
9834
9835   gdk_device_ungrab (pointer, GDK_CURRENT_TIME);
9836   gdk_device_ungrab (keyboard, GDK_CURRENT_TIME);
9837
9838   gtk_grab_remove (button);
9839
9840   send_event = gdk_event_new (GDK_LEAVE_NOTIFY);
9841   send_event->crossing.send_event = TRUE;
9842   send_event->crossing.window = g_object_ref (gtk_button_get_event_window (GTK_BUTTON (button)));
9843   send_event->crossing.subwindow = NULL;
9844   send_event->crossing.detail = GDK_NOTIFY_ANCESTOR;
9845   send_event->crossing.time = GDK_CURRENT_TIME;
9846   gdk_event_set_device (send_event, device);
9847
9848   gtk_propagate_event (button, send_event);
9849   gdk_event_free (send_event);
9850
9851   send_event = gdk_event_new (GDK_BUTTON_RELEASE);
9852   send_event->button.window = g_object_ref (gdk_screen_get_root_window (screen));
9853   send_event->button.send_event = TRUE;
9854   send_event->button.time = GDK_CURRENT_TIME;
9855   send_event->button.x = -1;
9856   send_event->button.y = -1;
9857   send_event->button.axes = NULL;
9858   send_event->button.state = 0;
9859   send_event->button.button = GDK_BUTTON_PRIMARY;
9860   send_event->button.x_root = 0;
9861   send_event->button.y_root = 0;
9862   gdk_event_set_device (send_event, device);
9863
9864   gtk_propagate_event (button, send_event);
9865   gdk_event_free (send_event);
9866
9867   /* Kids, don't try this at home */
9868   g_object_ref (button);
9869   gtk_container_remove (GTK_CONTAINER (tree_view), button);
9870   gtk_widget_set_parent_window (button, tree_view->priv->drag_window);
9871   gtk_widget_set_parent (button, GTK_WIDGET (tree_view));
9872   g_object_unref (button);
9873
9874   gtk_widget_get_allocation (button, &button_allocation);
9875   tree_view->priv->drag_column_x = button_allocation.x;
9876   allocation = button_allocation;
9877   allocation.x = 0;
9878   gtk_widget_size_allocate (button, &allocation);
9879   gtk_widget_set_parent_window (button, tree_view->priv->drag_window);
9880
9881   tree_view->priv->drag_column = column;
9882   gdk_window_show (tree_view->priv->drag_window);
9883
9884   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
9885   while (gtk_events_pending ())
9886     gtk_main_iteration ();
9887
9888   tree_view->priv->in_column_drag = TRUE;
9889
9890   gdk_device_grab (pointer,
9891                    tree_view->priv->drag_window,
9892                    GDK_OWNERSHIP_NONE,
9893                    FALSE,
9894                    GDK_POINTER_MOTION_MASK|GDK_BUTTON_RELEASE_MASK,
9895                    NULL,
9896                    GDK_CURRENT_TIME);
9897   gdk_device_grab (keyboard,
9898                    tree_view->priv->drag_window,
9899                    GDK_OWNERSHIP_NONE,
9900                    FALSE,
9901                    GDK_KEY_PRESS_MASK|GDK_KEY_RELEASE_MASK,
9902                    NULL,
9903                    GDK_CURRENT_TIME);
9904 }
9905
9906 static void
9907 gtk_tree_view_queue_draw_arrow (GtkTreeView        *tree_view,
9908                                 GtkRBTree          *tree,
9909                                 GtkRBNode          *node)
9910 {
9911   GtkAllocation allocation;
9912   GdkRectangle rect;
9913
9914   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
9915     return;
9916
9917   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
9918   rect.x = 0;
9919   rect.width = gtk_tree_view_get_expander_size (tree_view);
9920   rect.width = MAX (rect.width, MAX (tree_view->priv->width, allocation.width));
9921
9922   rect.y = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
9923   rect.height = gtk_tree_view_get_row_height (tree_view, node);
9924
9925   gdk_window_invalidate_rect (tree_view->priv->bin_window, &rect, TRUE);
9926 }
9927
9928 void
9929 _gtk_tree_view_queue_draw_node (GtkTreeView        *tree_view,
9930                                 GtkRBTree          *tree,
9931                                 GtkRBNode          *node,
9932                                 const GdkRectangle *clip_rect)
9933 {
9934   GtkAllocation allocation;
9935   GdkRectangle rect;
9936
9937   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
9938     return;
9939
9940   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
9941   rect.x = 0;
9942   rect.width = MAX (tree_view->priv->width, allocation.width);
9943
9944   rect.y = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
9945   rect.height = gtk_tree_view_get_row_height (tree_view, node);
9946
9947   if (clip_rect)
9948     {
9949       GdkRectangle new_rect;
9950
9951       gdk_rectangle_intersect (clip_rect, &rect, &new_rect);
9952
9953       gdk_window_invalidate_rect (tree_view->priv->bin_window, &new_rect, TRUE);
9954     }
9955   else
9956     {
9957       gdk_window_invalidate_rect (tree_view->priv->bin_window, &rect, TRUE);
9958     }
9959 }
9960
9961 static inline gint
9962 gtk_tree_view_get_effective_header_height (GtkTreeView *tree_view)
9963 {
9964   if (tree_view->priv->headers_visible)
9965     return tree_view->priv->header_height;
9966   /* else */
9967   return 0;
9968 }
9969
9970 gint
9971 _gtk_tree_view_get_header_height (GtkTreeView *tree_view)
9972 {
9973   return tree_view->priv->header_height;
9974 }
9975
9976 void
9977 _gtk_tree_view_get_row_separator_func (GtkTreeView                 *tree_view,
9978                                        GtkTreeViewRowSeparatorFunc *func,
9979                                        gpointer                    *data)
9980 {
9981   *func = tree_view->priv->row_separator_func;
9982   *data = tree_view->priv->row_separator_data;
9983 }
9984
9985 GtkTreePath *
9986 _gtk_tree_view_get_anchor_path (GtkTreeView *tree_view)
9987 {
9988   if (tree_view->priv->anchor)
9989     return gtk_tree_row_reference_get_path (tree_view->priv->anchor);
9990
9991   return NULL;
9992 }
9993
9994 void
9995 _gtk_tree_view_set_anchor_path (GtkTreeView *tree_view,
9996                                 GtkTreePath *anchor_path)
9997 {
9998   if (tree_view->priv->anchor)
9999     {
10000       gtk_tree_row_reference_free (tree_view->priv->anchor);
10001       tree_view->priv->anchor = NULL;
10002     }
10003
10004   if (anchor_path && tree_view->priv->model)
10005     tree_view->priv->anchor =
10006       gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), 
10007                                         tree_view->priv->model, anchor_path);
10008 }
10009
10010 GtkRBTree *
10011 _gtk_tree_view_get_rbtree (GtkTreeView *tree_view)
10012 {
10013   return tree_view->priv->tree;
10014 }
10015
10016 gboolean
10017 _gtk_tree_view_get_cursor_node (GtkTreeView  *tree_view,
10018                                 GtkRBTree   **tree,
10019                                 GtkRBNode   **node)
10020 {
10021   GtkTreeViewPrivate *priv;
10022
10023   priv = tree_view->priv;
10024
10025   if (priv->cursor_node == NULL)
10026     return FALSE;
10027
10028   *tree = priv->cursor_tree;
10029   *node = priv->cursor_node;
10030
10031   return TRUE;
10032 }
10033
10034 GdkWindow *
10035 _gtk_tree_view_get_header_window (GtkTreeView *tree_view)
10036 {
10037   return tree_view->priv->header_window;
10038 }
10039
10040 GtkTreeViewColumn *
10041 _gtk_tree_view_get_focus_column (GtkTreeView *tree_view)
10042 {
10043   return tree_view->priv->focus_column;
10044 }
10045
10046 void
10047 _gtk_tree_view_set_focus_column (GtkTreeView       *tree_view,
10048                                  GtkTreeViewColumn *column)
10049 {
10050   GtkTreeViewColumn *old_column = tree_view->priv->focus_column;
10051
10052   if (old_column == column)
10053     return;
10054
10055   tree_view->priv->focus_column = column;
10056
10057   _gtk_tree_view_accessible_update_focus_column (tree_view, 
10058                                                  old_column,
10059                                                  column);
10060 }
10061
10062
10063 static void
10064 gtk_tree_view_queue_draw_path (GtkTreeView        *tree_view,
10065                                GtkTreePath        *path,
10066                                const GdkRectangle *clip_rect)
10067 {
10068   GtkRBTree *tree = NULL;
10069   GtkRBNode *node = NULL;
10070
10071   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
10072
10073   if (tree)
10074     _gtk_tree_view_queue_draw_node (tree_view, tree, node, clip_rect);
10075 }
10076
10077 /* x and y are the mouse position
10078  */
10079 static void
10080 gtk_tree_view_draw_arrow (GtkTreeView *tree_view,
10081                           cairo_t     *cr,
10082                           GtkRBTree   *tree,
10083                           GtkRBNode   *node)
10084 {
10085   GdkRectangle area;
10086   GtkStateFlags state = 0;
10087   GtkStyleContext *context;
10088   GtkWidget *widget;
10089   gint x_offset = 0;
10090   gint x2;
10091   gint vertical_separator;
10092   gint expander_size;
10093   GtkCellRendererState flags = 0;
10094
10095   widget = GTK_WIDGET (tree_view);
10096   context = gtk_widget_get_style_context (widget);
10097
10098   gtk_widget_style_get (widget,
10099                         "vertical-separator", &vertical_separator,
10100                         NULL);
10101   expander_size = gtk_tree_view_get_expander_size (tree_view) - EXPANDER_EXTRA_PADDING;
10102
10103   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
10104     return;
10105
10106   gtk_tree_view_get_arrow_xrange (tree_view, tree, &x_offset, &x2);
10107
10108   area.x = x_offset;
10109   area.y = gtk_tree_view_get_cell_area_y_offset (tree_view, tree, node,
10110                                                  vertical_separator);
10111   area.width = expander_size;
10112   area.height = gtk_tree_view_get_cell_area_height (tree_view, node,
10113                                                     vertical_separator);
10114
10115   if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
10116     flags |= GTK_CELL_RENDERER_SELECTED;
10117
10118   if (node == tree_view->priv->prelight_node &&
10119       tree_view->priv->arrow_prelit)
10120     flags |= GTK_CELL_RENDERER_PRELIT;
10121
10122   state = gtk_cell_renderer_get_state (NULL, widget, flags);
10123
10124   if (node->children != NULL)
10125     state |= GTK_STATE_FLAG_ACTIVE;
10126   else
10127     state &= ~(GTK_STATE_FLAG_ACTIVE);
10128
10129   gtk_style_context_save (context);
10130
10131   gtk_style_context_set_state (context, state);
10132   gtk_style_context_add_class (context, GTK_STYLE_CLASS_EXPANDER);
10133
10134   gtk_render_expander (context, cr,
10135                        area.x, area.y,
10136                        area.width, area.height);
10137
10138   gtk_style_context_restore (context);
10139 }
10140
10141 static void
10142 gtk_tree_view_focus_to_cursor (GtkTreeView *tree_view)
10143
10144 {
10145   GtkTreePath *cursor_path;
10146
10147   if ((tree_view->priv->tree == NULL) ||
10148       (! gtk_widget_get_realized (GTK_WIDGET (tree_view))))
10149     return;
10150
10151   cursor_path = NULL;
10152   if (tree_view->priv->cursor_node)
10153     cursor_path = _gtk_tree_path_new_from_rbtree (tree_view->priv->cursor_tree,
10154                                                   tree_view->priv->cursor_node);
10155
10156   if (cursor_path == NULL)
10157     {
10158       /* Consult the selection before defaulting to the
10159        * first focusable element
10160        */
10161       GList *selected_rows;
10162       GtkTreeModel *model;
10163       GtkTreeSelection *selection;
10164
10165       selection = gtk_tree_view_get_selection (tree_view);
10166       selected_rows = gtk_tree_selection_get_selected_rows (selection, &model);
10167
10168       if (selected_rows)
10169         {
10170           cursor_path = gtk_tree_path_copy((const GtkTreePath *)(selected_rows->data));
10171           g_list_free_full (selected_rows, (GDestroyNotify) gtk_tree_path_free);
10172         }
10173       else
10174         {
10175           cursor_path = gtk_tree_path_new_first ();
10176           search_first_focusable_path (tree_view, &cursor_path,
10177                                        TRUE, NULL, NULL);
10178         }
10179
10180       if (cursor_path)
10181         {
10182           if (gtk_tree_selection_get_mode (tree_view->priv->selection) == GTK_SELECTION_MULTIPLE)
10183             gtk_tree_view_real_set_cursor (tree_view, cursor_path, 0);
10184           else
10185             gtk_tree_view_real_set_cursor (tree_view, cursor_path, CLEAR_AND_SELECT);
10186         }
10187     }
10188
10189   if (cursor_path)
10190     {
10191       tree_view->priv->draw_keyfocus = TRUE;
10192
10193       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10194       gtk_tree_path_free (cursor_path);
10195
10196       if (tree_view->priv->focus_column == NULL)
10197         {
10198           GList *list;
10199           for (list = tree_view->priv->columns; list; list = list->next)
10200             {
10201               if (gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (list->data)))
10202                 {
10203                   GtkCellArea *cell_area;
10204
10205                   _gtk_tree_view_set_focus_column (tree_view, GTK_TREE_VIEW_COLUMN (list->data));
10206
10207                   /* This happens when the treeview initially grabs focus and there
10208                    * is no column in focus, here we explicitly focus into the first cell */
10209                   cell_area = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (tree_view->priv->focus_column));
10210                   if (!gtk_cell_area_get_focus_cell (cell_area))
10211                     {
10212                       gboolean rtl;
10213
10214                       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
10215                       gtk_cell_area_focus (cell_area,
10216                                            rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT);
10217                     }
10218
10219                   break;
10220                 }
10221             }
10222         }
10223     }
10224 }
10225
10226 static void
10227 gtk_tree_view_move_cursor_up_down (GtkTreeView *tree_view,
10228                                    gint         count)
10229 {
10230   gint selection_count;
10231   GtkRBTree *new_cursor_tree = NULL;
10232   GtkRBNode *new_cursor_node = NULL;
10233   GtkTreePath *cursor_path = NULL;
10234   gboolean grab_focus = TRUE;
10235   gboolean selectable;
10236   GtkDirectionType direction;
10237   GtkCellArea *cell_area = NULL;
10238   GtkCellRenderer *last_focus_cell = NULL;
10239   GtkTreeIter iter;
10240
10241   if (! gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10242     return;
10243
10244   if (tree_view->priv->cursor_node == NULL)
10245     return;
10246
10247   cursor_path = _gtk_tree_path_new_from_rbtree (tree_view->priv->cursor_tree,
10248                                                 tree_view->priv->cursor_node);
10249
10250   direction = count < 0 ? GTK_DIR_UP : GTK_DIR_DOWN;
10251
10252   if (tree_view->priv->focus_column)
10253     cell_area = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (tree_view->priv->focus_column));
10254
10255   /* If focus stays in the area for this row, then just return for this round */
10256   if (cell_area && (count == -1 || count == 1) &&
10257       gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path))
10258     {
10259       gtk_tree_view_column_cell_set_cell_data (tree_view->priv->focus_column,
10260                                                tree_view->priv->model,
10261                                                &iter,
10262                                                GTK_RBNODE_FLAG_SET (tree_view->priv->cursor_node, GTK_RBNODE_IS_PARENT),
10263                                                tree_view->priv->cursor_node->children ? TRUE : FALSE);
10264
10265       /* Save the last cell that had focus, if we hit the end of the view we'll give
10266        * focus back to it. */
10267       last_focus_cell = gtk_cell_area_get_focus_cell (cell_area);
10268
10269       /* If focus stays in the area, no need to change the cursor row */
10270       if (gtk_cell_area_focus (cell_area, direction))
10271         return;
10272     }
10273
10274   selection_count = gtk_tree_selection_count_selected_rows (tree_view->priv->selection);
10275   selectable = _gtk_tree_selection_row_is_selectable (tree_view->priv->selection,
10276                                                       tree_view->priv->cursor_node,
10277                                                       cursor_path);
10278
10279   if (selection_count == 0
10280       && gtk_tree_selection_get_mode (tree_view->priv->selection) != GTK_SELECTION_NONE
10281       && !tree_view->priv->modify_selection_pressed
10282       && selectable)
10283     {
10284       /* Don't move the cursor, but just select the current node */
10285       new_cursor_tree = tree_view->priv->cursor_tree;
10286       new_cursor_node = tree_view->priv->cursor_node;
10287     }
10288   else
10289     {
10290       if (count == -1)
10291         _gtk_rbtree_prev_full (tree_view->priv->cursor_tree, tree_view->priv->cursor_node,
10292                                &new_cursor_tree, &new_cursor_node);
10293       else
10294         _gtk_rbtree_next_full (tree_view->priv->cursor_tree, tree_view->priv->cursor_node,
10295                                &new_cursor_tree, &new_cursor_node);
10296     }
10297
10298   gtk_tree_path_free (cursor_path);
10299
10300   if (new_cursor_node)
10301     {
10302       cursor_path = _gtk_tree_path_new_from_rbtree (new_cursor_tree, new_cursor_node);
10303
10304       search_first_focusable_path (tree_view, &cursor_path,
10305                                    (count != -1),
10306                                    &new_cursor_tree,
10307                                    &new_cursor_node);
10308
10309       if (cursor_path)
10310         gtk_tree_path_free (cursor_path);
10311     }
10312
10313   /*
10314    * If the list has only one item and multi-selection is set then select
10315    * the row (if not yet selected).
10316    */
10317   if (gtk_tree_selection_get_mode (tree_view->priv->selection) == GTK_SELECTION_MULTIPLE &&
10318       new_cursor_node == NULL)
10319     {
10320       if (count == -1)
10321         _gtk_rbtree_next_full (tree_view->priv->cursor_tree, tree_view->priv->cursor_node,
10322                                &new_cursor_tree, &new_cursor_node);
10323       else
10324         _gtk_rbtree_prev_full (tree_view->priv->cursor_tree, tree_view->priv->cursor_node,
10325                                &new_cursor_tree, &new_cursor_node);
10326
10327       if (new_cursor_node == NULL
10328           && !GTK_RBNODE_FLAG_SET (tree_view->priv->cursor_node, GTK_RBNODE_IS_SELECTED))
10329         {
10330           new_cursor_node = tree_view->priv->cursor_node;
10331           new_cursor_tree = tree_view->priv->cursor_tree;
10332         }
10333       else
10334         {
10335           new_cursor_tree = NULL;
10336           new_cursor_node = NULL;
10337         }
10338     }
10339
10340   if (new_cursor_node)
10341     {
10342       cursor_path = _gtk_tree_path_new_from_rbtree (new_cursor_tree, new_cursor_node);
10343       gtk_tree_view_real_set_cursor (tree_view, cursor_path, CLEAR_AND_SELECT | CLAMP_NODE);
10344       gtk_tree_path_free (cursor_path);
10345
10346       /* Give focus to the area in the new row */
10347       if (cell_area)
10348         gtk_cell_area_focus (cell_area, direction);
10349     }
10350   else
10351     {
10352       gtk_tree_view_clamp_node_visible (tree_view, 
10353                                         tree_view->priv->cursor_tree,
10354                                         tree_view->priv->cursor_node);
10355
10356       if (!tree_view->priv->extend_selection_pressed)
10357         {
10358           if (! gtk_widget_keynav_failed (GTK_WIDGET (tree_view),
10359                                           count < 0 ?
10360                                           GTK_DIR_UP : GTK_DIR_DOWN))
10361             {
10362               GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (tree_view));
10363
10364               if (toplevel)
10365                 gtk_widget_child_focus (toplevel,
10366                                         count < 0 ?
10367                                         GTK_DIR_TAB_BACKWARD :
10368                                         GTK_DIR_TAB_FORWARD);
10369
10370               grab_focus = FALSE;
10371             }
10372         }
10373       else
10374         {
10375           gtk_widget_error_bell (GTK_WIDGET (tree_view));
10376         }
10377
10378       if (cell_area)
10379         gtk_cell_area_set_focus_cell (cell_area, last_focus_cell);
10380     }
10381
10382   if (grab_focus)
10383     gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10384 }
10385
10386 static void
10387 gtk_tree_view_move_cursor_page_up_down (GtkTreeView *tree_view,
10388                                         gint         count)
10389 {
10390   GtkTreePath *old_cursor_path = NULL;
10391   GtkTreePath *cursor_path = NULL;
10392   GtkRBTree *start_cursor_tree = NULL;
10393   GtkRBNode *start_cursor_node = NULL;
10394   GtkRBTree *cursor_tree;
10395   GtkRBNode *cursor_node;
10396   gint y;
10397   gint window_y;
10398   gint vertical_separator;
10399
10400   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10401     return;
10402
10403   if (tree_view->priv->cursor_node == NULL)
10404     return;
10405
10406   old_cursor_path = _gtk_tree_path_new_from_rbtree (tree_view->priv->cursor_tree,
10407                                                     tree_view->priv->cursor_node);
10408
10409   gtk_widget_style_get (GTK_WIDGET (tree_view), "vertical-separator", &vertical_separator, NULL);
10410
10411   y = _gtk_rbtree_node_find_offset (tree_view->priv->cursor_tree, tree_view->priv->cursor_node);
10412   window_y = RBTREE_Y_TO_TREE_WINDOW_Y (tree_view, y);
10413   y += tree_view->priv->cursor_offset;
10414   y += count * (int)gtk_adjustment_get_page_increment (tree_view->priv->vadjustment);
10415   y = CLAMP (y, (gint)gtk_adjustment_get_lower (tree_view->priv->vadjustment),  (gint)gtk_adjustment_get_upper (tree_view->priv->vadjustment) - vertical_separator);
10416
10417   if (y >= tree_view->priv->height)
10418     y = tree_view->priv->height - 1;
10419
10420   tree_view->priv->cursor_offset =
10421     _gtk_rbtree_find_offset (tree_view->priv->tree, y,
10422                              &cursor_tree, &cursor_node);
10423
10424   if (cursor_tree == NULL)
10425     {
10426       /* FIXME: we lost the cursor.  Should we try to get one? */
10427       gtk_tree_path_free (old_cursor_path);
10428       return;
10429     }
10430
10431   if (tree_view->priv->cursor_offset
10432       > gtk_tree_view_get_row_height (tree_view, cursor_node))
10433     {
10434       _gtk_rbtree_next_full (cursor_tree, cursor_node,
10435                              &cursor_tree, &cursor_node);
10436       tree_view->priv->cursor_offset -= gtk_tree_view_get_row_height (tree_view, cursor_node);
10437     }
10438
10439   y -= tree_view->priv->cursor_offset;
10440   cursor_path = _gtk_tree_path_new_from_rbtree (cursor_tree, cursor_node);
10441
10442   start_cursor_tree = cursor_tree;
10443   start_cursor_node = cursor_node;
10444
10445   if (! search_first_focusable_path (tree_view, &cursor_path,
10446                                      (count != -1),
10447                                      &cursor_tree, &cursor_node))
10448     {
10449       /* It looks like we reached the end of the view without finding
10450        * a focusable row.  We will step backwards to find the last
10451        * focusable row.
10452        */
10453       cursor_tree = start_cursor_tree;
10454       cursor_node = start_cursor_node;
10455       cursor_path = _gtk_tree_path_new_from_rbtree (cursor_tree, cursor_node);
10456
10457       search_first_focusable_path (tree_view, &cursor_path,
10458                                    (count == -1),
10459                                    &cursor_tree, &cursor_node);
10460     }
10461
10462   if (!cursor_path)
10463     goto cleanup;
10464
10465   /* update y */
10466   y = _gtk_rbtree_node_find_offset (cursor_tree, cursor_node);
10467
10468   gtk_tree_view_real_set_cursor (tree_view, cursor_path, CLEAR_AND_SELECT);
10469
10470   y -= window_y;
10471   gtk_tree_view_scroll_to_point (tree_view, -1, y);
10472   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10473   _gtk_tree_view_queue_draw_node (tree_view, cursor_tree, cursor_node, NULL);
10474
10475   if (!gtk_tree_path_compare (old_cursor_path, cursor_path))
10476     gtk_widget_error_bell (GTK_WIDGET (tree_view));
10477
10478   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10479
10480 cleanup:
10481   gtk_tree_path_free (old_cursor_path);
10482   gtk_tree_path_free (cursor_path);
10483 }
10484
10485 static void
10486 gtk_tree_view_move_cursor_left_right (GtkTreeView *tree_view,
10487                                       gint         count)
10488 {
10489   GtkTreePath *cursor_path = NULL;
10490   GtkTreeViewColumn *column;
10491   GtkTreeIter iter;
10492   GList *list;
10493   gboolean found_column = FALSE;
10494   gboolean rtl;
10495   GtkDirectionType direction;
10496   GtkCellArea     *cell_area;
10497   GtkCellRenderer *last_focus_cell = NULL;
10498   GtkCellArea     *last_focus_area = NULL;
10499
10500   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
10501
10502   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10503     return;
10504
10505   if (tree_view->priv->cursor_node == NULL)
10506     return;
10507
10508   cursor_path = _gtk_tree_path_new_from_rbtree (tree_view->priv->cursor_tree,
10509                                                 tree_view->priv->cursor_node);
10510
10511   if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path) == FALSE)
10512     {
10513       gtk_tree_path_free (cursor_path);
10514       return;
10515     }
10516   gtk_tree_path_free (cursor_path);
10517
10518   list = rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns);
10519   if (tree_view->priv->focus_column)
10520     {
10521       /* Save the cell/area we are moving focus from, if moving the cursor
10522        * by one step hits the end we'll set focus back here */
10523       last_focus_area = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (tree_view->priv->focus_column));
10524       last_focus_cell = gtk_cell_area_get_focus_cell (last_focus_area);
10525
10526       for (; list; list = (rtl ? list->prev : list->next))
10527         {
10528           if (list->data == tree_view->priv->focus_column)
10529             break;
10530         }
10531     }
10532
10533   direction = count > 0 ? GTK_DIR_RIGHT : GTK_DIR_LEFT;
10534
10535   while (list)
10536     {
10537       column = list->data;
10538       if (gtk_tree_view_column_get_visible (column) == FALSE)
10539         goto loop_end;
10540
10541       gtk_tree_view_column_cell_set_cell_data (column,
10542                                                tree_view->priv->model,
10543                                                &iter,
10544                                                GTK_RBNODE_FLAG_SET (tree_view->priv->cursor_node, GTK_RBNODE_IS_PARENT),
10545                                                tree_view->priv->cursor_node->children ? TRUE : FALSE);
10546
10547       cell_area = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (column));
10548       if (gtk_cell_area_focus (cell_area, direction))
10549         {
10550           _gtk_tree_view_set_focus_column (tree_view, column);
10551           found_column = TRUE;
10552           break;
10553         }
10554
10555     loop_end:
10556       if (count == 1)
10557         list = rtl ? list->prev : list->next;
10558       else
10559         list = rtl ? list->next : list->prev;
10560     }
10561
10562   if (found_column)
10563     {
10564       if (!gtk_tree_view_has_can_focus_cell (tree_view))
10565         _gtk_tree_view_queue_draw_node (tree_view,
10566                                         tree_view->priv->cursor_tree,
10567                                         tree_view->priv->cursor_node,
10568                                         NULL);
10569       g_signal_emit (tree_view, tree_view_signals[CURSOR_CHANGED], 0);
10570       gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10571     }
10572   else
10573     {
10574       gtk_widget_error_bell (GTK_WIDGET (tree_view));
10575
10576       if (last_focus_area)
10577         gtk_cell_area_set_focus_cell (last_focus_area, last_focus_cell);
10578     }
10579
10580   gtk_tree_view_clamp_column_visible (tree_view,
10581                                       tree_view->priv->focus_column, TRUE);
10582 }
10583
10584 static void
10585 gtk_tree_view_move_cursor_start_end (GtkTreeView *tree_view,
10586                                      gint         count)
10587 {
10588   GtkRBTree *cursor_tree;
10589   GtkRBNode *cursor_node;
10590   GtkTreePath *path;
10591   GtkTreePath *old_path;
10592
10593   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10594     return;
10595
10596   g_return_if_fail (tree_view->priv->tree != NULL);
10597
10598   gtk_tree_view_get_cursor (tree_view, &old_path, NULL);
10599
10600   cursor_tree = tree_view->priv->tree;
10601
10602   if (count == -1)
10603     {
10604       cursor_node = _gtk_rbtree_first (cursor_tree);
10605
10606       /* Now go forward to find the first focusable row. */
10607       path = _gtk_tree_path_new_from_rbtree (cursor_tree, cursor_node);
10608       search_first_focusable_path (tree_view, &path,
10609                                    TRUE, &cursor_tree, &cursor_node);
10610     }
10611   else
10612     {
10613       cursor_node = cursor_tree->root;
10614
10615       do
10616         {
10617           while (cursor_node && !_gtk_rbtree_is_nil (cursor_node->right))
10618             cursor_node = cursor_node->right;
10619           if (cursor_node->children == NULL)
10620             break;
10621
10622           cursor_tree = cursor_node->children;
10623           cursor_node = cursor_tree->root;
10624         }
10625       while (1);
10626
10627       /* Now go backwards to find last focusable row. */
10628       path = _gtk_tree_path_new_from_rbtree (cursor_tree, cursor_node);
10629       search_first_focusable_path (tree_view, &path,
10630                                    FALSE, &cursor_tree, &cursor_node);
10631     }
10632
10633   if (!path)
10634     goto cleanup;
10635
10636   if (gtk_tree_path_compare (old_path, path))
10637     {
10638       gtk_tree_view_real_set_cursor (tree_view, path, CLEAR_AND_SELECT | CLAMP_NODE);
10639       gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10640     }
10641   else
10642     {
10643       gtk_widget_error_bell (GTK_WIDGET (tree_view));
10644     }
10645
10646 cleanup:
10647   gtk_tree_path_free (old_path);
10648   gtk_tree_path_free (path);
10649 }
10650
10651 static gboolean
10652 gtk_tree_view_real_select_all (GtkTreeView *tree_view)
10653 {
10654   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10655     return FALSE;
10656
10657   if (gtk_tree_selection_get_mode (tree_view->priv->selection) != GTK_SELECTION_MULTIPLE)
10658     return FALSE;
10659
10660   gtk_tree_selection_select_all (tree_view->priv->selection);
10661
10662   return TRUE;
10663 }
10664
10665 static gboolean
10666 gtk_tree_view_real_unselect_all (GtkTreeView *tree_view)
10667 {
10668   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10669     return FALSE;
10670
10671   if (gtk_tree_selection_get_mode (tree_view->priv->selection) != GTK_SELECTION_MULTIPLE)
10672     return FALSE;
10673
10674   gtk_tree_selection_unselect_all (tree_view->priv->selection);
10675
10676   return TRUE;
10677 }
10678
10679 static gboolean
10680 gtk_tree_view_real_select_cursor_row (GtkTreeView *tree_view,
10681                                       gboolean     start_editing)
10682 {
10683   GtkRBTree *new_tree = NULL;
10684   GtkRBNode *new_node = NULL;
10685   GtkRBTree *cursor_tree = NULL;
10686   GtkRBNode *cursor_node = NULL;
10687   GtkTreePath *cursor_path = NULL;
10688   GtkTreeSelectMode mode = 0;
10689
10690   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10691     return FALSE;
10692
10693   if (tree_view->priv->cursor_node == NULL)
10694     return FALSE;
10695
10696   cursor_path = _gtk_tree_path_new_from_rbtree (tree_view->priv->cursor_tree,
10697                                                 tree_view->priv->cursor_node);
10698
10699   _gtk_tree_view_find_node (tree_view, cursor_path,
10700                             &cursor_tree, &cursor_node);
10701
10702   if (cursor_tree == NULL)
10703     {
10704       gtk_tree_path_free (cursor_path);
10705       return FALSE;
10706     }
10707
10708   if (!tree_view->priv->extend_selection_pressed && start_editing &&
10709       tree_view->priv->focus_column)
10710     {
10711       if (gtk_tree_view_start_editing (tree_view, cursor_path, FALSE))
10712         {
10713           gtk_tree_path_free (cursor_path);
10714           return TRUE;
10715         }
10716     }
10717
10718   if (tree_view->priv->modify_selection_pressed)
10719     mode |= GTK_TREE_SELECT_MODE_TOGGLE;
10720   if (tree_view->priv->extend_selection_pressed)
10721     mode |= GTK_TREE_SELECT_MODE_EXTEND;
10722
10723   _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
10724                                             cursor_node,
10725                                             cursor_tree,
10726                                             cursor_path,
10727                                             mode,
10728                                             FALSE);
10729
10730   /* We bail out if the original (tree, node) don't exist anymore after
10731    * handling the selection-changed callback.  We do return TRUE because
10732    * the key press has been handled at this point.
10733    */
10734   _gtk_tree_view_find_node (tree_view, cursor_path, &new_tree, &new_node);
10735
10736   if (cursor_tree != new_tree || cursor_node != new_node)
10737     return FALSE;
10738
10739   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10740
10741   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10742   _gtk_tree_view_queue_draw_node (tree_view, cursor_tree, cursor_node, NULL);
10743
10744   if (!tree_view->priv->extend_selection_pressed)
10745     gtk_tree_view_row_activated (tree_view, cursor_path,
10746                                  tree_view->priv->focus_column);
10747     
10748   gtk_tree_path_free (cursor_path);
10749
10750   return TRUE;
10751 }
10752
10753 static gboolean
10754 gtk_tree_view_real_toggle_cursor_row (GtkTreeView *tree_view)
10755 {
10756   GtkRBTree *new_tree = NULL;
10757   GtkRBNode *new_node = NULL;
10758   GtkTreePath *cursor_path = NULL;
10759
10760   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10761     return FALSE;
10762
10763   if (tree_view->priv->cursor_node == NULL)
10764     return FALSE;
10765
10766   cursor_path = _gtk_tree_path_new_from_rbtree (tree_view->priv->cursor_tree,
10767                                                 tree_view->priv->cursor_node);
10768
10769   _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
10770                                             tree_view->priv->cursor_node,
10771                                             tree_view->priv->cursor_tree,
10772                                             cursor_path,
10773                                             GTK_TREE_SELECT_MODE_TOGGLE,
10774                                             FALSE);
10775
10776   /* We bail out if the original (tree, node) don't exist anymore after
10777    * handling the selection-changed callback.  We do return TRUE because
10778    * the key press has been handled at this point.
10779    */
10780   _gtk_tree_view_find_node (tree_view, cursor_path, &new_tree, &new_node);
10781
10782   if (tree_view->priv->cursor_node != new_node)
10783     return FALSE;
10784
10785   gtk_tree_view_clamp_node_visible (tree_view,
10786                                     tree_view->priv->cursor_tree,
10787                                     tree_view->priv->cursor_node);
10788
10789   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10790   gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10791   gtk_tree_path_free (cursor_path);
10792
10793   return TRUE;
10794 }
10795
10796 static gboolean
10797 gtk_tree_view_real_expand_collapse_cursor_row (GtkTreeView *tree_view,
10798                                                gboolean     logical,
10799                                                gboolean     expand,
10800                                                gboolean     open_all)
10801 {
10802   GtkTreePath *cursor_path = NULL;
10803
10804   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10805     return FALSE;
10806
10807   if (tree_view->priv->cursor_node == NULL)
10808     return FALSE;
10809
10810   cursor_path = _gtk_tree_path_new_from_rbtree (tree_view->priv->cursor_tree,
10811                                                 tree_view->priv->cursor_node);
10812
10813   /* Don't handle the event if we aren't an expander */
10814   if (!GTK_RBNODE_FLAG_SET (tree_view->priv->cursor_node, GTK_RBNODE_IS_PARENT))
10815     return FALSE;
10816
10817   if (!logical
10818       && gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL)
10819     expand = !expand;
10820
10821   if (expand)
10822     gtk_tree_view_real_expand_row (tree_view,
10823                                    cursor_path,
10824                                    tree_view->priv->cursor_tree,
10825                                    tree_view->priv->cursor_node,
10826                                    open_all,
10827                                    TRUE);
10828   else
10829     gtk_tree_view_real_collapse_row (tree_view,
10830                                      cursor_path,
10831                                      tree_view->priv->cursor_tree,
10832                                      tree_view->priv->cursor_node,
10833                                      TRUE);
10834
10835   gtk_tree_path_free (cursor_path);
10836
10837   return TRUE;
10838 }
10839
10840 static gboolean
10841 gtk_tree_view_real_select_cursor_parent (GtkTreeView *tree_view)
10842 {
10843   GtkTreePath *cursor_path = NULL;
10844   GdkModifierType state;
10845
10846   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10847     goto out;
10848
10849   if (tree_view->priv->cursor_node == NULL)
10850     goto out;
10851
10852   cursor_path = _gtk_tree_path_new_from_rbtree (tree_view->priv->cursor_tree,
10853                                                 tree_view->priv->cursor_node);
10854
10855   if (tree_view->priv->cursor_tree->parent_node)
10856     {
10857       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10858
10859       gtk_tree_path_up (cursor_path);
10860
10861       if (gtk_get_current_event_state (&state))
10862         {
10863           GdkModifierType modify_mod_mask;
10864
10865           modify_mod_mask =
10866             gtk_widget_get_modifier_mask (GTK_WIDGET (tree_view),
10867                                           GDK_MODIFIER_INTENT_MODIFY_SELECTION);
10868
10869           if ((state & modify_mod_mask) == modify_mod_mask)
10870             tree_view->priv->modify_selection_pressed = TRUE;
10871         }
10872
10873       gtk_tree_view_real_set_cursor (tree_view, cursor_path, CLEAR_AND_SELECT | CLAMP_NODE);
10874       gtk_tree_path_free (cursor_path);
10875
10876       gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10877
10878       tree_view->priv->modify_selection_pressed = FALSE;
10879
10880       return TRUE;
10881     }
10882
10883  out:
10884
10885   tree_view->priv->search_entry_avoid_unhandled_binding = TRUE;
10886   return FALSE;
10887 }
10888
10889 static gboolean
10890 gtk_tree_view_search_entry_flush_timeout (GtkTreeView *tree_view)
10891 {
10892   gtk_tree_view_search_dialog_hide (tree_view->priv->search_window, tree_view, NULL);
10893   tree_view->priv->typeselect_flush_timeout = 0;
10894
10895   return FALSE;
10896 }
10897
10898 /* Cut and paste from gtkwindow.c */
10899 static void
10900 send_focus_change (GtkWidget *widget,
10901                    GdkDevice *device,
10902                    gboolean   in)
10903 {
10904   GdkDeviceManager *device_manager;
10905   GList *devices, *d;
10906
10907   device_manager = gdk_display_get_device_manager (gtk_widget_get_display (widget));
10908   devices = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER);
10909   devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_SLAVE));
10910   devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_FLOATING));
10911
10912   for (d = devices; d; d = d->next)
10913     {
10914       GdkDevice *dev = d->data;
10915       GdkEvent *fevent;
10916       GdkWindow *window;
10917
10918       if (gdk_device_get_source (dev) != GDK_SOURCE_KEYBOARD)
10919         continue;
10920
10921       window = gtk_widget_get_window (widget);
10922
10923       /* Skip non-master keyboards that haven't
10924        * selected for events from this window
10925        */
10926       if (gdk_device_get_device_type (dev) != GDK_DEVICE_TYPE_MASTER &&
10927           !gdk_window_get_device_events (window, dev))
10928         continue;
10929
10930       fevent = gdk_event_new (GDK_FOCUS_CHANGE);
10931
10932       fevent->focus_change.type = GDK_FOCUS_CHANGE;
10933       fevent->focus_change.window = g_object_ref (window);
10934       fevent->focus_change.in = in;
10935       gdk_event_set_device (fevent, device);
10936
10937       gtk_widget_send_focus_change (widget, fevent);
10938
10939       gdk_event_free (fevent);
10940     }
10941
10942   g_list_free (devices);
10943 }
10944
10945 static void
10946 gtk_tree_view_ensure_interactive_directory (GtkTreeView *tree_view)
10947 {
10948   GtkWidget *frame, *vbox, *toplevel;
10949   GdkScreen *screen;
10950
10951   if (tree_view->priv->search_custom_entry_set)
10952     return;
10953
10954   toplevel = gtk_widget_get_toplevel (GTK_WIDGET (tree_view));
10955   screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
10956
10957    if (tree_view->priv->search_window != NULL)
10958      {
10959        if (gtk_window_has_group (GTK_WINDOW (toplevel)))
10960          gtk_window_group_add_window (gtk_window_get_group (GTK_WINDOW (toplevel)),
10961                                       GTK_WINDOW (tree_view->priv->search_window));
10962        else if (gtk_window_has_group (GTK_WINDOW (tree_view->priv->search_window)))
10963          gtk_window_group_remove_window (gtk_window_get_group (GTK_WINDOW (tree_view->priv->search_window)),
10964                                          GTK_WINDOW (tree_view->priv->search_window));
10965
10966        gtk_window_set_screen (GTK_WINDOW (tree_view->priv->search_window), screen);
10967
10968        return;
10969      }
10970    
10971   tree_view->priv->search_window = gtk_window_new (GTK_WINDOW_POPUP);
10972   gtk_window_set_screen (GTK_WINDOW (tree_view->priv->search_window), screen);
10973
10974   if (gtk_window_has_group (GTK_WINDOW (toplevel)))
10975     gtk_window_group_add_window (gtk_window_get_group (GTK_WINDOW (toplevel)),
10976                                  GTK_WINDOW (tree_view->priv->search_window));
10977
10978   gtk_window_set_type_hint (GTK_WINDOW (tree_view->priv->search_window),
10979                             GDK_WINDOW_TYPE_HINT_UTILITY);
10980   gtk_window_set_modal (GTK_WINDOW (tree_view->priv->search_window), TRUE);
10981   g_signal_connect (tree_view->priv->search_window, "delete-event",
10982                     G_CALLBACK (gtk_tree_view_search_delete_event),
10983                     tree_view);
10984   g_signal_connect (tree_view->priv->search_window, "key-press-event",
10985                     G_CALLBACK (gtk_tree_view_search_key_press_event),
10986                     tree_view);
10987   g_signal_connect (tree_view->priv->search_window, "button-press-event",
10988                     G_CALLBACK (gtk_tree_view_search_button_press_event),
10989                     tree_view);
10990   g_signal_connect (tree_view->priv->search_window, "scroll-event",
10991                     G_CALLBACK (gtk_tree_view_search_scroll_event),
10992                     tree_view);
10993
10994   frame = gtk_frame_new (NULL);
10995   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
10996   gtk_widget_show (frame);
10997   gtk_container_add (GTK_CONTAINER (tree_view->priv->search_window), frame);
10998
10999   vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
11000   gtk_widget_show (vbox);
11001   gtk_container_add (GTK_CONTAINER (frame), vbox);
11002   gtk_container_set_border_width (GTK_CONTAINER (vbox), 3);
11003
11004   /* add entry */
11005   tree_view->priv->search_entry = gtk_entry_new ();
11006   gtk_widget_show (tree_view->priv->search_entry);
11007   g_signal_connect (tree_view->priv->search_entry, "populate-popup",
11008                     G_CALLBACK (gtk_tree_view_search_disable_popdown),
11009                     tree_view);
11010   g_signal_connect (tree_view->priv->search_entry,
11011                     "activate", G_CALLBACK (gtk_tree_view_search_activate),
11012                     tree_view);
11013
11014   g_signal_connect (_gtk_entry_get_im_context (GTK_ENTRY (tree_view->priv->search_entry)),
11015                     "preedit-changed",
11016                     G_CALLBACK (gtk_tree_view_search_preedit_changed),
11017                     tree_view);
11018
11019   gtk_container_add (GTK_CONTAINER (vbox),
11020                      tree_view->priv->search_entry);
11021
11022   gtk_widget_realize (tree_view->priv->search_entry);
11023 }
11024
11025 /* Pops up the interactive search entry.  If keybinding is TRUE then the user
11026  * started this by typing the start_interactive_search keybinding.  Otherwise, it came from 
11027  */
11028 static gboolean
11029 gtk_tree_view_real_start_interactive_search (GtkTreeView *tree_view,
11030                                              GdkDevice   *device,
11031                                              gboolean     keybinding)
11032 {
11033   /* We only start interactive search if we have focus or the columns
11034    * have focus.  If one of our children have focus, we don't want to
11035    * start the search.
11036    */
11037   GList *list;
11038   gboolean found_focus = FALSE;
11039   GtkWidgetClass *entry_parent_class;
11040   
11041   if (!tree_view->priv->enable_search && !keybinding)
11042     return FALSE;
11043
11044   if (tree_view->priv->search_custom_entry_set)
11045     return FALSE;
11046
11047   if (tree_view->priv->search_window != NULL &&
11048       gtk_widget_get_visible (tree_view->priv->search_window))
11049     return TRUE;
11050
11051   for (list = tree_view->priv->columns; list; list = list->next)
11052     {
11053       GtkTreeViewColumn *column;
11054       GtkWidget         *button;
11055
11056       column = list->data;
11057       if (!gtk_tree_view_column_get_visible (column))
11058         continue;
11059
11060       button = gtk_tree_view_column_get_button (column);
11061       if (gtk_widget_has_focus (button))
11062         {
11063           found_focus = TRUE;
11064           break;
11065         }
11066     }
11067   
11068   if (gtk_widget_has_focus (GTK_WIDGET (tree_view)))
11069     found_focus = TRUE;
11070
11071   if (!found_focus)
11072     return FALSE;
11073
11074   if (tree_view->priv->search_column < 0)
11075     return FALSE;
11076
11077   gtk_tree_view_ensure_interactive_directory (tree_view);
11078
11079   if (keybinding)
11080     gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
11081
11082   /* done, show it */
11083   tree_view->priv->search_position_func (tree_view, tree_view->priv->search_window, tree_view->priv->search_position_user_data);
11084   gtk_widget_show (tree_view->priv->search_window);
11085   if (tree_view->priv->search_entry_changed_id == 0)
11086     {
11087       tree_view->priv->search_entry_changed_id =
11088         g_signal_connect (tree_view->priv->search_entry, "changed",
11089                           G_CALLBACK (gtk_tree_view_search_init),
11090                           tree_view);
11091     }
11092
11093   tree_view->priv->typeselect_flush_timeout =
11094     gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
11095                    (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
11096                    tree_view);
11097
11098   /* Grab focus will select all the text.  We don't want that to happen, so we
11099    * call the parent instance and bypass the selection change.  This is probably
11100    * really non-kosher. */
11101   entry_parent_class = g_type_class_peek_parent (GTK_ENTRY_GET_CLASS (tree_view->priv->search_entry));
11102   (entry_parent_class->grab_focus) (tree_view->priv->search_entry);
11103
11104   /* send focus-in event */
11105   send_focus_change (tree_view->priv->search_entry, device, TRUE);
11106
11107   /* search first matching iter */
11108   gtk_tree_view_search_init (tree_view->priv->search_entry, tree_view);
11109
11110   return TRUE;
11111 }
11112
11113 static gboolean
11114 gtk_tree_view_start_interactive_search (GtkTreeView *tree_view)
11115 {
11116   return gtk_tree_view_real_start_interactive_search (tree_view,
11117                                                       gtk_get_current_event_device (),
11118                                                       TRUE);
11119 }
11120
11121 /* this function returns the new width of the column being resized given
11122  * the column and x position of the cursor; the x cursor position is passed
11123  * in as a pointer and automagicly corrected if it's beyond min/max limits
11124  */
11125 static gint
11126 gtk_tree_view_new_column_width (GtkTreeView *tree_view,
11127                                 gint       i,
11128                                 gint      *x)
11129 {
11130   GtkAllocation allocation;
11131   GtkTreeViewColumn *column;
11132   GtkRequisition button_req;
11133   gint max_width, min_width;
11134   gint width;
11135   gboolean rtl;
11136
11137   /* first translate the x position from widget->window
11138    * to clist->clist_window
11139    */
11140   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
11141   column = g_list_nth (tree_view->priv->columns, i)->data;
11142   gtk_widget_get_allocation (gtk_tree_view_column_get_button (column), &allocation);
11143   width = rtl ? (allocation.x + allocation.width - *x) : (*x - allocation.x);
11144
11145   /* Clamp down the value */
11146   min_width = gtk_tree_view_column_get_min_width (column);
11147   if (min_width == -1)
11148     {
11149       gtk_widget_get_preferred_size (gtk_tree_view_column_get_button (column), &button_req, NULL);
11150       width = MAX (button_req.width, width);
11151     }
11152   else
11153     width = MAX (min_width, width);
11154
11155   max_width = gtk_tree_view_column_get_max_width (column);
11156   if (max_width != -1)
11157     width = MIN (width, max_width);
11158
11159   *x = rtl ? (allocation.x + allocation.width - width) : (allocation.x + width);
11160
11161   return width;
11162 }
11163
11164
11165 /* FIXME this adjust_allocation is a big cut-and-paste from
11166  * GtkCList, needs to be some "official" way to do this
11167  * factored out.
11168  */
11169 typedef struct
11170 {
11171   GdkWindow *window;
11172   int dx;
11173   int dy;
11174 } ScrollData;
11175
11176 /* The window to which widget->window is relative */
11177 #define ALLOCATION_WINDOW(widget)               \
11178    (!gtk_widget_get_has_window (widget) ?                   \
11179     gtk_widget_get_window (widget) :                        \
11180     gdk_window_get_parent (gtk_widget_get_window (widget)))
11181
11182 static void
11183 adjust_allocation_recurse (GtkWidget *widget,
11184                            gpointer   data)
11185 {
11186   GtkAllocation allocation;
11187   ScrollData *scroll_data = data;
11188
11189   /* Need to really size allocate instead of just poking
11190    * into widget->allocation if the widget is not realized.
11191    * FIXME someone figure out why this was.
11192    */
11193   gtk_widget_get_allocation (widget, &allocation);
11194   if (!gtk_widget_get_realized (widget))
11195     {
11196       if (gtk_widget_get_visible (widget))
11197         {
11198           GdkRectangle tmp_rectangle = allocation;
11199           tmp_rectangle.x += scroll_data->dx;
11200           tmp_rectangle.y += scroll_data->dy;
11201           
11202           gtk_widget_size_allocate (widget, &tmp_rectangle);
11203         }
11204     }
11205   else
11206     {
11207       if (ALLOCATION_WINDOW (widget) == scroll_data->window)
11208         {
11209           allocation.x += scroll_data->dx;
11210           allocation.y += scroll_data->dy;
11211           gtk_widget_set_allocation (widget, &allocation);
11212
11213           if (GTK_IS_CONTAINER (widget))
11214             gtk_container_forall (GTK_CONTAINER (widget),
11215                                   adjust_allocation_recurse,
11216                                   data);
11217         }
11218     }
11219 }
11220
11221 static void
11222 adjust_allocation (GtkWidget *widget,
11223                    int        dx,
11224                    int        dy)
11225 {
11226   ScrollData scroll_data;
11227
11228   if (gtk_widget_get_realized (widget))
11229     scroll_data.window = ALLOCATION_WINDOW (widget);
11230   else
11231     scroll_data.window = NULL;
11232     
11233   scroll_data.dx = dx;
11234   scroll_data.dy = dy;
11235   
11236   adjust_allocation_recurse (widget, &scroll_data);
11237 }
11238
11239 /* Callbacks */
11240 static void
11241 gtk_tree_view_adjustment_changed (GtkAdjustment *adjustment,
11242                                   GtkTreeView   *tree_view)
11243 {
11244   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11245     {
11246       gint dy;
11247         
11248       gdk_window_move (tree_view->priv->bin_window,
11249                        - gtk_adjustment_get_value (tree_view->priv->hadjustment),
11250                        gtk_tree_view_get_effective_header_height (tree_view));
11251       gdk_window_move (tree_view->priv->header_window,
11252                        - gtk_adjustment_get_value (tree_view->priv->hadjustment),
11253                        0);
11254       dy = tree_view->priv->dy - (int) gtk_adjustment_get_value (tree_view->priv->vadjustment);
11255       if (dy)
11256         {
11257           update_prelight (tree_view,
11258                            tree_view->priv->event_last_x,
11259                            tree_view->priv->event_last_y - dy);
11260
11261           if (tree_view->priv->edited_column)
11262             {
11263               GList *list;
11264               GtkTreeViewChild *child = NULL;
11265               GtkCellEditable *edit_widget;
11266               GtkCellArea *area;
11267
11268               area        = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (tree_view->priv->edited_column));
11269               edit_widget = gtk_cell_area_get_edit_widget (area);
11270               if (GTK_IS_WIDGET (edit_widget))
11271                 {
11272                   adjust_allocation (GTK_WIDGET (edit_widget), 0, dy);
11273
11274                   for (list = tree_view->priv->children; list; list = list->next)
11275                     {
11276                       child = (GtkTreeViewChild *)list->data;
11277                       if (child->widget == GTK_WIDGET (edit_widget))
11278                         {
11279                           child->y += dy;
11280                           break;
11281                         }
11282                     }
11283                 }
11284             }
11285         }
11286       gdk_window_scroll (tree_view->priv->bin_window, 0, dy);
11287
11288       if (tree_view->priv->dy != (int) gtk_adjustment_get_value (tree_view->priv->vadjustment))
11289         {
11290           /* update our dy and top_row */
11291           tree_view->priv->dy = (int) gtk_adjustment_get_value (tree_view->priv->vadjustment);
11292
11293           if (!tree_view->priv->in_top_row_to_dy)
11294             gtk_tree_view_dy_to_top_row (tree_view);
11295         }
11296     }
11297 }
11298
11299 \f
11300
11301 /* Public methods
11302  */
11303
11304 /**
11305  * gtk_tree_view_new:
11306  *
11307  * Creates a new #GtkTreeView widget.
11308  *
11309  * Return value: A newly created #GtkTreeView widget.
11310  **/
11311 GtkWidget *
11312 gtk_tree_view_new (void)
11313 {
11314   return g_object_new (GTK_TYPE_TREE_VIEW, NULL);
11315 }
11316
11317 /**
11318  * gtk_tree_view_new_with_model:
11319  * @model: the model.
11320  *
11321  * Creates a new #GtkTreeView widget with the model initialized to @model.
11322  *
11323  * Return value: A newly created #GtkTreeView widget.
11324  **/
11325 GtkWidget *
11326 gtk_tree_view_new_with_model (GtkTreeModel *model)
11327 {
11328   return g_object_new (GTK_TYPE_TREE_VIEW, "model", model, NULL);
11329 }
11330
11331 /* Public Accessors
11332  */
11333
11334 /**
11335  * gtk_tree_view_get_model:
11336  * @tree_view: a #GtkTreeView
11337  *
11338  * Returns the model the #GtkTreeView is based on.  Returns %NULL if the
11339  * model is unset.
11340  *
11341  * Return value: (transfer none): A #GtkTreeModel, or %NULL if none is currently being used.
11342  **/
11343 GtkTreeModel *
11344 gtk_tree_view_get_model (GtkTreeView *tree_view)
11345 {
11346   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11347
11348   return tree_view->priv->model;
11349 }
11350
11351 /**
11352  * gtk_tree_view_set_model:
11353  * @tree_view: A #GtkTreeView.
11354  * @model: (allow-none): The model.
11355  *
11356  * Sets the model for a #GtkTreeView.  If the @tree_view already has a model
11357  * set, it will remove it before setting the new model.  If @model is %NULL,
11358  * then it will unset the old model.
11359  **/
11360 void
11361 gtk_tree_view_set_model (GtkTreeView  *tree_view,
11362                          GtkTreeModel *model)
11363 {
11364   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11365   g_return_if_fail (model == NULL || GTK_IS_TREE_MODEL (model));
11366
11367   if (model == tree_view->priv->model)
11368     return;
11369
11370   if (tree_view->priv->scroll_to_path)
11371     {
11372       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
11373       tree_view->priv->scroll_to_path = NULL;
11374     }
11375
11376   if (tree_view->priv->rubber_band_status)
11377     gtk_tree_view_stop_rubber_band (tree_view);
11378
11379   if (tree_view->priv->model)
11380     {
11381       GList *tmplist = tree_view->priv->columns;
11382
11383       gtk_tree_view_unref_and_check_selection_tree (tree_view, tree_view->priv->tree);
11384       gtk_tree_view_stop_editing (tree_view, TRUE);
11385
11386       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
11387                                             gtk_tree_view_row_changed,
11388                                             tree_view);
11389       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
11390                                             gtk_tree_view_row_inserted,
11391                                             tree_view);
11392       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
11393                                             gtk_tree_view_row_has_child_toggled,
11394                                             tree_view);
11395       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
11396                                             gtk_tree_view_row_deleted,
11397                                             tree_view);
11398       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
11399                                             gtk_tree_view_rows_reordered,
11400                                             tree_view);
11401
11402       for (; tmplist; tmplist = tmplist->next)
11403         _gtk_tree_view_column_unset_model (tmplist->data,
11404                                            tree_view->priv->model);
11405
11406       if (tree_view->priv->tree)
11407         gtk_tree_view_free_rbtree (tree_view);
11408
11409       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
11410       tree_view->priv->drag_dest_row = NULL;
11411       gtk_tree_row_reference_free (tree_view->priv->anchor);
11412       tree_view->priv->anchor = NULL;
11413       gtk_tree_row_reference_free (tree_view->priv->top_row);
11414       tree_view->priv->top_row = NULL;
11415       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
11416       tree_view->priv->scroll_to_path = NULL;
11417
11418       tree_view->priv->scroll_to_column = NULL;
11419
11420       g_object_unref (tree_view->priv->model);
11421
11422       tree_view->priv->search_column = -1;
11423       tree_view->priv->fixed_height_check = 0;
11424       tree_view->priv->fixed_height = -1;
11425       tree_view->priv->dy = tree_view->priv->top_row_dy = 0;
11426       tree_view->priv->last_button_x = -1;
11427       tree_view->priv->last_button_y = -1;
11428     }
11429
11430   tree_view->priv->model = model;
11431
11432   if (tree_view->priv->model)
11433     {
11434       gint i;
11435       GtkTreePath *path;
11436       GtkTreeIter iter;
11437       GtkTreeModelFlags flags;
11438
11439       if (tree_view->priv->search_column == -1)
11440         {
11441           for (i = 0; i < gtk_tree_model_get_n_columns (model); i++)
11442             {
11443               GType type = gtk_tree_model_get_column_type (model, i);
11444
11445               if (g_value_type_transformable (type, G_TYPE_STRING))
11446                 {
11447                   tree_view->priv->search_column = i;
11448                   break;
11449                 }
11450             }
11451         }
11452
11453       g_object_ref (tree_view->priv->model);
11454       g_signal_connect (tree_view->priv->model,
11455                         "row-changed",
11456                         G_CALLBACK (gtk_tree_view_row_changed),
11457                         tree_view);
11458       g_signal_connect (tree_view->priv->model,
11459                         "row-inserted",
11460                         G_CALLBACK (gtk_tree_view_row_inserted),
11461                         tree_view);
11462       g_signal_connect (tree_view->priv->model,
11463                         "row-has-child-toggled",
11464                         G_CALLBACK (gtk_tree_view_row_has_child_toggled),
11465                         tree_view);
11466       g_signal_connect (tree_view->priv->model,
11467                         "row-deleted",
11468                         G_CALLBACK (gtk_tree_view_row_deleted),
11469                         tree_view);
11470       g_signal_connect (tree_view->priv->model,
11471                         "rows-reordered",
11472                         G_CALLBACK (gtk_tree_view_rows_reordered),
11473                         tree_view);
11474
11475       flags = gtk_tree_model_get_flags (tree_view->priv->model);
11476       if ((flags & GTK_TREE_MODEL_LIST_ONLY) == GTK_TREE_MODEL_LIST_ONLY)
11477         tree_view->priv->is_list = TRUE;
11478       else
11479         tree_view->priv->is_list = FALSE;
11480
11481       path = gtk_tree_path_new_first ();
11482       if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, path))
11483         {
11484           tree_view->priv->tree = _gtk_rbtree_new ();
11485           gtk_tree_view_build_tree (tree_view, tree_view->priv->tree, &iter, 1, FALSE);
11486           _gtk_tree_view_accessible_add (tree_view, tree_view->priv->tree, NULL);
11487         }
11488       gtk_tree_path_free (path);
11489
11490       /*  FIXME: do I need to do this? gtk_tree_view_create_buttons (tree_view); */
11491       install_presize_handler (tree_view);
11492     }
11493
11494   gtk_tree_view_real_set_cursor (tree_view, NULL, CURSOR_INVALID);
11495
11496   g_object_notify (G_OBJECT (tree_view), "model");
11497
11498   if (tree_view->priv->selection)
11499   _gtk_tree_selection_emit_changed (tree_view->priv->selection);
11500
11501   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11502     gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11503 }
11504
11505 /**
11506  * gtk_tree_view_get_selection:
11507  * @tree_view: A #GtkTreeView.
11508  *
11509  * Gets the #GtkTreeSelection associated with @tree_view.
11510  *
11511  * Return value: (transfer none): A #GtkTreeSelection object.
11512  **/
11513 GtkTreeSelection *
11514 gtk_tree_view_get_selection (GtkTreeView *tree_view)
11515 {
11516   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11517
11518   return tree_view->priv->selection;
11519 }
11520
11521 /**
11522  * gtk_tree_view_get_hadjustment:
11523  * @tree_view: A #GtkTreeView
11524  *
11525  * Gets the #GtkAdjustment currently being used for the horizontal aspect.
11526  *
11527  * Return value: (transfer none): A #GtkAdjustment object, or %NULL
11528  *     if none is currently being used.
11529  *
11530  * Deprecated: 3.0: Use gtk_scrollable_get_hadjustment()
11531  **/
11532 GtkAdjustment *
11533 gtk_tree_view_get_hadjustment (GtkTreeView *tree_view)
11534 {
11535   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11536
11537   return gtk_tree_view_do_get_hadjustment (tree_view);
11538 }
11539
11540 static GtkAdjustment *
11541 gtk_tree_view_do_get_hadjustment (GtkTreeView *tree_view)
11542 {
11543   return tree_view->priv->hadjustment;
11544 }
11545
11546 /**
11547  * gtk_tree_view_set_hadjustment:
11548  * @tree_view: A #GtkTreeView
11549  * @adjustment: (allow-none): The #GtkAdjustment to set, or %NULL
11550  *
11551  * Sets the #GtkAdjustment for the current horizontal aspect.
11552  *
11553  * Deprecated: 3.0: Use gtk_scrollable_set_hadjustment()
11554  **/
11555 void
11556 gtk_tree_view_set_hadjustment (GtkTreeView   *tree_view,
11557                                GtkAdjustment *adjustment)
11558 {
11559   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11560   g_return_if_fail (adjustment == NULL || GTK_IS_ADJUSTMENT (adjustment));
11561
11562   gtk_tree_view_do_set_hadjustment (tree_view, adjustment);
11563 }
11564
11565 static void
11566 gtk_tree_view_do_set_hadjustment (GtkTreeView   *tree_view,
11567                                   GtkAdjustment *adjustment)
11568 {
11569   GtkTreeViewPrivate *priv = tree_view->priv;
11570
11571   if (adjustment && priv->hadjustment == adjustment)
11572     return;
11573
11574   if (priv->hadjustment != NULL)
11575     {
11576       g_signal_handlers_disconnect_by_func (priv->hadjustment,
11577                                             gtk_tree_view_adjustment_changed,
11578                                             tree_view);
11579       g_object_unref (priv->hadjustment);
11580     }
11581
11582   if (adjustment == NULL)
11583     adjustment = gtk_adjustment_new (0.0, 0.0, 0.0,
11584                                      0.0, 0.0, 0.0);
11585
11586   g_signal_connect (adjustment, "value-changed",
11587                     G_CALLBACK (gtk_tree_view_adjustment_changed), tree_view);
11588   priv->hadjustment = g_object_ref_sink (adjustment);
11589   /* FIXME: Adjustment should probably be populated here with fresh values, but
11590    * internal details are too complicated for me to decipher right now.
11591    */
11592   gtk_tree_view_adjustment_changed (NULL, tree_view);
11593
11594   g_object_notify (G_OBJECT (tree_view), "hadjustment");
11595 }
11596
11597 /**
11598  * gtk_tree_view_get_vadjustment:
11599  * @tree_view: A #GtkTreeView
11600  *
11601  * Gets the #GtkAdjustment currently being used for the vertical aspect.
11602  *
11603  * Return value: (transfer none): A #GtkAdjustment object, or %NULL
11604  *     if none is currently being used.
11605  *
11606  * Deprecated: 3.0: Use gtk_scrollable_get_vadjustment()
11607  **/
11608 GtkAdjustment *
11609 gtk_tree_view_get_vadjustment (GtkTreeView *tree_view)
11610 {
11611   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11612
11613   return gtk_tree_view_do_get_vadjustment (tree_view);
11614 }
11615
11616 static GtkAdjustment *
11617 gtk_tree_view_do_get_vadjustment (GtkTreeView *tree_view)
11618 {
11619   return tree_view->priv->vadjustment;
11620 }
11621
11622 /**
11623  * gtk_tree_view_set_vadjustment:
11624  * @tree_view: A #GtkTreeView
11625  * @adjustment: (allow-none): The #GtkAdjustment to set, or %NULL
11626  *
11627  * Sets the #GtkAdjustment for the current vertical aspect.
11628  *
11629  * Deprecated: 3.0: Use gtk_scrollable_set_vadjustment()
11630  **/
11631 void
11632 gtk_tree_view_set_vadjustment (GtkTreeView   *tree_view,
11633                                GtkAdjustment *adjustment)
11634 {
11635   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11636   g_return_if_fail (adjustment == NULL || GTK_IS_ADJUSTMENT (adjustment));
11637
11638   gtk_tree_view_do_set_vadjustment (tree_view, adjustment);
11639 }
11640
11641 static void
11642 gtk_tree_view_do_set_vadjustment (GtkTreeView   *tree_view,
11643                                   GtkAdjustment *adjustment)
11644 {
11645   GtkTreeViewPrivate *priv = tree_view->priv;
11646
11647   if (adjustment && priv->vadjustment == adjustment)
11648     return;
11649
11650   if (priv->vadjustment != NULL)
11651     {
11652       g_signal_handlers_disconnect_by_func (priv->vadjustment,
11653                                             gtk_tree_view_adjustment_changed,
11654                                             tree_view);
11655       g_object_unref (priv->vadjustment);
11656     }
11657
11658   if (adjustment == NULL)
11659     adjustment = gtk_adjustment_new (0.0, 0.0, 0.0,
11660                                      0.0, 0.0, 0.0);
11661
11662   g_signal_connect (adjustment, "value-changed",
11663                     G_CALLBACK (gtk_tree_view_adjustment_changed), tree_view);
11664   priv->vadjustment = g_object_ref_sink (adjustment);
11665   /* FIXME: Adjustment should probably be populated here with fresh values, but
11666    * internal details are too complicated for me to decipher right now.
11667    */
11668   gtk_tree_view_adjustment_changed (NULL, tree_view);
11669   g_object_notify (G_OBJECT (tree_view), "vadjustment");
11670 }
11671
11672 /* Column and header operations */
11673
11674 /**
11675  * gtk_tree_view_get_headers_visible:
11676  * @tree_view: A #GtkTreeView.
11677  *
11678  * Returns %TRUE if the headers on the @tree_view are visible.
11679  *
11680  * Return value: Whether the headers are visible or not.
11681  **/
11682 gboolean
11683 gtk_tree_view_get_headers_visible (GtkTreeView *tree_view)
11684 {
11685   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
11686
11687   return tree_view->priv->headers_visible;
11688 }
11689
11690 /**
11691  * gtk_tree_view_set_headers_visible:
11692  * @tree_view: A #GtkTreeView.
11693  * @headers_visible: %TRUE if the headers are visible
11694  *
11695  * Sets the visibility state of the headers.
11696  **/
11697 void
11698 gtk_tree_view_set_headers_visible (GtkTreeView *tree_view,
11699                                    gboolean     headers_visible)
11700 {
11701   gint x, y;
11702   GList *list;
11703   GtkTreeViewColumn *column;
11704   GtkAllocation allocation;
11705   GtkWidget *button;
11706
11707   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11708
11709   headers_visible = !! headers_visible;
11710
11711   if (tree_view->priv->headers_visible == headers_visible)
11712     return;
11713
11714   tree_view->priv->headers_visible = headers_visible == TRUE;
11715
11716   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11717     {
11718       gdk_window_get_position (tree_view->priv->bin_window, &x, &y);
11719       if (headers_visible)
11720         {
11721           gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
11722           gdk_window_move_resize (tree_view->priv->bin_window,
11723                                   x, y  + gtk_tree_view_get_effective_header_height (tree_view),
11724                                   tree_view->priv->width, allocation.height -  + gtk_tree_view_get_effective_header_height (tree_view));
11725
11726           if (gtk_widget_get_mapped (GTK_WIDGET (tree_view)))
11727             gtk_tree_view_map_buttons (tree_view);
11728         }
11729       else
11730         {
11731           gdk_window_move_resize (tree_view->priv->bin_window, x, y, tree_view->priv->width, tree_view->priv->height);
11732
11733           for (list = tree_view->priv->columns; list; list = list->next)
11734             {
11735               column = list->data;
11736               button = gtk_tree_view_column_get_button (column);
11737
11738               gtk_widget_hide (button);
11739               gtk_widget_unmap (button);
11740             }
11741           gdk_window_hide (tree_view->priv->header_window);
11742         }
11743     }
11744
11745   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
11746   gtk_adjustment_configure (tree_view->priv->vadjustment,
11747                             gtk_adjustment_get_value (tree_view->priv->vadjustment),
11748                             0,
11749                             tree_view->priv->height,
11750                             gtk_adjustment_get_step_increment (tree_view->priv->vadjustment),
11751                             (allocation.height - gtk_tree_view_get_effective_header_height (tree_view)) / 2,
11752                             allocation.height - gtk_tree_view_get_effective_header_height (tree_view));
11753
11754   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11755
11756   g_object_notify (G_OBJECT (tree_view), "headers-visible");
11757 }
11758
11759 /**
11760  * gtk_tree_view_columns_autosize:
11761  * @tree_view: A #GtkTreeView.
11762  *
11763  * Resizes all columns to their optimal width. Only works after the
11764  * treeview has been realized.
11765  **/
11766 void
11767 gtk_tree_view_columns_autosize (GtkTreeView *tree_view)
11768 {
11769   gboolean dirty = FALSE;
11770   GList *list;
11771   GtkTreeViewColumn *column;
11772
11773   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11774
11775   for (list = tree_view->priv->columns; list; list = list->next)
11776     {
11777       column = list->data;
11778       if (gtk_tree_view_column_get_sizing (column) == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
11779         continue;
11780       _gtk_tree_view_column_cell_set_dirty (column, TRUE);
11781       dirty = TRUE;
11782     }
11783
11784   if (dirty)
11785     gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11786 }
11787
11788 /**
11789  * gtk_tree_view_set_headers_clickable:
11790  * @tree_view: A #GtkTreeView.
11791  * @setting: %TRUE if the columns are clickable.
11792  *
11793  * Allow the column title buttons to be clicked.
11794  **/
11795 void
11796 gtk_tree_view_set_headers_clickable (GtkTreeView *tree_view,
11797                                      gboolean   setting)
11798 {
11799   GList *list;
11800
11801   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11802
11803   for (list = tree_view->priv->columns; list; list = list->next)
11804     gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (list->data), setting);
11805
11806   g_object_notify (G_OBJECT (tree_view), "headers-clickable");
11807 }
11808
11809
11810 /**
11811  * gtk_tree_view_get_headers_clickable:
11812  * @tree_view: A #GtkTreeView.
11813  *
11814  * Returns whether all header columns are clickable.
11815  *
11816  * Return value: %TRUE if all header columns are clickable, otherwise %FALSE
11817  *
11818  * Since: 2.10
11819  **/
11820 gboolean 
11821 gtk_tree_view_get_headers_clickable (GtkTreeView *tree_view)
11822 {
11823   GList *list;
11824   
11825   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
11826
11827   for (list = tree_view->priv->columns; list; list = list->next)
11828     if (!gtk_tree_view_column_get_clickable (GTK_TREE_VIEW_COLUMN (list->data)))
11829       return FALSE;
11830
11831   return TRUE;
11832 }
11833
11834 /**
11835  * gtk_tree_view_set_rules_hint:
11836  * @tree_view: a #GtkTreeView
11837  * @setting: %TRUE if the tree requires reading across rows
11838  *
11839  * This function tells GTK+ that the user interface for your
11840  * application requires users to read across tree rows and associate
11841  * cells with one another. By default, GTK+ will then render the tree
11842  * with alternating row colors. Do <emphasis>not</emphasis> use it
11843  * just because you prefer the appearance of the ruled tree; that's a
11844  * question for the theme. Some themes will draw tree rows in
11845  * alternating colors even when rules are turned off, and users who
11846  * prefer that appearance all the time can choose those themes. You
11847  * should call this function only as a <emphasis>semantic</emphasis>
11848  * hint to the theme engine that your tree makes alternating colors
11849  * useful from a functional standpoint (since it has lots of columns,
11850  * generally).
11851  *
11852  **/
11853 void
11854 gtk_tree_view_set_rules_hint (GtkTreeView  *tree_view,
11855                               gboolean      setting)
11856 {
11857   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11858
11859   setting = setting != FALSE;
11860
11861   if (tree_view->priv->has_rules != setting)
11862     {
11863       tree_view->priv->has_rules = setting;
11864       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
11865     }
11866
11867   g_object_notify (G_OBJECT (tree_view), "rules-hint");
11868 }
11869
11870 /**
11871  * gtk_tree_view_get_rules_hint:
11872  * @tree_view: a #GtkTreeView
11873  *
11874  * Gets the setting set by gtk_tree_view_set_rules_hint().
11875  *
11876  * Return value: %TRUE if rules are useful for the user of this tree
11877  **/
11878 gboolean
11879 gtk_tree_view_get_rules_hint (GtkTreeView  *tree_view)
11880 {
11881   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
11882
11883   return tree_view->priv->has_rules;
11884 }
11885
11886 /* Public Column functions
11887  */
11888
11889 /**
11890  * gtk_tree_view_append_column:
11891  * @tree_view: A #GtkTreeView.
11892  * @column: The #GtkTreeViewColumn to add.
11893  *
11894  * Appends @column to the list of columns. If @tree_view has "fixed_height"
11895  * mode enabled, then @column must have its "sizing" property set to be
11896  * GTK_TREE_VIEW_COLUMN_FIXED.
11897  *
11898  * Return value: The number of columns in @tree_view after appending.
11899  **/
11900 gint
11901 gtk_tree_view_append_column (GtkTreeView       *tree_view,
11902                              GtkTreeViewColumn *column)
11903 {
11904   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11905   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
11906   g_return_val_if_fail (gtk_tree_view_column_get_tree_view (column) == NULL, -1);
11907
11908   return gtk_tree_view_insert_column (tree_view, column, -1);
11909 }
11910
11911 void
11912 _gtk_tree_view_reset_header_styles (GtkTreeView *tree_view)
11913 {
11914   GList *columns;
11915
11916   for (columns = tree_view->priv->columns; columns; columns = columns->next)
11917     {
11918       GtkTreeViewColumn *column = columns->data;
11919       GtkWidget *header_widget;
11920
11921       if (!gtk_tree_view_column_get_visible (column))
11922         continue;
11923
11924       header_widget = gtk_tree_view_column_get_widget (column);
11925
11926       if (!header_widget)
11927         header_widget = gtk_tree_view_column_get_button (column);
11928
11929       _gtk_widget_invalidate_style_context (header_widget, GTK_CSS_CHANGE_POSITION | GTK_CSS_CHANGE_SIBLING_POSITION);
11930     }
11931 }
11932
11933
11934 /**
11935  * gtk_tree_view_remove_column:
11936  * @tree_view: A #GtkTreeView.
11937  * @column: The #GtkTreeViewColumn to remove.
11938  *
11939  * Removes @column from @tree_view.
11940  *
11941  * Return value: The number of columns in @tree_view after removing.
11942  **/
11943 gint
11944 gtk_tree_view_remove_column (GtkTreeView       *tree_view,
11945                              GtkTreeViewColumn *column)
11946 {
11947   guint position;
11948
11949   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11950   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
11951   g_return_val_if_fail (gtk_tree_view_column_get_tree_view (column) == GTK_WIDGET (tree_view), -1);
11952
11953   if (tree_view->priv->focus_column == column)
11954     _gtk_tree_view_set_focus_column (tree_view, NULL);
11955
11956   if (tree_view->priv->edited_column == column)
11957     {
11958       gtk_tree_view_stop_editing (tree_view, TRUE);
11959
11960       /* no need to, but just to be sure ... */
11961       tree_view->priv->edited_column = NULL;
11962     }
11963
11964   if (tree_view->priv->expander_column == column)
11965     tree_view->priv->expander_column = NULL;
11966
11967   g_signal_handlers_disconnect_by_func (column,
11968                                         G_CALLBACK (column_sizing_notify),
11969                                         tree_view);
11970
11971   _gtk_tree_view_column_unset_tree_view (column);
11972
11973   position = g_list_index (tree_view->priv->columns, column);
11974
11975   tree_view->priv->columns = g_list_remove (tree_view->priv->columns, column);
11976   tree_view->priv->n_columns--;
11977
11978   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11979     {
11980       GList *list;
11981
11982       _gtk_tree_view_column_unrealize_button (column);
11983       for (list = tree_view->priv->columns; list; list = list->next)
11984         {
11985           GtkTreeViewColumn *tmp_column;
11986
11987           tmp_column = GTK_TREE_VIEW_COLUMN (list->data);
11988           if (gtk_tree_view_column_get_visible (tmp_column))
11989             _gtk_tree_view_column_cell_set_dirty (tmp_column, TRUE);
11990         }
11991
11992       if (tree_view->priv->n_columns == 0 &&
11993           gtk_tree_view_get_headers_visible (tree_view))
11994         gdk_window_hide (tree_view->priv->header_window);
11995
11996       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11997     }
11998
11999   _gtk_tree_view_reset_header_styles (tree_view);
12000
12001   _gtk_tree_view_accessible_remove_column (tree_view, column, position);
12002
12003   g_object_unref (column);
12004   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
12005
12006   return tree_view->priv->n_columns;
12007 }
12008
12009 /**
12010  * gtk_tree_view_insert_column:
12011  * @tree_view: A #GtkTreeView.
12012  * @column: The #GtkTreeViewColumn to be inserted.
12013  * @position: The position to insert @column in.
12014  *
12015  * This inserts the @column into the @tree_view at @position.  If @position is
12016  * -1, then the column is inserted at the end. If @tree_view has
12017  * "fixed_height" mode enabled, then @column must have its "sizing" property
12018  * set to be GTK_TREE_VIEW_COLUMN_FIXED.
12019  *
12020  * Return value: The number of columns in @tree_view after insertion.
12021  **/
12022 gint
12023 gtk_tree_view_insert_column (GtkTreeView       *tree_view,
12024                              GtkTreeViewColumn *column,
12025                              gint               position)
12026 {
12027   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
12028   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
12029   g_return_val_if_fail (gtk_tree_view_column_get_tree_view (column) == NULL, -1);
12030
12031   if (tree_view->priv->fixed_height_mode)
12032     g_return_val_if_fail (gtk_tree_view_column_get_sizing (column)
12033                           == GTK_TREE_VIEW_COLUMN_FIXED, -1);
12034
12035   if (position < 0 || position > tree_view->priv->n_columns)
12036     position = tree_view->priv->n_columns;
12037
12038   g_object_ref_sink (column);
12039
12040   if (tree_view->priv->n_columns == 0 &&
12041       gtk_widget_get_realized (GTK_WIDGET (tree_view)) &&
12042       gtk_tree_view_get_headers_visible (tree_view))
12043     {
12044       gdk_window_show (tree_view->priv->header_window);
12045     }
12046
12047   g_signal_connect (column, "notify::sizing",
12048                     G_CALLBACK (column_sizing_notify), tree_view);
12049
12050   tree_view->priv->columns = g_list_insert (tree_view->priv->columns,
12051                                             column, position);
12052   tree_view->priv->n_columns++;
12053
12054   _gtk_tree_view_column_set_tree_view (column, tree_view);
12055
12056   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
12057     {
12058       GList *list;
12059
12060       _gtk_tree_view_column_realize_button (column);
12061
12062       for (list = tree_view->priv->columns; list; list = list->next)
12063         {
12064           column = GTK_TREE_VIEW_COLUMN (list->data);
12065           if (gtk_tree_view_column_get_visible (column))
12066             _gtk_tree_view_column_cell_set_dirty (column, TRUE);
12067         }
12068       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
12069     }
12070
12071   _gtk_tree_view_reset_header_styles (tree_view);
12072
12073   _gtk_tree_view_accessible_add_column (tree_view, column, position);
12074
12075   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
12076
12077   return tree_view->priv->n_columns;
12078 }
12079
12080 /**
12081  * gtk_tree_view_insert_column_with_attributes:
12082  * @tree_view: A #GtkTreeView
12083  * @position: The position to insert the new column in
12084  * @title: The title to set the header to
12085  * @cell: The #GtkCellRenderer
12086  * @...: A %NULL-terminated list of attributes
12087  *
12088  * Creates a new #GtkTreeViewColumn and inserts it into the @tree_view at
12089  * @position.  If @position is -1, then the newly created column is inserted at
12090  * the end.  The column is initialized with the attributes given. If @tree_view
12091  * has "fixed_height" mode enabled, then the new column will have its sizing
12092  * property set to be GTK_TREE_VIEW_COLUMN_FIXED.
12093  *
12094  * Return value: The number of columns in @tree_view after insertion.
12095  **/
12096 gint
12097 gtk_tree_view_insert_column_with_attributes (GtkTreeView     *tree_view,
12098                                              gint             position,
12099                                              const gchar     *title,
12100                                              GtkCellRenderer *cell,
12101                                              ...)
12102 {
12103   GtkTreeViewColumn *column;
12104   gchar *attribute;
12105   va_list args;
12106   gint column_id;
12107
12108   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
12109
12110   column = gtk_tree_view_column_new ();
12111   if (tree_view->priv->fixed_height_mode)
12112     gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
12113
12114   gtk_tree_view_column_set_title (column, title);
12115   gtk_tree_view_column_pack_start (column, cell, TRUE);
12116
12117   va_start (args, cell);
12118
12119   attribute = va_arg (args, gchar *);
12120
12121   while (attribute != NULL)
12122     {
12123       column_id = va_arg (args, gint);
12124       gtk_tree_view_column_add_attribute (column, cell, attribute, column_id);
12125       attribute = va_arg (args, gchar *);
12126     }
12127
12128   va_end (args);
12129
12130   return gtk_tree_view_insert_column (tree_view, column, position);
12131 }
12132
12133 /**
12134  * gtk_tree_view_insert_column_with_data_func:
12135  * @tree_view: a #GtkTreeView
12136  * @position: Position to insert, -1 for append
12137  * @title: column title
12138  * @cell: cell renderer for column
12139  * @func: function to set attributes of cell renderer
12140  * @data: data for @func
12141  * @dnotify: destroy notifier for @data
12142  *
12143  * Convenience function that inserts a new column into the #GtkTreeView
12144  * with the given cell renderer and a #GtkTreeCellDataFunc to set cell renderer
12145  * attributes (normally using data from the model). See also
12146  * gtk_tree_view_column_set_cell_data_func(), gtk_tree_view_column_pack_start().
12147  * If @tree_view has "fixed_height" mode enabled, then the new column will have its
12148  * "sizing" property set to be GTK_TREE_VIEW_COLUMN_FIXED.
12149  *
12150  * Return value: number of columns in the tree view post-insert
12151  **/
12152 gint
12153 gtk_tree_view_insert_column_with_data_func  (GtkTreeView               *tree_view,
12154                                              gint                       position,
12155                                              const gchar               *title,
12156                                              GtkCellRenderer           *cell,
12157                                              GtkTreeCellDataFunc        func,
12158                                              gpointer                   data,
12159                                              GDestroyNotify             dnotify)
12160 {
12161   GtkTreeViewColumn *column;
12162
12163   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
12164
12165   column = gtk_tree_view_column_new ();
12166   if (tree_view->priv->fixed_height_mode)
12167     gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
12168
12169   gtk_tree_view_column_set_title (column, title);
12170   gtk_tree_view_column_pack_start (column, cell, TRUE);
12171   gtk_tree_view_column_set_cell_data_func (column, cell, func, data, dnotify);
12172
12173   return gtk_tree_view_insert_column (tree_view, column, position);
12174 }
12175
12176 /**
12177  * gtk_tree_view_get_n_columns:
12178  * @tree_view: a #GtkTreeView
12179  *
12180  * Queries the number of columns in the given @tree_view.
12181  *
12182  * Returns: The number of columns in the @tree_view
12183  *
12184  * Since: 3.4
12185  **/
12186 guint
12187 gtk_tree_view_get_n_columns (GtkTreeView *tree_view)
12188 {
12189   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
12190
12191   return tree_view->priv->n_columns;
12192 }
12193
12194 /**
12195  * gtk_tree_view_get_column:
12196  * @tree_view: A #GtkTreeView.
12197  * @n: The position of the column, counting from 0.
12198  *
12199  * Gets the #GtkTreeViewColumn at the given position in the #tree_view.
12200  *
12201  * Return value: (transfer none): The #GtkTreeViewColumn, or %NULL if the
12202  *     position is outside the range of columns.
12203  **/
12204 GtkTreeViewColumn *
12205 gtk_tree_view_get_column (GtkTreeView *tree_view,
12206                           gint         n)
12207 {
12208   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
12209
12210   if (n < 0 || n >= tree_view->priv->n_columns)
12211     return NULL;
12212
12213   if (tree_view->priv->columns == NULL)
12214     return NULL;
12215
12216   return GTK_TREE_VIEW_COLUMN (g_list_nth (tree_view->priv->columns, n)->data);
12217 }
12218
12219 /**
12220  * gtk_tree_view_get_columns:
12221  * @tree_view: A #GtkTreeView
12222  *
12223  * Returns a #GList of all the #GtkTreeViewColumn s currently in @tree_view.
12224  * The returned list must be freed with g_list_free ().
12225  *
12226  * Return value: (element-type GtkTreeViewColumn) (transfer container): A list of #GtkTreeViewColumn s
12227  **/
12228 GList *
12229 gtk_tree_view_get_columns (GtkTreeView *tree_view)
12230 {
12231   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
12232
12233   return g_list_copy (tree_view->priv->columns);
12234 }
12235
12236 /**
12237  * gtk_tree_view_move_column_after:
12238  * @tree_view: A #GtkTreeView
12239  * @column: The #GtkTreeViewColumn to be moved.
12240  * @base_column: (allow-none): The #GtkTreeViewColumn to be moved relative to, or %NULL.
12241  *
12242  * Moves @column to be after to @base_column.  If @base_column is %NULL, then
12243  * @column is placed in the first position.
12244  **/
12245 void
12246 gtk_tree_view_move_column_after (GtkTreeView       *tree_view,
12247                                  GtkTreeViewColumn *column,
12248                                  GtkTreeViewColumn *base_column)
12249 {
12250   GList *column_list_el, *base_el = NULL;
12251
12252   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12253
12254   column_list_el = g_list_find (tree_view->priv->columns, column);
12255   g_return_if_fail (column_list_el != NULL);
12256
12257   if (base_column)
12258     {
12259       base_el = g_list_find (tree_view->priv->columns, base_column);
12260       g_return_if_fail (base_el != NULL);
12261     }
12262
12263   if (column_list_el->prev == base_el)
12264     return;
12265
12266   tree_view->priv->columns = g_list_remove_link (tree_view->priv->columns, column_list_el);
12267   if (base_el == NULL)
12268     {
12269       column_list_el->prev = NULL;
12270       column_list_el->next = tree_view->priv->columns;
12271       if (column_list_el->next)
12272         column_list_el->next->prev = column_list_el;
12273       tree_view->priv->columns = column_list_el;
12274     }
12275   else
12276     {
12277       column_list_el->prev = base_el;
12278       column_list_el->next = base_el->next;
12279       if (column_list_el->next)
12280         column_list_el->next->prev = column_list_el;
12281       base_el->next = column_list_el;
12282     }
12283
12284   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
12285     {
12286       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
12287       gtk_tree_view_size_allocate_columns (GTK_WIDGET (tree_view), NULL);
12288     }
12289
12290   _gtk_tree_view_reset_header_styles (tree_view);
12291
12292   _gtk_tree_view_accessible_reorder_column (tree_view, column);
12293
12294   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
12295 }
12296
12297 /**
12298  * gtk_tree_view_set_expander_column:
12299  * @tree_view: A #GtkTreeView
12300  * @column: %NULL, or the column to draw the expander arrow at.
12301  *
12302  * Sets the column to draw the expander arrow at. It must be in @tree_view.  
12303  * If @column is %NULL, then the expander arrow is always at the first 
12304  * visible column.
12305  *
12306  * If you do not want expander arrow to appear in your tree, set the 
12307  * expander column to a hidden column.
12308  **/
12309 void
12310 gtk_tree_view_set_expander_column (GtkTreeView       *tree_view,
12311                                    GtkTreeViewColumn *column)
12312 {
12313   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12314   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
12315   g_return_if_fail (column == NULL || gtk_tree_view_column_get_tree_view (column) == GTK_WIDGET (tree_view));
12316
12317   if (tree_view->priv->expander_column != column)
12318     {
12319       tree_view->priv->expander_column = column;
12320       g_object_notify (G_OBJECT (tree_view), "expander-column");
12321     }
12322 }
12323
12324 /**
12325  * gtk_tree_view_get_expander_column:
12326  * @tree_view: A #GtkTreeView
12327  *
12328  * Returns the column that is the current expander column.
12329  * This column has the expander arrow drawn next to it.
12330  *
12331  * Return value: (transfer none): The expander column.
12332  **/
12333 GtkTreeViewColumn *
12334 gtk_tree_view_get_expander_column (GtkTreeView *tree_view)
12335 {
12336   GList *list;
12337
12338   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
12339
12340   for (list = tree_view->priv->columns; list; list = list->next)
12341     if (gtk_tree_view_is_expander_column (tree_view, GTK_TREE_VIEW_COLUMN (list->data)))
12342       return (GtkTreeViewColumn *) list->data;
12343   return NULL;
12344 }
12345
12346
12347 /**
12348  * gtk_tree_view_set_column_drag_function:
12349  * @tree_view: A #GtkTreeView.
12350  * @func: (allow-none): A function to determine which columns are reorderable, or %NULL.
12351  * @user_data: (allow-none): User data to be passed to @func, or %NULL
12352  * @destroy: (allow-none): Destroy notifier for @user_data, or %NULL
12353  *
12354  * Sets a user function for determining where a column may be dropped when
12355  * dragged.  This function is called on every column pair in turn at the
12356  * beginning of a column drag to determine where a drop can take place.  The
12357  * arguments passed to @func are: the @tree_view, the #GtkTreeViewColumn being
12358  * dragged, the two #GtkTreeViewColumn s determining the drop spot, and
12359  * @user_data.  If either of the #GtkTreeViewColumn arguments for the drop spot
12360  * are %NULL, then they indicate an edge.  If @func is set to be %NULL, then
12361  * @tree_view reverts to the default behavior of allowing all columns to be
12362  * dropped everywhere.
12363  **/
12364 void
12365 gtk_tree_view_set_column_drag_function (GtkTreeView               *tree_view,
12366                                         GtkTreeViewColumnDropFunc  func,
12367                                         gpointer                   user_data,
12368                                         GDestroyNotify             destroy)
12369 {
12370   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12371
12372   if (tree_view->priv->column_drop_func_data_destroy)
12373     tree_view->priv->column_drop_func_data_destroy (tree_view->priv->column_drop_func_data);
12374
12375   tree_view->priv->column_drop_func = func;
12376   tree_view->priv->column_drop_func_data = user_data;
12377   tree_view->priv->column_drop_func_data_destroy = destroy;
12378 }
12379
12380 /**
12381  * gtk_tree_view_scroll_to_point:
12382  * @tree_view: a #GtkTreeView
12383  * @tree_x: X coordinate of new top-left pixel of visible area, or -1
12384  * @tree_y: Y coordinate of new top-left pixel of visible area, or -1
12385  *
12386  * Scrolls the tree view such that the top-left corner of the visible
12387  * area is @tree_x, @tree_y, where @tree_x and @tree_y are specified
12388  * in tree coordinates.  The @tree_view must be realized before
12389  * this function is called.  If it isn't, you probably want to be
12390  * using gtk_tree_view_scroll_to_cell().
12391  *
12392  * If either @tree_x or @tree_y are -1, then that direction isn't scrolled.
12393  **/
12394 void
12395 gtk_tree_view_scroll_to_point (GtkTreeView *tree_view,
12396                                gint         tree_x,
12397                                gint         tree_y)
12398 {
12399   GtkAdjustment *hadj;
12400   GtkAdjustment *vadj;
12401
12402   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12403   g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (tree_view)));
12404
12405   hadj = tree_view->priv->hadjustment;
12406   vadj = tree_view->priv->vadjustment;
12407
12408   if (tree_x != -1)
12409     gtk_adjustment_set_value (hadj, tree_x);
12410   if (tree_y != -1)
12411     gtk_adjustment_set_value (vadj, tree_y);
12412 }
12413
12414 /**
12415  * gtk_tree_view_scroll_to_cell:
12416  * @tree_view: A #GtkTreeView.
12417  * @path: (allow-none): The path of the row to move to, or %NULL.
12418  * @column: (allow-none): The #GtkTreeViewColumn to move horizontally to, or %NULL.
12419  * @use_align: whether to use alignment arguments, or %FALSE.
12420  * @row_align: The vertical alignment of the row specified by @path.
12421  * @col_align: The horizontal alignment of the column specified by @column.
12422  *
12423  * Moves the alignments of @tree_view to the position specified by @column and
12424  * @path.  If @column is %NULL, then no horizontal scrolling occurs.  Likewise,
12425  * if @path is %NULL no vertical scrolling occurs.  At a minimum, one of @column
12426  * or @path need to be non-%NULL.  @row_align determines where the row is
12427  * placed, and @col_align determines where @column is placed.  Both are expected
12428  * to be between 0.0 and 1.0. 0.0 means left/top alignment, 1.0 means
12429  * right/bottom alignment, 0.5 means center.
12430  *
12431  * If @use_align is %FALSE, then the alignment arguments are ignored, and the
12432  * tree does the minimum amount of work to scroll the cell onto the screen.
12433  * This means that the cell will be scrolled to the edge closest to its current
12434  * position.  If the cell is currently visible on the screen, nothing is done.
12435  *
12436  * This function only works if the model is set, and @path is a valid row on the
12437  * model.  If the model changes before the @tree_view is realized, the centered
12438  * path will be modified to reflect this change.
12439  **/
12440 void
12441 gtk_tree_view_scroll_to_cell (GtkTreeView       *tree_view,
12442                               GtkTreePath       *path,
12443                               GtkTreeViewColumn *column,
12444                               gboolean           use_align,
12445                               gfloat             row_align,
12446                               gfloat             col_align)
12447 {
12448   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12449   g_return_if_fail (tree_view->priv->model != NULL);
12450   g_return_if_fail (tree_view->priv->tree != NULL);
12451   g_return_if_fail (row_align >= 0.0 && row_align <= 1.0);
12452   g_return_if_fail (col_align >= 0.0 && col_align <= 1.0);
12453   g_return_if_fail (path != NULL || column != NULL);
12454
12455 #if 0
12456   g_print ("gtk_tree_view_scroll_to_cell:\npath: %s\ncolumn: %s\nuse_align: %d\nrow_align: %f\ncol_align: %f\n",
12457            gtk_tree_path_to_string (path), column?"non-null":"null", use_align, row_align, col_align);
12458 #endif
12459   row_align = CLAMP (row_align, 0.0, 1.0);
12460   col_align = CLAMP (col_align, 0.0, 1.0);
12461
12462
12463   /* Note: Despite the benefits that come from having one code path for the
12464    * scrolling code, we short-circuit validate_visible_area's immplementation as
12465    * it is much slower than just going to the point.
12466    */
12467   if (!gtk_widget_get_visible (GTK_WIDGET (tree_view)) ||
12468       !gtk_widget_get_realized (GTK_WIDGET (tree_view)) ||
12469       _gtk_widget_get_alloc_needed (GTK_WIDGET (tree_view)) ||
12470       GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID))
12471     {
12472       if (tree_view->priv->scroll_to_path)
12473         gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
12474
12475       tree_view->priv->scroll_to_path = NULL;
12476       tree_view->priv->scroll_to_column = NULL;
12477
12478       if (path)
12479         tree_view->priv->scroll_to_path = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
12480       if (column)
12481         tree_view->priv->scroll_to_column = column;
12482       tree_view->priv->scroll_to_use_align = use_align;
12483       tree_view->priv->scroll_to_row_align = row_align;
12484       tree_view->priv->scroll_to_col_align = col_align;
12485
12486       install_presize_handler (tree_view);
12487     }
12488   else
12489     {
12490       GdkRectangle cell_rect;
12491       GdkRectangle vis_rect;
12492       gint dest_x, dest_y;
12493
12494       gtk_tree_view_get_background_area (tree_view, path, column, &cell_rect);
12495       gtk_tree_view_get_visible_rect (tree_view, &vis_rect);
12496
12497       cell_rect.y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, cell_rect.y);
12498
12499       dest_x = vis_rect.x;
12500       dest_y = vis_rect.y;
12501
12502       if (column)
12503         {
12504           if (use_align)
12505             {
12506               dest_x = cell_rect.x - ((vis_rect.width - cell_rect.width) * col_align);
12507             }
12508           else
12509             {
12510               if (cell_rect.x < vis_rect.x)
12511                 dest_x = cell_rect.x;
12512               if (cell_rect.x + cell_rect.width > vis_rect.x + vis_rect.width)
12513                 dest_x = cell_rect.x + cell_rect.width - vis_rect.width;
12514             }
12515         }
12516
12517       if (path)
12518         {
12519           if (use_align)
12520             {
12521               dest_y = cell_rect.y - ((vis_rect.height - cell_rect.height) * row_align);
12522               dest_y = MAX (dest_y, 0);
12523             }
12524           else
12525             {
12526               if (cell_rect.y < vis_rect.y)
12527                 dest_y = cell_rect.y;
12528               if (cell_rect.y + cell_rect.height > vis_rect.y + vis_rect.height)
12529                 dest_y = cell_rect.y + cell_rect.height - vis_rect.height;
12530             }
12531         }
12532
12533       gtk_tree_view_scroll_to_point (tree_view, dest_x, dest_y);
12534     }
12535 }
12536
12537 /**
12538  * gtk_tree_view_row_activated:
12539  * @tree_view: A #GtkTreeView
12540  * @path: The #GtkTreePath to be activated.
12541  * @column: The #GtkTreeViewColumn to be activated.
12542  *
12543  * Activates the cell determined by @path and @column.
12544  **/
12545 void
12546 gtk_tree_view_row_activated (GtkTreeView       *tree_view,
12547                              GtkTreePath       *path,
12548                              GtkTreeViewColumn *column)
12549 {
12550   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12551
12552   g_signal_emit (tree_view, tree_view_signals[ROW_ACTIVATED], 0, path, column);
12553 }
12554
12555
12556 static void
12557 gtk_tree_view_expand_all_emission_helper (GtkRBTree *tree,
12558                                           GtkRBNode *node,
12559                                           gpointer   data)
12560 {
12561   GtkTreeView *tree_view = data;
12562
12563   if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT &&
12564       node->children)
12565     {
12566       GtkTreePath *path;
12567       GtkTreeIter iter;
12568
12569       path = _gtk_tree_path_new_from_rbtree (tree, node);
12570       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
12571
12572       g_signal_emit (tree_view, tree_view_signals[ROW_EXPANDED], 0, &iter, path);
12573
12574       gtk_tree_path_free (path);
12575     }
12576
12577   if (node->children)
12578     _gtk_rbtree_traverse (node->children,
12579                           node->children->root,
12580                           G_PRE_ORDER,
12581                           gtk_tree_view_expand_all_emission_helper,
12582                           tree_view);
12583 }
12584
12585 /**
12586  * gtk_tree_view_expand_all:
12587  * @tree_view: A #GtkTreeView.
12588  *
12589  * Recursively expands all nodes in the @tree_view.
12590  **/
12591 void
12592 gtk_tree_view_expand_all (GtkTreeView *tree_view)
12593 {
12594   GtkTreePath *path;
12595   GtkRBTree *tree;
12596   GtkRBNode *node;
12597
12598   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12599
12600   if (tree_view->priv->tree == NULL)
12601     return;
12602
12603   path = gtk_tree_path_new_first ();
12604   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
12605
12606   while (node)
12607     {
12608       gtk_tree_view_real_expand_row (tree_view, path, tree, node, TRUE, FALSE);
12609       node = _gtk_rbtree_next (tree, node);
12610       gtk_tree_path_next (path);
12611   }
12612
12613   gtk_tree_path_free (path);
12614 }
12615
12616 /**
12617  * gtk_tree_view_collapse_all:
12618  * @tree_view: A #GtkTreeView.
12619  *
12620  * Recursively collapses all visible, expanded nodes in @tree_view.
12621  **/
12622 void
12623 gtk_tree_view_collapse_all (GtkTreeView *tree_view)
12624 {
12625   GtkRBTree *tree;
12626   GtkRBNode *node;
12627   GtkTreePath *path;
12628   gint *indices;
12629
12630   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12631
12632   if (tree_view->priv->tree == NULL)
12633     return;
12634
12635   path = gtk_tree_path_new ();
12636   gtk_tree_path_down (path);
12637   indices = gtk_tree_path_get_indices (path);
12638
12639   tree = tree_view->priv->tree;
12640   node = _gtk_rbtree_first (tree);
12641
12642   while (node)
12643     {
12644       if (node->children)
12645         gtk_tree_view_real_collapse_row (tree_view, path, tree, node, FALSE);
12646       indices[0]++;
12647       node = _gtk_rbtree_next (tree, node);
12648     }
12649
12650   gtk_tree_path_free (path);
12651 }
12652
12653 /**
12654  * gtk_tree_view_expand_to_path:
12655  * @tree_view: A #GtkTreeView.
12656  * @path: path to a row.
12657  *
12658  * Expands the row at @path. This will also expand all parent rows of
12659  * @path as necessary.
12660  *
12661  * Since: 2.2
12662  **/
12663 void
12664 gtk_tree_view_expand_to_path (GtkTreeView *tree_view,
12665                               GtkTreePath *path)
12666 {
12667   gint i, depth;
12668   gint *indices;
12669   GtkTreePath *tmp;
12670
12671   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12672   g_return_if_fail (path != NULL);
12673
12674   depth = gtk_tree_path_get_depth (path);
12675   indices = gtk_tree_path_get_indices (path);
12676
12677   tmp = gtk_tree_path_new ();
12678   g_return_if_fail (tmp != NULL);
12679
12680   for (i = 0; i < depth; i++)
12681     {
12682       gtk_tree_path_append_index (tmp, indices[i]);
12683       gtk_tree_view_expand_row (tree_view, tmp, FALSE);
12684     }
12685
12686   gtk_tree_path_free (tmp);
12687 }
12688
12689 /* FIXME the bool return values for expand_row and collapse_row are
12690  * not analagous; they should be TRUE if the row had children and
12691  * was not already in the requested state.
12692  */
12693
12694
12695 static gboolean
12696 gtk_tree_view_real_expand_row (GtkTreeView *tree_view,
12697                                GtkTreePath *path,
12698                                GtkRBTree   *tree,
12699                                GtkRBNode   *node,
12700                                gboolean     open_all,
12701                                gboolean     animate)
12702 {
12703   GtkTreeIter iter;
12704   GtkTreeIter temp;
12705   gboolean expand;
12706
12707   if (animate)
12708     g_object_get (gtk_widget_get_settings (GTK_WIDGET (tree_view)),
12709                   "gtk-enable-animations", &animate,
12710                   NULL);
12711
12712   remove_auto_expand_timeout (tree_view);
12713
12714   if (node->children && !open_all)
12715     return FALSE;
12716
12717   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
12718     return FALSE;
12719
12720   gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
12721   if (! gtk_tree_model_iter_has_child (tree_view->priv->model, &iter))
12722     return FALSE;
12723
12724
12725    if (node->children && open_all)
12726     {
12727       gboolean retval = FALSE;
12728       GtkTreePath *tmp_path = gtk_tree_path_copy (path);
12729
12730       gtk_tree_path_append_index (tmp_path, 0);
12731       tree = node->children;
12732       node = _gtk_rbtree_first (tree);
12733       /* try to expand the children */
12734       do
12735         {
12736          gboolean t;
12737          t = gtk_tree_view_real_expand_row (tree_view, tmp_path, tree, node,
12738                                             TRUE, animate);
12739          if (t)
12740            retval = TRUE;
12741
12742          gtk_tree_path_next (tmp_path);
12743          node = _gtk_rbtree_next (tree, node);
12744        }
12745       while (node != NULL);
12746
12747       gtk_tree_path_free (tmp_path);
12748
12749       return retval;
12750     }
12751
12752   g_signal_emit (tree_view, tree_view_signals[TEST_EXPAND_ROW], 0, &iter, path, &expand);
12753
12754   if (!gtk_tree_model_iter_has_child (tree_view->priv->model, &iter))
12755     return FALSE;
12756
12757   if (expand)
12758     return FALSE;
12759
12760   node->children = _gtk_rbtree_new ();
12761   node->children->parent_tree = tree;
12762   node->children->parent_node = node;
12763
12764   gtk_tree_model_iter_children (tree_view->priv->model, &temp, &iter);
12765
12766   gtk_tree_view_build_tree (tree_view,
12767                             node->children,
12768                             &temp,
12769                             gtk_tree_path_get_depth (path) + 1,
12770                             open_all);
12771
12772   _gtk_tree_view_accessible_add (tree_view, node->children, NULL);
12773   _gtk_tree_view_accessible_add_state (tree_view,
12774                                        tree, node,
12775                                        GTK_CELL_RENDERER_EXPANDED);
12776
12777   install_presize_handler (tree_view);
12778
12779   g_signal_emit (tree_view, tree_view_signals[ROW_EXPANDED], 0, &iter, path);
12780   if (open_all && node->children)
12781     {
12782       _gtk_rbtree_traverse (node->children,
12783                             node->children->root,
12784                             G_PRE_ORDER,
12785                             gtk_tree_view_expand_all_emission_helper,
12786                             tree_view);
12787     }
12788   return TRUE;
12789 }
12790
12791
12792 /**
12793  * gtk_tree_view_expand_row:
12794  * @tree_view: a #GtkTreeView
12795  * @path: path to a row
12796  * @open_all: whether to recursively expand, or just expand immediate children
12797  *
12798  * Opens the row so its children are visible.
12799  *
12800  * Return value: %TRUE if the row existed and had children
12801  **/
12802 gboolean
12803 gtk_tree_view_expand_row (GtkTreeView *tree_view,
12804                           GtkTreePath *path,
12805                           gboolean     open_all)
12806 {
12807   GtkRBTree *tree;
12808   GtkRBNode *node;
12809
12810   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12811   g_return_val_if_fail (tree_view->priv->model != NULL, FALSE);
12812   g_return_val_if_fail (path != NULL, FALSE);
12813
12814   if (_gtk_tree_view_find_node (tree_view,
12815                                 path,
12816                                 &tree,
12817                                 &node))
12818     return FALSE;
12819
12820   if (tree != NULL)
12821     return gtk_tree_view_real_expand_row (tree_view, path, tree, node, open_all, FALSE);
12822   else
12823     return FALSE;
12824 }
12825
12826 static gboolean
12827 gtk_tree_view_real_collapse_row (GtkTreeView *tree_view,
12828                                  GtkTreePath *path,
12829                                  GtkRBTree   *tree,
12830                                  GtkRBNode   *node,
12831                                  gboolean     animate)
12832 {
12833   GtkTreeIter iter;
12834   GtkTreeIter children;
12835   gboolean collapse;
12836   gint x, y;
12837   GList *list;
12838   GdkWindow *child;
12839   gboolean selection_changed, cursor_changed;
12840
12841   if (animate)
12842     g_object_get (gtk_widget_get_settings (GTK_WIDGET (tree_view)),
12843                   "gtk-enable-animations", &animate,
12844                   NULL);
12845
12846   remove_auto_expand_timeout (tree_view);
12847
12848   if (node->children == NULL)
12849     return FALSE;
12850   gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
12851
12852   g_signal_emit (tree_view, tree_view_signals[TEST_COLLAPSE_ROW], 0, &iter, path, &collapse);
12853
12854   if (collapse)
12855     return FALSE;
12856
12857   /* if the prelighted node is a child of us, we want to unprelight it.  We have
12858    * a chance to prelight the correct node below */
12859
12860   if (tree_view->priv->prelight_tree)
12861     {
12862       GtkRBTree *parent_tree;
12863       GtkRBNode *parent_node;
12864
12865       parent_tree = tree_view->priv->prelight_tree->parent_tree;
12866       parent_node = tree_view->priv->prelight_tree->parent_node;
12867       while (parent_tree)
12868         {
12869           if (parent_tree == tree && parent_node == node)
12870             {
12871               ensure_unprelighted (tree_view);
12872               break;
12873             }
12874           parent_node = parent_tree->parent_node;
12875           parent_tree = parent_tree->parent_tree;
12876         }
12877     }
12878
12879   TREE_VIEW_INTERNAL_ASSERT (gtk_tree_model_iter_children (tree_view->priv->model, &children, &iter), FALSE);
12880
12881   for (list = tree_view->priv->columns; list; list = list->next)
12882     {
12883       GtkTreeViewColumn *column = list->data;
12884
12885       if (gtk_tree_view_column_get_visible (column) == FALSE)
12886         continue;
12887       if (gtk_tree_view_column_get_sizing (column) == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
12888         _gtk_tree_view_column_cell_set_dirty (column, TRUE);
12889     }
12890
12891   if (tree_view->priv->destroy_count_func)
12892     {
12893       GtkTreePath *child_path;
12894       gint child_count = 0;
12895       child_path = gtk_tree_path_copy (path);
12896       gtk_tree_path_down (child_path);
12897       if (node->children)
12898         _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, &child_count);
12899       tree_view->priv->destroy_count_func (tree_view, child_path, child_count, tree_view->priv->destroy_count_data);
12900       gtk_tree_path_free (child_path);
12901     }
12902
12903   if (tree_view->priv->cursor_node)
12904     {
12905       cursor_changed = (node->children == tree_view->priv->cursor_tree)
12906                        || _gtk_rbtree_contains (node->children, tree_view->priv->cursor_tree);
12907     }
12908   else
12909     cursor_changed = FALSE;
12910
12911   if (gtk_tree_row_reference_valid (tree_view->priv->anchor))
12912     {
12913       GtkTreePath *anchor_path = gtk_tree_row_reference_get_path (tree_view->priv->anchor);
12914       if (gtk_tree_path_is_ancestor (path, anchor_path))
12915         {
12916           gtk_tree_row_reference_free (tree_view->priv->anchor);
12917           tree_view->priv->anchor = NULL;
12918         }
12919       gtk_tree_path_free (anchor_path);
12920     }
12921
12922   selection_changed = gtk_tree_view_unref_and_check_selection_tree (tree_view, node->children);
12923   
12924   /* Stop a pending double click */
12925   tree_view->priv->last_button_x = -1;
12926   tree_view->priv->last_button_y = -1;
12927
12928   _gtk_tree_view_accessible_remove (tree_view, node->children, NULL);
12929   _gtk_tree_view_accessible_remove_state (tree_view,
12930                                           tree, node,
12931                                           GTK_CELL_RENDERER_EXPANDED);
12932
12933   _gtk_rbtree_remove (node->children);
12934
12935   if (cursor_changed)
12936     gtk_tree_view_real_set_cursor (tree_view, path, CLEAR_AND_SELECT | CURSOR_INVALID);
12937   if (selection_changed)
12938     g_signal_emit_by_name (tree_view->priv->selection, "changed");
12939
12940   if (gtk_widget_get_mapped (GTK_WIDGET (tree_view)))
12941     {
12942       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
12943     }
12944
12945   g_signal_emit (tree_view, tree_view_signals[ROW_COLLAPSED], 0, &iter, path);
12946   
12947   if (gtk_widget_get_mapped (GTK_WIDGET (tree_view)))
12948     {
12949       /* now that we've collapsed all rows, we want to try to set the prelight
12950        * again. To do this, we fake a motion event and send it to ourselves. */
12951
12952       child = gdk_window_get_device_position (gdk_window_get_parent (tree_view->priv->bin_window),
12953                                               gdk_device_manager_get_client_pointer (
12954                                                 gdk_display_get_device_manager (
12955                                                   gtk_widget_get_display (GTK_WIDGET (tree_view)))),
12956                                               &x, &y, NULL);
12957       if (child == tree_view->priv->bin_window)
12958         {
12959           GdkEventMotion event;
12960           gint child_x, child_y;
12961
12962           gdk_window_get_position (child, &child_x, &child_y);
12963
12964           event.window = tree_view->priv->bin_window;
12965           event.x = x - child_x;
12966           event.y = y - child_y;
12967
12968           /* despite the fact this isn't a real event, I'm almost positive it will
12969            * never trigger a drag event.  maybe_drag is the only function that uses
12970            * more than just event.x and event.y. */
12971           gtk_tree_view_motion_bin_window (GTK_WIDGET (tree_view), &event);
12972         }
12973     }
12974
12975   return TRUE;
12976 }
12977
12978 /**
12979  * gtk_tree_view_collapse_row:
12980  * @tree_view: a #GtkTreeView
12981  * @path: path to a row in the @tree_view
12982  *
12983  * Collapses a row (hides its child rows, if they exist).
12984  *
12985  * Return value: %TRUE if the row was collapsed.
12986  **/
12987 gboolean
12988 gtk_tree_view_collapse_row (GtkTreeView *tree_view,
12989                             GtkTreePath *path)
12990 {
12991   GtkRBTree *tree;
12992   GtkRBNode *node;
12993
12994   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12995   g_return_val_if_fail (tree_view->priv->tree != NULL, FALSE);
12996   g_return_val_if_fail (path != NULL, FALSE);
12997
12998   if (_gtk_tree_view_find_node (tree_view,
12999                                 path,
13000                                 &tree,
13001                                 &node))
13002     return FALSE;
13003
13004   if (tree == NULL || node->children == NULL)
13005     return FALSE;
13006
13007   return gtk_tree_view_real_collapse_row (tree_view, path, tree, node, FALSE);
13008 }
13009
13010 static void
13011 gtk_tree_view_map_expanded_rows_helper (GtkTreeView            *tree_view,
13012                                         GtkRBTree              *tree,
13013                                         GtkTreePath            *path,
13014                                         GtkTreeViewMappingFunc  func,
13015                                         gpointer                user_data)
13016 {
13017   GtkRBNode *node;
13018
13019   if (tree == NULL || tree->root == NULL)
13020     return;
13021
13022   node = _gtk_rbtree_first (tree);
13023
13024   while (node)
13025     {
13026       if (node->children)
13027         {
13028           (* func) (tree_view, path, user_data);
13029           gtk_tree_path_down (path);
13030           gtk_tree_view_map_expanded_rows_helper (tree_view, node->children, path, func, user_data);
13031           gtk_tree_path_up (path);
13032         }
13033       gtk_tree_path_next (path);
13034       node = _gtk_rbtree_next (tree, node);
13035     }
13036 }
13037
13038 /**
13039  * gtk_tree_view_map_expanded_rows:
13040  * @tree_view: A #GtkTreeView
13041  * @func: (scope call): A function to be called
13042  * @data: User data to be passed to the function.
13043  *
13044  * Calls @func on all expanded rows.
13045  **/
13046 void
13047 gtk_tree_view_map_expanded_rows (GtkTreeView            *tree_view,
13048                                  GtkTreeViewMappingFunc  func,
13049                                  gpointer                user_data)
13050 {
13051   GtkTreePath *path;
13052
13053   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13054   g_return_if_fail (func != NULL);
13055
13056   path = gtk_tree_path_new_first ();
13057
13058   gtk_tree_view_map_expanded_rows_helper (tree_view,
13059                                           tree_view->priv->tree,
13060                                           path, func, user_data);
13061
13062   gtk_tree_path_free (path);
13063 }
13064
13065 /**
13066  * gtk_tree_view_row_expanded:
13067  * @tree_view: A #GtkTreeView.
13068  * @path: A #GtkTreePath to test expansion state.
13069  *
13070  * Returns %TRUE if the node pointed to by @path is expanded in @tree_view.
13071  *
13072  * Return value: %TRUE if #path is expanded.
13073  **/
13074 gboolean
13075 gtk_tree_view_row_expanded (GtkTreeView *tree_view,
13076                             GtkTreePath *path)
13077 {
13078   GtkRBTree *tree;
13079   GtkRBNode *node;
13080
13081   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
13082   g_return_val_if_fail (path != NULL, FALSE);
13083
13084   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
13085
13086   if (node == NULL)
13087     return FALSE;
13088
13089   return (node->children != NULL);
13090 }
13091
13092 /**
13093  * gtk_tree_view_get_reorderable:
13094  * @tree_view: a #GtkTreeView
13095  *
13096  * Retrieves whether the user can reorder the tree via drag-and-drop. See
13097  * gtk_tree_view_set_reorderable().
13098  *
13099  * Return value: %TRUE if the tree can be reordered.
13100  **/
13101 gboolean
13102 gtk_tree_view_get_reorderable (GtkTreeView *tree_view)
13103 {
13104   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
13105
13106   return tree_view->priv->reorderable;
13107 }
13108
13109 /**
13110  * gtk_tree_view_set_reorderable:
13111  * @tree_view: A #GtkTreeView.
13112  * @reorderable: %TRUE, if the tree can be reordered.
13113  *
13114  * This function is a convenience function to allow you to reorder
13115  * models that support the #GtkTreeDragSourceIface and the
13116  * #GtkTreeDragDestIface.  Both #GtkTreeStore and #GtkListStore support
13117  * these.  If @reorderable is %TRUE, then the user can reorder the
13118  * model by dragging and dropping rows. The developer can listen to
13119  * these changes by connecting to the model's row_inserted and
13120  * row_deleted signals. The reordering is implemented by setting up
13121  * the tree view as a drag source and destination. Therefore, drag and
13122  * drop can not be used in a reorderable view for any other purpose.
13123  *
13124  * This function does not give you any degree of control over the order -- any
13125  * reordering is allowed.  If more control is needed, you should probably
13126  * handle drag and drop manually.
13127  **/
13128 void
13129 gtk_tree_view_set_reorderable (GtkTreeView *tree_view,
13130                                gboolean     reorderable)
13131 {
13132   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13133
13134   reorderable = reorderable != FALSE;
13135
13136   if (tree_view->priv->reorderable == reorderable)
13137     return;
13138
13139   if (reorderable)
13140     {
13141       const GtkTargetEntry row_targets[] = {
13142         { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, 0 }
13143       };
13144
13145       gtk_tree_view_enable_model_drag_source (tree_view,
13146                                               GDK_BUTTON1_MASK,
13147                                               row_targets,
13148                                               G_N_ELEMENTS (row_targets),
13149                                               GDK_ACTION_MOVE);
13150       gtk_tree_view_enable_model_drag_dest (tree_view,
13151                                             row_targets,
13152                                             G_N_ELEMENTS (row_targets),
13153                                             GDK_ACTION_MOVE);
13154     }
13155   else
13156     {
13157       gtk_tree_view_unset_rows_drag_source (tree_view);
13158       gtk_tree_view_unset_rows_drag_dest (tree_view);
13159     }
13160
13161   tree_view->priv->reorderable = reorderable;
13162
13163   g_object_notify (G_OBJECT (tree_view), "reorderable");
13164 }
13165
13166 static void
13167 gtk_tree_view_real_set_cursor (GtkTreeView     *tree_view,
13168                                GtkTreePath     *path,
13169                                SetCursorFlags   flags)
13170 {
13171   if (!(flags & CURSOR_INVALID) && tree_view->priv->cursor_node)
13172     {
13173       _gtk_tree_view_accessible_remove_state (tree_view,
13174                                               tree_view->priv->cursor_tree,
13175                                               tree_view->priv->cursor_node,
13176                                               GTK_CELL_RENDERER_FOCUSED);
13177       _gtk_tree_view_queue_draw_node (tree_view,
13178                                       tree_view->priv->cursor_tree,
13179                                       tree_view->priv->cursor_node,
13180                                       NULL);
13181     }
13182
13183   /* One cannot set the cursor on a separator.   Also, if
13184    * _gtk_tree_view_find_node returns TRUE, it ran out of tree
13185    * before finding the tree and node belonging to path.  The
13186    * path maps to a non-existing path and we will silently bail out.
13187    * We unset tree and node to avoid further processing.
13188    */
13189   if (path == NULL || 
13190       row_is_separator (tree_view, NULL, path)
13191       || _gtk_tree_view_find_node (tree_view,
13192                                    path,
13193                                    &tree_view->priv->cursor_tree,
13194                                    &tree_view->priv->cursor_node))
13195     {
13196       tree_view->priv->cursor_tree = NULL;
13197       tree_view->priv->cursor_node = NULL;
13198     }
13199
13200   if (tree_view->priv->cursor_node != NULL)
13201     {
13202       GtkRBTree *new_tree = NULL;
13203       GtkRBNode *new_node = NULL;
13204
13205       if ((flags & CLEAR_AND_SELECT) && !tree_view->priv->modify_selection_pressed)
13206         {
13207           GtkTreeSelectMode mode = 0;
13208
13209           if (tree_view->priv->extend_selection_pressed)
13210             mode |= GTK_TREE_SELECT_MODE_EXTEND;
13211
13212           _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
13213                                                     tree_view->priv->cursor_node,
13214                                                     tree_view->priv->cursor_tree,
13215                                                     path,
13216                                                     mode,
13217                                                     FALSE);
13218         }
13219
13220       /* We have to re-find tree and node here again, somebody might have
13221        * cleared the node or the whole tree in the GtkTreeSelection::changed
13222        * callback. If the nodes differ we bail out here.
13223        */
13224       _gtk_tree_view_find_node (tree_view, path, &new_tree, &new_node);
13225
13226       if (tree_view->priv->cursor_node != new_node)
13227         return;
13228
13229       if (flags & CLAMP_NODE)
13230         {
13231           gtk_tree_view_clamp_node_visible (tree_view,
13232                                             tree_view->priv->cursor_tree,
13233                                             tree_view->priv->cursor_node);
13234           _gtk_tree_view_queue_draw_node (tree_view,
13235                                           tree_view->priv->cursor_tree,
13236                                           tree_view->priv->cursor_node,
13237                                           NULL);
13238         }
13239
13240       _gtk_tree_view_accessible_add_state (tree_view,
13241                                            tree_view->priv->cursor_tree,
13242                                            tree_view->priv->cursor_node,
13243                                            GTK_CELL_RENDERER_FOCUSED);
13244     }
13245
13246   g_signal_emit (tree_view, tree_view_signals[CURSOR_CHANGED], 0);
13247 }
13248
13249 /**
13250  * gtk_tree_view_get_cursor:
13251  * @tree_view: A #GtkTreeView
13252  * @path: (out) (transfer full) (allow-none): A pointer to be filled with the current cursor path, or %NULL
13253  * @focus_column: (out) (transfer none) (allow-none): A pointer to be filled with the current focus column, or %NULL
13254  *
13255  * Fills in @path and @focus_column with the current path and focus column.  If
13256  * the cursor isn't currently set, then *@path will be %NULL.  If no column
13257  * currently has focus, then *@focus_column will be %NULL.
13258  *
13259  * The returned #GtkTreePath must be freed with gtk_tree_path_free() when
13260  * you are done with it.
13261  **/
13262 void
13263 gtk_tree_view_get_cursor (GtkTreeView        *tree_view,
13264                           GtkTreePath       **path,
13265                           GtkTreeViewColumn **focus_column)
13266 {
13267   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13268
13269   if (path)
13270     {
13271       if (tree_view->priv->cursor_node)
13272         *path = _gtk_tree_path_new_from_rbtree (tree_view->priv->cursor_tree,
13273                                                 tree_view->priv->cursor_node);
13274       else
13275         *path = NULL;
13276     }
13277
13278   if (focus_column)
13279     {
13280       *focus_column = tree_view->priv->focus_column;
13281     }
13282 }
13283
13284 /**
13285  * gtk_tree_view_set_cursor:
13286  * @tree_view: A #GtkTreeView
13287  * @path: A #GtkTreePath
13288  * @focus_column: (allow-none): A #GtkTreeViewColumn, or %NULL
13289  * @start_editing: %TRUE if the specified cell should start being edited.
13290  *
13291  * Sets the current keyboard focus to be at @path, and selects it.  This is
13292  * useful when you want to focus the user's attention on a particular row.  If
13293  * @focus_column is not %NULL, then focus is given to the column specified by 
13294  * it. Additionally, if @focus_column is specified, and @start_editing is 
13295  * %TRUE, then editing should be started in the specified cell.  
13296  * This function is often followed by @gtk_widget_grab_focus (@tree_view) 
13297  * in order to give keyboard focus to the widget.  Please note that editing 
13298  * can only happen when the widget is realized.
13299  *
13300  * If @path is invalid for @model, the current cursor (if any) will be unset
13301  * and the function will return without failing.
13302  **/
13303 void
13304 gtk_tree_view_set_cursor (GtkTreeView       *tree_view,
13305                           GtkTreePath       *path,
13306                           GtkTreeViewColumn *focus_column,
13307                           gboolean           start_editing)
13308 {
13309   gtk_tree_view_set_cursor_on_cell (tree_view, path, focus_column,
13310                                     NULL, start_editing);
13311 }
13312
13313 /**
13314  * gtk_tree_view_set_cursor_on_cell:
13315  * @tree_view: A #GtkTreeView
13316  * @path: A #GtkTreePath
13317  * @focus_column: (allow-none): A #GtkTreeViewColumn, or %NULL
13318  * @focus_cell: (allow-none): A #GtkCellRenderer, or %NULL
13319  * @start_editing: %TRUE if the specified cell should start being edited.
13320  *
13321  * Sets the current keyboard focus to be at @path, and selects it.  This is
13322  * useful when you want to focus the user's attention on a particular row.  If
13323  * @focus_column is not %NULL, then focus is given to the column specified by
13324  * it. If @focus_column and @focus_cell are not %NULL, and @focus_column
13325  * contains 2 or more editable or activatable cells, then focus is given to
13326  * the cell specified by @focus_cell. Additionally, if @focus_column is
13327  * specified, and @start_editing is %TRUE, then editing should be started in
13328  * the specified cell.  This function is often followed by
13329  * @gtk_widget_grab_focus (@tree_view) in order to give keyboard focus to the
13330  * widget.  Please note that editing can only happen when the widget is
13331  * realized.
13332  *
13333  * If @path is invalid for @model, the current cursor (if any) will be unset
13334  * and the function will return without failing.
13335  *
13336  * Since: 2.2
13337  **/
13338 void
13339 gtk_tree_view_set_cursor_on_cell (GtkTreeView       *tree_view,
13340                                   GtkTreePath       *path,
13341                                   GtkTreeViewColumn *focus_column,
13342                                   GtkCellRenderer   *focus_cell,
13343                                   gboolean           start_editing)
13344 {
13345   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13346   g_return_if_fail (path != NULL);
13347   g_return_if_fail (focus_column == NULL || GTK_IS_TREE_VIEW_COLUMN (focus_column));
13348
13349   if (!tree_view->priv->model)
13350     return;
13351
13352   if (focus_cell)
13353     {
13354       g_return_if_fail (focus_column);
13355       g_return_if_fail (GTK_IS_CELL_RENDERER (focus_cell));
13356     }
13357
13358   /* cancel the current editing, if it exists */
13359   if (tree_view->priv->edited_column &&
13360       gtk_cell_area_get_edit_widget
13361       (gtk_cell_layout_get_area (GTK_CELL_LAYOUT (tree_view->priv->edited_column))))
13362     gtk_tree_view_stop_editing (tree_view, TRUE);
13363
13364   gtk_tree_view_real_set_cursor (tree_view, path, CLEAR_AND_SELECT | CLAMP_NODE);
13365
13366   if (focus_column &&
13367       gtk_tree_view_column_get_visible (focus_column))
13368     {
13369       GList *list;
13370       gboolean column_in_tree = FALSE;
13371
13372       for (list = tree_view->priv->columns; list; list = list->next)
13373         if (list->data == focus_column)
13374           {
13375             column_in_tree = TRUE;
13376             break;
13377           }
13378       g_return_if_fail (column_in_tree);
13379       _gtk_tree_view_set_focus_column (tree_view, focus_column);
13380       if (focus_cell)
13381         gtk_tree_view_column_focus_cell (focus_column, focus_cell);
13382       if (start_editing)
13383         gtk_tree_view_start_editing (tree_view, path, TRUE);
13384     }
13385 }
13386
13387 /**
13388  * gtk_tree_view_get_bin_window:
13389  * @tree_view: A #GtkTreeView
13390  *
13391  * Returns the window that @tree_view renders to.
13392  * This is used primarily to compare to <literal>event->window</literal>
13393  * to confirm that the event on @tree_view is on the right window.
13394  *
13395  * Return value: (transfer none): A #GdkWindow, or %NULL when @tree_view
13396  *     hasn't been realized yet
13397  **/
13398 GdkWindow *
13399 gtk_tree_view_get_bin_window (GtkTreeView *tree_view)
13400 {
13401   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
13402
13403   return tree_view->priv->bin_window;
13404 }
13405
13406 /**
13407  * gtk_tree_view_get_path_at_pos:
13408  * @tree_view: A #GtkTreeView.
13409  * @x: The x position to be identified (relative to bin_window).
13410  * @y: The y position to be identified (relative to bin_window).
13411  * @path: (out) (allow-none): A pointer to a #GtkTreePath pointer to be filled in, or %NULL
13412  * @column: (out) (transfer none) (allow-none): A pointer to a #GtkTreeViewColumn pointer to be filled in, or %NULL
13413  * @cell_x: (out) (allow-none): A pointer where the X coordinate relative to the cell can be placed, or %NULL
13414  * @cell_y: (out) (allow-none): A pointer where the Y coordinate relative to the cell can be placed, or %NULL
13415  *
13416  * Finds the path at the point (@x, @y), relative to bin_window coordinates
13417  * (please see gtk_tree_view_get_bin_window()).
13418  * That is, @x and @y are relative to an events coordinates. @x and @y must
13419  * come from an event on the @tree_view only where <literal>event->window ==
13420  * gtk_tree_view_get_bin_window (<!-- -->)</literal>. It is primarily for
13421  * things like popup menus. If @path is non-%NULL, then it will be filled
13422  * with the #GtkTreePath at that point.  This path should be freed with
13423  * gtk_tree_path_free().  If @column is non-%NULL, then it will be filled
13424  * with the column at that point.  @cell_x and @cell_y return the coordinates
13425  * relative to the cell background (i.e. the @background_area passed to
13426  * gtk_cell_renderer_render()).  This function is only meaningful if
13427  * @tree_view is realized.  Therefore this function will always return %FALSE
13428  * if @tree_view is not realized or does not have a model.
13429  *
13430  * For converting widget coordinates (eg. the ones you get from
13431  * GtkWidget::query-tooltip), please see
13432  * gtk_tree_view_convert_widget_to_bin_window_coords().
13433  *
13434  * Return value: %TRUE if a row exists at that coordinate.
13435  **/
13436 gboolean
13437 gtk_tree_view_get_path_at_pos (GtkTreeView        *tree_view,
13438                                gint                x,
13439                                gint                y,
13440                                GtkTreePath       **path,
13441                                GtkTreeViewColumn **column,
13442                                gint               *cell_x,
13443                                gint               *cell_y)
13444 {
13445   GtkRBTree *tree;
13446   GtkRBNode *node;
13447   gint y_offset;
13448
13449   g_return_val_if_fail (tree_view != NULL, FALSE);
13450
13451   if (path)
13452     *path = NULL;
13453   if (column)
13454     *column = NULL;
13455
13456   if (tree_view->priv->bin_window == NULL)
13457     return FALSE;
13458
13459   if (tree_view->priv->tree == NULL)
13460     return FALSE;
13461
13462   if (x > gtk_adjustment_get_upper (tree_view->priv->hadjustment))
13463     return FALSE;
13464
13465   if (x < 0 || y < 0)
13466     return FALSE;
13467
13468   if (column || cell_x)
13469     {
13470       GtkTreeViewColumn *tmp_column;
13471       GtkTreeViewColumn *last_column = NULL;
13472       GList *list;
13473       gint remaining_x = x;
13474       gboolean found = FALSE;
13475       gboolean rtl;
13476       gint width;
13477
13478       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
13479       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
13480            list;
13481            list = (rtl ? list->prev : list->next))
13482         {
13483           tmp_column = list->data;
13484
13485           if (gtk_tree_view_column_get_visible (tmp_column) == FALSE)
13486             continue;
13487
13488           last_column = tmp_column;
13489           width = gtk_tree_view_column_get_width (tmp_column);
13490           if (remaining_x <= width)
13491             {
13492               found = TRUE;
13493
13494               if (column)
13495                 *column = tmp_column;
13496
13497               if (cell_x)
13498                 *cell_x = remaining_x;
13499
13500               break;
13501             }
13502           remaining_x -= width;
13503         }
13504
13505       /* If found is FALSE and there is a last_column, then it the remainder
13506        * space is in that area
13507        */
13508       if (!found)
13509         {
13510           if (last_column)
13511             {
13512               if (column)
13513                 *column = last_column;
13514               
13515               if (cell_x)
13516                 *cell_x = gtk_tree_view_column_get_width (last_column) + remaining_x;
13517             }
13518           else
13519             {
13520               return FALSE;
13521             }
13522         }
13523     }
13524
13525   y_offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
13526                                       TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, y),
13527                                       &tree, &node);
13528
13529   if (tree == NULL)
13530     return FALSE;
13531
13532   if (cell_y)
13533     *cell_y = y_offset;
13534
13535   if (path)
13536     *path = _gtk_tree_path_new_from_rbtree (tree, node);
13537
13538   return TRUE;
13539 }
13540
13541
13542 static inline gint
13543 gtk_tree_view_get_cell_area_height (GtkTreeView *tree_view,
13544                                     GtkRBNode   *node,
13545                                     gint         vertical_separator)
13546 {
13547   int expander_size = gtk_tree_view_get_expander_size (tree_view);
13548   int height;
13549
13550   /* The "cell" areas are the cell_area passed in to gtk_cell_renderer_render(),
13551    * i.e. just the cells, no spacing.
13552    *
13553    * The cell area height is at least expander_size - vertical_separator.
13554    * For regular nodes, the height is then at least expander_size. We should
13555    * be able to enforce the expander_size minimum here, because this
13556    * function will not be called for irregular (e.g. separator) rows.
13557    */
13558   height = gtk_tree_view_get_row_height (tree_view, node);
13559   if (height < expander_size)
13560     height = expander_size;
13561
13562   return height - vertical_separator;
13563 }
13564
13565 static inline gint
13566 gtk_tree_view_get_cell_area_y_offset (GtkTreeView *tree_view,
13567                                       GtkRBTree   *tree,
13568                                       GtkRBNode   *node,
13569                                       gint         vertical_separator)
13570 {
13571   int offset;
13572
13573   offset = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
13574   offset += vertical_separator / 2;
13575
13576   return offset;
13577 }
13578
13579 /**
13580  * gtk_tree_view_get_cell_area:
13581  * @tree_view: a #GtkTreeView
13582  * @path: (allow-none): a #GtkTreePath for the row, or %NULL to get only horizontal coordinates
13583  * @column: (allow-none): a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordinates
13584  * @rect: (out): rectangle to fill with cell rect
13585  *
13586  * Fills the bounding rectangle in bin_window coordinates for the cell at the
13587  * row specified by @path and the column specified by @column.  If @path is
13588  * %NULL, or points to a path not currently displayed, the @y and @height fields
13589  * of the rectangle will be filled with 0. If @column is %NULL, the @x and @width
13590  * fields will be filled with 0.  The sum of all cell rects does not cover the
13591  * entire tree; there are extra pixels in between rows, for example. The
13592  * returned rectangle is equivalent to the @cell_area passed to
13593  * gtk_cell_renderer_render().  This function is only valid if @tree_view is
13594  * realized.
13595  **/
13596 void
13597 gtk_tree_view_get_cell_area (GtkTreeView        *tree_view,
13598                              GtkTreePath        *path,
13599                              GtkTreeViewColumn  *column,
13600                              GdkRectangle       *rect)
13601 {
13602   GtkRBTree *tree = NULL;
13603   GtkRBNode *node = NULL;
13604   gint vertical_separator;
13605   gint horizontal_separator;
13606
13607   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13608   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
13609   g_return_if_fail (rect != NULL);
13610   g_return_if_fail (!column || gtk_tree_view_column_get_tree_view (column) == (GtkWidget *) tree_view);
13611   g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (tree_view)));
13612
13613   gtk_widget_style_get (GTK_WIDGET (tree_view),
13614                         "vertical-separator", &vertical_separator,
13615                         "horizontal-separator", &horizontal_separator,
13616                         NULL);
13617
13618   rect->x = 0;
13619   rect->y = 0;
13620   rect->width = 0;
13621   rect->height = 0;
13622
13623   if (column)
13624     {
13625       rect->x = gtk_tree_view_column_get_x_offset (column) + horizontal_separator/2;
13626       rect->width = gtk_tree_view_column_get_width (column) - horizontal_separator;
13627     }
13628
13629   if (path)
13630     {
13631       gboolean ret = _gtk_tree_view_find_node (tree_view, path, &tree, &node);
13632
13633       /* Get vertical coords */
13634       if ((!ret && tree == NULL) || ret)
13635         return;
13636
13637       if (row_is_separator (tree_view, NULL, path))
13638         {
13639           /* There isn't really a "cell area" for separator, so we
13640            * return the y, height values for background area instead.
13641            */
13642           rect->y = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
13643           rect->height = gtk_tree_view_get_row_height (tree_view, node);
13644         }
13645       else
13646         {
13647           rect->y = gtk_tree_view_get_cell_area_y_offset (tree_view, tree, node,
13648                                                           vertical_separator);
13649           rect->height = gtk_tree_view_get_cell_area_height (tree_view, node,
13650                                                              vertical_separator);
13651         }
13652
13653       if (column &&
13654           gtk_tree_view_is_expander_column (tree_view, column))
13655         {
13656           gint depth = gtk_tree_path_get_depth (path);
13657           gboolean rtl;
13658
13659           rtl = gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL;
13660
13661           if (!rtl)
13662             rect->x += (depth - 1) * tree_view->priv->level_indentation;
13663           rect->width -= (depth - 1) * tree_view->priv->level_indentation;
13664
13665           if (gtk_tree_view_draw_expanders (tree_view))
13666             {
13667               int expander_size = gtk_tree_view_get_expander_size (tree_view);
13668               if (!rtl)
13669                 rect->x += depth * expander_size;
13670               rect->width -= depth * expander_size;
13671             }
13672
13673           rect->width = MAX (rect->width, 0);
13674         }
13675     }
13676 }
13677
13678 static inline gint
13679 gtk_tree_view_get_row_height (GtkTreeView *tree_view,
13680                               GtkRBNode   *node)
13681 {
13682   int expander_size = gtk_tree_view_get_expander_size (tree_view);
13683   int height;
13684
13685   /* The "background" areas of all rows/cells add up to cover the entire tree.
13686    * The background includes all inter-row and inter-cell spacing.
13687    *
13688    * If the row pointed at by node does not have a height set, we default
13689    * to expander_size, which is the minimum height for regular nodes.
13690    * Non-regular nodes (e.g. separators) can have a height set smaller
13691    * than expander_size and should not be overruled here.
13692    */
13693   height = GTK_RBNODE_GET_HEIGHT (node);
13694   if (height <= 0)
13695     height = expander_size;
13696
13697   return height;
13698 }
13699
13700 static inline gint
13701 gtk_tree_view_get_row_y_offset (GtkTreeView *tree_view,
13702                                 GtkRBTree   *tree,
13703                                 GtkRBNode   *node)
13704 {
13705   int offset;
13706
13707   offset = _gtk_rbtree_node_find_offset (tree, node);
13708
13709   return RBTREE_Y_TO_TREE_WINDOW_Y (tree_view, offset);
13710 }
13711
13712 /**
13713  * gtk_tree_view_get_background_area:
13714  * @tree_view: a #GtkTreeView
13715  * @path: (allow-none): a #GtkTreePath for the row, or %NULL to get only horizontal coordinates
13716  * @column: (allow-none): a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordiantes
13717  * @rect: (out): rectangle to fill with cell background rect
13718  *
13719  * Fills the bounding rectangle in bin_window coordinates for the cell at the
13720  * row specified by @path and the column specified by @column.  If @path is
13721  * %NULL, or points to a node not found in the tree, the @y and @height fields of
13722  * the rectangle will be filled with 0. If @column is %NULL, the @x and @width
13723  * fields will be filled with 0.  The returned rectangle is equivalent to the
13724  * @background_area passed to gtk_cell_renderer_render().  These background
13725  * areas tile to cover the entire bin window.  Contrast with the @cell_area,
13726  * returned by gtk_tree_view_get_cell_area(), which returns only the cell
13727  * itself, excluding surrounding borders and the tree expander area.
13728  *
13729  **/
13730 void
13731 gtk_tree_view_get_background_area (GtkTreeView        *tree_view,
13732                                    GtkTreePath        *path,
13733                                    GtkTreeViewColumn  *column,
13734                                    GdkRectangle       *rect)
13735 {
13736   GtkRBTree *tree = NULL;
13737   GtkRBNode *node = NULL;
13738
13739   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13740   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
13741   g_return_if_fail (rect != NULL);
13742
13743   rect->x = 0;
13744   rect->y = 0;
13745   rect->width = 0;
13746   rect->height = 0;
13747
13748   if (path)
13749     {
13750       /* Get vertical coords */
13751
13752       if (!_gtk_tree_view_find_node (tree_view, path, &tree, &node) &&
13753           tree == NULL)
13754         return;
13755
13756       rect->y = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
13757       rect->height = gtk_tree_view_get_row_height (tree_view, node);
13758     }
13759
13760   if (column)
13761     {
13762       gint x2 = 0;
13763
13764       gtk_tree_view_get_background_xrange (tree_view, tree, column, &rect->x, &x2);
13765       rect->width = x2 - rect->x;
13766     }
13767 }
13768
13769 /**
13770  * gtk_tree_view_get_visible_rect:
13771  * @tree_view: a #GtkTreeView
13772  * @visible_rect: (out): rectangle to fill
13773  *
13774  * Fills @visible_rect with the currently-visible region of the
13775  * buffer, in tree coordinates. Convert to bin_window coordinates with
13776  * gtk_tree_view_convert_tree_to_bin_window_coords().
13777  * Tree coordinates start at 0,0 for row 0 of the tree, and cover the entire
13778  * scrollable area of the tree.
13779  **/
13780 void
13781 gtk_tree_view_get_visible_rect (GtkTreeView  *tree_view,
13782                                 GdkRectangle *visible_rect)
13783 {
13784   GtkAllocation allocation;
13785   GtkWidget *widget;
13786
13787   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13788
13789   widget = GTK_WIDGET (tree_view);
13790
13791   if (visible_rect)
13792     {
13793       gtk_widget_get_allocation (widget, &allocation);
13794       visible_rect->x = gtk_adjustment_get_value (tree_view->priv->hadjustment);
13795       visible_rect->y = gtk_adjustment_get_value (tree_view->priv->vadjustment);
13796       visible_rect->width = allocation.width;
13797       visible_rect->height = allocation.height - gtk_tree_view_get_effective_header_height (tree_view);
13798     }
13799 }
13800
13801 /**
13802  * gtk_tree_view_convert_widget_to_tree_coords:
13803  * @tree_view: a #GtkTreeView
13804  * @wx: X coordinate relative to the widget
13805  * @wy: Y coordinate relative to the widget
13806  * @tx: (out): return location for tree X coordinate
13807  * @ty: (out): return location for tree Y coordinate
13808  *
13809  * Converts widget coordinates to coordinates for the
13810  * tree (the full scrollable area of the tree).
13811  *
13812  * Since: 2.12
13813  **/
13814 void
13815 gtk_tree_view_convert_widget_to_tree_coords (GtkTreeView *tree_view,
13816                                              gint         wx,
13817                                              gint         wy,
13818                                              gint        *tx,
13819                                              gint        *ty)
13820 {
13821   gint x, y;
13822
13823   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13824
13825   gtk_tree_view_convert_widget_to_bin_window_coords (tree_view,
13826                                                      wx, wy,
13827                                                      &x, &y);
13828   gtk_tree_view_convert_bin_window_to_tree_coords (tree_view,
13829                                                    x, y,
13830                                                    tx, ty);
13831 }
13832
13833 /**
13834  * gtk_tree_view_convert_tree_to_widget_coords:
13835  * @tree_view: a #GtkTreeView
13836  * @tx: X coordinate relative to the tree
13837  * @ty: Y coordinate relative to the tree
13838  * @wx: (out): return location for widget X coordinate
13839  * @wy: (out): return location for widget Y coordinate
13840  *
13841  * Converts tree coordinates (coordinates in full scrollable area of the tree)
13842  * to widget coordinates.
13843  *
13844  * Since: 2.12
13845  **/
13846 void
13847 gtk_tree_view_convert_tree_to_widget_coords (GtkTreeView *tree_view,
13848                                              gint         tx,
13849                                              gint         ty,
13850                                              gint        *wx,
13851                                              gint        *wy)
13852 {
13853   gint x, y;
13854
13855   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13856
13857   gtk_tree_view_convert_tree_to_bin_window_coords (tree_view,
13858                                                    tx, ty,
13859                                                    &x, &y);
13860   gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
13861                                                      x, y,
13862                                                      wx, wy);
13863 }
13864
13865 /**
13866  * gtk_tree_view_convert_widget_to_bin_window_coords:
13867  * @tree_view: a #GtkTreeView
13868  * @wx: X coordinate relative to the widget
13869  * @wy: Y coordinate relative to the widget
13870  * @bx: (out): return location for bin_window X coordinate
13871  * @by: (out): return location for bin_window Y coordinate
13872  *
13873  * Converts widget coordinates to coordinates for the bin_window
13874  * (see gtk_tree_view_get_bin_window()).
13875  *
13876  * Since: 2.12
13877  **/
13878 void
13879 gtk_tree_view_convert_widget_to_bin_window_coords (GtkTreeView *tree_view,
13880                                                    gint         wx,
13881                                                    gint         wy,
13882                                                    gint        *bx,
13883                                                    gint        *by)
13884 {
13885   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13886
13887   if (bx)
13888     *bx = wx + gtk_adjustment_get_value (tree_view->priv->hadjustment);
13889   if (by)
13890     *by = wy - gtk_tree_view_get_effective_header_height (tree_view);
13891 }
13892
13893 /**
13894  * gtk_tree_view_convert_bin_window_to_widget_coords:
13895  * @tree_view: a #GtkTreeView
13896  * @bx: bin_window X coordinate
13897  * @by: bin_window Y coordinate
13898  * @wx: (out): return location for widget X coordinate
13899  * @wy: (out): return location for widget Y coordinate
13900  *
13901  * Converts bin_window coordinates (see gtk_tree_view_get_bin_window())
13902  * to widget relative coordinates.
13903  *
13904  * Since: 2.12
13905  **/
13906 void
13907 gtk_tree_view_convert_bin_window_to_widget_coords (GtkTreeView *tree_view,
13908                                                    gint         bx,
13909                                                    gint         by,
13910                                                    gint        *wx,
13911                                                    gint        *wy)
13912 {
13913   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13914
13915   if (wx)
13916     *wx = bx - gtk_adjustment_get_value (tree_view->priv->hadjustment);
13917   if (wy)
13918     *wy = by + gtk_tree_view_get_effective_header_height (tree_view);
13919 }
13920
13921 /**
13922  * gtk_tree_view_convert_tree_to_bin_window_coords:
13923  * @tree_view: a #GtkTreeView
13924  * @tx: tree X coordinate
13925  * @ty: tree Y coordinate
13926  * @bx: (out): return location for X coordinate relative to bin_window
13927  * @by: (out): return location for Y coordinate relative to bin_window
13928  *
13929  * Converts tree coordinates (coordinates in full scrollable area of the tree)
13930  * to bin_window coordinates.
13931  *
13932  * Since: 2.12
13933  **/
13934 void
13935 gtk_tree_view_convert_tree_to_bin_window_coords (GtkTreeView *tree_view,
13936                                                  gint         tx,
13937                                                  gint         ty,
13938                                                  gint        *bx,
13939                                                  gint        *by)
13940 {
13941   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13942
13943   if (bx)
13944     *bx = tx;
13945   if (by)
13946     *by = ty - tree_view->priv->dy;
13947 }
13948
13949 /**
13950  * gtk_tree_view_convert_bin_window_to_tree_coords:
13951  * @tree_view: a #GtkTreeView
13952  * @bx: X coordinate relative to bin_window
13953  * @by: Y coordinate relative to bin_window
13954  * @tx: (out): return location for tree X coordinate
13955  * @ty: (out): return location for tree Y coordinate
13956  *
13957  * Converts bin_window coordinates to coordinates for the
13958  * tree (the full scrollable area of the tree).
13959  *
13960  * Since: 2.12
13961  **/
13962 void
13963 gtk_tree_view_convert_bin_window_to_tree_coords (GtkTreeView *tree_view,
13964                                                  gint         bx,
13965                                                  gint         by,
13966                                                  gint        *tx,
13967                                                  gint        *ty)
13968 {
13969   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13970
13971   if (tx)
13972     *tx = bx;
13973   if (ty)
13974     *ty = by + tree_view->priv->dy;
13975 }
13976
13977
13978
13979 /**
13980  * gtk_tree_view_get_visible_range:
13981  * @tree_view: A #GtkTreeView
13982  * @start_path: (out) (allow-none): Return location for start of region,
13983  *              or %NULL.
13984  * @end_path: (out) (allow-none): Return location for end of region, or %NULL.
13985  *
13986  * Sets @start_path and @end_path to be the first and last visible path.
13987  * Note that there may be invisible paths in between.
13988  *
13989  * The paths should be freed with gtk_tree_path_free() after use.
13990  *
13991  * Returns: %TRUE, if valid paths were placed in @start_path and @end_path.
13992  *
13993  * Since: 2.8
13994  **/
13995 gboolean
13996 gtk_tree_view_get_visible_range (GtkTreeView  *tree_view,
13997                                  GtkTreePath **start_path,
13998                                  GtkTreePath **end_path)
13999 {
14000   GtkRBTree *tree;
14001   GtkRBNode *node;
14002   gboolean retval;
14003   
14004   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
14005
14006   if (!tree_view->priv->tree)
14007     return FALSE;
14008
14009   retval = TRUE;
14010
14011   if (start_path)
14012     {
14013       _gtk_rbtree_find_offset (tree_view->priv->tree,
14014                                TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, 0),
14015                                &tree, &node);
14016       if (node)
14017         *start_path = _gtk_tree_path_new_from_rbtree (tree, node);
14018       else
14019         retval = FALSE;
14020     }
14021
14022   if (end_path)
14023     {
14024       gint y;
14025
14026       if (tree_view->priv->height < gtk_adjustment_get_page_size (tree_view->priv->vadjustment))
14027         y = tree_view->priv->height - 1;
14028       else
14029         y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, gtk_adjustment_get_page_size (tree_view->priv->vadjustment)) - 1;
14030
14031       _gtk_rbtree_find_offset (tree_view->priv->tree, y, &tree, &node);
14032       if (node)
14033         *end_path = _gtk_tree_path_new_from_rbtree (tree, node);
14034       else
14035         retval = FALSE;
14036     }
14037
14038   return retval;
14039 }
14040
14041 /**
14042  * gtk_tree_view_is_blank_at_pos:
14043  * @tree_view: A #GtkTreeView
14044  * @x: The x position to be identified (relative to bin_window)
14045  * @y: The y position to be identified (relative to bin_window)
14046  * @path: (out) (allow-none): A pointer to a #GtkTreePath pointer to be filled in, or %NULL
14047  * @column: (out) (allow-none): A pointer to a #GtkTreeViewColumn pointer to be filled in, or %NULL
14048  * @cell_x: (out) (allow-none): A pointer where the X coordinate relative to the cell can be placed, or %NULL
14049  * @cell_y: (out) (allow-none): A pointer where the Y coordinate relative to the cell can be placed, or %NULL
14050  *
14051  * Determine whether the point (@x, @y) in @tree_view is blank, that is no
14052  * cell content nor an expander arrow is drawn at the location. If so, the
14053  * location can be considered as the background. You might wish to take
14054  * special action on clicks on the background, such as clearing a current
14055  * selection, having a custom context menu or starting rubber banding.
14056  *
14057  * The @x and @y coordinate that are provided must be relative to bin_window
14058  * coordinates.  That is, @x and @y must come from an event on @tree_view
14059  * where <literal>event->window == gtk_tree_view_get_bin_window (<!-- -->)</literal>.
14060  *
14061  * For converting widget coordinates (eg. the ones you get from
14062  * GtkWidget::query-tooltip), please see
14063  * gtk_tree_view_convert_widget_to_bin_window_coords().
14064  *
14065  * The @path, @column, @cell_x and @cell_y arguments will be filled in
14066  * likewise as for gtk_tree_view_get_path_at_pos().  Please see
14067  * gtk_tree_view_get_path_at_pos() for more information.
14068  *
14069  * Return value: %TRUE if the area at the given coordinates is blank,
14070  * %FALSE otherwise.
14071  *
14072  * Since: 3.0
14073  */
14074 gboolean
14075 gtk_tree_view_is_blank_at_pos (GtkTreeView       *tree_view,
14076                                gint                x,
14077                                gint                y,
14078                                GtkTreePath       **path,
14079                                GtkTreeViewColumn **column,
14080                                gint               *cell_x,
14081                                gint               *cell_y)
14082 {
14083   GtkRBTree *tree;
14084   GtkRBNode *node;
14085   GtkTreeIter iter;
14086   GtkTreePath *real_path;
14087   GtkTreeViewColumn *real_column;
14088   GdkRectangle cell_area, background_area;
14089
14090   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
14091
14092   if (!gtk_tree_view_get_path_at_pos (tree_view, x, y,
14093                                       &real_path, &real_column,
14094                                       cell_x, cell_y))
14095     /* If there's no path here, it is blank */
14096     return TRUE;
14097
14098   if (path)
14099     *path = real_path;
14100
14101   if (column)
14102     *column = real_column;
14103
14104   gtk_tree_model_get_iter (tree_view->priv->model, &iter, real_path);
14105   _gtk_tree_view_find_node (tree_view, real_path, &tree, &node);
14106
14107   /* Check if there's an expander arrow at (x, y) */
14108   if (real_column == tree_view->priv->expander_column
14109       && gtk_tree_view_draw_expanders (tree_view))
14110     {
14111       gboolean over_arrow;
14112
14113       over_arrow = coords_are_over_arrow (tree_view, tree, node, x, y);
14114
14115       if (over_arrow)
14116         {
14117           if (!path)
14118             gtk_tree_path_free (real_path);
14119           return FALSE;
14120         }
14121     }
14122
14123   /* Otherwise, have the column see if there's a cell at (x, y) */
14124   gtk_tree_view_column_cell_set_cell_data (real_column,
14125                                            tree_view->priv->model,
14126                                            &iter,
14127                                            GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
14128                                            node->children ? TRUE : FALSE);
14129
14130   gtk_tree_view_get_background_area (tree_view, real_path, real_column,
14131                                      &background_area);
14132   gtk_tree_view_get_cell_area (tree_view, real_path, real_column,
14133                                &cell_area);
14134
14135   if (!path)
14136     gtk_tree_path_free (real_path);
14137
14138   return _gtk_tree_view_column_is_blank_at_pos (real_column,
14139                                                 &cell_area,
14140                                                 &background_area,
14141                                                 x, y);
14142 }
14143
14144 static void
14145 unset_reorderable (GtkTreeView *tree_view)
14146 {
14147   if (tree_view->priv->reorderable)
14148     {
14149       tree_view->priv->reorderable = FALSE;
14150       g_object_notify (G_OBJECT (tree_view), "reorderable");
14151     }
14152 }
14153
14154 /**
14155  * gtk_tree_view_enable_model_drag_source:
14156  * @tree_view: a #GtkTreeView
14157  * @start_button_mask: Mask of allowed buttons to start drag
14158  * @targets: (array length=n_targets): the table of targets that the drag will support
14159  * @n_targets: the number of items in @targets
14160  * @actions: the bitmask of possible actions for a drag from this
14161  *    widget
14162  *
14163  * Turns @tree_view into a drag source for automatic DND. Calling this
14164  * method sets #GtkTreeView:reorderable to %FALSE.
14165  **/
14166 void
14167 gtk_tree_view_enable_model_drag_source (GtkTreeView              *tree_view,
14168                                         GdkModifierType           start_button_mask,
14169                                         const GtkTargetEntry     *targets,
14170                                         gint                      n_targets,
14171                                         GdkDragAction             actions)
14172 {
14173   TreeViewDragInfo *di;
14174
14175   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14176
14177   gtk_drag_source_set (GTK_WIDGET (tree_view),
14178                        0,
14179                        targets,
14180                        n_targets,
14181                        actions);
14182
14183   di = ensure_info (tree_view);
14184
14185   di->start_button_mask = start_button_mask;
14186   di->source_actions = actions;
14187   di->source_set = TRUE;
14188
14189   unset_reorderable (tree_view);
14190 }
14191
14192 /**
14193  * gtk_tree_view_enable_model_drag_dest:
14194  * @tree_view: a #GtkTreeView
14195  * @targets: (array length=n_targets): the table of targets that
14196  *           the drag will support
14197  * @n_targets: the number of items in @targets
14198  * @actions: the bitmask of possible actions for a drag from this
14199  *    widget
14200  * 
14201  * Turns @tree_view into a drop destination for automatic DND. Calling
14202  * this method sets #GtkTreeView:reorderable to %FALSE.
14203  **/
14204 void
14205 gtk_tree_view_enable_model_drag_dest (GtkTreeView              *tree_view,
14206                                       const GtkTargetEntry     *targets,
14207                                       gint                      n_targets,
14208                                       GdkDragAction             actions)
14209 {
14210   TreeViewDragInfo *di;
14211
14212   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14213
14214   gtk_drag_dest_set (GTK_WIDGET (tree_view),
14215                      0,
14216                      targets,
14217                      n_targets,
14218                      actions);
14219
14220   di = ensure_info (tree_view);
14221   di->dest_set = TRUE;
14222
14223   unset_reorderable (tree_view);
14224 }
14225
14226 /**
14227  * gtk_tree_view_unset_rows_drag_source:
14228  * @tree_view: a #GtkTreeView
14229  *
14230  * Undoes the effect of
14231  * gtk_tree_view_enable_model_drag_source(). Calling this method sets
14232  * #GtkTreeView:reorderable to %FALSE.
14233  **/
14234 void
14235 gtk_tree_view_unset_rows_drag_source (GtkTreeView *tree_view)
14236 {
14237   TreeViewDragInfo *di;
14238
14239   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14240
14241   di = get_info (tree_view);
14242
14243   if (di)
14244     {
14245       if (di->source_set)
14246         {
14247           gtk_drag_source_unset (GTK_WIDGET (tree_view));
14248           di->source_set = FALSE;
14249         }
14250
14251       if (!di->dest_set && !di->source_set)
14252         remove_info (tree_view);
14253     }
14254   
14255   unset_reorderable (tree_view);
14256 }
14257
14258 /**
14259  * gtk_tree_view_unset_rows_drag_dest:
14260  * @tree_view: a #GtkTreeView
14261  *
14262  * Undoes the effect of
14263  * gtk_tree_view_enable_model_drag_dest(). Calling this method sets
14264  * #GtkTreeView:reorderable to %FALSE.
14265  **/
14266 void
14267 gtk_tree_view_unset_rows_drag_dest (GtkTreeView *tree_view)
14268 {
14269   TreeViewDragInfo *di;
14270
14271   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14272
14273   di = get_info (tree_view);
14274
14275   if (di)
14276     {
14277       if (di->dest_set)
14278         {
14279           gtk_drag_dest_unset (GTK_WIDGET (tree_view));
14280           di->dest_set = FALSE;
14281         }
14282
14283       if (!di->dest_set && !di->source_set)
14284         remove_info (tree_view);
14285     }
14286
14287   unset_reorderable (tree_view);
14288 }
14289
14290 /**
14291  * gtk_tree_view_set_drag_dest_row:
14292  * @tree_view: a #GtkTreeView
14293  * @path: (allow-none): The path of the row to highlight, or %NULL
14294  * @pos: Specifies whether to drop before, after or into the row
14295  *
14296  * Sets the row that is highlighted for feedback.
14297  * If @path is %NULL, an existing highlight is removed.
14298  */
14299 void
14300 gtk_tree_view_set_drag_dest_row (GtkTreeView            *tree_view,
14301                                  GtkTreePath            *path,
14302                                  GtkTreeViewDropPosition pos)
14303 {
14304   GtkTreePath *current_dest;
14305
14306   /* Note; this function is exported to allow a custom DND
14307    * implementation, so it can't touch TreeViewDragInfo
14308    */
14309
14310   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14311
14312   current_dest = NULL;
14313
14314   if (tree_view->priv->drag_dest_row)
14315     {
14316       current_dest = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
14317       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
14318     }
14319
14320   /* special case a drop on an empty model */
14321   tree_view->priv->empty_view_drop = 0;
14322
14323   if (pos == GTK_TREE_VIEW_DROP_BEFORE && path
14324       && gtk_tree_path_get_depth (path) == 1
14325       && gtk_tree_path_get_indices (path)[0] == 0)
14326     {
14327       gint n_children;
14328
14329       n_children = gtk_tree_model_iter_n_children (tree_view->priv->model,
14330                                                    NULL);
14331
14332       if (!n_children)
14333         tree_view->priv->empty_view_drop = 1;
14334     }
14335
14336   tree_view->priv->drag_dest_pos = pos;
14337
14338   if (path)
14339     {
14340       tree_view->priv->drag_dest_row =
14341         gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
14342       gtk_tree_view_queue_draw_path (tree_view, path, NULL);
14343     }
14344   else
14345     tree_view->priv->drag_dest_row = NULL;
14346
14347   if (current_dest)
14348     {
14349       GtkRBTree *tree, *new_tree;
14350       GtkRBNode *node, *new_node;
14351
14352       _gtk_tree_view_find_node (tree_view, current_dest, &tree, &node);
14353       _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
14354
14355       if (tree && node)
14356         {
14357           _gtk_rbtree_next_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_rbtree_prev_full (tree, node, &new_tree, &new_node);
14362           if (new_tree && new_node)
14363             _gtk_tree_view_queue_draw_node (tree_view, new_tree, new_node, NULL);
14364         }
14365       gtk_tree_path_free (current_dest);
14366     }
14367 }
14368
14369 /**
14370  * gtk_tree_view_get_drag_dest_row:
14371  * @tree_view: a #GtkTreeView
14372  * @path: (out) (allow-none): Return location for the path of the highlighted row, or %NULL.
14373  * @pos: (out) (allow-none): Return location for the drop position, or %NULL
14374  * 
14375  * Gets information about the row that is highlighted for feedback.
14376  **/
14377 void
14378 gtk_tree_view_get_drag_dest_row (GtkTreeView              *tree_view,
14379                                  GtkTreePath             **path,
14380                                  GtkTreeViewDropPosition  *pos)
14381 {
14382   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14383
14384   if (path)
14385     {
14386       if (tree_view->priv->drag_dest_row)
14387         *path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
14388       else
14389         {
14390           if (tree_view->priv->empty_view_drop)
14391             *path = gtk_tree_path_new_from_indices (0, -1);
14392           else
14393             *path = NULL;
14394         }
14395     }
14396
14397   if (pos)
14398     *pos = tree_view->priv->drag_dest_pos;
14399 }
14400
14401 /**
14402  * gtk_tree_view_get_dest_row_at_pos:
14403  * @tree_view: a #GtkTreeView
14404  * @drag_x: the position to determine the destination row for
14405  * @drag_y: the position to determine the destination row for
14406  * @path: (out) (allow-none): Return location for the path of the highlighted row, or %NULL.
14407  * @pos: (out) (allow-none): Return location for the drop position, or %NULL
14408  * 
14409  * Determines the destination row for a given position.  @drag_x and
14410  * @drag_y are expected to be in widget coordinates.  This function is only
14411  * meaningful if @tree_view is realized.  Therefore this function will always
14412  * return %FALSE if @tree_view is not realized or does not have a model.
14413  * 
14414  * Return value: whether there is a row at the given position, %TRUE if this
14415  * is indeed the case.
14416  **/
14417 gboolean
14418 gtk_tree_view_get_dest_row_at_pos (GtkTreeView             *tree_view,
14419                                    gint                     drag_x,
14420                                    gint                     drag_y,
14421                                    GtkTreePath            **path,
14422                                    GtkTreeViewDropPosition *pos)
14423 {
14424   gint cell_y;
14425   gint bin_x, bin_y;
14426   gdouble offset_into_row;
14427   gdouble third;
14428   GdkRectangle cell;
14429   GtkTreeViewColumn *column = NULL;
14430   GtkTreePath *tmp_path = NULL;
14431
14432   /* Note; this function is exported to allow a custom DND
14433    * implementation, so it can't touch TreeViewDragInfo
14434    */
14435
14436   g_return_val_if_fail (tree_view != NULL, FALSE);
14437   g_return_val_if_fail (drag_x >= 0, FALSE);
14438   g_return_val_if_fail (drag_y >= 0, FALSE);
14439
14440   if (path)
14441     *path = NULL;
14442
14443   if (tree_view->priv->bin_window == NULL)
14444     return FALSE;
14445
14446   if (tree_view->priv->tree == NULL)
14447     return FALSE;
14448
14449   /* If in the top third of a row, we drop before that row; if
14450    * in the bottom third, drop after that row; if in the middle,
14451    * and the row has children, drop into the row.
14452    */
14453   gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, drag_x, drag_y,
14454                                                      &bin_x, &bin_y);
14455
14456   if (!gtk_tree_view_get_path_at_pos (tree_view,
14457                                       bin_x,
14458                                       bin_y,
14459                                       &tmp_path,
14460                                       &column,
14461                                       NULL,
14462                                       &cell_y))
14463     return FALSE;
14464
14465   gtk_tree_view_get_background_area (tree_view, tmp_path, column,
14466                                      &cell);
14467
14468   offset_into_row = cell_y;
14469
14470   if (path)
14471     *path = tmp_path;
14472   else
14473     gtk_tree_path_free (tmp_path);
14474
14475   tmp_path = NULL;
14476
14477   third = cell.height / 3.0;
14478
14479   if (pos)
14480     {
14481       if (offset_into_row < third)
14482         {
14483           *pos = GTK_TREE_VIEW_DROP_BEFORE;
14484         }
14485       else if (offset_into_row < (cell.height / 2.0))
14486         {
14487           *pos = GTK_TREE_VIEW_DROP_INTO_OR_BEFORE;
14488         }
14489       else if (offset_into_row < third * 2.0)
14490         {
14491           *pos = GTK_TREE_VIEW_DROP_INTO_OR_AFTER;
14492         }
14493       else
14494         {
14495           *pos = GTK_TREE_VIEW_DROP_AFTER;
14496         }
14497     }
14498
14499   return TRUE;
14500 }
14501
14502
14503
14504 /* KEEP IN SYNC WITH GTK_TREE_VIEW_BIN_EXPOSE */
14505 /**
14506  * gtk_tree_view_create_row_drag_icon:
14507  * @tree_view: a #GtkTreeView
14508  * @path: a #GtkTreePath in @tree_view
14509  *
14510  * Creates a #cairo_surface_t representation of the row at @path.  
14511  * This image is used for a drag icon.
14512  *
14513  * Return value: (transfer full): a newly-allocated surface of the drag icon.
14514  **/
14515 cairo_surface_t *
14516 gtk_tree_view_create_row_drag_icon (GtkTreeView  *tree_view,
14517                                     GtkTreePath  *path)
14518 {
14519   GtkTreeIter   iter;
14520   GtkRBTree    *tree;
14521   GtkRBNode    *node;
14522   GtkStyleContext *context;
14523   gint cell_offset;
14524   GList *list;
14525   GdkRectangle background_area;
14526   GtkWidget *widget;
14527   gint depth;
14528   /* start drawing inside the black outline */
14529   gint x = 1, y = 1;
14530   cairo_surface_t *surface;
14531   gint bin_window_width;
14532   gboolean is_separator = FALSE;
14533   gboolean rtl, allow_rules;
14534   cairo_t *cr;
14535
14536   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14537   g_return_val_if_fail (path != NULL, NULL);
14538
14539   widget = GTK_WIDGET (tree_view);
14540
14541   if (!gtk_widget_get_realized (widget))
14542     return NULL;
14543
14544   depth = gtk_tree_path_get_depth (path);
14545
14546   _gtk_tree_view_find_node (tree_view,
14547                             path,
14548                             &tree,
14549                             &node);
14550
14551   if (tree == NULL)
14552     return NULL;
14553
14554   if (!gtk_tree_model_get_iter (tree_view->priv->model,
14555                                 &iter,
14556                                 path))
14557     return NULL;
14558
14559   context = gtk_widget_get_style_context (widget);
14560
14561   gtk_style_context_save (context);
14562
14563   gtk_style_context_add_class (context, GTK_STYLE_CLASS_VIEW);
14564   gtk_style_context_add_region (context, GTK_STYLE_REGION_COLUMN, 0);
14565
14566   gtk_widget_style_get (widget,
14567                         "allow-rules", &allow_rules,
14568                         NULL);
14569
14570   if (allow_rules && tree_view->priv->has_rules)
14571     {
14572       GtkRegionFlags row_flags;
14573
14574       if ((_gtk_rbtree_node_get_index (tree, node) % 2))
14575         row_flags = GTK_REGION_ODD;
14576       else
14577         row_flags = GTK_REGION_EVEN;
14578
14579       gtk_style_context_add_region (context, GTK_STYLE_REGION_ROW, row_flags);
14580     }
14581
14582   is_separator = row_is_separator (tree_view, &iter, NULL);
14583
14584   cell_offset = x;
14585
14586   background_area.y = y;
14587   background_area.height = gtk_tree_view_get_row_height (tree_view, node);
14588
14589   bin_window_width = gdk_window_get_width (tree_view->priv->bin_window);
14590
14591   surface = gdk_window_create_similar_surface (tree_view->priv->bin_window,
14592                                                CAIRO_CONTENT_COLOR,
14593                                                bin_window_width + 2,
14594                                                background_area.height + 2);
14595
14596   cr = cairo_create (surface);
14597
14598   gtk_render_background (context, cr, 0, 0,
14599                          bin_window_width + 2,
14600                          background_area.height + 2);
14601
14602   rtl = gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL;
14603
14604   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
14605       list;
14606       list = (rtl ? list->prev : list->next))
14607     {
14608       GtkTreeViewColumn *column = list->data;
14609       GdkRectangle cell_area;
14610       gint vertical_separator;
14611
14612       if (!gtk_tree_view_column_get_visible (column))
14613         continue;
14614
14615       gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, &iter,
14616                                                GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
14617                                                node->children?TRUE:FALSE);
14618
14619       background_area.x = cell_offset;
14620       background_area.width = gtk_tree_view_column_get_width (column);
14621
14622       gtk_widget_style_get (widget,
14623                             "vertical-separator", &vertical_separator,
14624                             NULL);
14625
14626       cell_area = background_area;
14627
14628       cell_area.y += vertical_separator / 2;
14629       cell_area.height -= vertical_separator;
14630
14631       if (gtk_tree_view_is_expander_column (tree_view, column))
14632         {
14633           if (!rtl)
14634             cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
14635           cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
14636
14637           if (gtk_tree_view_draw_expanders (tree_view))
14638             {
14639               int expander_size = gtk_tree_view_get_expander_size (tree_view);
14640               if (!rtl)
14641                 cell_area.x += depth * expander_size;
14642               cell_area.width -= depth * expander_size;
14643             }
14644         }
14645
14646       if (gtk_tree_view_column_cell_is_visible (column))
14647         {
14648           if (is_separator)
14649             {
14650               gtk_style_context_save (context);
14651               gtk_style_context_add_class (context, GTK_STYLE_CLASS_SEPARATOR);
14652
14653               gtk_render_line (context, cr,
14654                                cell_area.x,
14655                                cell_area.y + cell_area.height / 2,
14656                                cell_area.x + cell_area.width,
14657                                cell_area.y + cell_area.height / 2);
14658
14659               gtk_style_context_restore (context);
14660             }
14661           else
14662             {
14663               _gtk_tree_view_column_cell_render (column,
14664                                                  cr,
14665                                                  &background_area,
14666                                                  &cell_area,
14667                                                  0, FALSE);
14668             }
14669         }
14670       cell_offset += gtk_tree_view_column_get_width (column);
14671     }
14672
14673   cairo_set_source_rgb (cr, 0, 0, 0);
14674   cairo_rectangle (cr, 
14675                    0.5, 0.5, 
14676                    bin_window_width + 1,
14677                    background_area.height + 1);
14678   cairo_set_line_width (cr, 1.0);
14679   cairo_stroke (cr);
14680
14681   cairo_destroy (cr);
14682
14683   cairo_surface_set_device_offset (surface, 2, 2);
14684
14685   gtk_style_context_restore (context);
14686
14687   return surface;
14688 }
14689
14690
14691 /**
14692  * gtk_tree_view_set_destroy_count_func:
14693  * @tree_view: A #GtkTreeView
14694  * @func: (allow-none): Function to be called when a view row is destroyed, or %NULL
14695  * @data: (allow-none): User data to be passed to @func, or %NULL
14696  * @destroy: (allow-none): Destroy notifier for @data, or %NULL
14697  *
14698  * This function should almost never be used.  It is meant for private use by
14699  * ATK for determining the number of visible children that are removed when the
14700  * user collapses a row, or a row is deleted.
14701  *
14702  * Deprecated: 3.4: Accessibility does not need the function anymore.
14703  **/
14704 void
14705 gtk_tree_view_set_destroy_count_func (GtkTreeView             *tree_view,
14706                                       GtkTreeDestroyCountFunc  func,
14707                                       gpointer                 data,
14708                                       GDestroyNotify           destroy)
14709 {
14710   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14711
14712   if (tree_view->priv->destroy_count_destroy)
14713     tree_view->priv->destroy_count_destroy (tree_view->priv->destroy_count_data);
14714
14715   tree_view->priv->destroy_count_func = func;
14716   tree_view->priv->destroy_count_data = data;
14717   tree_view->priv->destroy_count_destroy = destroy;
14718 }
14719
14720
14721 /*
14722  * Interactive search
14723  */
14724
14725 /**
14726  * gtk_tree_view_set_enable_search:
14727  * @tree_view: A #GtkTreeView
14728  * @enable_search: %TRUE, if the user can search interactively
14729  *
14730  * If @enable_search is set, then the user can type in text to search through
14731  * the tree interactively (this is sometimes called "typeahead find").
14732  * 
14733  * Note that even if this is %FALSE, the user can still initiate a search 
14734  * using the "start-interactive-search" key binding.
14735  */
14736 void
14737 gtk_tree_view_set_enable_search (GtkTreeView *tree_view,
14738                                  gboolean     enable_search)
14739 {
14740   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14741
14742   enable_search = !!enable_search;
14743   
14744   if (tree_view->priv->enable_search != enable_search)
14745     {
14746        tree_view->priv->enable_search = enable_search;
14747        g_object_notify (G_OBJECT (tree_view), "enable-search");
14748     }
14749 }
14750
14751 /**
14752  * gtk_tree_view_get_enable_search:
14753  * @tree_view: A #GtkTreeView
14754  *
14755  * Returns whether or not the tree allows to start interactive searching 
14756  * by typing in text.
14757  *
14758  * Return value: whether or not to let the user search interactively
14759  */
14760 gboolean
14761 gtk_tree_view_get_enable_search (GtkTreeView *tree_view)
14762 {
14763   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
14764
14765   return tree_view->priv->enable_search;
14766 }
14767
14768
14769 /**
14770  * gtk_tree_view_get_search_column:
14771  * @tree_view: A #GtkTreeView
14772  *
14773  * Gets the column searched on by the interactive search code.
14774  *
14775  * Return value: the column the interactive search code searches in.
14776  */
14777 gint
14778 gtk_tree_view_get_search_column (GtkTreeView *tree_view)
14779 {
14780   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
14781
14782   return (tree_view->priv->search_column);
14783 }
14784
14785 /**
14786  * gtk_tree_view_set_search_column:
14787  * @tree_view: A #GtkTreeView
14788  * @column: the column of the model to search in, or -1 to disable searching
14789  *
14790  * Sets @column as the column where the interactive search code should
14791  * search in for the current model. 
14792  * 
14793  * If the search column is set, users can use the "start-interactive-search"
14794  * key binding to bring up search popup. The enable-search property controls
14795  * whether simply typing text will also start an interactive search.
14796  *
14797  * Note that @column refers to a column of the current model. The search 
14798  * column is reset to -1 when the model is changed.
14799  */
14800 void
14801 gtk_tree_view_set_search_column (GtkTreeView *tree_view,
14802                                  gint         column)
14803 {
14804   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14805   g_return_if_fail (column >= -1);
14806
14807   if (tree_view->priv->search_column == column)
14808     return;
14809
14810   tree_view->priv->search_column = column;
14811   g_object_notify (G_OBJECT (tree_view), "search-column");
14812 }
14813
14814 /**
14815  * gtk_tree_view_get_search_equal_func: (skip)
14816  * @tree_view: A #GtkTreeView
14817  *
14818  * Returns the compare function currently in use.
14819  *
14820  * Return value: the currently used compare function for the search code.
14821  */
14822
14823 GtkTreeViewSearchEqualFunc
14824 gtk_tree_view_get_search_equal_func (GtkTreeView *tree_view)
14825 {
14826   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14827
14828   return tree_view->priv->search_equal_func;
14829 }
14830
14831 /**
14832  * gtk_tree_view_set_search_equal_func:
14833  * @tree_view: A #GtkTreeView
14834  * @search_equal_func: the compare function to use during the search
14835  * @search_user_data: (allow-none): user data to pass to @search_equal_func, or %NULL
14836  * @search_destroy: (allow-none): Destroy notifier for @search_user_data, or %NULL
14837  *
14838  * Sets the compare function for the interactive search capabilities; note
14839  * that somewhat like strcmp() returning 0 for equality
14840  * #GtkTreeViewSearchEqualFunc returns %FALSE on matches.
14841  **/
14842 void
14843 gtk_tree_view_set_search_equal_func (GtkTreeView                *tree_view,
14844                                      GtkTreeViewSearchEqualFunc  search_equal_func,
14845                                      gpointer                    search_user_data,
14846                                      GDestroyNotify              search_destroy)
14847 {
14848   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14849   g_return_if_fail (search_equal_func != NULL);
14850
14851   if (tree_view->priv->search_destroy)
14852     tree_view->priv->search_destroy (tree_view->priv->search_user_data);
14853
14854   tree_view->priv->search_equal_func = search_equal_func;
14855   tree_view->priv->search_user_data = search_user_data;
14856   tree_view->priv->search_destroy = search_destroy;
14857   if (tree_view->priv->search_equal_func == NULL)
14858     tree_view->priv->search_equal_func = gtk_tree_view_search_equal_func;
14859 }
14860
14861 /**
14862  * gtk_tree_view_get_search_entry:
14863  * @tree_view: A #GtkTreeView
14864  *
14865  * Returns the #GtkEntry which is currently in use as interactive search
14866  * entry for @tree_view.  In case the built-in entry is being used, %NULL
14867  * will be returned.
14868  *
14869  * Return value: (transfer none): the entry currently in use as search entry.
14870  *
14871  * Since: 2.10
14872  */
14873 GtkEntry *
14874 gtk_tree_view_get_search_entry (GtkTreeView *tree_view)
14875 {
14876   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14877
14878   if (tree_view->priv->search_custom_entry_set)
14879     return GTK_ENTRY (tree_view->priv->search_entry);
14880
14881   return NULL;
14882 }
14883
14884 /**
14885  * gtk_tree_view_set_search_entry:
14886  * @tree_view: A #GtkTreeView
14887  * @entry: (allow-none): the entry the interactive search code of @tree_view should use or %NULL
14888  *
14889  * Sets the entry which the interactive search code will use for this
14890  * @tree_view.  This is useful when you want to provide a search entry
14891  * in our interface at all time at a fixed position.  Passing %NULL for
14892  * @entry will make the interactive search code use the built-in popup
14893  * entry again.
14894  *
14895  * Since: 2.10
14896  */
14897 void
14898 gtk_tree_view_set_search_entry (GtkTreeView *tree_view,
14899                                 GtkEntry    *entry)
14900 {
14901   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14902   g_return_if_fail (entry == NULL || GTK_IS_ENTRY (entry));
14903
14904   if (tree_view->priv->search_custom_entry_set)
14905     {
14906       if (tree_view->priv->search_entry_changed_id)
14907         {
14908           g_signal_handler_disconnect (tree_view->priv->search_entry,
14909                                        tree_view->priv->search_entry_changed_id);
14910           tree_view->priv->search_entry_changed_id = 0;
14911         }
14912       g_signal_handlers_disconnect_by_func (tree_view->priv->search_entry,
14913                                             G_CALLBACK (gtk_tree_view_search_key_press_event),
14914                                             tree_view);
14915
14916       g_object_unref (tree_view->priv->search_entry);
14917     }
14918   else if (tree_view->priv->search_window)
14919     {
14920       gtk_widget_destroy (tree_view->priv->search_window);
14921
14922       tree_view->priv->search_window = NULL;
14923     }
14924
14925   if (entry)
14926     {
14927       tree_view->priv->search_entry = g_object_ref (entry);
14928       tree_view->priv->search_custom_entry_set = TRUE;
14929
14930       if (tree_view->priv->search_entry_changed_id == 0)
14931         {
14932           tree_view->priv->search_entry_changed_id =
14933             g_signal_connect (tree_view->priv->search_entry, "changed",
14934                               G_CALLBACK (gtk_tree_view_search_init),
14935                               tree_view);
14936         }
14937       
14938         g_signal_connect (tree_view->priv->search_entry, "key-press-event",
14939                           G_CALLBACK (gtk_tree_view_search_key_press_event),
14940                           tree_view);
14941
14942         gtk_tree_view_search_init (tree_view->priv->search_entry, tree_view);
14943     }
14944   else
14945     {
14946       tree_view->priv->search_entry = NULL;
14947       tree_view->priv->search_custom_entry_set = FALSE;
14948     }
14949 }
14950
14951 /**
14952  * gtk_tree_view_set_search_position_func:
14953  * @tree_view: A #GtkTreeView
14954  * @func: (allow-none): the function to use to position the search dialog, or %NULL
14955  *    to use the default search position function
14956  * @data: (allow-none): user data to pass to @func, or %NULL
14957  * @destroy: (allow-none): Destroy notifier for @data, or %NULL
14958  *
14959  * Sets the function to use when positioning the search dialog.
14960  *
14961  * Since: 2.10
14962  **/
14963 void
14964 gtk_tree_view_set_search_position_func (GtkTreeView                   *tree_view,
14965                                         GtkTreeViewSearchPositionFunc  func,
14966                                         gpointer                       user_data,
14967                                         GDestroyNotify                 destroy)
14968 {
14969   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14970
14971   if (tree_view->priv->search_position_destroy)
14972     tree_view->priv->search_position_destroy (tree_view->priv->search_position_user_data);
14973
14974   tree_view->priv->search_position_func = func;
14975   tree_view->priv->search_position_user_data = user_data;
14976   tree_view->priv->search_position_destroy = destroy;
14977   if (tree_view->priv->search_position_func == NULL)
14978     tree_view->priv->search_position_func = gtk_tree_view_search_position_func;
14979 }
14980
14981 /**
14982  * gtk_tree_view_get_search_position_func: (skip)
14983  * @tree_view: A #GtkTreeView
14984  *
14985  * Returns the positioning function currently in use.
14986  *
14987  * Return value: the currently used function for positioning the search dialog.
14988  *
14989  * Since: 2.10
14990  */
14991 GtkTreeViewSearchPositionFunc
14992 gtk_tree_view_get_search_position_func (GtkTreeView *tree_view)
14993 {
14994   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14995
14996   return tree_view->priv->search_position_func;
14997 }
14998
14999
15000 static void
15001 gtk_tree_view_search_dialog_hide (GtkWidget   *search_dialog,
15002                                   GtkTreeView *tree_view,
15003                                   GdkDevice   *device)
15004 {
15005   if (tree_view->priv->disable_popdown)
15006     return;
15007
15008   if (tree_view->priv->search_entry_changed_id)
15009     {
15010       g_signal_handler_disconnect (tree_view->priv->search_entry,
15011                                    tree_view->priv->search_entry_changed_id);
15012       tree_view->priv->search_entry_changed_id = 0;
15013     }
15014   if (tree_view->priv->typeselect_flush_timeout)
15015     {
15016       g_source_remove (tree_view->priv->typeselect_flush_timeout);
15017       tree_view->priv->typeselect_flush_timeout = 0;
15018     }
15019         
15020   if (gtk_widget_get_visible (search_dialog))
15021     {
15022       /* send focus-in event */
15023       send_focus_change (GTK_WIDGET (tree_view->priv->search_entry), device, FALSE);
15024       gtk_widget_hide (search_dialog);
15025       gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
15026       send_focus_change (GTK_WIDGET (tree_view), device, TRUE);
15027     }
15028 }
15029
15030 static void
15031 gtk_tree_view_search_position_func (GtkTreeView *tree_view,
15032                                     GtkWidget   *search_dialog,
15033                                     gpointer     user_data)
15034 {
15035   gint x, y;
15036   gint tree_x, tree_y;
15037   gint tree_width, tree_height;
15038   GdkWindow *tree_window = gtk_widget_get_window (GTK_WIDGET (tree_view));
15039   GdkScreen *screen = gdk_window_get_screen (tree_window);
15040   GtkRequisition requisition;
15041   gint monitor_num;
15042   GdkRectangle monitor;
15043
15044   monitor_num = gdk_screen_get_monitor_at_window (screen, tree_window);
15045   gdk_screen_get_monitor_workarea (screen, monitor_num, &monitor);
15046
15047   gtk_widget_realize (search_dialog);
15048
15049   gdk_window_get_origin (tree_window, &tree_x, &tree_y);
15050   tree_width = gdk_window_get_width (tree_window);
15051   tree_height = gdk_window_get_height (tree_window);
15052   gtk_widget_get_preferred_size (search_dialog, &requisition, NULL);
15053
15054   if (tree_x + tree_width > gdk_screen_get_width (screen))
15055     x = gdk_screen_get_width (screen) - requisition.width;
15056   else if (tree_x + tree_width - requisition.width < 0)
15057     x = 0;
15058   else
15059     x = tree_x + tree_width - requisition.width;
15060
15061   if (tree_y + tree_height + requisition.height > gdk_screen_get_height (screen))
15062     y = gdk_screen_get_height (screen) - requisition.height;
15063   else if (tree_y + tree_height < 0) /* isn't really possible ... */
15064     y = 0;
15065   else
15066     y = tree_y + tree_height;
15067
15068   gtk_window_move (GTK_WINDOW (search_dialog), x, y);
15069 }
15070
15071 static void
15072 gtk_tree_view_search_disable_popdown (GtkEntry *entry,
15073                                       GtkMenu  *menu,
15074                                       gpointer  data)
15075 {
15076   GtkTreeView *tree_view = (GtkTreeView *)data;
15077
15078   tree_view->priv->disable_popdown = 1;
15079   g_signal_connect (menu, "hide",
15080                     G_CALLBACK (gtk_tree_view_search_enable_popdown), data);
15081 }
15082
15083 /* Because we're visible but offscreen, we just set a flag in the preedit
15084  * callback.
15085  */
15086 static void
15087 gtk_tree_view_search_preedit_changed (GtkIMContext *im_context,
15088                                       GtkTreeView  *tree_view)
15089 {
15090   tree_view->priv->imcontext_changed = 1;
15091   if (tree_view->priv->typeselect_flush_timeout)
15092     {
15093       g_source_remove (tree_view->priv->typeselect_flush_timeout);
15094       tree_view->priv->typeselect_flush_timeout =
15095         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
15096                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
15097                        tree_view);
15098     }
15099
15100 }
15101
15102 static void
15103 gtk_tree_view_search_activate (GtkEntry    *entry,
15104                                GtkTreeView *tree_view)
15105 {
15106   GtkTreePath *path;
15107
15108   gtk_tree_view_search_dialog_hide (tree_view->priv->search_window,
15109                                     tree_view,
15110                                     gtk_get_current_event_device ());
15111
15112   /* If we have a row selected and it's the cursor row, we activate
15113    * the row XXX */
15114   if (tree_view->priv->cursor_node &&
15115       GTK_RBNODE_FLAG_SET (tree_view->priv->cursor_node, GTK_RBNODE_IS_SELECTED))
15116     {
15117       path = _gtk_tree_path_new_from_rbtree (tree_view->priv->cursor_tree,
15118                                              tree_view->priv->cursor_node);
15119       
15120       gtk_tree_view_row_activated (tree_view, path, tree_view->priv->focus_column);
15121       
15122       gtk_tree_path_free (path);
15123     }
15124 }
15125
15126 static gboolean
15127 gtk_tree_view_real_search_enable_popdown (gpointer data)
15128 {
15129   GtkTreeView *tree_view = (GtkTreeView *)data;
15130
15131   tree_view->priv->disable_popdown = 0;
15132
15133   return FALSE;
15134 }
15135
15136 static void
15137 gtk_tree_view_search_enable_popdown (GtkWidget *widget,
15138                                      gpointer   data)
15139 {
15140   gdk_threads_add_timeout_full (G_PRIORITY_HIGH, 200, gtk_tree_view_real_search_enable_popdown, g_object_ref (data), g_object_unref);
15141 }
15142
15143 static gboolean
15144 gtk_tree_view_search_delete_event (GtkWidget *widget,
15145                                    GdkEventAny *event,
15146                                    GtkTreeView *tree_view)
15147 {
15148   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
15149
15150   gtk_tree_view_search_dialog_hide (widget, tree_view, NULL);
15151
15152   return TRUE;
15153 }
15154
15155 static gboolean
15156 gtk_tree_view_search_button_press_event (GtkWidget *widget,
15157                                          GdkEventButton *event,
15158                                          GtkTreeView *tree_view)
15159 {
15160   GdkDevice *keyb_device;
15161
15162   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
15163
15164   keyb_device = gdk_device_get_associated_device (event->device);
15165   gtk_tree_view_search_dialog_hide (widget, tree_view, keyb_device);
15166
15167   if (event->window == tree_view->priv->bin_window)
15168     gtk_tree_view_button_press (GTK_WIDGET (tree_view), event);
15169
15170   return TRUE;
15171 }
15172
15173 static gboolean
15174 gtk_tree_view_search_scroll_event (GtkWidget *widget,
15175                                    GdkEventScroll *event,
15176                                    GtkTreeView *tree_view)
15177 {
15178   gboolean retval = FALSE;
15179
15180   if (event->direction == GDK_SCROLL_UP)
15181     {
15182       gtk_tree_view_search_move (widget, tree_view, TRUE);
15183       retval = TRUE;
15184     }
15185   else if (event->direction == GDK_SCROLL_DOWN)
15186     {
15187       gtk_tree_view_search_move (widget, tree_view, FALSE);
15188       retval = TRUE;
15189     }
15190
15191   /* renew the flush timeout */
15192   if (retval && tree_view->priv->typeselect_flush_timeout
15193       && !tree_view->priv->search_custom_entry_set)
15194     {
15195       g_source_remove (tree_view->priv->typeselect_flush_timeout);
15196       tree_view->priv->typeselect_flush_timeout =
15197         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
15198                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
15199                        tree_view);
15200     }
15201
15202   return retval;
15203 }
15204
15205 static gboolean
15206 gtk_tree_view_search_key_press_event (GtkWidget *widget,
15207                                       GdkEventKey *event,
15208                                       GtkTreeView *tree_view)
15209 {
15210   GdkModifierType default_accel;
15211   gboolean        retval = FALSE;
15212
15213   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
15214   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15215
15216   /* close window and cancel the search */
15217   if (!tree_view->priv->search_custom_entry_set
15218       && (event->keyval == GDK_KEY_Escape ||
15219           event->keyval == GDK_KEY_Tab ||
15220             event->keyval == GDK_KEY_KP_Tab ||
15221             event->keyval == GDK_KEY_ISO_Left_Tab))
15222     {
15223       gtk_tree_view_search_dialog_hide (widget, tree_view,
15224                                         gdk_event_get_device ((GdkEvent *) event));
15225       return TRUE;
15226     }
15227
15228   default_accel = gtk_widget_get_modifier_mask (widget,
15229                                                 GDK_MODIFIER_INTENT_PRIMARY_ACCELERATOR);
15230
15231   /* select previous matching iter */
15232   if (event->keyval == GDK_KEY_Up || event->keyval == GDK_KEY_KP_Up)
15233     {
15234       if (!gtk_tree_view_search_move (widget, tree_view, TRUE))
15235         gtk_widget_error_bell (widget);
15236
15237       retval = TRUE;
15238     }
15239
15240   if (((event->state & (default_accel | GDK_SHIFT_MASK)) == (default_accel | GDK_SHIFT_MASK))
15241       && (event->keyval == GDK_KEY_g || event->keyval == GDK_KEY_G))
15242     {
15243       if (!gtk_tree_view_search_move (widget, tree_view, TRUE))
15244         gtk_widget_error_bell (widget);
15245
15246       retval = TRUE;
15247     }
15248
15249   /* select next matching iter */
15250   if (event->keyval == GDK_KEY_Down || event->keyval == GDK_KEY_KP_Down)
15251     {
15252       if (!gtk_tree_view_search_move (widget, tree_view, FALSE))
15253         gtk_widget_error_bell (widget);
15254
15255       retval = TRUE;
15256     }
15257
15258   if (((event->state & (default_accel | GDK_SHIFT_MASK)) == default_accel)
15259       && (event->keyval == GDK_KEY_g || event->keyval == GDK_KEY_G))
15260     {
15261       if (!gtk_tree_view_search_move (widget, tree_view, FALSE))
15262         gtk_widget_error_bell (widget);
15263
15264       retval = TRUE;
15265     }
15266
15267   /* renew the flush timeout */
15268   if (retval && tree_view->priv->typeselect_flush_timeout
15269       && !tree_view->priv->search_custom_entry_set)
15270     {
15271       g_source_remove (tree_view->priv->typeselect_flush_timeout);
15272       tree_view->priv->typeselect_flush_timeout =
15273         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
15274                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
15275                        tree_view);
15276     }
15277
15278   return retval;
15279 }
15280
15281 /*  this function returns FALSE if there is a search string but
15282  *  nothing was found, and TRUE otherwise.
15283  */
15284 static gboolean
15285 gtk_tree_view_search_move (GtkWidget   *window,
15286                            GtkTreeView *tree_view,
15287                            gboolean     up)
15288 {
15289   gboolean ret;
15290   gint len;
15291   gint count = 0;
15292   const gchar *text;
15293   GtkTreeIter iter;
15294   GtkTreeModel *model;
15295   GtkTreeSelection *selection;
15296
15297   text = gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry));
15298
15299   g_return_val_if_fail (text != NULL, FALSE);
15300
15301   len = strlen (text);
15302
15303   if (up && tree_view->priv->selected_iter == 1)
15304     return strlen (text) < 1;
15305
15306   len = strlen (text);
15307
15308   if (len < 1)
15309     return TRUE;
15310
15311   model = gtk_tree_view_get_model (tree_view);
15312   selection = gtk_tree_view_get_selection (tree_view);
15313
15314   /* search */
15315   gtk_tree_selection_unselect_all (selection);
15316   if (!gtk_tree_model_get_iter_first (model, &iter))
15317     return TRUE;
15318
15319   ret = gtk_tree_view_search_iter (model, selection, &iter, text,
15320                                    &count, up?((tree_view->priv->selected_iter) - 1):((tree_view->priv->selected_iter + 1)));
15321
15322   if (ret)
15323     {
15324       /* found */
15325       tree_view->priv->selected_iter += up?(-1):(1);
15326       return TRUE;
15327     }
15328   else
15329     {
15330       /* return to old iter */
15331       count = 0;
15332       gtk_tree_model_get_iter_first (model, &iter);
15333       gtk_tree_view_search_iter (model, selection,
15334                                  &iter, text,
15335                                  &count, tree_view->priv->selected_iter);
15336       return FALSE;
15337     }
15338 }
15339
15340 static gboolean
15341 gtk_tree_view_search_equal_func (GtkTreeModel *model,
15342                                  gint          column,
15343                                  const gchar  *key,
15344                                  GtkTreeIter  *iter,
15345                                  gpointer      search_data)
15346 {
15347   gboolean retval = TRUE;
15348   const gchar *str;
15349   gchar *normalized_string;
15350   gchar *normalized_key;
15351   gchar *case_normalized_string = NULL;
15352   gchar *case_normalized_key = NULL;
15353   GValue value = G_VALUE_INIT;
15354   GValue transformed = G_VALUE_INIT;
15355
15356   gtk_tree_model_get_value (model, iter, column, &value);
15357
15358   g_value_init (&transformed, G_TYPE_STRING);
15359
15360   if (!g_value_transform (&value, &transformed))
15361     {
15362       g_value_unset (&value);
15363       return TRUE;
15364     }
15365
15366   g_value_unset (&value);
15367
15368   str = g_value_get_string (&transformed);
15369   if (!str)
15370     {
15371       g_value_unset (&transformed);
15372       return TRUE;
15373     }
15374
15375   normalized_string = g_utf8_normalize (str, -1, G_NORMALIZE_ALL);
15376   normalized_key = g_utf8_normalize (key, -1, G_NORMALIZE_ALL);
15377
15378   if (normalized_string && normalized_key)
15379     {
15380       case_normalized_string = g_utf8_casefold (normalized_string, -1);
15381       case_normalized_key = g_utf8_casefold (normalized_key, -1);
15382
15383       if (strncmp (case_normalized_key, case_normalized_string, strlen (case_normalized_key)) == 0)
15384         retval = FALSE;
15385     }
15386
15387   g_value_unset (&transformed);
15388   g_free (normalized_key);
15389   g_free (normalized_string);
15390   g_free (case_normalized_key);
15391   g_free (case_normalized_string);
15392
15393   return retval;
15394 }
15395
15396 static gboolean
15397 gtk_tree_view_search_iter (GtkTreeModel     *model,
15398                            GtkTreeSelection *selection,
15399                            GtkTreeIter      *iter,
15400                            const gchar      *text,
15401                            gint             *count,
15402                            gint              n)
15403 {
15404   GtkRBTree *tree = NULL;
15405   GtkRBNode *node = NULL;
15406   GtkTreePath *path;
15407
15408   GtkTreeView *tree_view = gtk_tree_selection_get_tree_view (selection);
15409
15410   path = gtk_tree_model_get_path (model, iter);
15411   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
15412
15413   do
15414     {
15415       if (! tree_view->priv->search_equal_func (model, tree_view->priv->search_column, text, iter, tree_view->priv->search_user_data))
15416         {
15417           (*count)++;
15418           if (*count == n)
15419             {
15420               gtk_tree_view_scroll_to_cell (tree_view, path, NULL,
15421                                             TRUE, 0.5, 0.0);
15422               gtk_tree_selection_select_iter (selection, iter);
15423               gtk_tree_view_real_set_cursor (tree_view, path, CLAMP_NODE);
15424
15425               if (path)
15426                 gtk_tree_path_free (path);
15427
15428               return TRUE;
15429             }
15430         }
15431
15432       if (node->children)
15433         {
15434           gboolean has_child;
15435           GtkTreeIter tmp;
15436
15437           tree = node->children;
15438           node = _gtk_rbtree_first (tree);
15439
15440           tmp = *iter;
15441           has_child = gtk_tree_model_iter_children (model, iter, &tmp);
15442           gtk_tree_path_down (path);
15443
15444           /* sanity check */
15445           TREE_VIEW_INTERNAL_ASSERT (has_child, FALSE);
15446         }
15447       else
15448         {
15449           gboolean done = FALSE;
15450
15451           do
15452             {
15453               node = _gtk_rbtree_next (tree, node);
15454
15455               if (node)
15456                 {
15457                   gboolean has_next;
15458
15459                   has_next = gtk_tree_model_iter_next (model, iter);
15460
15461                   done = TRUE;
15462                   gtk_tree_path_next (path);
15463
15464                   /* sanity check */
15465                   TREE_VIEW_INTERNAL_ASSERT (has_next, FALSE);
15466                 }
15467               else
15468                 {
15469                   gboolean has_parent;
15470                   GtkTreeIter tmp_iter = *iter;
15471
15472                   node = tree->parent_node;
15473                   tree = tree->parent_tree;
15474
15475                   if (!tree)
15476                     {
15477                       if (path)
15478                         gtk_tree_path_free (path);
15479
15480                       /* we've run out of tree, done with this func */
15481                       return FALSE;
15482                     }
15483
15484                   has_parent = gtk_tree_model_iter_parent (model,
15485                                                            iter,
15486                                                            &tmp_iter);
15487                   gtk_tree_path_up (path);
15488
15489                   /* sanity check */
15490                   TREE_VIEW_INTERNAL_ASSERT (has_parent, FALSE);
15491                 }
15492             }
15493           while (!done);
15494         }
15495     }
15496   while (1);
15497
15498   return FALSE;
15499 }
15500
15501 static void
15502 gtk_tree_view_search_init (GtkWidget   *entry,
15503                            GtkTreeView *tree_view)
15504 {
15505   gint ret;
15506   gint count = 0;
15507   const gchar *text;
15508   GtkTreeIter iter;
15509   GtkTreeModel *model;
15510   GtkTreeSelection *selection;
15511
15512   g_return_if_fail (GTK_IS_ENTRY (entry));
15513   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15514
15515   text = gtk_entry_get_text (GTK_ENTRY (entry));
15516
15517   model = gtk_tree_view_get_model (tree_view);
15518   selection = gtk_tree_view_get_selection (tree_view);
15519
15520   /* search */
15521   gtk_tree_selection_unselect_all (selection);
15522   if (tree_view->priv->typeselect_flush_timeout
15523       && !tree_view->priv->search_custom_entry_set)
15524     {
15525       g_source_remove (tree_view->priv->typeselect_flush_timeout);
15526       tree_view->priv->typeselect_flush_timeout =
15527         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
15528                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
15529                        tree_view);
15530     }
15531
15532   if (*text == '\0')
15533     return;
15534
15535   if (!gtk_tree_model_get_iter_first (model, &iter))
15536     return;
15537
15538   ret = gtk_tree_view_search_iter (model, selection,
15539                                    &iter, text,
15540                                    &count, 1);
15541
15542   if (ret)
15543     tree_view->priv->selected_iter = 1;
15544 }
15545
15546 void
15547 _gtk_tree_view_remove_editable (GtkTreeView       *tree_view,
15548                                 GtkTreeViewColumn *column,
15549                                 GtkCellEditable   *cell_editable)
15550 {
15551   if (tree_view->priv->edited_column == NULL)
15552     return;
15553
15554   g_return_if_fail (column == tree_view->priv->edited_column);
15555
15556   tree_view->priv->edited_column = NULL;
15557
15558   if (gtk_widget_has_focus (GTK_WIDGET (cell_editable)))
15559     gtk_widget_grab_focus (GTK_WIDGET (tree_view));
15560
15561   gtk_container_remove (GTK_CONTAINER (tree_view),
15562                         GTK_WIDGET (cell_editable));
15563
15564   /* FIXME should only redraw a single node */
15565   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15566 }
15567
15568 static gboolean
15569 gtk_tree_view_start_editing (GtkTreeView *tree_view,
15570                              GtkTreePath *cursor_path,
15571                              gboolean     edit_only)
15572 {
15573   GtkTreeIter iter;
15574   GdkRectangle cell_area;
15575   GtkTreeViewColumn *focus_column;
15576   guint flags = 0; /* can be 0, as the flags are primarily for rendering */
15577   gint retval = FALSE;
15578   GtkRBTree *cursor_tree;
15579   GtkRBNode *cursor_node;
15580
15581   g_assert (tree_view->priv->focus_column);
15582   focus_column = tree_view->priv->focus_column;
15583
15584   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
15585     return FALSE;
15586
15587   if (_gtk_tree_view_find_node (tree_view, cursor_path, &cursor_tree, &cursor_node) ||
15588       cursor_node == NULL)
15589     return FALSE;
15590
15591   gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path);
15592
15593   validate_row (tree_view, cursor_tree, cursor_node, &iter, cursor_path);
15594
15595   gtk_tree_view_column_cell_set_cell_data (focus_column,
15596                                            tree_view->priv->model,
15597                                            &iter,
15598                                            GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_PARENT),
15599                                            cursor_node->children ? TRUE : FALSE);
15600   gtk_tree_view_get_cell_area (tree_view,
15601                                cursor_path,
15602                                focus_column,
15603                                &cell_area);
15604
15605   if (gtk_cell_area_activate (gtk_cell_layout_get_area (GTK_CELL_LAYOUT (focus_column)),
15606                               _gtk_tree_view_column_get_context (focus_column),
15607                               GTK_WIDGET (tree_view),
15608                               &cell_area,
15609                               flags, edit_only))
15610     retval = TRUE;
15611
15612   return retval;
15613 }
15614
15615 void
15616 _gtk_tree_view_add_editable (GtkTreeView       *tree_view,
15617                              GtkTreeViewColumn *column,
15618                              GtkTreePath       *path,
15619                              GtkCellEditable   *cell_editable,
15620                              GdkRectangle      *cell_area)
15621 {
15622   gint pre_val = gtk_adjustment_get_value (tree_view->priv->vadjustment);
15623   GtkRequisition requisition;
15624
15625   tree_view->priv->edited_column = column;
15626
15627   gtk_tree_view_real_set_cursor (tree_view, path, CLAMP_NODE);
15628   cell_area->y += pre_val - (int)gtk_adjustment_get_value (tree_view->priv->vadjustment);
15629
15630   gtk_widget_get_preferred_size (GTK_WIDGET (cell_editable),
15631                                  &requisition, NULL);
15632
15633   tree_view->priv->draw_keyfocus = TRUE;
15634
15635   if (requisition.height < cell_area->height)
15636     {
15637       gint diff = cell_area->height - requisition.height;
15638       gtk_tree_view_put (tree_view,
15639                          GTK_WIDGET (cell_editable),
15640                          cell_area->x, cell_area->y + diff/2,
15641                          cell_area->width, requisition.height);
15642     }
15643   else
15644     {
15645       gtk_tree_view_put (tree_view,
15646                          GTK_WIDGET (cell_editable),
15647                          cell_area->x, cell_area->y,
15648                          cell_area->width, cell_area->height);
15649     }
15650 }
15651
15652 static void
15653 gtk_tree_view_stop_editing (GtkTreeView *tree_view,
15654                             gboolean     cancel_editing)
15655 {
15656   GtkTreeViewColumn *column;
15657
15658   if (tree_view->priv->edited_column == NULL)
15659     return;
15660
15661   /*
15662    * This is very evil. We need to do this, because
15663    * gtk_cell_editable_editing_done may trigger gtk_tree_view_row_changed
15664    * later on. If gtk_tree_view_row_changed notices
15665    * tree_view->priv->edited_column != NULL, it'll call
15666    * gtk_tree_view_stop_editing again. Bad things will happen then.
15667    *
15668    * Please read that again if you intend to modify anything here.
15669    */
15670
15671   column = tree_view->priv->edited_column;
15672   gtk_cell_area_stop_editing (gtk_cell_layout_get_area (GTK_CELL_LAYOUT (column)), cancel_editing);
15673   tree_view->priv->edited_column = NULL;
15674 }
15675
15676
15677 /**
15678  * gtk_tree_view_set_hover_selection:
15679  * @tree_view: a #GtkTreeView
15680  * @hover: %TRUE to enable hover selection mode
15681  *
15682  * Enables or disables the hover selection mode of @tree_view.
15683  * Hover selection makes the selected row follow the pointer.
15684  * Currently, this works only for the selection modes 
15685  * %GTK_SELECTION_SINGLE and %GTK_SELECTION_BROWSE.
15686  * 
15687  * Since: 2.6
15688  **/
15689 void     
15690 gtk_tree_view_set_hover_selection (GtkTreeView *tree_view,
15691                                    gboolean     hover)
15692 {
15693   hover = hover != FALSE;
15694
15695   if (hover != tree_view->priv->hover_selection)
15696     {
15697       tree_view->priv->hover_selection = hover;
15698
15699       g_object_notify (G_OBJECT (tree_view), "hover-selection");
15700     }
15701 }
15702
15703 /**
15704  * gtk_tree_view_get_hover_selection:
15705  * @tree_view: a #GtkTreeView
15706  * 
15707  * Returns whether hover selection mode is turned on for @tree_view.
15708  * 
15709  * Return value: %TRUE if @tree_view is in hover selection mode
15710  *
15711  * Since: 2.6 
15712  **/
15713 gboolean 
15714 gtk_tree_view_get_hover_selection (GtkTreeView *tree_view)
15715 {
15716   return tree_view->priv->hover_selection;
15717 }
15718
15719 /**
15720  * gtk_tree_view_set_hover_expand:
15721  * @tree_view: a #GtkTreeView
15722  * @expand: %TRUE to enable hover selection mode
15723  *
15724  * Enables or disables the hover expansion mode of @tree_view.
15725  * Hover expansion makes rows expand or collapse if the pointer 
15726  * moves over them.
15727  * 
15728  * Since: 2.6
15729  **/
15730 void     
15731 gtk_tree_view_set_hover_expand (GtkTreeView *tree_view,
15732                                 gboolean     expand)
15733 {
15734   expand = expand != FALSE;
15735
15736   if (expand != tree_view->priv->hover_expand)
15737     {
15738       tree_view->priv->hover_expand = expand;
15739
15740       g_object_notify (G_OBJECT (tree_view), "hover-expand");
15741     }
15742 }
15743
15744 /**
15745  * gtk_tree_view_get_hover_expand:
15746  * @tree_view: a #GtkTreeView
15747  * 
15748  * Returns whether hover expansion mode is turned on for @tree_view.
15749  * 
15750  * Return value: %TRUE if @tree_view is in hover expansion mode
15751  *
15752  * Since: 2.6 
15753  **/
15754 gboolean 
15755 gtk_tree_view_get_hover_expand (GtkTreeView *tree_view)
15756 {
15757   return tree_view->priv->hover_expand;
15758 }
15759
15760 /**
15761  * gtk_tree_view_set_rubber_banding:
15762  * @tree_view: a #GtkTreeView
15763  * @enable: %TRUE to enable rubber banding
15764  *
15765  * Enables or disables rubber banding in @tree_view.  If the selection mode
15766  * is #GTK_SELECTION_MULTIPLE, rubber banding will allow the user to select
15767  * multiple rows by dragging the mouse.
15768  * 
15769  * Since: 2.10
15770  **/
15771 void
15772 gtk_tree_view_set_rubber_banding (GtkTreeView *tree_view,
15773                                   gboolean     enable)
15774 {
15775   enable = enable != FALSE;
15776
15777   if (enable != tree_view->priv->rubber_banding_enable)
15778     {
15779       tree_view->priv->rubber_banding_enable = enable;
15780
15781       g_object_notify (G_OBJECT (tree_view), "rubber-banding");
15782     }
15783 }
15784
15785 /**
15786  * gtk_tree_view_get_rubber_banding:
15787  * @tree_view: a #GtkTreeView
15788  * 
15789  * Returns whether rubber banding is turned on for @tree_view.  If the
15790  * selection mode is #GTK_SELECTION_MULTIPLE, rubber banding will allow the
15791  * user to select multiple rows by dragging the mouse.
15792  * 
15793  * Return value: %TRUE if rubber banding in @tree_view is enabled.
15794  *
15795  * Since: 2.10
15796  **/
15797 gboolean
15798 gtk_tree_view_get_rubber_banding (GtkTreeView *tree_view)
15799 {
15800   return tree_view->priv->rubber_banding_enable;
15801 }
15802
15803 /**
15804  * gtk_tree_view_is_rubber_banding_active:
15805  * @tree_view: a #GtkTreeView
15806  * 
15807  * Returns whether a rubber banding operation is currently being done
15808  * in @tree_view.
15809  *
15810  * Return value: %TRUE if a rubber banding operation is currently being
15811  * done in @tree_view.
15812  *
15813  * Since: 2.12
15814  **/
15815 gboolean
15816 gtk_tree_view_is_rubber_banding_active (GtkTreeView *tree_view)
15817 {
15818   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15819
15820   if (tree_view->priv->rubber_banding_enable
15821       && tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
15822     return TRUE;
15823
15824   return FALSE;
15825 }
15826
15827 /**
15828  * gtk_tree_view_get_row_separator_func: (skip)
15829  * @tree_view: a #GtkTreeView
15830  * 
15831  * Returns the current row separator function.
15832  * 
15833  * Return value: the current row separator function.
15834  *
15835  * Since: 2.6
15836  **/
15837 GtkTreeViewRowSeparatorFunc 
15838 gtk_tree_view_get_row_separator_func (GtkTreeView *tree_view)
15839 {
15840   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
15841
15842   return tree_view->priv->row_separator_func;
15843 }
15844
15845 /**
15846  * gtk_tree_view_set_row_separator_func:
15847  * @tree_view: a #GtkTreeView
15848  * @func: (allow-none): a #GtkTreeViewRowSeparatorFunc
15849  * @data: (allow-none): user data to pass to @func, or %NULL
15850  * @destroy: (allow-none): destroy notifier for @data, or %NULL
15851  * 
15852  * Sets the row separator function, which is used to determine
15853  * whether a row should be drawn as a separator. If the row separator
15854  * function is %NULL, no separators are drawn. This is the default value.
15855  *
15856  * Since: 2.6
15857  **/
15858 void
15859 gtk_tree_view_set_row_separator_func (GtkTreeView                 *tree_view,
15860                                       GtkTreeViewRowSeparatorFunc  func,
15861                                       gpointer                     data,
15862                                       GDestroyNotify               destroy)
15863 {
15864   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15865
15866   if (tree_view->priv->row_separator_destroy)
15867     tree_view->priv->row_separator_destroy (tree_view->priv->row_separator_data);
15868
15869   tree_view->priv->row_separator_func = func;
15870   tree_view->priv->row_separator_data = data;
15871   tree_view->priv->row_separator_destroy = destroy;
15872
15873   /* Have the tree recalculate heights */
15874   _gtk_rbtree_mark_invalid (tree_view->priv->tree);
15875   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
15876 }
15877
15878   
15879 static void
15880 gtk_tree_view_grab_notify (GtkWidget *widget,
15881                            gboolean   was_grabbed)
15882 {
15883   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
15884
15885   tree_view->priv->in_grab = !was_grabbed;
15886
15887   if (!was_grabbed)
15888     {
15889       tree_view->priv->pressed_button = -1;
15890
15891       if (tree_view->priv->rubber_band_status)
15892         gtk_tree_view_stop_rubber_band (tree_view);
15893     }
15894 }
15895
15896 static void
15897 gtk_tree_view_state_flags_changed (GtkWidget     *widget,
15898                                    GtkStateFlags  previous_state)
15899 {
15900   if (gtk_widget_get_realized (widget))
15901     gtk_tree_view_ensure_background (GTK_TREE_VIEW (widget));
15902
15903   gtk_widget_queue_draw (widget);
15904 }
15905
15906 /**
15907  * gtk_tree_view_get_grid_lines:
15908  * @tree_view: a #GtkTreeView
15909  *
15910  * Returns which grid lines are enabled in @tree_view.
15911  *
15912  * Return value: a #GtkTreeViewGridLines value indicating which grid lines
15913  * are enabled.
15914  *
15915  * Since: 2.10
15916  */
15917 GtkTreeViewGridLines
15918 gtk_tree_view_get_grid_lines (GtkTreeView *tree_view)
15919 {
15920   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
15921
15922   return tree_view->priv->grid_lines;
15923 }
15924
15925 /**
15926  * gtk_tree_view_set_grid_lines:
15927  * @tree_view: a #GtkTreeView
15928  * @grid_lines: a #GtkTreeViewGridLines value indicating which grid lines to
15929  * enable.
15930  *
15931  * Sets which grid lines to draw in @tree_view.
15932  *
15933  * Since: 2.10
15934  */
15935 void
15936 gtk_tree_view_set_grid_lines (GtkTreeView           *tree_view,
15937                               GtkTreeViewGridLines   grid_lines)
15938 {
15939   GtkTreeViewPrivate *priv;
15940   GtkWidget *widget;
15941   GtkTreeViewGridLines old_grid_lines;
15942
15943   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15944
15945   priv = tree_view->priv;
15946   widget = GTK_WIDGET (tree_view);
15947
15948   old_grid_lines = priv->grid_lines;
15949   priv->grid_lines = grid_lines;
15950   
15951   if (gtk_widget_get_realized (widget))
15952     {
15953       if (grid_lines == GTK_TREE_VIEW_GRID_LINES_NONE &&
15954           priv->grid_line_width)
15955         {
15956           priv->grid_line_width = 0;
15957         }
15958       
15959       if (grid_lines != GTK_TREE_VIEW_GRID_LINES_NONE && 
15960           !priv->grid_line_width)
15961         {
15962           gint8 *dash_list;
15963
15964           gtk_widget_style_get (widget,
15965                                 "grid-line-width", &priv->grid_line_width,
15966                                 "grid-line-pattern", (gchar *)&dash_list,
15967                                 NULL);
15968       
15969           if (dash_list)
15970             {
15971               priv->grid_line_dashes[0] = dash_list[0];
15972               if (dash_list[0])
15973                 priv->grid_line_dashes[1] = dash_list[1];
15974               
15975               g_free (dash_list);
15976             }
15977           else
15978             {
15979               priv->grid_line_dashes[0] = 1;
15980               priv->grid_line_dashes[1] = 1;
15981             }
15982         }      
15983     }
15984
15985   if (old_grid_lines != grid_lines)
15986     {
15987       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15988       
15989       g_object_notify (G_OBJECT (tree_view), "enable-grid-lines");
15990     }
15991 }
15992
15993 /**
15994  * gtk_tree_view_get_enable_tree_lines:
15995  * @tree_view: a #GtkTreeView.
15996  *
15997  * Returns whether or not tree lines are drawn in @tree_view.
15998  *
15999  * Return value: %TRUE if tree lines are drawn in @tree_view, %FALSE
16000  * otherwise.
16001  *
16002  * Since: 2.10
16003  */
16004 gboolean
16005 gtk_tree_view_get_enable_tree_lines (GtkTreeView *tree_view)
16006 {
16007   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
16008
16009   return tree_view->priv->tree_lines_enabled;
16010 }
16011
16012 /**
16013  * gtk_tree_view_set_enable_tree_lines:
16014  * @tree_view: a #GtkTreeView
16015  * @enabled: %TRUE to enable tree line drawing, %FALSE otherwise.
16016  *
16017  * Sets whether to draw lines interconnecting the expanders in @tree_view.
16018  * This does not have any visible effects for lists.
16019  *
16020  * Since: 2.10
16021  */
16022 void
16023 gtk_tree_view_set_enable_tree_lines (GtkTreeView *tree_view,
16024                                      gboolean     enabled)
16025 {
16026   GtkTreeViewPrivate *priv;
16027   GtkWidget *widget;
16028   gboolean was_enabled;
16029
16030   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
16031
16032   enabled = enabled != FALSE;
16033
16034   priv = tree_view->priv;
16035   widget = GTK_WIDGET (tree_view);
16036
16037   was_enabled = priv->tree_lines_enabled;
16038
16039   priv->tree_lines_enabled = enabled;
16040
16041   if (gtk_widget_get_realized (widget))
16042     {
16043       if (!enabled && priv->tree_line_width)
16044         {
16045           priv->tree_line_width = 0;
16046         }
16047       
16048       if (enabled && !priv->tree_line_width)
16049         {
16050           gint8 *dash_list;
16051           gtk_widget_style_get (widget,
16052                                 "tree-line-width", &priv->tree_line_width,
16053                                 "tree-line-pattern", (gchar *)&dash_list,
16054                                 NULL);
16055           
16056           if (dash_list)
16057             {
16058               priv->tree_line_dashes[0] = dash_list[0];
16059               if (dash_list[0])
16060                 priv->tree_line_dashes[1] = dash_list[1];
16061               
16062               g_free (dash_list);
16063             }
16064           else
16065             {
16066               priv->tree_line_dashes[0] = 1;
16067               priv->tree_line_dashes[1] = 1;
16068             }
16069         }
16070     }
16071
16072   if (was_enabled != enabled)
16073     {
16074       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
16075
16076       g_object_notify (G_OBJECT (tree_view), "enable-tree-lines");
16077     }
16078 }
16079
16080
16081 /**
16082  * gtk_tree_view_set_show_expanders:
16083  * @tree_view: a #GtkTreeView
16084  * @enabled: %TRUE to enable expander drawing, %FALSE otherwise.
16085  *
16086  * Sets whether to draw and enable expanders and indent child rows in
16087  * @tree_view.  When disabled there will be no expanders visible in trees
16088  * and there will be no way to expand and collapse rows by default.  Also
16089  * note that hiding the expanders will disable the default indentation.  You
16090  * can set a custom indentation in this case using
16091  * gtk_tree_view_set_level_indentation().
16092  * This does not have any visible effects for lists.
16093  *
16094  * Since: 2.12
16095  */
16096 void
16097 gtk_tree_view_set_show_expanders (GtkTreeView *tree_view,
16098                                   gboolean     enabled)
16099 {
16100   gboolean was_enabled;
16101
16102   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
16103
16104   enabled = enabled != FALSE;
16105   was_enabled = tree_view->priv->show_expanders;
16106
16107   tree_view->priv->show_expanders = enabled == TRUE;
16108
16109   if (enabled != was_enabled)
16110     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
16111 }
16112
16113 /**
16114  * gtk_tree_view_get_show_expanders:
16115  * @tree_view: a #GtkTreeView.
16116  *
16117  * Returns whether or not expanders are drawn in @tree_view.
16118  *
16119  * Return value: %TRUE if expanders are drawn in @tree_view, %FALSE
16120  * otherwise.
16121  *
16122  * Since: 2.12
16123  */
16124 gboolean
16125 gtk_tree_view_get_show_expanders (GtkTreeView *tree_view)
16126 {
16127   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
16128
16129   return tree_view->priv->show_expanders;
16130 }
16131
16132 /**
16133  * gtk_tree_view_set_level_indentation:
16134  * @tree_view: a #GtkTreeView
16135  * @indentation: the amount, in pixels, of extra indentation in @tree_view.
16136  *
16137  * Sets the amount of extra indentation for child levels to use in @tree_view
16138  * in addition to the default indentation.  The value should be specified in
16139  * pixels, a value of 0 disables this feature and in this case only the default
16140  * indentation will be used.
16141  * This does not have any visible effects for lists.
16142  *
16143  * Since: 2.12
16144  */
16145 void
16146 gtk_tree_view_set_level_indentation (GtkTreeView *tree_view,
16147                                      gint         indentation)
16148 {
16149   tree_view->priv->level_indentation = indentation;
16150
16151   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
16152 }
16153
16154 /**
16155  * gtk_tree_view_get_level_indentation:
16156  * @tree_view: a #GtkTreeView.
16157  *
16158  * Returns the amount, in pixels, of extra indentation for child levels
16159  * in @tree_view.
16160  *
16161  * Return value: the amount of extra indentation for child levels in
16162  * @tree_view.  A return value of 0 means that this feature is disabled.
16163  *
16164  * Since: 2.12
16165  */
16166 gint
16167 gtk_tree_view_get_level_indentation (GtkTreeView *tree_view)
16168 {
16169   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
16170
16171   return tree_view->priv->level_indentation;
16172 }
16173
16174 /**
16175  * gtk_tree_view_set_tooltip_row:
16176  * @tree_view: a #GtkTreeView
16177  * @tooltip: a #GtkTooltip
16178  * @path: a #GtkTreePath
16179  *
16180  * Sets the tip area of @tooltip to be the area covered by the row at @path.
16181  * See also gtk_tree_view_set_tooltip_column() for a simpler alternative.
16182  * See also gtk_tooltip_set_tip_area().
16183  *
16184  * Since: 2.12
16185  */
16186 void
16187 gtk_tree_view_set_tooltip_row (GtkTreeView *tree_view,
16188                                GtkTooltip  *tooltip,
16189                                GtkTreePath *path)
16190 {
16191   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
16192   g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
16193
16194   gtk_tree_view_set_tooltip_cell (tree_view, tooltip, path, NULL, NULL);
16195 }
16196
16197 /**
16198  * gtk_tree_view_set_tooltip_cell:
16199  * @tree_view: a #GtkTreeView
16200  * @tooltip: a #GtkTooltip
16201  * @path: (allow-none): a #GtkTreePath or %NULL
16202  * @column: (allow-none): a #GtkTreeViewColumn or %NULL
16203  * @cell: (allow-none): a #GtkCellRenderer or %NULL
16204  *
16205  * Sets the tip area of @tooltip to the area @path, @column and @cell have
16206  * in common.  For example if @path is %NULL and @column is set, the tip
16207  * area will be set to the full area covered by @column.  See also
16208  * gtk_tooltip_set_tip_area().
16209  *
16210  * Note that if @path is not specified and @cell is set and part of a column
16211  * containing the expander, the tooltip might not show and hide at the correct
16212  * position.  In such cases @path must be set to the current node under the
16213  * mouse cursor for this function to operate correctly.
16214  *
16215  * See also gtk_tree_view_set_tooltip_column() for a simpler alternative.
16216  *
16217  * Since: 2.12
16218  */
16219 void
16220 gtk_tree_view_set_tooltip_cell (GtkTreeView       *tree_view,
16221                                 GtkTooltip        *tooltip,
16222                                 GtkTreePath       *path,
16223                                 GtkTreeViewColumn *column,
16224                                 GtkCellRenderer   *cell)
16225 {
16226   GtkAllocation allocation;
16227   GdkRectangle rect;
16228
16229   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
16230   g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
16231   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
16232   g_return_if_fail (cell == NULL || GTK_IS_CELL_RENDERER (cell));
16233
16234   /* Determine x values. */
16235   if (column && cell)
16236     {
16237       GdkRectangle tmp;
16238       gint start, width;
16239
16240       /* We always pass in path here, whether it is NULL or not.
16241        * For cells in expander columns path must be specified so that
16242        * we can correctly account for the indentation.  This also means
16243        * that the tooltip is constrained vertically by the "Determine y
16244        * values" code below; this is not a real problem since cells actually
16245        * don't stretch vertically in constrast to columns.
16246        */
16247       gtk_tree_view_get_cell_area (tree_view, path, column, &tmp);
16248       gtk_tree_view_column_cell_get_position (column, cell, &start, &width);
16249
16250       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
16251                                                          tmp.x + start, 0,
16252                                                          &rect.x, NULL);
16253       rect.width = width;
16254     }
16255   else if (column)
16256     {
16257       GdkRectangle tmp;
16258
16259       gtk_tree_view_get_background_area (tree_view, NULL, column, &tmp);
16260       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
16261                                                          tmp.x, 0,
16262                                                          &rect.x, NULL);
16263       rect.width = tmp.width;
16264     }
16265   else
16266     {
16267       gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
16268       rect.x = 0;
16269       rect.width = allocation.width;
16270     }
16271
16272   /* Determine y values. */
16273   if (path)
16274     {
16275       GdkRectangle tmp;
16276
16277       gtk_tree_view_get_background_area (tree_view, path, NULL, &tmp);
16278       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
16279                                                          0, tmp.y,
16280                                                          NULL, &rect.y);
16281       rect.height = tmp.height;
16282     }
16283   else
16284     {
16285       rect.y = 0;
16286       rect.height = gtk_adjustment_get_page_size (tree_view->priv->vadjustment);
16287     }
16288
16289   gtk_tooltip_set_tip_area (tooltip, &rect);
16290 }
16291
16292 /**
16293  * gtk_tree_view_get_tooltip_context:
16294  * @tree_view: a #GtkTreeView
16295  * @x: (inout): the x coordinate (relative to widget coordinates)
16296  * @y: (inout): the y coordinate (relative to widget coordinates)
16297  * @keyboard_tip: whether this is a keyboard tooltip or not
16298  * @model: (out) (allow-none) (transfer none): a pointer to receive a
16299  *         #GtkTreeModel or %NULL
16300  * @path: (out) (allow-none): a pointer to receive a #GtkTreePath or %NULL
16301  * @iter: (out) (allow-none): a pointer to receive a #GtkTreeIter or %NULL
16302  *
16303  * This function is supposed to be used in a #GtkWidget::query-tooltip
16304  * signal handler for #GtkTreeView.  The @x, @y and @keyboard_tip values
16305  * which are received in the signal handler, should be passed to this
16306  * function without modification.
16307  *
16308  * The return value indicates whether there is a tree view row at the given
16309  * coordinates (%TRUE) or not (%FALSE) for mouse tooltips.  For keyboard
16310  * tooltips the row returned will be the cursor row.  When %TRUE, then any of
16311  * @model, @path and @iter which have been provided will be set to point to
16312  * that row and the corresponding model.  @x and @y will always be converted
16313  * to be relative to @tree_view's bin_window if @keyboard_tooltip is %FALSE.
16314  *
16315  * Return value: whether or not the given tooltip context points to a row.
16316  *
16317  * Since: 2.12
16318  */
16319 gboolean
16320 gtk_tree_view_get_tooltip_context (GtkTreeView   *tree_view,
16321                                    gint          *x,
16322                                    gint          *y,
16323                                    gboolean       keyboard_tip,
16324                                    GtkTreeModel **model,
16325                                    GtkTreePath  **path,
16326                                    GtkTreeIter   *iter)
16327 {
16328   GtkTreePath *tmppath = NULL;
16329
16330   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
16331   g_return_val_if_fail (x != NULL, FALSE);
16332   g_return_val_if_fail (y != NULL, FALSE);
16333
16334   if (keyboard_tip)
16335     {
16336       gtk_tree_view_get_cursor (tree_view, &tmppath, NULL);
16337
16338       if (!tmppath)
16339         return FALSE;
16340     }
16341   else
16342     {
16343       gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, *x, *y,
16344                                                          x, y);
16345
16346       if (!gtk_tree_view_get_path_at_pos (tree_view, *x, *y,
16347                                           &tmppath, NULL, NULL, NULL))
16348         return FALSE;
16349     }
16350
16351   if (model)
16352     *model = gtk_tree_view_get_model (tree_view);
16353
16354   if (iter)
16355     gtk_tree_model_get_iter (gtk_tree_view_get_model (tree_view),
16356                              iter, tmppath);
16357
16358   if (path)
16359     *path = tmppath;
16360   else
16361     gtk_tree_path_free (tmppath);
16362
16363   return TRUE;
16364 }
16365
16366 static gboolean
16367 gtk_tree_view_set_tooltip_query_cb (GtkWidget  *widget,
16368                                     gint        x,
16369                                     gint        y,
16370                                     gboolean    keyboard_tip,
16371                                     GtkTooltip *tooltip,
16372                                     gpointer    data)
16373 {
16374   GValue value = G_VALUE_INIT;
16375   GValue transformed = G_VALUE_INIT;
16376   GtkTreeIter iter;
16377   GtkTreePath *path;
16378   GtkTreeModel *model;
16379   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
16380
16381   if (!gtk_tree_view_get_tooltip_context (GTK_TREE_VIEW (widget),
16382                                           &x, &y,
16383                                           keyboard_tip,
16384                                           &model, &path, &iter))
16385     return FALSE;
16386
16387   gtk_tree_model_get_value (model, &iter,
16388                             tree_view->priv->tooltip_column, &value);
16389
16390   g_value_init (&transformed, G_TYPE_STRING);
16391
16392   if (!g_value_transform (&value, &transformed))
16393     {
16394       g_value_unset (&value);
16395       gtk_tree_path_free (path);
16396
16397       return FALSE;
16398     }
16399
16400   g_value_unset (&value);
16401
16402   if (!g_value_get_string (&transformed))
16403     {
16404       g_value_unset (&transformed);
16405       gtk_tree_path_free (path);
16406
16407       return FALSE;
16408     }
16409
16410   gtk_tooltip_set_markup (tooltip, g_value_get_string (&transformed));
16411   gtk_tree_view_set_tooltip_row (tree_view, tooltip, path);
16412
16413   gtk_tree_path_free (path);
16414   g_value_unset (&transformed);
16415
16416   return TRUE;
16417 }
16418
16419 /**
16420  * gtk_tree_view_set_tooltip_column:
16421  * @tree_view: a #GtkTreeView
16422  * @column: an integer, which is a valid column number for @tree_view's model
16423  *
16424  * If you only plan to have simple (text-only) tooltips on full rows, you
16425  * can use this function to have #GtkTreeView handle these automatically
16426  * for you. @column should be set to the column in @tree_view's model
16427  * containing the tooltip texts, or -1 to disable this feature.
16428  *
16429  * When enabled, #GtkWidget::has-tooltip will be set to %TRUE and
16430  * @tree_view will connect a #GtkWidget::query-tooltip signal handler.
16431  *
16432  * Note that the signal handler sets the text with gtk_tooltip_set_markup(),
16433  * so &amp;, &lt;, etc have to be escaped in the text.
16434  *
16435  * Since: 2.12
16436  */
16437 void
16438 gtk_tree_view_set_tooltip_column (GtkTreeView *tree_view,
16439                                   gint         column)
16440 {
16441   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
16442
16443   if (column == tree_view->priv->tooltip_column)
16444     return;
16445
16446   if (column == -1)
16447     {
16448       g_signal_handlers_disconnect_by_func (tree_view,
16449                                             gtk_tree_view_set_tooltip_query_cb,
16450                                             NULL);
16451       gtk_widget_set_has_tooltip (GTK_WIDGET (tree_view), FALSE);
16452     }
16453   else
16454     {
16455       if (tree_view->priv->tooltip_column == -1)
16456         {
16457           g_signal_connect (tree_view, "query-tooltip",
16458                             G_CALLBACK (gtk_tree_view_set_tooltip_query_cb), NULL);
16459           gtk_widget_set_has_tooltip (GTK_WIDGET (tree_view), TRUE);
16460         }
16461     }
16462
16463   tree_view->priv->tooltip_column = column;
16464   g_object_notify (G_OBJECT (tree_view), "tooltip-column");
16465 }
16466
16467 /**
16468  * gtk_tree_view_get_tooltip_column:
16469  * @tree_view: a #GtkTreeView
16470  *
16471  * Returns the column of @tree_view's model which is being used for
16472  * displaying tooltips on @tree_view's rows.
16473  *
16474  * Return value: the index of the tooltip column that is currently being
16475  * used, or -1 if this is disabled.
16476  *
16477  * Since: 2.12
16478  */
16479 gint
16480 gtk_tree_view_get_tooltip_column (GtkTreeView *tree_view)
16481 {
16482   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
16483
16484   return tree_view->priv->tooltip_column;
16485 }