]> Pileus Git - ~andy/gtk/blob - gtk/gtktreeview.c
Merge branch 'master' into broadway
[~andy/gtk] / gtk / gtktreeview.c
1 /* gtktreeview.c
2  * Copyright (C) 2000  Red Hat, Inc.,  Jonathan Blandford <jrb@redhat.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20
21 #include "config.h"
22
23 #include <math.h>
24 #include <string.h>
25
26 #include "gtktreeview.h"
27 #include "gtkrbtree.h"
28 #include "gtktreednd.h"
29 #include "gtktreeprivate.h"
30 #include "gtkcellrenderer.h"
31 #include "gtkmainprivate.h"
32 #include "gtkmarshalers.h"
33 #include "gtkbuildable.h"
34 #include "gtkbutton.h"
35 #include "gtkalignment.h"
36 #include "gtklabel.h"
37 #include "gtkhbox.h"
38 #include "gtkvbox.h"
39 #include "gtkarrow.h"
40 #include "gtkintl.h"
41 #include "gtkbindings.h"
42 #include "gtkcontainer.h"
43 #include "gtkentry.h"
44 #include "gtkframe.h"
45 #include "gtktreemodelsort.h"
46 #include "gtktooltip.h"
47 #include "gtkscrollable.h"
48 #include "gtkcelllayout.h"
49 #include "gtkprivate.h"
50 #include "gtkwidgetprivate.h"
51 #include "gtkentryprivate.h"
52 #include "gtkstylecontextprivate.h"
53 #include "gtktypebuiltins.h"
54
55
56 /**
57  * SECTION:gtktreeview
58  * @Short_description: A widget for displaying both trees and lists
59  * @Title: GtkTreeView
60  * @See_also: #GtkTreeViewColumn, #GtkTreeSelection, #GtkTreeDnd, #GtkTreeMode,
61  *   #GtkTreeSortable, #GtkTreeModelSort, #GtkListStore, #GtkTreeStore,
62  *   #GtkCellRenderer, #GtkCellEditable, #GtkCellRendererPixbuf,
63  *   #GtkCellRendererText, #GtkCellRendererToggle
64  *
65  * Widget that displays any object that implements the #GtkTreeModel interface.
66  *
67  * Please refer to the <link linkend="TreeWidget">tree widget conceptual
68  * overview</link> for an overview of all the objects and data types related
69  * to the tree widget and how they work together.
70  *
71  * Several different coordinate systems are exposed in the GtkTreeView API.
72  * These are:
73  *
74  * <inlinegraphic fileref="tree-view-coordinates.png" format="PNG"></inlinegraphic>
75  * <variablelist><title>Coordinate systems in GtkTreeView API</title>
76  * <varlistentry><term>Widget coordinates</term>
77  * <listitem>
78  * <para>
79  * Coordinates relative to the widget (usually <literal>widget->window</literal>).
80  * </para>
81  * </listitem>
82  * </varlistentry>
83  * <varlistentry><term>Bin window coordinates</term>
84  * <listitem>
85  * <para>
86  * Coordinates relative to the window that GtkTreeView renders to.
87  * </para>
88  * </listitem>
89  * </varlistentry>
90  * <varlistentry><term>Tree coordinates</term>
91  * <listitem>
92  * <para>
93  * Coordinates relative to the entire scrollable area of GtkTreeView. These
94  * coordinates start at (0, 0) for row 0 of the tree.
95  * </para>
96  * </listitem>
97  * </varlistentry>
98  * </variablelist>
99  *
100  * Several functions are available for converting between the different
101  * coordinate systems.  The most common translations are between widget and bin
102  * window coordinates and between bin window and tree coordinates. For the
103  * former you can use gtk_tree_view_convert_widget_to_bin_window_coords()
104  * (and vice versa), for the latter gtk_tree_view_convert_bin_window_to_tree_coords()
105  * (and vice versa).
106  *
107  * <refsect2 id="GtkTreeView-BUILDER-UI">
108  * <title>GtkTreeView as GtkBuildable</title>
109  * The GtkTreeView implementation of the GtkBuildable interface accepts
110  * #GtkTreeViewColumn objects as &lt;child&gt; elements and exposes the
111  * internal #GtkTreeSelection in UI definitions.
112  * <example>
113  * <title>A UI definition fragment with GtkTreeView</title>
114  * <programlisting><![CDATA[
115  * <object class="GtkTreeView" id="treeview">
116  *   <property name="model">liststore1</property>
117  *   <child>
118  *     <object class="GtkTreeViewColumn" id="test-column">
119  *       <property name="title">Test</property>
120  *       <child>
121  *         <object class="GtkCellRendererText" id="test-renderer"/>
122  *         <attributes>
123  *           <attribute name="text">1</attribute>
124  *         </attributes>
125  *       </child>
126  *     </object>
127  *   </child>
128  *   <child internal-child="selection">
129  *     <object class="GtkTreeSelection" id="selection">
130  *       <signal name="changed" handler="on_treeview_selection_changed"/>
131  *     </object>
132  *   </child>
133  * </object>
134  * ]]></programlisting>
135  * </example>
136  * </refsect2>
137  */
138
139 enum
140 {
141   DRAG_COLUMN_WINDOW_STATE_UNSET = 0,
142   DRAG_COLUMN_WINDOW_STATE_ORIGINAL = 1,
143   DRAG_COLUMN_WINDOW_STATE_ARROW = 2,
144   DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT = 3,
145   DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT = 4
146 };
147
148 enum
149 {
150   RUBBER_BAND_OFF = 0,
151   RUBBER_BAND_MAYBE_START = 1,
152   RUBBER_BAND_ACTIVE = 2
153 };
154
155  /* This lovely little value is used to determine how far away from the title bar
156   * you can move the mouse and still have a column drag work.
157   */
158 #define TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER(tree_view) (10*gtk_tree_view_get_effective_header_height(tree_view))
159
160 #ifdef __GNUC__
161
162 #define TREE_VIEW_INTERNAL_ASSERT(expr, ret)     G_STMT_START{          \
163      if (!(expr))                                                       \
164        {                                                                \
165          g_log (G_LOG_DOMAIN,                                           \
166                 G_LOG_LEVEL_CRITICAL,                                   \
167                 "%s (%s): assertion `%s' failed.\n"                     \
168                 "There is a disparity between the internal view of the GtkTreeView,\n"    \
169                 "and the GtkTreeModel.  This generally means that the model has changed\n"\
170                 "without letting the view know.  Any display from now on is likely to\n"  \
171                 "be incorrect.\n",                                                        \
172                 G_STRLOC,                                               \
173                 G_STRFUNC,                                              \
174                 #expr);                                                 \
175          return ret;                                                    \
176        };                               }G_STMT_END
177
178 #define TREE_VIEW_INTERNAL_ASSERT_VOID(expr)     G_STMT_START{          \
179      if (!(expr))                                                       \
180        {                                                                \
181          g_log (G_LOG_DOMAIN,                                           \
182                 G_LOG_LEVEL_CRITICAL,                                   \
183                 "%s (%s): assertion `%s' failed.\n"                     \
184                 "There is a disparity between the internal view of the GtkTreeView,\n"    \
185                 "and the GtkTreeModel.  This generally means that the model has changed\n"\
186                 "without letting the view know.  Any display from now on is likely to\n"  \
187                 "be incorrect.\n",                                                        \
188                 G_STRLOC,                                               \
189                 G_STRFUNC,                                              \
190                 #expr);                                                 \
191          return;                                                        \
192        };                               }G_STMT_END
193
194 #else
195
196 #define TREE_VIEW_INTERNAL_ASSERT(expr, ret)     G_STMT_START{          \
197      if (!(expr))                                                       \
198        {                                                                \
199          g_log (G_LOG_DOMAIN,                                           \
200                 G_LOG_LEVEL_CRITICAL,                                   \
201                 "file %s: line %d: assertion `%s' failed.\n"       \
202                 "There is a disparity between the internal view of the GtkTreeView,\n"    \
203                 "and the GtkTreeModel.  This generally means that the model has changed\n"\
204                 "without letting the view know.  Any display from now on is likely to\n"  \
205                 "be incorrect.\n",                                                        \
206                 __FILE__,                                               \
207                 __LINE__,                                               \
208                 #expr);                                                 \
209          return ret;                                                    \
210        };                               }G_STMT_END
211
212 #define TREE_VIEW_INTERNAL_ASSERT_VOID(expr)     G_STMT_START{          \
213      if (!(expr))                                                       \
214        {                                                                \
215          g_log (G_LOG_DOMAIN,                                           \
216                 G_LOG_LEVEL_CRITICAL,                                   \
217                 "file %s: line %d: assertion '%s' failed.\n"            \
218                 "There is a disparity between the internal view of the GtkTreeView,\n"    \
219                 "and the GtkTreeModel.  This generally means that the model has changed\n"\
220                 "without letting the view know.  Any display from now on is likely to\n"  \
221                 "be incorrect.\n",                                                        \
222                 __FILE__,                                               \
223                 __LINE__,                                               \
224                 #expr);                                                 \
225          return;                                                        \
226        };                               }G_STMT_END
227 #endif
228
229 #define GTK_TREE_VIEW_PRIORITY_VALIDATE (GDK_PRIORITY_REDRAW + 5)
230 #define GTK_TREE_VIEW_PRIORITY_SCROLL_SYNC (GTK_TREE_VIEW_PRIORITY_VALIDATE + 2)
231 #define GTK_TREE_VIEW_TIME_MS_PER_IDLE 30
232 #define SCROLL_EDGE_SIZE 15
233 #define EXPANDER_EXTRA_PADDING 4
234 #define GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT 5000
235 #define AUTO_EXPAND_TIMEOUT 500
236
237 /* Translate from bin_window coordinates to rbtree (tree coordinates) and
238  * vice versa.
239  */
240 #define TREE_WINDOW_Y_TO_RBTREE_Y(tree_view,y) ((y) + tree_view->priv->dy)
241 #define RBTREE_Y_TO_TREE_WINDOW_Y(tree_view,y) ((y) - tree_view->priv->dy)
242
243 typedef struct _GtkTreeViewColumnReorder GtkTreeViewColumnReorder;
244 struct _GtkTreeViewColumnReorder
245 {
246   gint left_align;
247   gint right_align;
248   GtkTreeViewColumn *left_column;
249   GtkTreeViewColumn *right_column;
250 };
251
252 typedef struct _GtkTreeViewChild GtkTreeViewChild;
253 struct _GtkTreeViewChild
254 {
255   GtkWidget *widget;
256   gint x;
257   gint y;
258   gint width;
259   gint height;
260 };
261
262
263 typedef struct _TreeViewDragInfo TreeViewDragInfo;
264 struct _TreeViewDragInfo
265 {
266   GdkModifierType start_button_mask;
267   GtkTargetList *_unused_source_target_list;
268   GdkDragAction source_actions;
269
270   GtkTargetList *_unused_dest_target_list;
271
272   guint source_set : 1;
273   guint dest_set : 1;
274 };
275
276
277 struct _GtkTreeViewPrivate
278 {
279   GtkTreeModel *model;
280
281   /* tree information */
282   GtkRBTree *tree;
283
284   /* Container info */
285   GList *children;
286   gint width;
287   gint height;
288
289   /* Adjustments */
290   GtkAdjustment *hadjustment;
291   GtkAdjustment *vadjustment;
292   gint           min_display_width;
293   gint           min_display_height;
294
295   /* Sub windows */
296   GdkWindow *bin_window;
297   GdkWindow *header_window;
298
299   /* Scroll position state keeping */
300   GtkTreeRowReference *top_row;
301   gint top_row_dy;
302   /* dy == y pos of top_row + top_row_dy */
303   /* we cache it for simplicity of the code */
304   gint dy;
305
306   guint presize_handler_timer;
307   guint validate_rows_timer;
308   guint scroll_sync_timer;
309
310   /* Indentation and expander layout */
311   gint expander_size;
312   GtkTreeViewColumn *expander_column;
313
314   gint level_indentation;
315
316   /* Key navigation (focus), selection */
317   gint cursor_offset;
318
319   GtkTreeRowReference *anchor;
320   GtkTreeRowReference *cursor;
321
322   GtkTreeViewColumn *focus_column;
323
324   /* Current pressed node, previously pressed, prelight */
325   GtkRBNode *button_pressed_node;
326   GtkRBTree *button_pressed_tree;
327
328   gint pressed_button;
329   gint press_start_x;
330   gint press_start_y;
331
332   gint event_last_x;
333   gint event_last_y;
334
335   guint last_button_time;
336   gint last_button_x;
337   gint last_button_y;
338
339   GtkRBNode *prelight_node;
340   GtkRBTree *prelight_tree;
341
342   /* Cell Editing */
343   GtkTreeViewColumn *edited_column;
344
345   /* The node that's currently being collapsed or expanded */
346   GtkRBNode *expanded_collapsed_node;
347   GtkRBTree *expanded_collapsed_tree;
348   guint expand_collapse_timeout;
349
350   /* Auto expand/collapse timeout in hover mode */
351   guint auto_expand_timeout;
352
353   /* Selection information */
354   GtkTreeSelection *selection;
355
356   /* Header information */
357   gint n_columns;
358   GList *columns;
359   gint header_height;
360
361   GtkTreeViewColumnDropFunc column_drop_func;
362   gpointer column_drop_func_data;
363   GDestroyNotify column_drop_func_data_destroy;
364   GList *column_drag_info;
365   GtkTreeViewColumnReorder *cur_reorder;
366
367   gint prev_width_before_expander;
368
369   /* Interactive Header reordering */
370   GdkWindow *drag_window;
371   GdkWindow *drag_highlight_window;
372   GtkTreeViewColumn *drag_column;
373   gint drag_column_x;
374
375   /* Interactive Header Resizing */
376   gint drag_pos;
377   gint x_drag;
378
379   /* Non-interactive Header Resizing, expand flag support */
380   gint prev_width;
381
382   gint last_extra_space;
383   gint last_extra_space_per_column;
384   gint last_number_of_expand_columns;
385
386   /* ATK Hack */
387   GtkTreeDestroyCountFunc destroy_count_func;
388   gpointer destroy_count_data;
389   GDestroyNotify destroy_count_destroy;
390
391   /* Scroll timeout (e.g. during dnd, rubber banding) */
392   guint scroll_timeout;
393
394   /* Row drag-and-drop */
395   GtkTreeRowReference *drag_dest_row;
396   GtkTreeViewDropPosition drag_dest_pos;
397   guint open_dest_timeout;
398
399   /* Rubber banding */
400   gint rubber_band_status;
401   gint rubber_band_x;
402   gint rubber_band_y;
403   gint rubber_band_shift;
404   gint rubber_band_ctrl;
405
406   GtkRBNode *rubber_band_start_node;
407   GtkRBTree *rubber_band_start_tree;
408
409   GtkRBNode *rubber_band_end_node;
410   GtkRBTree *rubber_band_end_tree;
411
412   /* fixed height */
413   gint fixed_height;
414
415   /* Scroll-to functionality when unrealized */
416   GtkTreeRowReference *scroll_to_path;
417   GtkTreeViewColumn *scroll_to_column;
418   gfloat scroll_to_row_align;
419   gfloat scroll_to_col_align;
420
421   /* Interactive search */
422   gint selected_iter;
423   gint search_column;
424   GtkTreeViewSearchPositionFunc search_position_func;
425   GtkTreeViewSearchEqualFunc search_equal_func;
426   gpointer search_user_data;
427   GDestroyNotify search_destroy;
428   gpointer search_position_user_data;
429   GDestroyNotify search_position_destroy;
430   GtkWidget *search_window;
431   GtkWidget *search_entry;
432   gulong search_entry_changed_id;
433   guint typeselect_flush_timeout;
434
435   /* Grid and tree lines */
436   GtkTreeViewGridLines grid_lines;
437   double grid_line_dashes[2];
438   int grid_line_width;
439
440   gboolean tree_lines_enabled;
441   double tree_line_dashes[2];
442   int tree_line_width;
443
444   /* Row separators */
445   GtkTreeViewRowSeparatorFunc row_separator_func;
446   gpointer row_separator_data;
447   GDestroyNotify row_separator_destroy;
448
449   /* Tooltip support */
450   gint tooltip_column;
451
452   /* Here comes the bitfield */
453   guint scroll_to_use_align : 1;
454
455   guint fixed_height_mode : 1;
456   guint fixed_height_check : 1;
457
458   guint reorderable : 1;
459   guint header_has_focus : 1;
460   guint drag_column_window_state : 3;
461   /* hint to display rows in alternating colors */
462   guint has_rules : 1;
463   guint mark_rows_col_dirty : 1;
464
465   /* for DnD */
466   guint empty_view_drop : 1;
467
468   guint ctrl_pressed : 1;
469   guint shift_pressed : 1;
470
471   guint init_hadjust_value : 1;
472
473   guint in_top_row_to_dy : 1;
474
475   /* interactive search */
476   guint enable_search : 1;
477   guint disable_popdown : 1;
478   guint search_custom_entry_set : 1;
479   
480   guint hover_selection : 1;
481   guint hover_expand : 1;
482   guint imcontext_changed : 1;
483
484   guint rubber_banding_enable : 1;
485
486   guint in_grab : 1;
487
488   guint post_validation_flag : 1;
489
490   /* Whether our key press handler is to avoid sending an unhandled binding to the search entry */
491   guint search_entry_avoid_unhandled_binding : 1;
492
493   /* GtkScrollablePolicy needs to be checked when
494    * driving the scrollable adjustment values */
495   guint hscroll_policy : 1;
496   guint vscroll_policy : 1;
497
498   /* GtkTreeView flags */
499   guint is_list : 1;
500   guint show_expanders : 1;
501   guint in_column_resize : 1;
502   guint arrow_prelit : 1;
503   guint headers_visible : 1;
504   guint draw_keyfocus : 1;
505   guint model_setup : 1;
506   guint in_column_drag : 1;
507 };
508
509
510 /* Signals */
511 enum
512 {
513   ROW_ACTIVATED,
514   TEST_EXPAND_ROW,
515   TEST_COLLAPSE_ROW,
516   ROW_EXPANDED,
517   ROW_COLLAPSED,
518   COLUMNS_CHANGED,
519   CURSOR_CHANGED,
520   MOVE_CURSOR,
521   SELECT_ALL,
522   UNSELECT_ALL,
523   SELECT_CURSOR_ROW,
524   TOGGLE_CURSOR_ROW,
525   EXPAND_COLLAPSE_CURSOR_ROW,
526   SELECT_CURSOR_PARENT,
527   START_INTERACTIVE_SEARCH,
528   LAST_SIGNAL
529 };
530
531 /* Properties */
532 enum {
533   PROP_0,
534   PROP_MODEL,
535   PROP_HADJUSTMENT,
536   PROP_VADJUSTMENT,
537   PROP_HSCROLL_POLICY,
538   PROP_VSCROLL_POLICY,
539   PROP_HEADERS_VISIBLE,
540   PROP_HEADERS_CLICKABLE,
541   PROP_EXPANDER_COLUMN,
542   PROP_REORDERABLE,
543   PROP_RULES_HINT,
544   PROP_ENABLE_SEARCH,
545   PROP_SEARCH_COLUMN,
546   PROP_FIXED_HEIGHT_MODE,
547   PROP_HOVER_SELECTION,
548   PROP_HOVER_EXPAND,
549   PROP_SHOW_EXPANDERS,
550   PROP_LEVEL_INDENTATION,
551   PROP_RUBBER_BANDING,
552   PROP_ENABLE_GRID_LINES,
553   PROP_ENABLE_TREE_LINES,
554   PROP_TOOLTIP_COLUMN
555 };
556
557 /* object signals */
558 static void     gtk_tree_view_finalize             (GObject          *object);
559 static void     gtk_tree_view_set_property         (GObject         *object,
560                                                     guint            prop_id,
561                                                     const GValue    *value,
562                                                     GParamSpec      *pspec);
563 static void     gtk_tree_view_get_property         (GObject         *object,
564                                                     guint            prop_id,
565                                                     GValue          *value,
566                                                     GParamSpec      *pspec);
567
568 /* gtkwidget signals */
569 static void     gtk_tree_view_destroy              (GtkWidget        *widget);
570 static void     gtk_tree_view_realize              (GtkWidget        *widget);
571 static void     gtk_tree_view_unrealize            (GtkWidget        *widget);
572 static void     gtk_tree_view_map                  (GtkWidget        *widget);
573 static void     gtk_tree_view_get_preferred_width  (GtkWidget        *widget,
574                                                     gint             *minimum,
575                                                     gint             *natural);
576 static void     gtk_tree_view_get_preferred_height (GtkWidget        *widget,
577                                                     gint             *minimum,
578                                                     gint             *natural);
579 static void     gtk_tree_view_size_request         (GtkWidget        *widget,
580                                                     GtkRequisition   *requisition,
581                                                     gboolean          may_validate);
582 static void     gtk_tree_view_size_allocate        (GtkWidget        *widget,
583                                                     GtkAllocation    *allocation);
584 static gboolean gtk_tree_view_draw                 (GtkWidget        *widget,
585                                                     cairo_t          *cr);
586 static gboolean gtk_tree_view_key_press            (GtkWidget        *widget,
587                                                     GdkEventKey      *event);
588 static gboolean gtk_tree_view_key_release          (GtkWidget        *widget,
589                                                     GdkEventKey      *event);
590 static gboolean gtk_tree_view_motion               (GtkWidget        *widget,
591                                                     GdkEventMotion   *event);
592 static gboolean gtk_tree_view_enter_notify         (GtkWidget        *widget,
593                                                     GdkEventCrossing *event);
594 static gboolean gtk_tree_view_leave_notify         (GtkWidget        *widget,
595                                                     GdkEventCrossing *event);
596 static gboolean gtk_tree_view_button_press         (GtkWidget        *widget,
597                                                     GdkEventButton   *event);
598 static gboolean gtk_tree_view_button_release       (GtkWidget        *widget,
599                                                     GdkEventButton   *event);
600 static gboolean gtk_tree_view_grab_broken          (GtkWidget          *widget,
601                                                     GdkEventGrabBroken *event);
602 #if 0
603 static gboolean gtk_tree_view_configure            (GtkWidget         *widget,
604                                                     GdkEventConfigure *event);
605 #endif
606
607 static GtkWidgetPath * gtk_tree_view_get_path_for_child (GtkContainer *container,
608                                                          GtkWidget    *child);
609
610 static void     gtk_tree_view_set_focus_child      (GtkContainer     *container,
611                                                     GtkWidget        *child);
612 static gint     gtk_tree_view_focus_out            (GtkWidget        *widget,
613                                                     GdkEventFocus    *event);
614 static gint     gtk_tree_view_focus                (GtkWidget        *widget,
615                                                     GtkDirectionType  direction);
616 static void     gtk_tree_view_grab_focus           (GtkWidget        *widget);
617 static void     gtk_tree_view_style_updated        (GtkWidget        *widget);
618 static void     gtk_tree_view_grab_notify          (GtkWidget        *widget,
619                                                     gboolean          was_grabbed);
620 static void     gtk_tree_view_state_flags_changed  (GtkWidget        *widget,
621                                                     GtkStateFlags     previous_state);
622
623 /* container signals */
624 static void     gtk_tree_view_remove               (GtkContainer     *container,
625                                                     GtkWidget        *widget);
626 static void     gtk_tree_view_forall               (GtkContainer     *container,
627                                                     gboolean          include_internals,
628                                                     GtkCallback       callback,
629                                                     gpointer          callback_data);
630
631 /* Source side drag signals */
632 static void gtk_tree_view_drag_begin       (GtkWidget        *widget,
633                                             GdkDragContext   *context);
634 static void gtk_tree_view_drag_end         (GtkWidget        *widget,
635                                             GdkDragContext   *context);
636 static void gtk_tree_view_drag_data_get    (GtkWidget        *widget,
637                                             GdkDragContext   *context,
638                                             GtkSelectionData *selection_data,
639                                             guint             info,
640                                             guint             time);
641 static void gtk_tree_view_drag_data_delete (GtkWidget        *widget,
642                                             GdkDragContext   *context);
643
644 /* Target side drag signals */
645 static void     gtk_tree_view_drag_leave         (GtkWidget        *widget,
646                                                   GdkDragContext   *context,
647                                                   guint             time);
648 static gboolean gtk_tree_view_drag_motion        (GtkWidget        *widget,
649                                                   GdkDragContext   *context,
650                                                   gint              x,
651                                                   gint              y,
652                                                   guint             time);
653 static gboolean gtk_tree_view_drag_drop          (GtkWidget        *widget,
654                                                   GdkDragContext   *context,
655                                                   gint              x,
656                                                   gint              y,
657                                                   guint             time);
658 static void     gtk_tree_view_drag_data_received (GtkWidget        *widget,
659                                                   GdkDragContext   *context,
660                                                   gint              x,
661                                                   gint              y,
662                                                   GtkSelectionData *selection_data,
663                                                   guint             info,
664                                                   guint             time);
665
666 /* tree_model signals */
667 static void     gtk_tree_view_set_hadjustment             (GtkTreeView     *tree_view,
668                                                            GtkAdjustment   *adjustment);
669 static void     gtk_tree_view_set_vadjustment             (GtkTreeView     *tree_view,
670                                                            GtkAdjustment   *adjustment);
671 static gboolean gtk_tree_view_real_move_cursor            (GtkTreeView     *tree_view,
672                                                            GtkMovementStep  step,
673                                                            gint             count);
674 static gboolean gtk_tree_view_real_select_all             (GtkTreeView     *tree_view);
675 static gboolean gtk_tree_view_real_unselect_all           (GtkTreeView     *tree_view);
676 static gboolean gtk_tree_view_real_select_cursor_row      (GtkTreeView     *tree_view,
677                                                            gboolean         start_editing);
678 static gboolean gtk_tree_view_real_toggle_cursor_row      (GtkTreeView     *tree_view);
679 static gboolean gtk_tree_view_real_expand_collapse_cursor_row (GtkTreeView     *tree_view,
680                                                                gboolean         logical,
681                                                                gboolean         expand,
682                                                                gboolean         open_all);
683 static gboolean gtk_tree_view_real_select_cursor_parent   (GtkTreeView     *tree_view);
684 static void gtk_tree_view_row_changed                     (GtkTreeModel    *model,
685                                                            GtkTreePath     *path,
686                                                            GtkTreeIter     *iter,
687                                                            gpointer         data);
688 static void gtk_tree_view_row_inserted                    (GtkTreeModel    *model,
689                                                            GtkTreePath     *path,
690                                                            GtkTreeIter     *iter,
691                                                            gpointer         data);
692 static void gtk_tree_view_row_has_child_toggled           (GtkTreeModel    *model,
693                                                            GtkTreePath     *path,
694                                                            GtkTreeIter     *iter,
695                                                            gpointer         data);
696 static void gtk_tree_view_row_deleted                     (GtkTreeModel    *model,
697                                                            GtkTreePath     *path,
698                                                            gpointer         data);
699 static void gtk_tree_view_rows_reordered                  (GtkTreeModel    *model,
700                                                            GtkTreePath     *parent,
701                                                            GtkTreeIter     *iter,
702                                                            gint            *new_order,
703                                                            gpointer         data);
704
705 /* Incremental reflow */
706 static gboolean validate_row             (GtkTreeView *tree_view,
707                                           GtkRBTree   *tree,
708                                           GtkRBNode   *node,
709                                           GtkTreeIter *iter,
710                                           GtkTreePath *path);
711 static void     validate_visible_area    (GtkTreeView *tree_view);
712 static gboolean validate_rows_handler    (GtkTreeView *tree_view);
713 static gboolean do_validate_rows         (GtkTreeView *tree_view,
714                                           gboolean     size_request);
715 static gboolean validate_rows            (GtkTreeView *tree_view);
716 static gboolean presize_handler_callback (gpointer     data);
717 static void     install_presize_handler  (GtkTreeView *tree_view);
718 static void     install_scroll_sync_handler (GtkTreeView *tree_view);
719 static void     gtk_tree_view_set_top_row   (GtkTreeView *tree_view,
720                                              GtkTreePath *path,
721                                              gint         offset);
722 static void     gtk_tree_view_dy_to_top_row (GtkTreeView *tree_view);
723 static void     gtk_tree_view_top_row_to_dy (GtkTreeView *tree_view);
724 static void     invalidate_empty_focus      (GtkTreeView *tree_view);
725
726 /* Internal functions */
727 static gboolean gtk_tree_view_is_expander_column             (GtkTreeView        *tree_view,
728                                                               GtkTreeViewColumn  *column);
729 static inline gboolean gtk_tree_view_draw_expanders          (GtkTreeView        *tree_view);
730 static void     gtk_tree_view_add_move_binding               (GtkBindingSet      *binding_set,
731                                                               guint               keyval,
732                                                               guint               modmask,
733                                                               gboolean            add_shifted_binding,
734                                                               GtkMovementStep     step,
735                                                               gint                count);
736 static gint     gtk_tree_view_unref_and_check_selection_tree (GtkTreeView        *tree_view,
737                                                               GtkRBTree          *tree);
738 static void     gtk_tree_view_queue_draw_path                (GtkTreeView        *tree_view,
739                                                               GtkTreePath        *path,
740                                                               const GdkRectangle *clip_rect);
741 static void     gtk_tree_view_queue_draw_arrow               (GtkTreeView        *tree_view,
742                                                               GtkRBTree          *tree,
743                                                               GtkRBNode          *node);
744 static void     gtk_tree_view_draw_arrow                     (GtkTreeView        *tree_view,
745                                                               cairo_t            *cr,
746                                                               GtkRBTree          *tree,
747                                                               GtkRBNode          *node,
748                                                               gint                x,
749                                                               gint                y);
750 static void     gtk_tree_view_get_arrow_xrange               (GtkTreeView        *tree_view,
751                                                               GtkRBTree          *tree,
752                                                               gint               *x1,
753                                                               gint               *x2);
754 static gint     gtk_tree_view_new_column_width               (GtkTreeView        *tree_view,
755                                                               gint                i,
756                                                               gint               *x);
757 static void     gtk_tree_view_adjustment_changed             (GtkAdjustment      *adjustment,
758                                                               GtkTreeView        *tree_view);
759 static void     gtk_tree_view_build_tree                     (GtkTreeView        *tree_view,
760                                                               GtkRBTree          *tree,
761                                                               GtkTreeIter        *iter,
762                                                               gint                depth,
763                                                               gboolean            recurse);
764 static void     gtk_tree_view_clamp_node_visible             (GtkTreeView        *tree_view,
765                                                               GtkRBTree          *tree,
766                                                               GtkRBNode          *node);
767 static void     gtk_tree_view_clamp_column_visible           (GtkTreeView        *tree_view,
768                                                               GtkTreeViewColumn  *column,
769                                                               gboolean            focus_to_cell);
770 static gboolean gtk_tree_view_maybe_begin_dragging_row       (GtkTreeView        *tree_view,
771                                                               GdkEventMotion     *event);
772 static void     gtk_tree_view_focus_to_cursor                (GtkTreeView        *tree_view);
773 static void     gtk_tree_view_move_cursor_up_down            (GtkTreeView        *tree_view,
774                                                               gint                count);
775 static void     gtk_tree_view_move_cursor_page_up_down       (GtkTreeView        *tree_view,
776                                                               gint                count);
777 static void     gtk_tree_view_move_cursor_left_right         (GtkTreeView        *tree_view,
778                                                               gint                count);
779 static void     gtk_tree_view_move_cursor_start_end          (GtkTreeView        *tree_view,
780                                                               gint                count);
781 static gboolean gtk_tree_view_real_collapse_row              (GtkTreeView        *tree_view,
782                                                               GtkTreePath        *path,
783                                                               GtkRBTree          *tree,
784                                                               GtkRBNode          *node,
785                                                               gboolean            animate);
786 static gboolean gtk_tree_view_real_expand_row                (GtkTreeView        *tree_view,
787                                                               GtkTreePath        *path,
788                                                               GtkRBTree          *tree,
789                                                               GtkRBNode          *node,
790                                                               gboolean            open_all,
791                                                               gboolean            animate);
792 static void     gtk_tree_view_real_set_cursor                (GtkTreeView        *tree_view,
793                                                               GtkTreePath        *path,
794                                                               gboolean            clear_and_select,
795                                                               gboolean            clamp_node);
796 static gboolean gtk_tree_view_has_can_focus_cell             (GtkTreeView        *tree_view);
797 static void     column_sizing_notify                         (GObject            *object,
798                                                               GParamSpec         *pspec,
799                                                               gpointer            data);
800 static void     gtk_tree_view_stop_rubber_band               (GtkTreeView        *tree_view);
801 static void     update_prelight                              (GtkTreeView        *tree_view,
802                                                               int                 x,
803                                                               int                 y);
804
805 static inline gint gtk_tree_view_get_effective_header_height (GtkTreeView *tree_view);
806
807 static inline gint gtk_tree_view_get_cell_area_y_offset      (GtkTreeView *tree_view,
808                                                               GtkRBTree   *tree,
809                                                               GtkRBNode   *node,
810                                                               gint         vertical_separator);
811 static inline gint gtk_tree_view_get_cell_area_height        (GtkTreeView *tree_view,
812                                                               GtkRBNode   *node,
813                                                               gint         vertical_separator);
814
815 static inline gint gtk_tree_view_get_row_y_offset            (GtkTreeView *tree_view,
816                                                               GtkRBTree   *tree,
817                                                               GtkRBNode   *node);
818 static inline gint gtk_tree_view_get_row_height              (GtkTreeView *tree_view,
819                                                               GtkRBNode   *node);
820
821 /* interactive search */
822 static void     gtk_tree_view_ensure_interactive_directory (GtkTreeView *tree_view);
823 static void     gtk_tree_view_search_dialog_hide        (GtkWidget        *search_dialog,
824                                                          GtkTreeView      *tree_view,
825                                                          GdkDevice        *device);
826 static void     gtk_tree_view_search_position_func      (GtkTreeView      *tree_view,
827                                                          GtkWidget        *search_dialog,
828                                                          gpointer          user_data);
829 static void     gtk_tree_view_search_disable_popdown    (GtkEntry         *entry,
830                                                          GtkMenu          *menu,
831                                                          gpointer          data);
832 static void     gtk_tree_view_search_preedit_changed    (GtkIMContext     *im_context,
833                                                          GtkTreeView      *tree_view);
834 static void     gtk_tree_view_search_activate           (GtkEntry         *entry,
835                                                          GtkTreeView      *tree_view);
836 static gboolean gtk_tree_view_real_search_enable_popdown(gpointer          data);
837 static void     gtk_tree_view_search_enable_popdown     (GtkWidget        *widget,
838                                                          gpointer          data);
839 static gboolean gtk_tree_view_search_delete_event       (GtkWidget        *widget,
840                                                          GdkEventAny      *event,
841                                                          GtkTreeView      *tree_view);
842 static gboolean gtk_tree_view_search_button_press_event (GtkWidget        *widget,
843                                                          GdkEventButton   *event,
844                                                          GtkTreeView      *tree_view);
845 static gboolean gtk_tree_view_search_scroll_event       (GtkWidget        *entry,
846                                                          GdkEventScroll   *event,
847                                                          GtkTreeView      *tree_view);
848 static gboolean gtk_tree_view_search_key_press_event    (GtkWidget        *entry,
849                                                          GdkEventKey      *event,
850                                                          GtkTreeView      *tree_view);
851 static gboolean gtk_tree_view_search_move               (GtkWidget        *window,
852                                                          GtkTreeView      *tree_view,
853                                                          gboolean          up);
854 static gboolean gtk_tree_view_search_equal_func         (GtkTreeModel     *model,
855                                                          gint              column,
856                                                          const gchar      *key,
857                                                          GtkTreeIter      *iter,
858                                                          gpointer          search_data);
859 static gboolean gtk_tree_view_search_iter               (GtkTreeModel     *model,
860                                                          GtkTreeSelection *selection,
861                                                          GtkTreeIter      *iter,
862                                                          const gchar      *text,
863                                                          gint             *count,
864                                                          gint              n);
865 static void     gtk_tree_view_search_init               (GtkWidget        *entry,
866                                                          GtkTreeView      *tree_view);
867 static void     gtk_tree_view_put                       (GtkTreeView      *tree_view,
868                                                          GtkWidget        *child_widget,
869                                                          gint              x,
870                                                          gint              y,
871                                                          gint              width,
872                                                          gint              height);
873 static gboolean gtk_tree_view_start_editing             (GtkTreeView      *tree_view,
874                                                          GtkTreePath      *cursor_path,
875                                                          gboolean          edit_only);
876 static void gtk_tree_view_stop_editing                  (GtkTreeView *tree_view,
877                                                          gboolean     cancel_editing);
878 static gboolean gtk_tree_view_real_start_interactive_search (GtkTreeView *tree_view,
879                                                              GdkDevice   *device,
880                                                              gboolean     keybinding);
881 static gboolean gtk_tree_view_start_interactive_search      (GtkTreeView *tree_view);
882 static GtkTreeViewColumn *gtk_tree_view_get_drop_column (GtkTreeView       *tree_view,
883                                                          GtkTreeViewColumn *column,
884                                                          gint               drop_position);
885
886 /* GtkBuildable */
887 static void     gtk_tree_view_buildable_add_child          (GtkBuildable      *tree_view,
888                                                             GtkBuilder        *builder,
889                                                             GObject           *child,
890                                                             const gchar       *type);
891 static GObject *gtk_tree_view_buildable_get_internal_child (GtkBuildable      *buildable,
892                                                             GtkBuilder        *builder,
893                                                             const gchar       *childname);
894 static void     gtk_tree_view_buildable_init               (GtkBuildableIface *iface);
895
896
897 static gboolean scroll_row_timeout                   (gpointer     data);
898 static void     add_scroll_timeout                   (GtkTreeView *tree_view);
899 static void     remove_scroll_timeout                (GtkTreeView *tree_view);
900
901 static guint tree_view_signals [LAST_SIGNAL] = { 0 };
902
903 \f
904
905 /* GType Methods
906  */
907
908 G_DEFINE_TYPE_WITH_CODE (GtkTreeView, gtk_tree_view, GTK_TYPE_CONTAINER,
909                          G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
910                                                 gtk_tree_view_buildable_init)
911                          G_IMPLEMENT_INTERFACE (GTK_TYPE_SCROLLABLE, NULL))
912
913 static void
914 gtk_tree_view_class_init (GtkTreeViewClass *class)
915 {
916   GObjectClass *o_class;
917   GtkWidgetClass *widget_class;
918   GtkContainerClass *container_class;
919   GtkBindingSet *binding_set;
920
921   binding_set = gtk_binding_set_by_class (class);
922
923   o_class = (GObjectClass *) class;
924   widget_class = (GtkWidgetClass *) class;
925   container_class = (GtkContainerClass *) class;
926
927   /* GObject signals */
928   o_class->set_property = gtk_tree_view_set_property;
929   o_class->get_property = gtk_tree_view_get_property;
930   o_class->finalize = gtk_tree_view_finalize;
931
932   /* GtkWidget signals */
933   widget_class->destroy = gtk_tree_view_destroy;
934   widget_class->map = gtk_tree_view_map;
935   widget_class->realize = gtk_tree_view_realize;
936   widget_class->unrealize = gtk_tree_view_unrealize;
937   widget_class->get_preferred_width = gtk_tree_view_get_preferred_width;
938   widget_class->get_preferred_height = gtk_tree_view_get_preferred_height;
939   widget_class->size_allocate = gtk_tree_view_size_allocate;
940   widget_class->button_press_event = gtk_tree_view_button_press;
941   widget_class->button_release_event = gtk_tree_view_button_release;
942   widget_class->grab_broken_event = gtk_tree_view_grab_broken;
943   /*widget_class->configure_event = gtk_tree_view_configure;*/
944   widget_class->motion_notify_event = gtk_tree_view_motion;
945   widget_class->draw = gtk_tree_view_draw;
946   widget_class->key_press_event = gtk_tree_view_key_press;
947   widget_class->key_release_event = gtk_tree_view_key_release;
948   widget_class->enter_notify_event = gtk_tree_view_enter_notify;
949   widget_class->leave_notify_event = gtk_tree_view_leave_notify;
950   widget_class->focus_out_event = gtk_tree_view_focus_out;
951   widget_class->drag_begin = gtk_tree_view_drag_begin;
952   widget_class->drag_end = gtk_tree_view_drag_end;
953   widget_class->drag_data_get = gtk_tree_view_drag_data_get;
954   widget_class->drag_data_delete = gtk_tree_view_drag_data_delete;
955   widget_class->drag_leave = gtk_tree_view_drag_leave;
956   widget_class->drag_motion = gtk_tree_view_drag_motion;
957   widget_class->drag_drop = gtk_tree_view_drag_drop;
958   widget_class->drag_data_received = gtk_tree_view_drag_data_received;
959   widget_class->focus = gtk_tree_view_focus;
960   widget_class->grab_focus = gtk_tree_view_grab_focus;
961   widget_class->style_updated = gtk_tree_view_style_updated;
962   widget_class->grab_notify = gtk_tree_view_grab_notify;
963   widget_class->state_flags_changed = gtk_tree_view_state_flags_changed;
964
965   /* GtkContainer signals */
966   container_class->remove = gtk_tree_view_remove;
967   container_class->forall = gtk_tree_view_forall;
968   container_class->set_focus_child = gtk_tree_view_set_focus_child;
969   container_class->get_path_for_child = gtk_tree_view_get_path_for_child;
970
971   class->move_cursor = gtk_tree_view_real_move_cursor;
972   class->select_all = gtk_tree_view_real_select_all;
973   class->unselect_all = gtk_tree_view_real_unselect_all;
974   class->select_cursor_row = gtk_tree_view_real_select_cursor_row;
975   class->toggle_cursor_row = gtk_tree_view_real_toggle_cursor_row;
976   class->expand_collapse_cursor_row = gtk_tree_view_real_expand_collapse_cursor_row;
977   class->select_cursor_parent = gtk_tree_view_real_select_cursor_parent;
978   class->start_interactive_search = gtk_tree_view_start_interactive_search;
979
980   /* Properties */
981
982   g_object_class_install_property (o_class,
983                                    PROP_MODEL,
984                                    g_param_spec_object ("model",
985                                                         P_("TreeView Model"),
986                                                         P_("The model for the tree view"),
987                                                         GTK_TYPE_TREE_MODEL,
988                                                         GTK_PARAM_READWRITE));
989
990   g_object_class_override_property (o_class, PROP_HADJUSTMENT,    "hadjustment");
991   g_object_class_override_property (o_class, PROP_VADJUSTMENT,    "vadjustment");
992   g_object_class_override_property (o_class, PROP_HSCROLL_POLICY, "hscroll-policy");
993   g_object_class_override_property (o_class, PROP_VSCROLL_POLICY, "vscroll-policy");
994
995   g_object_class_install_property (o_class,
996                                    PROP_HEADERS_VISIBLE,
997                                    g_param_spec_boolean ("headers-visible",
998                                                          P_("Headers Visible"),
999                                                          P_("Show the column header buttons"),
1000                                                          TRUE,
1001                                                          GTK_PARAM_READWRITE));
1002
1003   g_object_class_install_property (o_class,
1004                                    PROP_HEADERS_CLICKABLE,
1005                                    g_param_spec_boolean ("headers-clickable",
1006                                                          P_("Headers Clickable"),
1007                                                          P_("Column headers respond to click events"),
1008                                                          TRUE,
1009                                                          GTK_PARAM_READWRITE));
1010
1011   g_object_class_install_property (o_class,
1012                                    PROP_EXPANDER_COLUMN,
1013                                    g_param_spec_object ("expander-column",
1014                                                         P_("Expander Column"),
1015                                                         P_("Set the column for the expander column"),
1016                                                         GTK_TYPE_TREE_VIEW_COLUMN,
1017                                                         GTK_PARAM_READWRITE));
1018
1019   g_object_class_install_property (o_class,
1020                                    PROP_REORDERABLE,
1021                                    g_param_spec_boolean ("reorderable",
1022                                                          P_("Reorderable"),
1023                                                          P_("View is reorderable"),
1024                                                          FALSE,
1025                                                          GTK_PARAM_READWRITE));
1026
1027   g_object_class_install_property (o_class,
1028                                    PROP_RULES_HINT,
1029                                    g_param_spec_boolean ("rules-hint",
1030                                                          P_("Rules Hint"),
1031                                                          P_("Set a hint to the theme engine to draw rows in alternating colors"),
1032                                                          FALSE,
1033                                                          GTK_PARAM_READWRITE));
1034
1035     g_object_class_install_property (o_class,
1036                                      PROP_ENABLE_SEARCH,
1037                                      g_param_spec_boolean ("enable-search",
1038                                                            P_("Enable Search"),
1039                                                            P_("View allows user to search through columns interactively"),
1040                                                            TRUE,
1041                                                            GTK_PARAM_READWRITE));
1042
1043     g_object_class_install_property (o_class,
1044                                      PROP_SEARCH_COLUMN,
1045                                      g_param_spec_int ("search-column",
1046                                                        P_("Search Column"),
1047                                                        P_("Model column to search through during interactive search"),
1048                                                        -1,
1049                                                        G_MAXINT,
1050                                                        -1,
1051                                                        GTK_PARAM_READWRITE));
1052
1053     /**
1054      * GtkTreeView:fixed-height-mode:
1055      *
1056      * Setting the ::fixed-height-mode property to %TRUE speeds up 
1057      * #GtkTreeView by assuming that all rows have the same height. 
1058      * Only enable this option if all rows are the same height.  
1059      * Please see gtk_tree_view_set_fixed_height_mode() for more 
1060      * information on this option.
1061      *
1062      * Since: 2.4
1063      **/
1064     g_object_class_install_property (o_class,
1065                                      PROP_FIXED_HEIGHT_MODE,
1066                                      g_param_spec_boolean ("fixed-height-mode",
1067                                                            P_("Fixed Height Mode"),
1068                                                            P_("Speeds up GtkTreeView by assuming that all rows have the same height"),
1069                                                            FALSE,
1070                                                            GTK_PARAM_READWRITE));
1071     
1072     /**
1073      * GtkTreeView:hover-selection:
1074      * 
1075      * Enables or disables the hover selection mode of @tree_view.
1076      * Hover selection makes the selected row follow the pointer.
1077      * Currently, this works only for the selection modes 
1078      * %GTK_SELECTION_SINGLE and %GTK_SELECTION_BROWSE.
1079      *
1080      * This mode is primarily intended for treeviews in popups, e.g.
1081      * in #GtkComboBox or #GtkEntryCompletion.
1082      *
1083      * Since: 2.6
1084      */
1085     g_object_class_install_property (o_class,
1086                                      PROP_HOVER_SELECTION,
1087                                      g_param_spec_boolean ("hover-selection",
1088                                                            P_("Hover Selection"),
1089                                                            P_("Whether the selection should follow the pointer"),
1090                                                            FALSE,
1091                                                            GTK_PARAM_READWRITE));
1092
1093     /**
1094      * GtkTreeView:hover-expand:
1095      * 
1096      * Enables or disables the hover expansion mode of @tree_view.
1097      * Hover expansion makes rows expand or collapse if the pointer moves 
1098      * over them.
1099      *
1100      * This mode is primarily intended for treeviews in popups, e.g.
1101      * in #GtkComboBox or #GtkEntryCompletion.
1102      *
1103      * Since: 2.6
1104      */
1105     g_object_class_install_property (o_class,
1106                                      PROP_HOVER_EXPAND,
1107                                      g_param_spec_boolean ("hover-expand",
1108                                                            P_("Hover Expand"),
1109                                                            P_("Whether rows should be expanded/collapsed when the pointer moves over them"),
1110                                                            FALSE,
1111                                                            GTK_PARAM_READWRITE));
1112
1113     /**
1114      * GtkTreeView:show-expanders:
1115      *
1116      * %TRUE if the view has expanders.
1117      *
1118      * Since: 2.12
1119      */
1120     g_object_class_install_property (o_class,
1121                                      PROP_SHOW_EXPANDERS,
1122                                      g_param_spec_boolean ("show-expanders",
1123                                                            P_("Show Expanders"),
1124                                                            P_("View has expanders"),
1125                                                            TRUE,
1126                                                            GTK_PARAM_READWRITE));
1127
1128     /**
1129      * GtkTreeView:level-indentation:
1130      *
1131      * Extra indentation for each level.
1132      *
1133      * Since: 2.12
1134      */
1135     g_object_class_install_property (o_class,
1136                                      PROP_LEVEL_INDENTATION,
1137                                      g_param_spec_int ("level-indentation",
1138                                                        P_("Level Indentation"),
1139                                                        P_("Extra indentation for each level"),
1140                                                        0,
1141                                                        G_MAXINT,
1142                                                        0,
1143                                                        GTK_PARAM_READWRITE));
1144
1145     g_object_class_install_property (o_class,
1146                                      PROP_RUBBER_BANDING,
1147                                      g_param_spec_boolean ("rubber-banding",
1148                                                            P_("Rubber Banding"),
1149                                                            P_("Whether to enable selection of multiple items by dragging the mouse pointer"),
1150                                                            FALSE,
1151                                                            GTK_PARAM_READWRITE));
1152
1153     g_object_class_install_property (o_class,
1154                                      PROP_ENABLE_GRID_LINES,
1155                                      g_param_spec_enum ("enable-grid-lines",
1156                                                         P_("Enable Grid Lines"),
1157                                                         P_("Whether grid lines should be drawn in the tree view"),
1158                                                         GTK_TYPE_TREE_VIEW_GRID_LINES,
1159                                                         GTK_TREE_VIEW_GRID_LINES_NONE,
1160                                                         GTK_PARAM_READWRITE));
1161
1162     g_object_class_install_property (o_class,
1163                                      PROP_ENABLE_TREE_LINES,
1164                                      g_param_spec_boolean ("enable-tree-lines",
1165                                                            P_("Enable Tree Lines"),
1166                                                            P_("Whether tree lines should be drawn in the tree view"),
1167                                                            FALSE,
1168                                                            GTK_PARAM_READWRITE));
1169
1170     g_object_class_install_property (o_class,
1171                                      PROP_TOOLTIP_COLUMN,
1172                                      g_param_spec_int ("tooltip-column",
1173                                                        P_("Tooltip Column"),
1174                                                        P_("The column in the model containing the tooltip texts for the rows"),
1175                                                        -1,
1176                                                        G_MAXINT,
1177                                                        -1,
1178                                                        GTK_PARAM_READWRITE));
1179
1180   /* Style properties */
1181 #define _TREE_VIEW_EXPANDER_SIZE 12
1182 #define _TREE_VIEW_VERTICAL_SEPARATOR 2
1183 #define _TREE_VIEW_HORIZONTAL_SEPARATOR 2
1184
1185   gtk_widget_class_install_style_property (widget_class,
1186                                            g_param_spec_int ("expander-size",
1187                                                              P_("Expander Size"),
1188                                                              P_("Size of the expander arrow"),
1189                                                              0,
1190                                                              G_MAXINT,
1191                                                              _TREE_VIEW_EXPANDER_SIZE,
1192                                                              GTK_PARAM_READABLE));
1193
1194   gtk_widget_class_install_style_property (widget_class,
1195                                            g_param_spec_int ("vertical-separator",
1196                                                              P_("Vertical Separator Width"),
1197                                                              P_("Vertical space between cells.  Must be an even number"),
1198                                                              0,
1199                                                              G_MAXINT,
1200                                                              _TREE_VIEW_VERTICAL_SEPARATOR,
1201                                                              GTK_PARAM_READABLE));
1202
1203   gtk_widget_class_install_style_property (widget_class,
1204                                            g_param_spec_int ("horizontal-separator",
1205                                                              P_("Horizontal Separator Width"),
1206                                                              P_("Horizontal space between cells.  Must be an even number"),
1207                                                              0,
1208                                                              G_MAXINT,
1209                                                              _TREE_VIEW_HORIZONTAL_SEPARATOR,
1210                                                              GTK_PARAM_READABLE));
1211
1212   gtk_widget_class_install_style_property (widget_class,
1213                                            g_param_spec_boolean ("allow-rules",
1214                                                                  P_("Allow Rules"),
1215                                                                  P_("Allow drawing of alternating color rows"),
1216                                                                  TRUE,
1217                                                                  GTK_PARAM_READABLE));
1218
1219   gtk_widget_class_install_style_property (widget_class,
1220                                            g_param_spec_boolean ("indent-expanders",
1221                                                                  P_("Indent Expanders"),
1222                                                                  P_("Make the expanders indented"),
1223                                                                  TRUE,
1224                                                                  GTK_PARAM_READABLE));
1225
1226   gtk_widget_class_install_style_property (widget_class,
1227                                            g_param_spec_boxed ("even-row-color",
1228                                                                P_("Even Row Color"),
1229                                                                P_("Color to use for even rows"),
1230                                                                GDK_TYPE_COLOR,
1231                                                                GTK_PARAM_READABLE));
1232
1233   gtk_widget_class_install_style_property (widget_class,
1234                                            g_param_spec_boxed ("odd-row-color",
1235                                                                P_("Odd Row Color"),
1236                                                                P_("Color to use for odd rows"),
1237                                                                GDK_TYPE_COLOR,
1238                                                                GTK_PARAM_READABLE));
1239
1240   gtk_widget_class_install_style_property (widget_class,
1241                                            g_param_spec_int ("grid-line-width",
1242                                                              P_("Grid line width"),
1243                                                              P_("Width, in pixels, of the tree view grid lines"),
1244                                                              0, G_MAXINT, 1,
1245                                                              GTK_PARAM_READABLE));
1246
1247   gtk_widget_class_install_style_property (widget_class,
1248                                            g_param_spec_int ("tree-line-width",
1249                                                              P_("Tree line width"),
1250                                                              P_("Width, in pixels, of the tree view lines"),
1251                                                              0, G_MAXINT, 1,
1252                                                              GTK_PARAM_READABLE));
1253
1254   gtk_widget_class_install_style_property (widget_class,
1255                                            g_param_spec_string ("grid-line-pattern",
1256                                                                 P_("Grid line pattern"),
1257                                                                 P_("Dash pattern used to draw the tree view grid lines"),
1258                                                                 "\1\1",
1259                                                                 GTK_PARAM_READABLE));
1260
1261   gtk_widget_class_install_style_property (widget_class,
1262                                            g_param_spec_string ("tree-line-pattern",
1263                                                                 P_("Tree line pattern"),
1264                                                                 P_("Dash pattern used to draw the tree view lines"),
1265                                                                 "\1\1",
1266                                                                 GTK_PARAM_READABLE));
1267
1268   /* Signals */
1269   /**
1270    * GtkTreeView::row-activated:
1271    * @tree_view: the object on which the signal is emitted
1272    * @path: the #GtkTreePath for the activated row
1273    * @column: the #GtkTreeViewColumn in which the activation occurred
1274    *
1275    * The "row-activated" signal is emitted when the method
1276    * gtk_tree_view_row_activated() is called or the user double clicks 
1277    * a treeview row. It is also emitted when a non-editable row is 
1278    * selected and one of the keys: Space, Shift+Space, Return or 
1279    * Enter is pressed.
1280    * 
1281    * For selection handling refer to the <link linkend="TreeWidget">tree 
1282    * widget conceptual overview</link> as well as #GtkTreeSelection.
1283    */
1284   tree_view_signals[ROW_ACTIVATED] =
1285     g_signal_new (I_("row-activated"),
1286                   G_TYPE_FROM_CLASS (o_class),
1287                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1288                   G_STRUCT_OFFSET (GtkTreeViewClass, row_activated),
1289                   NULL, NULL,
1290                   _gtk_marshal_VOID__BOXED_OBJECT,
1291                   G_TYPE_NONE, 2,
1292                   GTK_TYPE_TREE_PATH,
1293                   GTK_TYPE_TREE_VIEW_COLUMN);
1294
1295   /**
1296    * GtkTreeView::test-expand-row:
1297    * @tree_view: the object on which the signal is emitted
1298    * @iter: the tree iter of the row to expand
1299    * @path: a tree path that points to the row 
1300    * 
1301    * The given row is about to be expanded (show its children nodes). Use this
1302    * signal if you need to control the expandability of individual rows.
1303    *
1304    * Returns: %FALSE to allow expansion, %TRUE to reject
1305    */
1306   tree_view_signals[TEST_EXPAND_ROW] =
1307     g_signal_new (I_("test-expand-row"),
1308                   G_TYPE_FROM_CLASS (o_class),
1309                   G_SIGNAL_RUN_LAST,
1310                   G_STRUCT_OFFSET (GtkTreeViewClass, test_expand_row),
1311                   _gtk_boolean_handled_accumulator, NULL,
1312                   _gtk_marshal_BOOLEAN__BOXED_BOXED,
1313                   G_TYPE_BOOLEAN, 2,
1314                   GTK_TYPE_TREE_ITER,
1315                   GTK_TYPE_TREE_PATH);
1316
1317   /**
1318    * GtkTreeView::test-collapse-row:
1319    * @tree_view: the object on which the signal is emitted
1320    * @iter: the tree iter of the row to collapse
1321    * @path: a tree path that points to the row 
1322    * 
1323    * The given row is about to be collapsed (hide its children nodes). Use this
1324    * signal if you need to control the collapsibility of individual rows.
1325    *
1326    * Returns: %FALSE to allow collapsing, %TRUE to reject
1327    */
1328   tree_view_signals[TEST_COLLAPSE_ROW] =
1329     g_signal_new (I_("test-collapse-row"),
1330                   G_TYPE_FROM_CLASS (o_class),
1331                   G_SIGNAL_RUN_LAST,
1332                   G_STRUCT_OFFSET (GtkTreeViewClass, test_collapse_row),
1333                   _gtk_boolean_handled_accumulator, NULL,
1334                   _gtk_marshal_BOOLEAN__BOXED_BOXED,
1335                   G_TYPE_BOOLEAN, 2,
1336                   GTK_TYPE_TREE_ITER,
1337                   GTK_TYPE_TREE_PATH);
1338
1339   /**
1340    * GtkTreeView::row-expanded:
1341    * @tree_view: the object on which the signal is emitted
1342    * @iter: the tree iter of the expanded row
1343    * @path: a tree path that points to the row 
1344    * 
1345    * The given row has been expanded (child nodes are shown).
1346    */
1347   tree_view_signals[ROW_EXPANDED] =
1348     g_signal_new (I_("row-expanded"),
1349                   G_TYPE_FROM_CLASS (o_class),
1350                   G_SIGNAL_RUN_LAST,
1351                   G_STRUCT_OFFSET (GtkTreeViewClass, row_expanded),
1352                   NULL, NULL,
1353                   _gtk_marshal_VOID__BOXED_BOXED,
1354                   G_TYPE_NONE, 2,
1355                   GTK_TYPE_TREE_ITER,
1356                   GTK_TYPE_TREE_PATH);
1357
1358   /**
1359    * GtkTreeView::row-collapsed:
1360    * @tree_view: the object on which the signal is emitted
1361    * @iter: the tree iter of the collapsed row
1362    * @path: a tree path that points to the row 
1363    * 
1364    * The given row has been collapsed (child nodes are hidden).
1365    */
1366   tree_view_signals[ROW_COLLAPSED] =
1367     g_signal_new (I_("row-collapsed"),
1368                   G_TYPE_FROM_CLASS (o_class),
1369                   G_SIGNAL_RUN_LAST,
1370                   G_STRUCT_OFFSET (GtkTreeViewClass, row_collapsed),
1371                   NULL, NULL,
1372                   _gtk_marshal_VOID__BOXED_BOXED,
1373                   G_TYPE_NONE, 2,
1374                   GTK_TYPE_TREE_ITER,
1375                   GTK_TYPE_TREE_PATH);
1376
1377   /**
1378    * GtkTreeView::columns-changed:
1379    * @tree_view: the object on which the signal is emitted 
1380    * 
1381    * The number of columns of the treeview has changed.
1382    */
1383   tree_view_signals[COLUMNS_CHANGED] =
1384     g_signal_new (I_("columns-changed"),
1385                   G_TYPE_FROM_CLASS (o_class),
1386                   G_SIGNAL_RUN_LAST,
1387                   G_STRUCT_OFFSET (GtkTreeViewClass, columns_changed),
1388                   NULL, NULL,
1389                   _gtk_marshal_VOID__VOID,
1390                   G_TYPE_NONE, 0);
1391
1392   /**
1393    * GtkTreeView::cursor-changed:
1394    * @tree_view: the object on which the signal is emitted
1395    * 
1396    * The position of the cursor (focused cell) has changed.
1397    */
1398   tree_view_signals[CURSOR_CHANGED] =
1399     g_signal_new (I_("cursor-changed"),
1400                   G_TYPE_FROM_CLASS (o_class),
1401                   G_SIGNAL_RUN_LAST,
1402                   G_STRUCT_OFFSET (GtkTreeViewClass, cursor_changed),
1403                   NULL, NULL,
1404                   _gtk_marshal_VOID__VOID,
1405                   G_TYPE_NONE, 0);
1406
1407   tree_view_signals[MOVE_CURSOR] =
1408     g_signal_new (I_("move-cursor"),
1409                   G_TYPE_FROM_CLASS (o_class),
1410                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1411                   G_STRUCT_OFFSET (GtkTreeViewClass, move_cursor),
1412                   NULL, NULL,
1413                   _gtk_marshal_BOOLEAN__ENUM_INT,
1414                   G_TYPE_BOOLEAN, 2,
1415                   GTK_TYPE_MOVEMENT_STEP,
1416                   G_TYPE_INT);
1417
1418   tree_view_signals[SELECT_ALL] =
1419     g_signal_new (I_("select-all"),
1420                   G_TYPE_FROM_CLASS (o_class),
1421                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1422                   G_STRUCT_OFFSET (GtkTreeViewClass, select_all),
1423                   NULL, NULL,
1424                   _gtk_marshal_BOOLEAN__VOID,
1425                   G_TYPE_BOOLEAN, 0);
1426
1427   tree_view_signals[UNSELECT_ALL] =
1428     g_signal_new (I_("unselect-all"),
1429                   G_TYPE_FROM_CLASS (o_class),
1430                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1431                   G_STRUCT_OFFSET (GtkTreeViewClass, unselect_all),
1432                   NULL, NULL,
1433                   _gtk_marshal_BOOLEAN__VOID,
1434                   G_TYPE_BOOLEAN, 0);
1435
1436   tree_view_signals[SELECT_CURSOR_ROW] =
1437     g_signal_new (I_("select-cursor-row"),
1438                   G_TYPE_FROM_CLASS (o_class),
1439                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1440                   G_STRUCT_OFFSET (GtkTreeViewClass, select_cursor_row),
1441                   NULL, NULL,
1442                   _gtk_marshal_BOOLEAN__BOOLEAN,
1443                   G_TYPE_BOOLEAN, 1,
1444                   G_TYPE_BOOLEAN);
1445
1446   tree_view_signals[TOGGLE_CURSOR_ROW] =
1447     g_signal_new (I_("toggle-cursor-row"),
1448                   G_TYPE_FROM_CLASS (o_class),
1449                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1450                   G_STRUCT_OFFSET (GtkTreeViewClass, toggle_cursor_row),
1451                   NULL, NULL,
1452                   _gtk_marshal_BOOLEAN__VOID,
1453                   G_TYPE_BOOLEAN, 0);
1454
1455   tree_view_signals[EXPAND_COLLAPSE_CURSOR_ROW] =
1456     g_signal_new (I_("expand-collapse-cursor-row"),
1457                   G_TYPE_FROM_CLASS (o_class),
1458                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1459                   G_STRUCT_OFFSET (GtkTreeViewClass, expand_collapse_cursor_row),
1460                   NULL, NULL,
1461                   _gtk_marshal_BOOLEAN__BOOLEAN_BOOLEAN_BOOLEAN,
1462                   G_TYPE_BOOLEAN, 3,
1463                   G_TYPE_BOOLEAN,
1464                   G_TYPE_BOOLEAN,
1465                   G_TYPE_BOOLEAN);
1466
1467   tree_view_signals[SELECT_CURSOR_PARENT] =
1468     g_signal_new (I_("select-cursor-parent"),
1469                   G_TYPE_FROM_CLASS (o_class),
1470                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1471                   G_STRUCT_OFFSET (GtkTreeViewClass, select_cursor_parent),
1472                   NULL, NULL,
1473                   _gtk_marshal_BOOLEAN__VOID,
1474                   G_TYPE_BOOLEAN, 0);
1475
1476   tree_view_signals[START_INTERACTIVE_SEARCH] =
1477     g_signal_new (I_("start-interactive-search"),
1478                   G_TYPE_FROM_CLASS (o_class),
1479                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1480                   G_STRUCT_OFFSET (GtkTreeViewClass, start_interactive_search),
1481                   NULL, NULL,
1482                   _gtk_marshal_BOOLEAN__VOID,
1483                   G_TYPE_BOOLEAN, 0);
1484
1485   /* Key bindings */
1486   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Up, 0, TRUE,
1487                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
1488   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Up, 0, TRUE,
1489                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
1490
1491   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Down, 0, TRUE,
1492                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
1493   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Down, 0, TRUE,
1494                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
1495
1496   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_p, GDK_CONTROL_MASK, FALSE,
1497                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
1498
1499   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_n, GDK_CONTROL_MASK, FALSE,
1500                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
1501
1502   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Home, 0, TRUE,
1503                                   GTK_MOVEMENT_BUFFER_ENDS, -1);
1504   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Home, 0, TRUE,
1505                                   GTK_MOVEMENT_BUFFER_ENDS, -1);
1506
1507   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_End, 0, TRUE,
1508                                   GTK_MOVEMENT_BUFFER_ENDS, 1);
1509   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_End, 0, TRUE,
1510                                   GTK_MOVEMENT_BUFFER_ENDS, 1);
1511
1512   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Page_Up, 0, TRUE,
1513                                   GTK_MOVEMENT_PAGES, -1);
1514   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Page_Up, 0, TRUE,
1515                                   GTK_MOVEMENT_PAGES, -1);
1516
1517   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Page_Down, 0, TRUE,
1518                                   GTK_MOVEMENT_PAGES, 1);
1519   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Page_Down, 0, TRUE,
1520                                   GTK_MOVEMENT_PAGES, 1);
1521
1522
1523   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Right, 0, "move-cursor", 2,
1524                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1525                                 G_TYPE_INT, 1);
1526
1527   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Left, 0, "move-cursor", 2,
1528                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1529                                 G_TYPE_INT, -1);
1530
1531   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Right, 0, "move-cursor", 2,
1532                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1533                                 G_TYPE_INT, 1);
1534
1535   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Left, 0, "move-cursor", 2,
1536                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1537                                 G_TYPE_INT, -1);
1538
1539   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Right, GDK_CONTROL_MASK,
1540                                 "move-cursor", 2,
1541                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1542                                 G_TYPE_INT, 1);
1543
1544   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Left, GDK_CONTROL_MASK,
1545                                 "move-cursor", 2,
1546                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1547                                 G_TYPE_INT, -1);
1548
1549   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Right, GDK_CONTROL_MASK,
1550                                 "move-cursor", 2,
1551                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1552                                 G_TYPE_INT, 1);
1553
1554   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Left, GDK_CONTROL_MASK,
1555                                 "move-cursor", 2,
1556                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1557                                 G_TYPE_INT, -1);
1558
1559   gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, GDK_CONTROL_MASK, "toggle-cursor-row", 0);
1560   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Space, GDK_CONTROL_MASK, "toggle-cursor-row", 0);
1561
1562   gtk_binding_entry_add_signal (binding_set, GDK_KEY_a, GDK_CONTROL_MASK, "select-all", 0);
1563   gtk_binding_entry_add_signal (binding_set, GDK_KEY_slash, GDK_CONTROL_MASK, "select-all", 0);
1564
1565   gtk_binding_entry_add_signal (binding_set, GDK_KEY_A, GDK_CONTROL_MASK | GDK_SHIFT_MASK, "unselect-all", 0);
1566   gtk_binding_entry_add_signal (binding_set, GDK_KEY_backslash, GDK_CONTROL_MASK, "unselect-all", 0);
1567
1568   gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, GDK_SHIFT_MASK, "select-cursor-row", 1,
1569                                 G_TYPE_BOOLEAN, TRUE);
1570   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Space, GDK_SHIFT_MASK, "select-cursor-row", 1,
1571                                 G_TYPE_BOOLEAN, TRUE);
1572
1573   gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, 0, "select-cursor-row", 1,
1574                                 G_TYPE_BOOLEAN, TRUE);
1575   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Space, 0, "select-cursor-row", 1,
1576                                 G_TYPE_BOOLEAN, TRUE);
1577   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Return, 0, "select-cursor-row", 1,
1578                                 G_TYPE_BOOLEAN, TRUE);
1579   gtk_binding_entry_add_signal (binding_set, GDK_KEY_ISO_Enter, 0, "select-cursor-row", 1,
1580                                 G_TYPE_BOOLEAN, TRUE);
1581   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Enter, 0, "select-cursor-row", 1,
1582                                 G_TYPE_BOOLEAN, TRUE);
1583
1584   /* expand and collapse rows */
1585   gtk_binding_entry_add_signal (binding_set, GDK_KEY_plus, 0, "expand-collapse-cursor-row", 3,
1586                                 G_TYPE_BOOLEAN, TRUE,
1587                                 G_TYPE_BOOLEAN, TRUE,
1588                                 G_TYPE_BOOLEAN, FALSE);
1589
1590   gtk_binding_entry_add_signal (binding_set, GDK_KEY_asterisk, 0,
1591                                 "expand-collapse-cursor-row", 3,
1592                                 G_TYPE_BOOLEAN, TRUE,
1593                                 G_TYPE_BOOLEAN, TRUE,
1594                                 G_TYPE_BOOLEAN, TRUE);
1595   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Multiply, 0,
1596                                 "expand-collapse-cursor-row", 3,
1597                                 G_TYPE_BOOLEAN, TRUE,
1598                                 G_TYPE_BOOLEAN, TRUE,
1599                                 G_TYPE_BOOLEAN, TRUE);
1600
1601   gtk_binding_entry_add_signal (binding_set, GDK_KEY_slash, 0,
1602                                 "expand-collapse-cursor-row", 3,
1603                                 G_TYPE_BOOLEAN, TRUE,
1604                                 G_TYPE_BOOLEAN, FALSE,
1605                                 G_TYPE_BOOLEAN, FALSE);
1606   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Divide, 0,
1607                                 "expand-collapse-cursor-row", 3,
1608                                 G_TYPE_BOOLEAN, TRUE,
1609                                 G_TYPE_BOOLEAN, FALSE,
1610                                 G_TYPE_BOOLEAN, FALSE);
1611
1612   /* Not doable on US keyboards */
1613   gtk_binding_entry_add_signal (binding_set, GDK_KEY_plus, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1614                                 G_TYPE_BOOLEAN, TRUE,
1615                                 G_TYPE_BOOLEAN, TRUE,
1616                                 G_TYPE_BOOLEAN, TRUE);
1617   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Add, 0, "expand-collapse-cursor-row", 3,
1618                                 G_TYPE_BOOLEAN, TRUE,
1619                                 G_TYPE_BOOLEAN, TRUE,
1620                                 G_TYPE_BOOLEAN, FALSE);
1621   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Add, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1622                                 G_TYPE_BOOLEAN, TRUE,
1623                                 G_TYPE_BOOLEAN, TRUE,
1624                                 G_TYPE_BOOLEAN, TRUE);
1625   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Add, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1626                                 G_TYPE_BOOLEAN, TRUE,
1627                                 G_TYPE_BOOLEAN, TRUE,
1628                                 G_TYPE_BOOLEAN, TRUE);
1629   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Right, GDK_SHIFT_MASK,
1630                                 "expand-collapse-cursor-row", 3,
1631                                 G_TYPE_BOOLEAN, FALSE,
1632                                 G_TYPE_BOOLEAN, TRUE,
1633                                 G_TYPE_BOOLEAN, TRUE);
1634   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Right, GDK_SHIFT_MASK,
1635                                 "expand-collapse-cursor-row", 3,
1636                                 G_TYPE_BOOLEAN, FALSE,
1637                                 G_TYPE_BOOLEAN, TRUE,
1638                                 G_TYPE_BOOLEAN, TRUE);
1639   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Right,
1640                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1641                                 "expand-collapse-cursor-row", 3,
1642                                 G_TYPE_BOOLEAN, FALSE,
1643                                 G_TYPE_BOOLEAN, TRUE,
1644                                 G_TYPE_BOOLEAN, TRUE);
1645   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Right,
1646                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1647                                 "expand-collapse-cursor-row", 3,
1648                                 G_TYPE_BOOLEAN, FALSE,
1649                                 G_TYPE_BOOLEAN, TRUE,
1650                                 G_TYPE_BOOLEAN, TRUE);
1651
1652   gtk_binding_entry_add_signal (binding_set, GDK_KEY_minus, 0, "expand-collapse-cursor-row", 3,
1653                                 G_TYPE_BOOLEAN, TRUE,
1654                                 G_TYPE_BOOLEAN, FALSE,
1655                                 G_TYPE_BOOLEAN, FALSE);
1656   gtk_binding_entry_add_signal (binding_set, GDK_KEY_minus, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1657                                 G_TYPE_BOOLEAN, TRUE,
1658                                 G_TYPE_BOOLEAN, FALSE,
1659                                 G_TYPE_BOOLEAN, TRUE);
1660   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Subtract, 0, "expand-collapse-cursor-row", 3,
1661                                 G_TYPE_BOOLEAN, TRUE,
1662                                 G_TYPE_BOOLEAN, FALSE,
1663                                 G_TYPE_BOOLEAN, FALSE);
1664   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Subtract, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1665                                 G_TYPE_BOOLEAN, TRUE,
1666                                 G_TYPE_BOOLEAN, FALSE,
1667                                 G_TYPE_BOOLEAN, TRUE);
1668   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Left, GDK_SHIFT_MASK,
1669                                 "expand-collapse-cursor-row", 3,
1670                                 G_TYPE_BOOLEAN, FALSE,
1671                                 G_TYPE_BOOLEAN, FALSE,
1672                                 G_TYPE_BOOLEAN, TRUE);
1673   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Left, GDK_SHIFT_MASK,
1674                                 "expand-collapse-cursor-row", 3,
1675                                 G_TYPE_BOOLEAN, FALSE,
1676                                 G_TYPE_BOOLEAN, FALSE,
1677                                 G_TYPE_BOOLEAN, TRUE);
1678   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Left,
1679                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1680                                 "expand-collapse-cursor-row", 3,
1681                                 G_TYPE_BOOLEAN, FALSE,
1682                                 G_TYPE_BOOLEAN, FALSE,
1683                                 G_TYPE_BOOLEAN, TRUE);
1684   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Left,
1685                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1686                                 "expand-collapse-cursor-row", 3,
1687                                 G_TYPE_BOOLEAN, FALSE,
1688                                 G_TYPE_BOOLEAN, FALSE,
1689                                 G_TYPE_BOOLEAN, TRUE);
1690
1691   gtk_binding_entry_add_signal (binding_set, GDK_KEY_BackSpace, 0, "select-cursor-parent", 0);
1692   gtk_binding_entry_add_signal (binding_set, GDK_KEY_BackSpace, GDK_CONTROL_MASK, "select-cursor-parent", 0);
1693
1694   gtk_binding_entry_add_signal (binding_set, GDK_KEY_f, GDK_CONTROL_MASK, "start-interactive-search", 0);
1695
1696   gtk_binding_entry_add_signal (binding_set, GDK_KEY_F, GDK_CONTROL_MASK, "start-interactive-search", 0);
1697
1698   g_type_class_add_private (o_class, sizeof (GtkTreeViewPrivate));
1699 }
1700
1701 static void
1702 gtk_tree_view_init (GtkTreeView *tree_view)
1703 {
1704   tree_view->priv = G_TYPE_INSTANCE_GET_PRIVATE (tree_view, GTK_TYPE_TREE_VIEW, GtkTreeViewPrivate);
1705
1706   gtk_widget_set_can_focus (GTK_WIDGET (tree_view), TRUE);
1707   gtk_widget_set_redraw_on_allocate (GTK_WIDGET (tree_view), FALSE);
1708
1709   tree_view->priv->show_expanders = TRUE;
1710   tree_view->priv->draw_keyfocus = TRUE;
1711   tree_view->priv->headers_visible = TRUE;
1712
1713   /* We need some padding */
1714   tree_view->priv->dy = 0;
1715   tree_view->priv->cursor_offset = 0;
1716   tree_view->priv->n_columns = 0;
1717   tree_view->priv->header_height = 1;
1718   tree_view->priv->x_drag = 0;
1719   tree_view->priv->drag_pos = -1;
1720   tree_view->priv->header_has_focus = FALSE;
1721   tree_view->priv->pressed_button = -1;
1722   tree_view->priv->press_start_x = -1;
1723   tree_view->priv->press_start_y = -1;
1724   tree_view->priv->reorderable = FALSE;
1725   tree_view->priv->presize_handler_timer = 0;
1726   tree_view->priv->scroll_sync_timer = 0;
1727   tree_view->priv->fixed_height = -1;
1728   tree_view->priv->fixed_height_mode = FALSE;
1729   tree_view->priv->fixed_height_check = 0;
1730   tree_view->priv->selection = _gtk_tree_selection_new_with_tree_view (tree_view);
1731   tree_view->priv->enable_search = TRUE;
1732   tree_view->priv->search_column = -1;
1733   tree_view->priv->search_position_func = gtk_tree_view_search_position_func;
1734   tree_view->priv->search_equal_func = gtk_tree_view_search_equal_func;
1735   tree_view->priv->search_custom_entry_set = FALSE;
1736   tree_view->priv->typeselect_flush_timeout = 0;
1737   tree_view->priv->init_hadjust_value = TRUE;    
1738   tree_view->priv->width = 0;
1739           
1740   tree_view->priv->hover_selection = FALSE;
1741   tree_view->priv->hover_expand = FALSE;
1742
1743   tree_view->priv->level_indentation = 0;
1744
1745   tree_view->priv->rubber_banding_enable = FALSE;
1746
1747   tree_view->priv->grid_lines = GTK_TREE_VIEW_GRID_LINES_NONE;
1748   tree_view->priv->tree_lines_enabled = FALSE;
1749
1750   tree_view->priv->tooltip_column = -1;
1751
1752   tree_view->priv->post_validation_flag = FALSE;
1753
1754   tree_view->priv->last_button_x = -1;
1755   tree_view->priv->last_button_y = -1;
1756
1757   tree_view->priv->event_last_x = -10000;
1758   tree_view->priv->event_last_y = -10000;
1759
1760   gtk_tree_view_set_vadjustment (tree_view, NULL);
1761   gtk_tree_view_set_hadjustment (tree_view, NULL);
1762 }
1763
1764 \f
1765
1766 /* GObject Methods
1767  */
1768
1769 static void
1770 gtk_tree_view_set_property (GObject         *object,
1771                             guint            prop_id,
1772                             const GValue    *value,
1773                             GParamSpec      *pspec)
1774 {
1775   GtkTreeView *tree_view;
1776
1777   tree_view = GTK_TREE_VIEW (object);
1778
1779   switch (prop_id)
1780     {
1781     case PROP_MODEL:
1782       gtk_tree_view_set_model (tree_view, g_value_get_object (value));
1783       break;
1784     case PROP_HADJUSTMENT:
1785       gtk_tree_view_set_hadjustment (tree_view, g_value_get_object (value));
1786       break;
1787     case PROP_VADJUSTMENT:
1788       gtk_tree_view_set_vadjustment (tree_view, g_value_get_object (value));
1789       break;
1790     case PROP_HSCROLL_POLICY:
1791       tree_view->priv->hscroll_policy = g_value_get_enum (value);
1792       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
1793       break;
1794     case PROP_VSCROLL_POLICY:
1795       tree_view->priv->vscroll_policy = g_value_get_enum (value);
1796       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
1797       break;
1798     case PROP_HEADERS_VISIBLE:
1799       gtk_tree_view_set_headers_visible (tree_view, g_value_get_boolean (value));
1800       break;
1801     case PROP_HEADERS_CLICKABLE:
1802       gtk_tree_view_set_headers_clickable (tree_view, g_value_get_boolean (value));
1803       break;
1804     case PROP_EXPANDER_COLUMN:
1805       gtk_tree_view_set_expander_column (tree_view, g_value_get_object (value));
1806       break;
1807     case PROP_REORDERABLE:
1808       gtk_tree_view_set_reorderable (tree_view, g_value_get_boolean (value));
1809       break;
1810     case PROP_RULES_HINT:
1811       gtk_tree_view_set_rules_hint (tree_view, g_value_get_boolean (value));
1812       break;
1813     case PROP_ENABLE_SEARCH:
1814       gtk_tree_view_set_enable_search (tree_view, g_value_get_boolean (value));
1815       break;
1816     case PROP_SEARCH_COLUMN:
1817       gtk_tree_view_set_search_column (tree_view, g_value_get_int (value));
1818       break;
1819     case PROP_FIXED_HEIGHT_MODE:
1820       gtk_tree_view_set_fixed_height_mode (tree_view, g_value_get_boolean (value));
1821       break;
1822     case PROP_HOVER_SELECTION:
1823       tree_view->priv->hover_selection = g_value_get_boolean (value);
1824       break;
1825     case PROP_HOVER_EXPAND:
1826       tree_view->priv->hover_expand = g_value_get_boolean (value);
1827       break;
1828     case PROP_SHOW_EXPANDERS:
1829       gtk_tree_view_set_show_expanders (tree_view, g_value_get_boolean (value));
1830       break;
1831     case PROP_LEVEL_INDENTATION:
1832       tree_view->priv->level_indentation = g_value_get_int (value);
1833       break;
1834     case PROP_RUBBER_BANDING:
1835       tree_view->priv->rubber_banding_enable = g_value_get_boolean (value);
1836       break;
1837     case PROP_ENABLE_GRID_LINES:
1838       gtk_tree_view_set_grid_lines (tree_view, g_value_get_enum (value));
1839       break;
1840     case PROP_ENABLE_TREE_LINES:
1841       gtk_tree_view_set_enable_tree_lines (tree_view, g_value_get_boolean (value));
1842       break;
1843     case PROP_TOOLTIP_COLUMN:
1844       gtk_tree_view_set_tooltip_column (tree_view, g_value_get_int (value));
1845       break;
1846     default:
1847       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1848       break;
1849     }
1850 }
1851
1852 static void
1853 gtk_tree_view_get_property (GObject    *object,
1854                             guint       prop_id,
1855                             GValue     *value,
1856                             GParamSpec *pspec)
1857 {
1858   GtkTreeView *tree_view;
1859
1860   tree_view = GTK_TREE_VIEW (object);
1861
1862   switch (prop_id)
1863     {
1864     case PROP_MODEL:
1865       g_value_set_object (value, tree_view->priv->model);
1866       break;
1867     case PROP_HADJUSTMENT:
1868       g_value_set_object (value, tree_view->priv->hadjustment);
1869       break;
1870     case PROP_VADJUSTMENT:
1871       g_value_set_object (value, tree_view->priv->vadjustment);
1872       break;
1873     case PROP_HSCROLL_POLICY:
1874       g_value_set_enum (value, tree_view->priv->hscroll_policy);
1875       break;
1876     case PROP_VSCROLL_POLICY:
1877       g_value_set_enum (value, tree_view->priv->vscroll_policy);
1878       break;
1879     case PROP_HEADERS_VISIBLE:
1880       g_value_set_boolean (value, gtk_tree_view_get_headers_visible (tree_view));
1881       break;
1882     case PROP_HEADERS_CLICKABLE:
1883       g_value_set_boolean (value, gtk_tree_view_get_headers_clickable (tree_view));
1884       break;
1885     case PROP_EXPANDER_COLUMN:
1886       g_value_set_object (value, tree_view->priv->expander_column);
1887       break;
1888     case PROP_REORDERABLE:
1889       g_value_set_boolean (value, tree_view->priv->reorderable);
1890       break;
1891     case PROP_RULES_HINT:
1892       g_value_set_boolean (value, tree_view->priv->has_rules);
1893       break;
1894     case PROP_ENABLE_SEARCH:
1895       g_value_set_boolean (value, tree_view->priv->enable_search);
1896       break;
1897     case PROP_SEARCH_COLUMN:
1898       g_value_set_int (value, tree_view->priv->search_column);
1899       break;
1900     case PROP_FIXED_HEIGHT_MODE:
1901       g_value_set_boolean (value, tree_view->priv->fixed_height_mode);
1902       break;
1903     case PROP_HOVER_SELECTION:
1904       g_value_set_boolean (value, tree_view->priv->hover_selection);
1905       break;
1906     case PROP_HOVER_EXPAND:
1907       g_value_set_boolean (value, tree_view->priv->hover_expand);
1908       break;
1909     case PROP_SHOW_EXPANDERS:
1910       g_value_set_boolean (value, tree_view->priv->show_expanders);
1911       break;
1912     case PROP_LEVEL_INDENTATION:
1913       g_value_set_int (value, tree_view->priv->level_indentation);
1914       break;
1915     case PROP_RUBBER_BANDING:
1916       g_value_set_boolean (value, tree_view->priv->rubber_banding_enable);
1917       break;
1918     case PROP_ENABLE_GRID_LINES:
1919       g_value_set_enum (value, tree_view->priv->grid_lines);
1920       break;
1921     case PROP_ENABLE_TREE_LINES:
1922       g_value_set_boolean (value, tree_view->priv->tree_lines_enabled);
1923       break;
1924     case PROP_TOOLTIP_COLUMN:
1925       g_value_set_int (value, tree_view->priv->tooltip_column);
1926       break;
1927     default:
1928       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1929       break;
1930     }
1931 }
1932
1933 static void
1934 gtk_tree_view_finalize (GObject *object)
1935 {
1936   G_OBJECT_CLASS (gtk_tree_view_parent_class)->finalize (object);
1937 }
1938
1939
1940 static GtkBuildableIface *parent_buildable_iface;
1941
1942 static void
1943 gtk_tree_view_buildable_init (GtkBuildableIface *iface)
1944 {
1945   parent_buildable_iface = g_type_interface_peek_parent (iface);
1946   iface->add_child = gtk_tree_view_buildable_add_child;
1947   iface->get_internal_child = gtk_tree_view_buildable_get_internal_child;
1948 }
1949
1950 static void
1951 gtk_tree_view_buildable_add_child (GtkBuildable *tree_view,
1952                                    GtkBuilder  *builder,
1953                                    GObject     *child,
1954                                    const gchar *type)
1955 {
1956   gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), GTK_TREE_VIEW_COLUMN (child));
1957 }
1958
1959 static GObject *
1960 gtk_tree_view_buildable_get_internal_child (GtkBuildable      *buildable,
1961                                             GtkBuilder        *builder,
1962                                             const gchar       *childname)
1963 {
1964     if (strcmp (childname, "selection") == 0)
1965       return G_OBJECT (GTK_TREE_VIEW (buildable)->priv->selection);
1966     
1967     return parent_buildable_iface->get_internal_child (buildable,
1968                                                        builder,
1969                                                        childname);
1970 }
1971
1972 /* GtkWidget Methods
1973  */
1974
1975 static void
1976 gtk_tree_view_free_rbtree (GtkTreeView *tree_view)
1977 {
1978   _gtk_rbtree_free (tree_view->priv->tree);
1979   
1980   tree_view->priv->tree = NULL;
1981   tree_view->priv->button_pressed_node = NULL;
1982   tree_view->priv->button_pressed_tree = NULL;
1983   tree_view->priv->prelight_tree = NULL;
1984   tree_view->priv->prelight_node = NULL;
1985   tree_view->priv->expanded_collapsed_node = NULL;
1986   tree_view->priv->expanded_collapsed_tree = NULL;
1987 }
1988
1989 static void
1990 gtk_tree_view_destroy (GtkWidget *widget)
1991 {
1992   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
1993   GList *list;
1994
1995   gtk_tree_view_stop_editing (tree_view, TRUE);
1996
1997   if (tree_view->priv->columns != NULL)
1998     {
1999       list = tree_view->priv->columns;
2000       while (list)
2001         {
2002           GtkTreeViewColumn *column;
2003           column = GTK_TREE_VIEW_COLUMN (list->data);
2004           list = list->next;
2005           gtk_tree_view_remove_column (tree_view, column);
2006         }
2007       tree_view->priv->columns = NULL;
2008     }
2009
2010   if (tree_view->priv->tree != NULL)
2011     {
2012       gtk_tree_view_unref_and_check_selection_tree (tree_view, tree_view->priv->tree);
2013
2014       gtk_tree_view_free_rbtree (tree_view);
2015     }
2016
2017   if (tree_view->priv->selection != NULL)
2018     {
2019       _gtk_tree_selection_set_tree_view (tree_view->priv->selection, NULL);
2020       g_object_unref (tree_view->priv->selection);
2021       tree_view->priv->selection = NULL;
2022     }
2023
2024   if (tree_view->priv->scroll_to_path != NULL)
2025     {
2026       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
2027       tree_view->priv->scroll_to_path = NULL;
2028     }
2029
2030   if (tree_view->priv->drag_dest_row != NULL)
2031     {
2032       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
2033       tree_view->priv->drag_dest_row = NULL;
2034     }
2035
2036   if (tree_view->priv->top_row != NULL)
2037     {
2038       gtk_tree_row_reference_free (tree_view->priv->top_row);
2039       tree_view->priv->top_row = NULL;
2040     }
2041
2042   if (tree_view->priv->column_drop_func_data &&
2043       tree_view->priv->column_drop_func_data_destroy)
2044     {
2045       tree_view->priv->column_drop_func_data_destroy (tree_view->priv->column_drop_func_data);
2046       tree_view->priv->column_drop_func_data = NULL;
2047     }
2048
2049   if (tree_view->priv->destroy_count_destroy &&
2050       tree_view->priv->destroy_count_data)
2051     {
2052       tree_view->priv->destroy_count_destroy (tree_view->priv->destroy_count_data);
2053       tree_view->priv->destroy_count_data = NULL;
2054     }
2055
2056   gtk_tree_row_reference_free (tree_view->priv->cursor);
2057   tree_view->priv->cursor = NULL;
2058
2059   gtk_tree_row_reference_free (tree_view->priv->anchor);
2060   tree_view->priv->anchor = NULL;
2061
2062   /* destroy interactive search dialog */
2063   if (tree_view->priv->search_window)
2064     {
2065       gtk_widget_destroy (tree_view->priv->search_window);
2066       tree_view->priv->search_window = NULL;
2067       tree_view->priv->search_entry = NULL;
2068       if (tree_view->priv->typeselect_flush_timeout)
2069         {
2070           g_source_remove (tree_view->priv->typeselect_flush_timeout);
2071           tree_view->priv->typeselect_flush_timeout = 0;
2072         }
2073     }
2074
2075   if (tree_view->priv->search_destroy && tree_view->priv->search_user_data)
2076     {
2077       tree_view->priv->search_destroy (tree_view->priv->search_user_data);
2078       tree_view->priv->search_user_data = NULL;
2079     }
2080
2081   if (tree_view->priv->search_position_destroy && tree_view->priv->search_position_user_data)
2082     {
2083       tree_view->priv->search_position_destroy (tree_view->priv->search_position_user_data);
2084       tree_view->priv->search_position_user_data = NULL;
2085     }
2086
2087   if (tree_view->priv->row_separator_destroy && tree_view->priv->row_separator_data)
2088     {
2089       tree_view->priv->row_separator_destroy (tree_view->priv->row_separator_data);
2090       tree_view->priv->row_separator_data = NULL;
2091     }
2092   
2093   gtk_tree_view_set_model (tree_view, NULL);
2094
2095   if (tree_view->priv->hadjustment)
2096     {
2097       g_object_unref (tree_view->priv->hadjustment);
2098       tree_view->priv->hadjustment = NULL;
2099     }
2100   if (tree_view->priv->vadjustment)
2101     {
2102       g_object_unref (tree_view->priv->vadjustment);
2103       tree_view->priv->vadjustment = NULL;
2104     }
2105
2106   GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->destroy (widget);
2107 }
2108
2109 /* GtkWidget::map helper */
2110 static void
2111 gtk_tree_view_map_buttons (GtkTreeView *tree_view)
2112 {
2113   GList *list;
2114
2115   g_return_if_fail (gtk_widget_get_mapped (GTK_WIDGET (tree_view)));
2116
2117   if (tree_view->priv->headers_visible)
2118     {
2119       GtkTreeViewColumn *column;
2120       GtkWidget         *button;
2121       GdkWindow         *window;
2122
2123       for (list = tree_view->priv->columns; list; list = list->next)
2124         {
2125           column = list->data;
2126           button = gtk_tree_view_column_get_button (column);
2127
2128           if (gtk_tree_view_column_get_visible (column) && button)
2129             gtk_widget_show_now (button);
2130
2131           if (gtk_widget_get_visible (button) &&
2132               !gtk_widget_get_mapped (button))
2133             gtk_widget_map (button);
2134         }
2135       for (list = tree_view->priv->columns; list; list = list->next)
2136         {
2137           column = list->data;
2138           if (gtk_tree_view_column_get_visible (column) == FALSE)
2139             continue;
2140
2141           window = _gtk_tree_view_column_get_window (column);
2142           if (gtk_tree_view_column_get_resizable (column))
2143             {
2144               gdk_window_raise (window);
2145               gdk_window_show (window);
2146             }
2147           else
2148             gdk_window_hide (window);
2149         }
2150       gdk_window_show (tree_view->priv->header_window);
2151     }
2152 }
2153
2154 static void
2155 gtk_tree_view_map (GtkWidget *widget)
2156 {
2157   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2158   GList *tmp_list;
2159
2160   gtk_widget_set_mapped (widget, TRUE);
2161
2162   tmp_list = tree_view->priv->children;
2163   while (tmp_list)
2164     {
2165       GtkTreeViewChild *child = tmp_list->data;
2166       tmp_list = tmp_list->next;
2167
2168       if (gtk_widget_get_visible (child->widget))
2169         {
2170           if (!gtk_widget_get_mapped (child->widget))
2171             gtk_widget_map (child->widget);
2172         }
2173     }
2174   gdk_window_show (tree_view->priv->bin_window);
2175
2176   gtk_tree_view_map_buttons (tree_view);
2177
2178   gdk_window_show (gtk_widget_get_window (widget));
2179 }
2180
2181 static void
2182 gtk_tree_view_realize (GtkWidget *widget)
2183 {
2184   GtkAllocation allocation;
2185   GtkStyleContext *context;
2186   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2187   GdkWindow *window;
2188   GdkWindowAttr attributes;
2189   GList *tmp_list;
2190   gint attributes_mask;
2191
2192   gtk_widget_set_realized (widget, TRUE);
2193
2194   gtk_widget_get_allocation (widget, &allocation);
2195
2196   /* Make the main, clipping window */
2197   attributes.window_type = GDK_WINDOW_CHILD;
2198   attributes.x = allocation.x;
2199   attributes.y = allocation.y;
2200   attributes.width = allocation.width;
2201   attributes.height = allocation.height;
2202   attributes.wclass = GDK_INPUT_OUTPUT;
2203   attributes.visual = gtk_widget_get_visual (widget);
2204   attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK;
2205
2206   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
2207
2208   window = gdk_window_new (gtk_widget_get_parent_window (widget),
2209                            &attributes, attributes_mask);
2210   gtk_widget_set_window (widget, window);
2211   gdk_window_set_user_data (window, widget);
2212
2213   gtk_widget_get_allocation (widget, &allocation);
2214
2215   /* Make the window for the tree */
2216   attributes.x = 0;
2217   attributes.y = gtk_tree_view_get_effective_header_height (tree_view);
2218   attributes.width = MAX (tree_view->priv->width, allocation.width);
2219   attributes.height = allocation.height;
2220   attributes.event_mask = (GDK_EXPOSURE_MASK |
2221                            GDK_SCROLL_MASK |
2222                            GDK_POINTER_MOTION_MASK |
2223                            GDK_ENTER_NOTIFY_MASK |
2224                            GDK_LEAVE_NOTIFY_MASK |
2225                            GDK_BUTTON_PRESS_MASK |
2226                            GDK_BUTTON_RELEASE_MASK |
2227                            gtk_widget_get_events (widget));
2228
2229   tree_view->priv->bin_window = gdk_window_new (window,
2230                                                 &attributes, attributes_mask);
2231   gdk_window_set_user_data (tree_view->priv->bin_window, widget);
2232
2233   gtk_widget_get_allocation (widget, &allocation);
2234
2235   /* Make the column header window */
2236   attributes.x = 0;
2237   attributes.y = 0;
2238   attributes.width = MAX (tree_view->priv->width, allocation.width);
2239   attributes.height = tree_view->priv->header_height;
2240   attributes.event_mask = (GDK_EXPOSURE_MASK |
2241                            GDK_SCROLL_MASK |
2242                            GDK_ENTER_NOTIFY_MASK |
2243                            GDK_LEAVE_NOTIFY_MASK |
2244                            GDK_BUTTON_PRESS_MASK |
2245                            GDK_BUTTON_RELEASE_MASK |
2246                            GDK_KEY_PRESS_MASK |
2247                            GDK_KEY_RELEASE_MASK |
2248                            gtk_widget_get_events (widget));
2249
2250   tree_view->priv->header_window = gdk_window_new (window,
2251                                                    &attributes, attributes_mask);
2252   gdk_window_set_user_data (tree_view->priv->header_window, widget);
2253
2254   context = gtk_widget_get_style_context (widget);
2255
2256   gtk_style_context_save (context);
2257   gtk_style_context_add_class (context, GTK_STYLE_CLASS_VIEW);
2258   gtk_style_context_set_background (context, tree_view->priv->bin_window);
2259   gtk_style_context_restore (context);
2260
2261   gtk_style_context_set_background (context, tree_view->priv->header_window);
2262
2263   tmp_list = tree_view->priv->children;
2264   while (tmp_list)
2265     {
2266       GtkTreeViewChild *child = tmp_list->data;
2267       tmp_list = tmp_list->next;
2268
2269       gtk_widget_set_parent_window (child->widget, tree_view->priv->bin_window);
2270     }
2271
2272   for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
2273     _gtk_tree_view_column_realize_button (GTK_TREE_VIEW_COLUMN (tmp_list->data));
2274
2275   /* Need to call those here, since they create GCs */
2276   gtk_tree_view_set_grid_lines (tree_view, tree_view->priv->grid_lines);
2277   gtk_tree_view_set_enable_tree_lines (tree_view, tree_view->priv->tree_lines_enabled);
2278
2279   install_presize_handler (tree_view); 
2280 }
2281
2282 static void
2283 gtk_tree_view_unrealize (GtkWidget *widget)
2284 {
2285   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2286   GtkTreeViewPrivate *priv = tree_view->priv;
2287   GtkStyleContext *context;
2288   GList *list;
2289
2290   if (priv->scroll_timeout != 0)
2291     {
2292       g_source_remove (priv->scroll_timeout);
2293       priv->scroll_timeout = 0;
2294     }
2295
2296   if (priv->auto_expand_timeout != 0)
2297     {
2298       g_source_remove (priv->auto_expand_timeout);
2299       priv->auto_expand_timeout = 0;
2300     }
2301
2302   if (priv->open_dest_timeout != 0)
2303     {
2304       g_source_remove (priv->open_dest_timeout);
2305       priv->open_dest_timeout = 0;
2306     }
2307
2308   context = gtk_widget_get_style_context (widget);
2309   gtk_style_context_cancel_animations (context, NULL);
2310
2311   if (priv->presize_handler_timer != 0)
2312     {
2313       g_source_remove (priv->presize_handler_timer);
2314       priv->presize_handler_timer = 0;
2315     }
2316
2317   if (priv->validate_rows_timer != 0)
2318     {
2319       g_source_remove (priv->validate_rows_timer);
2320       priv->validate_rows_timer = 0;
2321     }
2322
2323   if (priv->scroll_sync_timer != 0)
2324     {
2325       g_source_remove (priv->scroll_sync_timer);
2326       priv->scroll_sync_timer = 0;
2327     }
2328
2329   if (priv->typeselect_flush_timeout)
2330     {
2331       g_source_remove (priv->typeselect_flush_timeout);
2332       priv->typeselect_flush_timeout = 0;
2333     }
2334   
2335   for (list = priv->columns; list; list = list->next)
2336     _gtk_tree_view_column_unrealize_button (GTK_TREE_VIEW_COLUMN (list->data));
2337
2338   gdk_window_set_user_data (priv->bin_window, NULL);
2339   gdk_window_destroy (priv->bin_window);
2340   priv->bin_window = NULL;
2341
2342   gdk_window_set_user_data (priv->header_window, NULL);
2343   gdk_window_destroy (priv->header_window);
2344   priv->header_window = NULL;
2345
2346   if (priv->drag_window)
2347     {
2348       gdk_window_set_user_data (priv->drag_window, NULL);
2349       gdk_window_destroy (priv->drag_window);
2350       priv->drag_window = NULL;
2351     }
2352
2353   if (priv->drag_highlight_window)
2354     {
2355       gdk_window_set_user_data (priv->drag_highlight_window, NULL);
2356       gdk_window_destroy (priv->drag_highlight_window);
2357       priv->drag_highlight_window = NULL;
2358     }
2359
2360   GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->unrealize (widget);
2361 }
2362
2363 /* GtkWidget::size_request helper */
2364 static void
2365 gtk_tree_view_size_request_columns (GtkTreeView *tree_view)
2366 {
2367   GList *list;
2368
2369   tree_view->priv->header_height = 0;
2370
2371   if (tree_view->priv->model)
2372     {
2373       for (list = tree_view->priv->columns; list; list = list->next)
2374         {
2375           GtkRequisition     requisition;
2376           GtkTreeViewColumn *column = list->data;
2377           GtkWidget         *button = gtk_tree_view_column_get_button (column);
2378
2379           if (button == NULL)
2380             continue;
2381
2382           column = list->data;
2383
2384           gtk_widget_get_preferred_size (button, &requisition, NULL);
2385           tree_view->priv->header_height = MAX (tree_view->priv->header_height, requisition.height);
2386         }
2387     }
2388 }
2389
2390
2391 /* Called only by ::size_request */
2392 static void
2393 gtk_tree_view_update_size (GtkTreeView *tree_view)
2394 {
2395   GList *list;
2396   GtkTreeViewColumn *column;
2397   gint i;
2398
2399   if (tree_view->priv->model == NULL)
2400     {
2401       tree_view->priv->width = 0;
2402       tree_view->priv->prev_width = 0;                   
2403       tree_view->priv->height = 0;
2404       return;
2405     }
2406
2407   tree_view->priv->prev_width = tree_view->priv->width;  
2408   tree_view->priv->width = 0;
2409
2410   /* keep this in sync with size_allocate below */
2411   for (list = tree_view->priv->columns, i = 0; list; list = list->next, i++)
2412     {
2413       column = list->data;
2414       if (!gtk_tree_view_column_get_visible (column))
2415         continue;
2416
2417       tree_view->priv->width += _gtk_tree_view_column_request_width (column);
2418     }
2419
2420   if (tree_view->priv->tree == NULL)
2421     tree_view->priv->height = 0;
2422   else
2423     tree_view->priv->height = tree_view->priv->tree->root->offset;
2424 }
2425
2426 static void
2427 gtk_tree_view_size_request (GtkWidget      *widget,
2428                             GtkRequisition *requisition,
2429                             gboolean        may_validate)
2430 {
2431   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2432
2433   if (may_validate)
2434     {
2435       /* we validate some rows initially just to make sure we have some size.
2436        * In practice, with a lot of static lists, this should get a good width.
2437        */
2438       do_validate_rows (tree_view, FALSE);
2439     }
2440
2441   gtk_tree_view_size_request_columns (tree_view);
2442   gtk_tree_view_update_size (GTK_TREE_VIEW (widget));
2443
2444   requisition->width = tree_view->priv->width;
2445   requisition->height = tree_view->priv->height + gtk_tree_view_get_effective_header_height (tree_view);
2446 }
2447
2448 static void
2449 gtk_tree_view_get_preferred_width (GtkWidget *widget,
2450                                    gint      *minimum,
2451                                    gint      *natural)
2452 {
2453   GtkRequisition requisition;
2454
2455   gtk_tree_view_size_request (widget, &requisition, TRUE);
2456
2457   *minimum = *natural = requisition.width;
2458 }
2459
2460 static void
2461 gtk_tree_view_get_preferred_height (GtkWidget *widget,
2462                                     gint      *minimum,
2463                                     gint      *natural)
2464 {
2465   GtkRequisition requisition;
2466
2467   gtk_tree_view_size_request (widget, &requisition, TRUE);
2468
2469   *minimum = *natural = requisition.height;
2470 }
2471
2472 static int
2473 gtk_tree_view_calculate_width_before_expander (GtkTreeView *tree_view)
2474 {
2475   int width = 0;
2476   GList *list;
2477   gboolean rtl;
2478
2479   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2480   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
2481        list->data != tree_view->priv->expander_column;
2482        list = (rtl ? list->prev : list->next))
2483     {
2484       GtkTreeViewColumn *column = list->data;
2485
2486       width += gtk_tree_view_column_get_width (column);
2487     }
2488
2489   return width;
2490 }
2491
2492 static void
2493 invalidate_column (GtkTreeView       *tree_view,
2494                    GtkTreeViewColumn *column)
2495 {
2496   gint column_offset = 0;
2497   GList *list;
2498   GtkWidget *widget = GTK_WIDGET (tree_view);
2499   gboolean rtl;
2500
2501   if (!gtk_widget_get_realized (widget))
2502     return;
2503
2504   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2505   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
2506        list;
2507        list = (rtl ? list->prev : list->next))
2508     {
2509       GtkTreeViewColumn *tmpcolumn = list->data;
2510       if (tmpcolumn == column)
2511         {
2512           GtkAllocation allocation;
2513           GdkRectangle invalid_rect;
2514
2515           gtk_widget_get_allocation (widget, &allocation);
2516           invalid_rect.x = column_offset;
2517           invalid_rect.y = 0;
2518           invalid_rect.width = gtk_tree_view_column_get_width (column);
2519           invalid_rect.height = allocation.height;
2520
2521           gdk_window_invalidate_rect (gtk_widget_get_window (widget), &invalid_rect, TRUE);
2522           break;
2523         }
2524
2525       column_offset += gtk_tree_view_column_get_width (tmpcolumn);
2526     }
2527 }
2528
2529 static void
2530 invalidate_last_column (GtkTreeView *tree_view)
2531 {
2532   GList *last_column;
2533   gboolean rtl;
2534
2535   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2536
2537   for (last_column = (rtl ? g_list_first (tree_view->priv->columns) : g_list_last (tree_view->priv->columns));
2538        last_column;
2539        last_column = (rtl ? last_column->next : last_column->prev))
2540     {
2541       if (gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (last_column->data)))
2542         {
2543           invalidate_column (tree_view, last_column->data);
2544           return;
2545         }
2546     }
2547 }
2548
2549 /* GtkWidget::size_allocate helper */
2550 static void
2551 gtk_tree_view_size_allocate_columns (GtkWidget *widget,
2552                                      gboolean  *width_changed)
2553 {
2554   GtkTreeView *tree_view;
2555   GList *list, *first_column, *last_column;
2556   GtkTreeViewColumn *column;
2557   GtkAllocation widget_allocation;
2558   gint width = 0;
2559   gint extra, extra_per_column, extra_for_last;
2560   gint full_requested_width = 0;
2561   gint number_of_expand_columns = 0;
2562   gboolean column_changed = FALSE;
2563   gboolean rtl;
2564   gboolean update_expand;
2565   
2566   tree_view = GTK_TREE_VIEW (widget);
2567
2568   for (last_column = g_list_last (tree_view->priv->columns);
2569        last_column &&
2570        !(gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (last_column->data)));
2571        last_column = last_column->prev)
2572     ;
2573   if (last_column == NULL)
2574     return;
2575
2576   for (first_column = g_list_first (tree_view->priv->columns);
2577        first_column &&
2578        !(gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (first_column->data)));
2579        first_column = first_column->next)
2580     ;
2581
2582   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
2583
2584   /* find out how many extra space and expandable columns we have */
2585   for (list = tree_view->priv->columns; list != last_column->next; list = list->next)
2586     {
2587       column = (GtkTreeViewColumn *)list->data;
2588
2589       if (!gtk_tree_view_column_get_visible (column))
2590         continue;
2591
2592       full_requested_width += _gtk_tree_view_column_request_width (column);
2593
2594       if (gtk_tree_view_column_get_expand (column))
2595         number_of_expand_columns++;
2596     }
2597
2598   /* Only update the expand value if the width of the widget has changed,
2599    * or the number of expand columns has changed, or if there are no expand
2600    * columns, or if we didn't have an size-allocation yet after the
2601    * last validated node.
2602    */
2603   update_expand = (width_changed && *width_changed == TRUE)
2604       || number_of_expand_columns != tree_view->priv->last_number_of_expand_columns
2605       || number_of_expand_columns == 0
2606       || tree_view->priv->post_validation_flag == TRUE;
2607
2608   tree_view->priv->post_validation_flag = FALSE;
2609
2610   gtk_widget_get_allocation (widget, &widget_allocation);
2611   if (!update_expand)
2612     {
2613       extra = tree_view->priv->last_extra_space;
2614       extra_for_last = MAX (widget_allocation.width - full_requested_width - extra, 0);
2615     }
2616   else
2617     {
2618       extra = MAX (widget_allocation.width - full_requested_width, 0);
2619       extra_for_last = 0;
2620
2621       tree_view->priv->last_extra_space = extra;
2622     }
2623
2624   if (number_of_expand_columns > 0)
2625     extra_per_column = extra/number_of_expand_columns;
2626   else
2627     extra_per_column = 0;
2628
2629   if (update_expand)
2630     {
2631       tree_view->priv->last_extra_space_per_column = extra_per_column;
2632       tree_view->priv->last_number_of_expand_columns = number_of_expand_columns;
2633     }
2634
2635   for (list = (rtl ? last_column : first_column); 
2636        list != (rtl ? first_column->prev : last_column->next);
2637        list = (rtl ? list->prev : list->next)) 
2638     {
2639       gint old_width, column_width;
2640
2641       column = list->data;
2642       old_width = gtk_tree_view_column_get_width (column);
2643
2644       if (!gtk_tree_view_column_get_visible (column))
2645         continue;
2646
2647       /* We need to handle the dragged button specially.
2648        */
2649       if (column == tree_view->priv->drag_column)
2650         {
2651           GtkAllocation drag_allocation;
2652           GtkWidget    *button;
2653
2654           button = gtk_tree_view_column_get_button (tree_view->priv->drag_column);
2655
2656           drag_allocation.x = 0;
2657           drag_allocation.y = 0;
2658           drag_allocation.width = gdk_window_get_width (tree_view->priv->drag_window);
2659           drag_allocation.height = gdk_window_get_height (tree_view->priv->drag_window);
2660           gtk_widget_size_allocate (button, &drag_allocation);
2661           width += drag_allocation.width;
2662           continue;
2663         }
2664
2665       column_width = _gtk_tree_view_column_request_width (column);
2666
2667       if (gtk_tree_view_column_get_expand (column))
2668         {
2669           if (number_of_expand_columns == 1)
2670             {
2671               /* We add the remander to the last column as
2672                * */
2673               column_width += extra;
2674             }
2675           else
2676             {
2677               column_width += extra_per_column;
2678               extra -= extra_per_column;
2679               number_of_expand_columns --;
2680             }
2681         }
2682       else if (number_of_expand_columns == 0 &&
2683                list == last_column)
2684         {
2685           column_width += extra;
2686         }
2687
2688       /* In addition to expand, the last column can get even more
2689        * extra space so all available space is filled up.
2690        */
2691       if (extra_for_last > 0 && list == last_column)
2692         column_width += extra_for_last;
2693
2694       _gtk_tree_view_column_allocate (column, width, column_width);
2695
2696       width += column_width;
2697
2698       if (column_width > old_width)
2699         column_changed = TRUE;
2700     }
2701
2702   /* We change the width here.  The user might have been resizing columns,
2703    * so the total width of the tree view changes.
2704    */
2705   tree_view->priv->width = width;
2706   if (width_changed)
2707     *width_changed = TRUE;
2708
2709   if (column_changed)
2710     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
2711 }
2712
2713
2714 static void
2715 gtk_tree_view_size_allocate (GtkWidget     *widget,
2716                              GtkAllocation *allocation)
2717 {
2718   GtkAllocation widget_allocation;
2719   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2720   GList *tmp_list;
2721   gboolean width_changed = FALSE;
2722   gint old_width;
2723
2724   gtk_widget_get_allocation (widget, &widget_allocation);
2725   old_width = widget_allocation.width;
2726   if (allocation->width != widget_allocation.width)
2727     width_changed = TRUE;
2728
2729   gtk_widget_set_allocation (widget, allocation);
2730
2731   tmp_list = tree_view->priv->children;
2732
2733   while (tmp_list)
2734     {
2735       GtkAllocation allocation;
2736
2737       GtkTreeViewChild *child = tmp_list->data;
2738       tmp_list = tmp_list->next;
2739
2740       /* totally ignore our child's requisition */
2741       allocation.x = child->x;
2742       allocation.y = child->y;
2743       allocation.width = child->width;
2744       allocation.height = child->height;
2745       gtk_widget_size_allocate (child->widget, &allocation);
2746     }
2747
2748   /* We size-allocate the columns first because the width of the
2749    * tree view (used in updating the adjustments below) might change.
2750    */
2751   gtk_tree_view_size_allocate_columns (widget, &width_changed);
2752
2753   g_object_freeze_notify (G_OBJECT (tree_view->priv->hadjustment));
2754   gtk_adjustment_set_page_size (tree_view->priv->hadjustment,
2755                                 allocation->width);
2756   gtk_adjustment_set_page_increment (tree_view->priv->hadjustment,
2757                                      allocation->width * 0.9);
2758   gtk_adjustment_set_step_increment (tree_view->priv->hadjustment,
2759                                      allocation->width * 0.1);
2760   gtk_adjustment_set_lower (tree_view->priv->hadjustment, 0);
2761   gtk_adjustment_set_upper (tree_view->priv->hadjustment,
2762                             MAX (gtk_adjustment_get_page_size (tree_view->priv->hadjustment),
2763                                  tree_view->priv->width));
2764   g_object_thaw_notify (G_OBJECT (tree_view->priv->hadjustment));
2765
2766   if (gtk_widget_get_direction(widget) == GTK_TEXT_DIR_RTL)   
2767     {
2768       if (allocation->width < tree_view->priv->width)
2769         {
2770           if (tree_view->priv->init_hadjust_value)
2771             {
2772               gtk_adjustment_set_value (tree_view->priv->hadjustment,
2773                                         MAX (tree_view->priv->width -
2774                                              allocation->width, 0));
2775               tree_view->priv->init_hadjust_value = FALSE;
2776             }
2777           else if (allocation->width != old_width)
2778             {
2779               gtk_adjustment_set_value (tree_view->priv->hadjustment,
2780                                         CLAMP (gtk_adjustment_get_value (tree_view->priv->hadjustment) - allocation->width + old_width,
2781                                                0,
2782                                                tree_view->priv->width - allocation->width));
2783             }
2784           else
2785             gtk_adjustment_set_value (tree_view->priv->hadjustment,
2786                                       CLAMP (tree_view->priv->width - (tree_view->priv->prev_width - gtk_adjustment_get_value (tree_view->priv->hadjustment)),
2787                                              0,
2788                                              tree_view->priv->width - allocation->width));
2789         }
2790       else
2791         {
2792           gtk_adjustment_set_value (tree_view->priv->hadjustment, 0);
2793           tree_view->priv->init_hadjust_value = TRUE;
2794         }
2795     }
2796   else
2797     if (gtk_adjustment_get_value (tree_view->priv->hadjustment) + allocation->width > tree_view->priv->width)
2798       gtk_adjustment_set_value (tree_view->priv->hadjustment,
2799                                 MAX (tree_view->priv->width -
2800                                      allocation->width, 0));
2801
2802   g_object_freeze_notify (G_OBJECT (tree_view->priv->vadjustment));
2803   gtk_adjustment_set_page_size (tree_view->priv->vadjustment,
2804                                 allocation->height -
2805                                 gtk_tree_view_get_effective_header_height (tree_view));
2806   gtk_adjustment_set_step_increment (tree_view->priv->vadjustment,
2807                                      gtk_adjustment_get_page_size (tree_view->priv->vadjustment) * 0.1);
2808   gtk_adjustment_set_page_increment (tree_view->priv->vadjustment,
2809                                      gtk_adjustment_get_page_size (tree_view->priv->vadjustment) * 0.9);
2810   gtk_adjustment_set_lower (tree_view->priv->vadjustment, 0);
2811   gtk_adjustment_set_upper (tree_view->priv->vadjustment,
2812                             MAX (gtk_adjustment_get_page_size (tree_view->priv->vadjustment),
2813                                  tree_view->priv->height));
2814   g_object_thaw_notify (G_OBJECT (tree_view->priv->vadjustment));
2815
2816   /* now the adjustments and window sizes are in sync, we can sync toprow/dy again */
2817   if (tree_view->priv->height <= gtk_adjustment_get_page_size (tree_view->priv->vadjustment))
2818     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
2819   else if (gtk_adjustment_get_value (tree_view->priv->vadjustment) + gtk_adjustment_get_page_size (tree_view->priv->vadjustment) > tree_view->priv->height)
2820     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment),
2821                               tree_view->priv->height - gtk_adjustment_get_page_size (tree_view->priv->vadjustment));
2822   else if (gtk_tree_row_reference_valid (tree_view->priv->top_row))
2823     gtk_tree_view_top_row_to_dy (tree_view);
2824   else
2825     gtk_tree_view_dy_to_top_row (tree_view);
2826   
2827   if (gtk_widget_get_realized (widget))
2828     {
2829       gdk_window_move_resize (gtk_widget_get_window (widget),
2830                               allocation->x, allocation->y,
2831                               allocation->width, allocation->height);
2832       gdk_window_move_resize (tree_view->priv->header_window,
2833                               - (gint) gtk_adjustment_get_value (tree_view->priv->hadjustment),
2834                               0,
2835                               MAX (tree_view->priv->width, allocation->width),
2836                               tree_view->priv->header_height);
2837       gdk_window_move_resize (tree_view->priv->bin_window,
2838                               - (gint) gtk_adjustment_get_value (tree_view->priv->hadjustment),
2839                               gtk_tree_view_get_effective_header_height (tree_view),
2840                               MAX (tree_view->priv->width, allocation->width),
2841                               allocation->height - gtk_tree_view_get_effective_header_height (tree_view));
2842     }
2843
2844   if (tree_view->priv->tree == NULL)
2845     invalidate_empty_focus (tree_view);
2846
2847   if (gtk_widget_get_realized (widget))
2848     {
2849       gboolean has_expand_column = FALSE;
2850       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
2851         {
2852           if (gtk_tree_view_column_get_expand (GTK_TREE_VIEW_COLUMN (tmp_list->data)))
2853             {
2854               has_expand_column = TRUE;
2855               break;
2856             }
2857         }
2858
2859       if (width_changed && tree_view->priv->expander_column)
2860         {
2861           /* Might seem awkward, but is the best heuristic I could come up
2862            * with.  Only if the width of the columns before the expander
2863            * changes, we will update the prelight status.  It is this
2864            * width that makes the expander move vertically.  Always updating
2865            * prelight status causes trouble with hover selections.
2866            */
2867           gint width_before_expander;
2868
2869           width_before_expander = gtk_tree_view_calculate_width_before_expander (tree_view);
2870
2871           if (tree_view->priv->prev_width_before_expander
2872               != width_before_expander)
2873               update_prelight (tree_view,
2874                                tree_view->priv->event_last_x,
2875                                tree_view->priv->event_last_y);
2876
2877           tree_view->priv->prev_width_before_expander = width_before_expander;
2878         }
2879
2880       /* This little hack only works if we have an LTR locale, and no column has the  */
2881       if (width_changed)
2882         {
2883           if (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_LTR &&
2884               ! has_expand_column)
2885             invalidate_last_column (tree_view);
2886           else
2887             gtk_widget_queue_draw (widget);
2888         }
2889     }
2890 }
2891
2892 /* Grabs the focus and unsets the GTK_TREE_VIEW_DRAW_KEYFOCUS flag */
2893 static void
2894 grab_focus_and_unset_draw_keyfocus (GtkTreeView *tree_view)
2895 {
2896   GtkWidget *widget = GTK_WIDGET (tree_view);
2897
2898   if (gtk_widget_get_can_focus (widget) && !gtk_widget_has_focus (widget))
2899     gtk_widget_grab_focus (widget);
2900   tree_view->priv->draw_keyfocus = 0;
2901 }
2902
2903 static inline gboolean
2904 row_is_separator (GtkTreeView *tree_view,
2905                   GtkTreeIter *iter,
2906                   GtkTreePath *path)
2907 {
2908   gboolean is_separator = FALSE;
2909
2910   if (tree_view->priv->row_separator_func)
2911     {
2912       GtkTreeIter tmpiter;
2913
2914       if (iter)
2915         tmpiter = *iter;
2916       else
2917         gtk_tree_model_get_iter (tree_view->priv->model, &tmpiter, path);
2918
2919       is_separator = tree_view->priv->row_separator_func (tree_view->priv->model,
2920                                                           &tmpiter,
2921                                                           tree_view->priv->row_separator_data);
2922     }
2923
2924   return is_separator;
2925 }
2926
2927 static gboolean
2928 gtk_tree_view_button_press (GtkWidget      *widget,
2929                             GdkEventButton *event)
2930 {
2931   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2932   GList *list;
2933   GtkTreeViewColumn *column = NULL;
2934   gint i;
2935   GdkRectangle background_area;
2936   GdkRectangle cell_area;
2937   gint vertical_separator;
2938   gint horizontal_separator;
2939   gboolean path_is_selectable;
2940   gboolean rtl;
2941
2942   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
2943   gtk_tree_view_stop_editing (tree_view, FALSE);
2944   gtk_widget_style_get (widget,
2945                         "vertical-separator", &vertical_separator,
2946                         "horizontal-separator", &horizontal_separator,
2947                         NULL);
2948
2949   /* Because grab_focus can cause reentrancy, we delay grab_focus until after
2950    * we're done handling the button press.
2951    */
2952
2953   if (event->window == tree_view->priv->bin_window)
2954     {
2955       GtkRBNode *node;
2956       GtkRBTree *tree;
2957       GtkTreePath *path;
2958       gint depth;
2959       gint new_y;
2960       gint y_offset;
2961       gint dval;
2962       gint pre_val, aft_val;
2963       GtkTreeViewColumn *column = NULL;
2964       gint column_handled_click = FALSE;
2965       gboolean row_double_click = FALSE;
2966       gboolean rtl;
2967       gboolean node_selected;
2968
2969       /* Empty tree? */
2970       if (tree_view->priv->tree == NULL)
2971         {
2972           grab_focus_and_unset_draw_keyfocus (tree_view);
2973           return TRUE;
2974         }
2975
2976       /* are we in an arrow? */
2977       if (tree_view->priv->prelight_node &&
2978           tree_view->priv->arrow_prelit &&
2979           gtk_tree_view_draw_expanders (tree_view))
2980         {
2981           if (event->button == 1)
2982             {
2983               gtk_grab_add (widget);
2984               tree_view->priv->button_pressed_node = tree_view->priv->prelight_node;
2985               tree_view->priv->button_pressed_tree = tree_view->priv->prelight_tree;
2986               gtk_tree_view_queue_draw_arrow (GTK_TREE_VIEW (widget),
2987                                               tree_view->priv->prelight_tree,
2988                                               tree_view->priv->prelight_node);
2989             }
2990
2991           grab_focus_and_unset_draw_keyfocus (tree_view);
2992           return TRUE;
2993         }
2994
2995       /* find the node that was clicked */
2996       new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
2997       if (new_y < 0)
2998         new_y = 0;
2999       y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
3000
3001       if (node == NULL)
3002         {
3003           /* We clicked in dead space */
3004           grab_focus_and_unset_draw_keyfocus (tree_view);
3005           return TRUE;
3006         }
3007
3008       /* Get the path and the node */
3009       path = _gtk_tree_view_find_path (tree_view, tree, node);
3010       path_is_selectable = !row_is_separator (tree_view, NULL, path);
3011
3012       if (!path_is_selectable)
3013         {
3014           gtk_tree_path_free (path);
3015           grab_focus_and_unset_draw_keyfocus (tree_view);
3016           return TRUE;
3017         }
3018
3019       depth = gtk_tree_path_get_depth (path);
3020       background_area.y = y_offset + event->y;
3021       background_area.height = gtk_tree_view_get_row_height (tree_view, node);
3022       background_area.x = 0;
3023
3024
3025       /* Let the column have a chance at selecting it. */
3026       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
3027       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
3028            list; list = (rtl ? list->prev : list->next))
3029         {
3030           GtkTreeViewColumn *candidate = list->data;
3031
3032           if (!gtk_tree_view_column_get_visible (candidate))
3033             continue;
3034
3035           background_area.width = gtk_tree_view_column_get_width (candidate);
3036           if ((background_area.x > (gint) event->x) ||
3037               (background_area.x + background_area.width <= (gint) event->x))
3038             {
3039               background_area.x += background_area.width;
3040               continue;
3041             }
3042
3043           /* we found the focus column */
3044           column = candidate;
3045           cell_area = background_area;
3046           cell_area.width -= horizontal_separator;
3047           cell_area.height -= vertical_separator;
3048           cell_area.x += horizontal_separator/2;
3049           cell_area.y += vertical_separator/2;
3050           if (gtk_tree_view_is_expander_column (tree_view, column))
3051             {
3052               if (!rtl)
3053                 cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
3054               cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
3055
3056               if (gtk_tree_view_draw_expanders (tree_view))
3057                 {
3058                   if (!rtl)
3059                     cell_area.x += depth * tree_view->priv->expander_size;
3060                   cell_area.width -= depth * tree_view->priv->expander_size;
3061                 }
3062             }
3063           break;
3064         }
3065
3066       if (column == NULL)
3067         {
3068           gtk_tree_path_free (path);
3069           grab_focus_and_unset_draw_keyfocus (tree_view);
3070           return FALSE;
3071         }
3072
3073       tree_view->priv->focus_column = column;
3074
3075       /* decide if we edit */
3076       if (event->type == GDK_BUTTON_PRESS && event->button == 1 &&
3077           !(event->state & gtk_accelerator_get_default_mod_mask ()))
3078         {
3079           GtkTreePath *anchor;
3080           GtkTreeIter iter;
3081
3082           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
3083           gtk_tree_view_column_cell_set_cell_data (column,
3084                                                    tree_view->priv->model,
3085                                                    &iter,
3086                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
3087                                                    node->children?TRUE:FALSE);
3088
3089           if (tree_view->priv->anchor)
3090             anchor = gtk_tree_row_reference_get_path (tree_view->priv->anchor);
3091           else
3092             anchor = NULL;
3093
3094           if ((anchor && !gtk_tree_path_compare (anchor, path))
3095               || !_gtk_tree_view_column_has_editable_cell (column))
3096             {
3097               GtkCellEditable *cell_editable = NULL;
3098
3099               /* FIXME: get the right flags */
3100               guint flags = 0;
3101
3102               if (_gtk_tree_view_column_cell_event (column,
3103                                                     (GdkEvent *)event,
3104                                                     &cell_area, flags))
3105                 {
3106                   GtkCellArea *area = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (column));
3107                   cell_editable = gtk_cell_area_get_edit_widget (area);
3108
3109                   if (cell_editable != NULL)
3110                     {
3111                       gtk_tree_path_free (path);
3112                       gtk_tree_path_free (anchor);
3113                       return TRUE;
3114                     }
3115                   column_handled_click = TRUE;
3116                 }
3117             }
3118           if (anchor)
3119             gtk_tree_path_free (anchor);
3120         }
3121
3122       /* select */
3123       node_selected = GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED);
3124       pre_val = gtk_adjustment_get_value (tree_view->priv->vadjustment);
3125
3126       /* we only handle selection modifications on the first button press
3127        */
3128       if (event->type == GDK_BUTTON_PRESS)
3129         {
3130           GtkCellRenderer *focus_cell;
3131
3132           if ((event->state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
3133             tree_view->priv->ctrl_pressed = TRUE;
3134           if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
3135             tree_view->priv->shift_pressed = TRUE;
3136
3137           /* We update the focus cell here, this is also needed if the
3138            * column does not contain an editable cell.  In this case,
3139            * GtkCellArea did not receive the event for processing (and
3140            * could not update the focus cell).
3141            */
3142           focus_cell = _gtk_tree_view_column_get_cell_at_pos (column,
3143                                                               &cell_area,
3144                                                               &background_area,
3145                                                               event->x,
3146                                                               event->y);
3147
3148           if (focus_cell)
3149             gtk_tree_view_column_focus_cell (column, focus_cell);
3150
3151           if (event->state & GDK_CONTROL_MASK)
3152             {
3153               gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
3154               gtk_tree_view_real_toggle_cursor_row (tree_view);
3155             }
3156           else if (event->state & GDK_SHIFT_MASK)
3157             {
3158               gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
3159               gtk_tree_view_real_select_cursor_row (tree_view, FALSE);
3160             }
3161           else
3162             {
3163               gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
3164             }
3165
3166           tree_view->priv->ctrl_pressed = FALSE;
3167           tree_view->priv->shift_pressed = FALSE;
3168         }
3169
3170       /* the treeview may have been scrolled because of _set_cursor,
3171        * correct here
3172        */
3173
3174       aft_val = gtk_adjustment_get_value (tree_view->priv->vadjustment);
3175       dval = pre_val - aft_val;
3176
3177       cell_area.y += dval;
3178       background_area.y += dval;
3179
3180       /* Save press to possibly begin a drag
3181        */
3182       if (!column_handled_click &&
3183           !tree_view->priv->in_grab &&
3184           tree_view->priv->pressed_button < 0)
3185         {
3186           tree_view->priv->pressed_button = event->button;
3187           tree_view->priv->press_start_x = event->x;
3188           tree_view->priv->press_start_y = event->y;
3189
3190           if (tree_view->priv->rubber_banding_enable
3191               && !node_selected
3192               && gtk_tree_selection_get_mode (tree_view->priv->selection) == GTK_SELECTION_MULTIPLE)
3193             {
3194               tree_view->priv->press_start_y += tree_view->priv->dy;
3195               tree_view->priv->rubber_band_x = event->x;
3196               tree_view->priv->rubber_band_y = event->y + tree_view->priv->dy;
3197               tree_view->priv->rubber_band_status = RUBBER_BAND_MAYBE_START;
3198
3199               if ((event->state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
3200                 tree_view->priv->rubber_band_ctrl = TRUE;
3201               if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
3202                 tree_view->priv->rubber_band_shift = TRUE;
3203             }
3204         }
3205
3206       /* Test if a double click happened on the same row. */
3207       if (event->button == 1 && event->type == GDK_BUTTON_PRESS)
3208         {
3209           int double_click_time, double_click_distance;
3210
3211           g_object_get (gtk_settings_get_default (),
3212                         "gtk-double-click-time", &double_click_time,
3213                         "gtk-double-click-distance", &double_click_distance,
3214                         NULL);
3215
3216           /* Same conditions as _gdk_event_button_generate */
3217           if (tree_view->priv->last_button_x != -1 &&
3218               (event->time < tree_view->priv->last_button_time + double_click_time) &&
3219               (ABS (event->x - tree_view->priv->last_button_x) <= double_click_distance) &&
3220               (ABS (event->y - tree_view->priv->last_button_y) <= double_click_distance))
3221             {
3222               /* We do no longer compare paths of this row and the
3223                * row clicked previously.  We use the double click
3224                * distance to decide whether this is a valid click,
3225                * allowing the mouse to slightly move over another row.
3226                */
3227               row_double_click = TRUE;
3228
3229               tree_view->priv->last_button_time = 0;
3230               tree_view->priv->last_button_x = -1;
3231               tree_view->priv->last_button_y = -1;
3232             }
3233           else
3234             {
3235               tree_view->priv->last_button_time = event->time;
3236               tree_view->priv->last_button_x = event->x;
3237               tree_view->priv->last_button_y = event->y;
3238             }
3239         }
3240
3241       if (row_double_click)
3242         {
3243           gtk_grab_remove (widget);
3244           gtk_tree_view_row_activated (tree_view, path, column);
3245
3246           if (tree_view->priv->pressed_button == event->button)
3247             tree_view->priv->pressed_button = -1;
3248         }
3249
3250       gtk_tree_path_free (path);
3251
3252       /* If we activated the row through a double click we don't want to grab
3253        * focus back, as moving focus to another widget is pretty common.
3254        */
3255       if (!row_double_click)
3256         grab_focus_and_unset_draw_keyfocus (tree_view);
3257
3258       return TRUE;
3259     }
3260
3261   /* We didn't click in the window.  Let's check to see if we clicked on a column resize window.
3262    */
3263   for (i = 0, list = tree_view->priv->columns; list; list = list->next, i++)
3264     {
3265       column = list->data;
3266       if (event->window == _gtk_tree_view_column_get_window (column) &&
3267           gtk_tree_view_column_get_resizable (column) &&
3268           _gtk_tree_view_column_get_window (column))
3269         {
3270           GtkWidget *button;
3271           GtkAllocation button_allocation;
3272           gpointer drag_data;
3273
3274           if (event->type == GDK_2BUTTON_PRESS &&
3275               gtk_tree_view_column_get_sizing (column) != GTK_TREE_VIEW_COLUMN_AUTOSIZE)
3276             {
3277               _gtk_tree_view_column_set_use_resized_width (column, FALSE);
3278               _gtk_tree_view_column_autosize (tree_view, column);
3279               return TRUE;
3280             }
3281
3282           if (gdk_device_grab (gdk_event_get_device ((GdkEvent*)event),
3283                                _gtk_tree_view_column_get_window (column),
3284                                GDK_OWNERSHIP_NONE,
3285                                FALSE,
3286                                GDK_POINTER_MOTION_HINT_MASK
3287                                 | GDK_BUTTON1_MOTION_MASK
3288                                 | GDK_BUTTON_RELEASE_MASK,
3289                                NULL,
3290                                event->time) != GDK_GRAB_SUCCESS)
3291             return FALSE;
3292
3293           gtk_grab_add (widget);
3294           tree_view->priv->in_column_resize = TRUE;
3295
3296           _gtk_tree_view_column_set_resized_width (column, gtk_tree_view_column_get_width (column) -
3297                                                    tree_view->priv->last_extra_space_per_column);
3298
3299           /* block attached dnd signal handler */
3300           drag_data = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
3301           if (drag_data)
3302             g_signal_handlers_block_matched (widget,
3303                                              G_SIGNAL_MATCH_DATA,
3304                                              0, 0, NULL, NULL,
3305                                              drag_data);
3306
3307           button = gtk_tree_view_column_get_button (column);
3308           gtk_widget_get_allocation (button, &button_allocation);
3309           tree_view->priv->drag_pos = i;
3310           tree_view->priv->x_drag = button_allocation.x + (rtl ? 0 : button_allocation.width);
3311
3312           if (!gtk_widget_has_focus (widget))
3313             gtk_widget_grab_focus (widget);
3314
3315           return TRUE;
3316         }
3317     }
3318   return FALSE;
3319 }
3320
3321 /* GtkWidget::button_release_event helper */
3322 static gboolean
3323 gtk_tree_view_button_release_drag_column (GtkWidget      *widget,
3324                                           GdkEventButton *event)
3325 {
3326   GtkTreeView *tree_view;
3327   GtkWidget *button;
3328   GList *l;
3329   gboolean rtl;
3330   GdkDevice *device, *other;
3331
3332   tree_view = GTK_TREE_VIEW (widget);
3333
3334   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
3335   device = gdk_event_get_device ((GdkEvent*)event);
3336   other = gdk_device_get_associated_device (device);
3337   gdk_device_ungrab (device, event->time);
3338   gdk_device_ungrab (other, event->time);
3339
3340   /* Move the button back */
3341   button = gtk_tree_view_column_get_button (tree_view->priv->drag_column);
3342   g_object_ref (button);
3343   gtk_container_remove (GTK_CONTAINER (tree_view), button);
3344   gtk_widget_set_parent_window (button, tree_view->priv->header_window);
3345   gtk_widget_set_parent (button, GTK_WIDGET (tree_view));
3346   g_object_unref (button);
3347   gtk_widget_queue_resize (widget);
3348   if (gtk_tree_view_column_get_resizable (tree_view->priv->drag_column))
3349     {
3350       gdk_window_raise (_gtk_tree_view_column_get_window (tree_view->priv->drag_column));
3351       gdk_window_show (_gtk_tree_view_column_get_window (tree_view->priv->drag_column));
3352     }
3353   else
3354     gdk_window_hide (_gtk_tree_view_column_get_window (tree_view->priv->drag_column));
3355
3356   gtk_widget_grab_focus (button);
3357
3358   if (rtl)
3359     {
3360       if (tree_view->priv->cur_reorder &&
3361           tree_view->priv->cur_reorder->right_column != tree_view->priv->drag_column)
3362         gtk_tree_view_move_column_after (tree_view, tree_view->priv->drag_column,
3363                                          tree_view->priv->cur_reorder->right_column);
3364     }
3365   else
3366     {
3367       if (tree_view->priv->cur_reorder &&
3368           tree_view->priv->cur_reorder->left_column != tree_view->priv->drag_column)
3369         gtk_tree_view_move_column_after (tree_view, tree_view->priv->drag_column,
3370                                          tree_view->priv->cur_reorder->left_column);
3371     }
3372   tree_view->priv->drag_column = NULL;
3373   gdk_window_hide (tree_view->priv->drag_window);
3374
3375   for (l = tree_view->priv->column_drag_info; l != NULL; l = l->next)
3376     g_slice_free (GtkTreeViewColumnReorder, l->data);
3377   g_list_free (tree_view->priv->column_drag_info);
3378   tree_view->priv->column_drag_info = NULL;
3379   tree_view->priv->cur_reorder = NULL;
3380
3381   if (tree_view->priv->drag_highlight_window)
3382     gdk_window_hide (tree_view->priv->drag_highlight_window);
3383
3384   /* Reset our flags */
3385   tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_UNSET;
3386   tree_view->priv->in_column_drag = FALSE;
3387
3388   return TRUE;
3389 }
3390
3391 /* GtkWidget::button_release_event helper */
3392 static gboolean
3393 gtk_tree_view_button_release_column_resize (GtkWidget      *widget,
3394                                             GdkEventButton *event)
3395 {
3396   GtkTreeView *tree_view;
3397   gpointer drag_data;
3398
3399   tree_view = GTK_TREE_VIEW (widget);
3400
3401   tree_view->priv->drag_pos = -1;
3402
3403   /* unblock attached dnd signal handler */
3404   drag_data = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
3405   if (drag_data)
3406     g_signal_handlers_unblock_matched (widget,
3407                                        G_SIGNAL_MATCH_DATA,
3408                                        0, 0, NULL, NULL,
3409                                        drag_data);
3410
3411   tree_view->priv->in_column_resize = FALSE;
3412   gtk_grab_remove (widget);
3413   gdk_device_ungrab (gdk_event_get_device ((GdkEvent*)event), event->time);
3414   return TRUE;
3415 }
3416
3417 static gboolean
3418 gtk_tree_view_button_release (GtkWidget      *widget,
3419                               GdkEventButton *event)
3420 {
3421   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
3422
3423   if (tree_view->priv->in_column_drag)
3424     return gtk_tree_view_button_release_drag_column (widget, event);
3425
3426   if (tree_view->priv->rubber_band_status)
3427     gtk_tree_view_stop_rubber_band (tree_view);
3428
3429   if (tree_view->priv->pressed_button == event->button)
3430     tree_view->priv->pressed_button = -1;
3431
3432   if (tree_view->priv->in_column_resize)
3433     return gtk_tree_view_button_release_column_resize (widget, event);
3434
3435   if (tree_view->priv->button_pressed_node == NULL)
3436     return FALSE;
3437
3438   if (event->button == 1)
3439     {
3440       if (tree_view->priv->button_pressed_node == tree_view->priv->prelight_node &&
3441           tree_view->priv->arrow_prelit)
3442         {
3443           GtkTreePath *path = NULL;
3444
3445           path = _gtk_tree_view_find_path (tree_view,
3446                                            tree_view->priv->button_pressed_tree,
3447                                            tree_view->priv->button_pressed_node);
3448           /* Actually activate the node */
3449           if (tree_view->priv->button_pressed_node->children == NULL)
3450             gtk_tree_view_real_expand_row (tree_view, path,
3451                                            tree_view->priv->button_pressed_tree,
3452                                            tree_view->priv->button_pressed_node,
3453                                            FALSE, TRUE);
3454           else
3455             gtk_tree_view_real_collapse_row (GTK_TREE_VIEW (widget), path,
3456                                              tree_view->priv->button_pressed_tree,
3457                                              tree_view->priv->button_pressed_node, TRUE);
3458           gtk_tree_path_free (path);
3459         }
3460
3461       gtk_grab_remove (widget);
3462       tree_view->priv->button_pressed_tree = NULL;
3463       tree_view->priv->button_pressed_node = NULL;
3464     }
3465
3466   return TRUE;
3467 }
3468
3469 static gboolean
3470 gtk_tree_view_grab_broken (GtkWidget          *widget,
3471                            GdkEventGrabBroken *event)
3472 {
3473   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
3474
3475   if (tree_view->priv->in_column_drag)
3476     gtk_tree_view_button_release_drag_column (widget, (GdkEventButton *)event);
3477
3478   if (tree_view->priv->in_column_resize)
3479     gtk_tree_view_button_release_column_resize (widget, (GdkEventButton *)event);
3480
3481   return TRUE;
3482 }
3483
3484 #if 0
3485 static gboolean
3486 gtk_tree_view_configure (GtkWidget *widget,
3487                          GdkEventConfigure *event)
3488 {
3489   GtkTreeView *tree_view;
3490
3491   tree_view = GTK_TREE_VIEW (widget);
3492   tree_view->priv->search_position_func (tree_view, tree_view->priv->search_window);
3493
3494   return FALSE;
3495 }
3496 #endif
3497
3498 /* GtkWidget::motion_event function set.
3499  */
3500
3501 static gboolean
3502 coords_are_over_arrow (GtkTreeView *tree_view,
3503                        GtkRBTree   *tree,
3504                        GtkRBNode   *node,
3505                        /* these are in bin window coords */
3506                        gint         x,
3507                        gint         y)
3508 {
3509   GdkRectangle arrow;
3510   gint x2;
3511
3512   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
3513     return FALSE;
3514
3515   if ((node->flags & GTK_RBNODE_IS_PARENT) == 0)
3516     return FALSE;
3517
3518   arrow.y = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
3519   arrow.height = gtk_tree_view_get_row_height (tree_view, node);
3520
3521   gtk_tree_view_get_arrow_xrange (tree_view, tree, &arrow.x, &x2);
3522
3523   arrow.width = x2 - arrow.x;
3524
3525   return (x >= arrow.x &&
3526           x < (arrow.x + arrow.width) &&
3527           y >= arrow.y &&
3528           y < (arrow.y + arrow.height));
3529 }
3530
3531 static gboolean
3532 auto_expand_timeout (gpointer data)
3533 {
3534   GtkTreeView *tree_view = GTK_TREE_VIEW (data);
3535   GtkTreePath *path;
3536
3537   if (tree_view->priv->prelight_node)
3538     {
3539       path = _gtk_tree_view_find_path (tree_view,
3540                                        tree_view->priv->prelight_tree,
3541                                        tree_view->priv->prelight_node);   
3542
3543       if (tree_view->priv->prelight_node->children)
3544         gtk_tree_view_collapse_row (tree_view, path);
3545       else
3546         gtk_tree_view_expand_row (tree_view, path, FALSE);
3547
3548       gtk_tree_path_free (path);
3549     }
3550
3551   tree_view->priv->auto_expand_timeout = 0;
3552
3553   return FALSE;
3554 }
3555
3556 static void
3557 remove_auto_expand_timeout (GtkTreeView *tree_view)
3558 {
3559   if (tree_view->priv->auto_expand_timeout != 0)
3560     {
3561       g_source_remove (tree_view->priv->auto_expand_timeout);
3562       tree_view->priv->auto_expand_timeout = 0;
3563     }
3564 }
3565
3566 static void
3567 do_prelight (GtkTreeView *tree_view,
3568              GtkRBTree   *tree,
3569              GtkRBNode   *node,
3570              /* these are in bin_window coords */
3571              gint         x,
3572              gint         y)
3573 {
3574   if (tree_view->priv->prelight_tree == tree &&
3575       tree_view->priv->prelight_node == node)
3576     {
3577       /*  We are still on the same node,
3578           but we might need to take care of the arrow  */
3579
3580       if (tree && node && gtk_tree_view_draw_expanders (tree_view))
3581         {
3582           gboolean over_arrow;
3583
3584           over_arrow = coords_are_over_arrow (tree_view, tree, node, x, y);
3585
3586           if (over_arrow != tree_view->priv->arrow_prelit)
3587             {
3588               if (over_arrow)
3589                 tree_view->priv->arrow_prelit = TRUE;
3590               else
3591                 tree_view->priv->arrow_prelit = FALSE;
3592
3593               gtk_tree_view_queue_draw_arrow (tree_view, tree, node);
3594             }
3595         }
3596
3597       return;
3598     }
3599
3600   if (tree_view->priv->prelight_tree && tree_view->priv->prelight_node)
3601     {
3602       /*  Unprelight the old node and arrow  */
3603
3604       GTK_RBNODE_UNSET_FLAG (tree_view->priv->prelight_node,
3605                              GTK_RBNODE_IS_PRELIT);
3606
3607       if (tree_view->priv->arrow_prelit
3608           && gtk_tree_view_draw_expanders (tree_view))
3609         {
3610           tree_view->priv->arrow_prelit = FALSE;
3611           
3612           gtk_tree_view_queue_draw_arrow (tree_view,
3613                                           tree_view->priv->prelight_tree,
3614                                           tree_view->priv->prelight_node);
3615         }
3616
3617       _gtk_tree_view_queue_draw_node (tree_view,
3618                                       tree_view->priv->prelight_tree,
3619                                       tree_view->priv->prelight_node,
3620                                       NULL);
3621     }
3622
3623
3624   if (tree_view->priv->hover_expand)
3625     remove_auto_expand_timeout (tree_view);
3626
3627   /*  Set the new prelight values  */
3628   tree_view->priv->prelight_node = node;
3629   tree_view->priv->prelight_tree = tree;
3630
3631   if (!node || !tree)
3632     return;
3633
3634   /*  Prelight the new node and arrow  */
3635
3636   if (gtk_tree_view_draw_expanders (tree_view)
3637       && coords_are_over_arrow (tree_view, tree, node, x, y))
3638     {
3639       tree_view->priv->arrow_prelit = TRUE;
3640
3641       gtk_tree_view_queue_draw_arrow (tree_view, tree, node);
3642     }
3643
3644   GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_PRELIT);
3645
3646   _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
3647
3648   if (tree_view->priv->hover_expand)
3649     {
3650       tree_view->priv->auto_expand_timeout = 
3651         gdk_threads_add_timeout (AUTO_EXPAND_TIMEOUT, auto_expand_timeout, tree_view);
3652     }
3653 }
3654
3655 static void
3656 prelight_or_select (GtkTreeView *tree_view,
3657                     GtkRBTree   *tree,
3658                     GtkRBNode   *node,
3659                     /* these are in bin_window coords */
3660                     gint         x,
3661                     gint         y)
3662 {
3663   GtkSelectionMode mode = gtk_tree_selection_get_mode (tree_view->priv->selection);
3664   
3665   if (tree_view->priv->hover_selection &&
3666       (mode == GTK_SELECTION_SINGLE || mode == GTK_SELECTION_BROWSE) &&
3667       !(tree_view->priv->edited_column &&
3668         gtk_cell_area_get_edit_widget 
3669         (gtk_cell_layout_get_area (GTK_CELL_LAYOUT (tree_view->priv->edited_column)))))
3670     {
3671       if (node)
3672         {
3673           if (!GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
3674             {
3675               GtkTreePath *path;
3676               
3677               path = _gtk_tree_view_find_path (tree_view, tree, node);
3678               gtk_tree_selection_select_path (tree_view->priv->selection, path);
3679               if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
3680                 {
3681                   tree_view->priv->draw_keyfocus = FALSE;
3682                   gtk_tree_view_real_set_cursor (tree_view, path, FALSE, FALSE);
3683                 }
3684               gtk_tree_path_free (path);
3685             }
3686         }
3687
3688       else if (mode == GTK_SELECTION_SINGLE)
3689         gtk_tree_selection_unselect_all (tree_view->priv->selection);
3690     }
3691
3692     do_prelight (tree_view, tree, node, x, y);
3693 }
3694
3695 static void
3696 ensure_unprelighted (GtkTreeView *tree_view)
3697 {
3698   do_prelight (tree_view,
3699                NULL, NULL,
3700                -1000, -1000); /* coords not possibly over an arrow */
3701
3702   g_assert (tree_view->priv->prelight_node == NULL);
3703 }
3704
3705 static void
3706 update_prelight (GtkTreeView *tree_view,
3707                  gint         x,
3708                  gint         y)
3709 {
3710   int new_y;
3711   GtkRBTree *tree;
3712   GtkRBNode *node;
3713
3714   if (tree_view->priv->tree == NULL)
3715     return;
3716
3717   if (x == -10000)
3718     {
3719       ensure_unprelighted (tree_view);
3720       return;
3721     }
3722
3723   new_y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, y);
3724   if (new_y < 0)
3725     new_y = 0;
3726
3727   _gtk_rbtree_find_offset (tree_view->priv->tree,
3728                            new_y, &tree, &node);
3729
3730   if (node)
3731     prelight_or_select (tree_view, tree, node, x, y);
3732 }
3733
3734
3735
3736
3737 /* Our motion arrow is either a box (in the case of the original spot)
3738  * or an arrow.  It is expander_size wide.
3739  */
3740 /*
3741  * 11111111111111
3742  * 01111111111110
3743  * 00111111111100
3744  * 00011111111000
3745  * 00001111110000
3746  * 00000111100000
3747  * 00000111100000
3748  * 00000111100000
3749  * ~ ~ ~ ~ ~ ~ ~
3750  * 00000111100000
3751  * 00000111100000
3752  * 00000111100000
3753  * 00001111110000
3754  * 00011111111000
3755  * 00111111111100
3756  * 01111111111110
3757  * 11111111111111
3758  */
3759
3760 static void
3761 gtk_tree_view_motion_draw_column_motion_arrow (GtkTreeView *tree_view)
3762 {
3763   GtkTreeViewColumnReorder *reorder = tree_view->priv->cur_reorder;
3764   GtkWidget *widget = GTK_WIDGET (tree_view);
3765   cairo_surface_t *mask_image;
3766   cairo_region_t *mask_region;
3767   gint x;
3768   gint y;
3769   gint width;
3770   gint height;
3771   gint arrow_type = DRAG_COLUMN_WINDOW_STATE_UNSET;
3772   GdkWindowAttr attributes;
3773   guint attributes_mask;
3774   cairo_t *cr;
3775
3776   if (!reorder ||
3777       reorder->left_column == tree_view->priv->drag_column ||
3778       reorder->right_column == tree_view->priv->drag_column)
3779     arrow_type = DRAG_COLUMN_WINDOW_STATE_ORIGINAL;
3780   else if (reorder->left_column || reorder->right_column)
3781     {
3782       GtkAllocation left_allocation, right_allocation;
3783       GdkRectangle visible_rect;
3784       GtkWidget *button;
3785
3786       gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
3787       if (reorder->left_column)
3788         {
3789           button = gtk_tree_view_column_get_button (reorder->left_column);
3790           gtk_widget_get_allocation (button, &left_allocation);
3791           x = left_allocation.x + left_allocation.width;
3792         }
3793       else
3794         {
3795           button = gtk_tree_view_column_get_button (reorder->right_column);
3796           gtk_widget_get_allocation (button, &right_allocation);
3797           x = right_allocation.x;
3798         }
3799
3800       if (x < visible_rect.x)
3801         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT;
3802       else if (x > visible_rect.x + visible_rect.width)
3803         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT;
3804       else
3805         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW;
3806     }
3807
3808   /* We want to draw the rectangle over the initial location. */
3809   if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ORIGINAL)
3810     {
3811       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ORIGINAL)
3812         {
3813           GtkAllocation drag_allocation;
3814           GtkWidget    *button;
3815
3816           if (tree_view->priv->drag_highlight_window)
3817             {
3818               gdk_window_set_user_data (tree_view->priv->drag_highlight_window,
3819                                         NULL);
3820               gdk_window_destroy (tree_view->priv->drag_highlight_window);
3821             }
3822
3823           button = gtk_tree_view_column_get_button (tree_view->priv->drag_column);
3824           attributes.window_type = GDK_WINDOW_CHILD;
3825           attributes.wclass = GDK_INPUT_OUTPUT;
3826           attributes.x = tree_view->priv->drag_column_x;
3827           attributes.y = 0;
3828           gtk_widget_get_allocation (button, &drag_allocation);
3829           width = attributes.width = drag_allocation.width;
3830           height = attributes.height = drag_allocation.height;
3831           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
3832           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3833           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
3834           tree_view->priv->drag_highlight_window = gdk_window_new (tree_view->priv->header_window, &attributes, attributes_mask);
3835           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
3836
3837           mask_image = cairo_image_surface_create (CAIRO_FORMAT_A1, width, height);
3838           cr = cairo_create (mask_image);
3839
3840           cairo_rectangle (cr, 1, 1, width - 2, height - 2);
3841           cairo_stroke (cr);
3842           cairo_destroy (cr);
3843
3844           mask_region = gdk_cairo_region_create_from_surface (mask_image);
3845           gdk_window_shape_combine_region (tree_view->priv->drag_highlight_window,
3846                                            mask_region, 0, 0);
3847
3848           cairo_region_destroy (mask_region);
3849           cairo_surface_destroy (mask_image);
3850
3851           tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_ORIGINAL;
3852         }
3853     }
3854   else if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW)
3855     {
3856       GtkAllocation button_allocation;
3857       GtkWidget    *button;
3858
3859       width = tree_view->priv->expander_size;
3860
3861       /* Get x, y, width, height of arrow */
3862       gdk_window_get_origin (tree_view->priv->header_window, &x, &y);
3863       if (reorder->left_column)
3864         {
3865           button = gtk_tree_view_column_get_button (reorder->left_column);
3866           gtk_widget_get_allocation (button, &button_allocation);
3867           x += button_allocation.x + button_allocation.width - width/2;
3868           height = button_allocation.height;
3869         }
3870       else
3871         {
3872           button = gtk_tree_view_column_get_button (reorder->right_column);
3873           gtk_widget_get_allocation (button, &button_allocation);
3874           x += button_allocation.x - width/2;
3875           height = button_allocation.height;
3876         }
3877       y -= tree_view->priv->expander_size/2; /* The arrow takes up only half the space */
3878       height += tree_view->priv->expander_size;
3879
3880       /* Create the new window */
3881       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW)
3882         {
3883           if (tree_view->priv->drag_highlight_window)
3884             {
3885               gdk_window_set_user_data (tree_view->priv->drag_highlight_window,
3886                                         NULL);
3887               gdk_window_destroy (tree_view->priv->drag_highlight_window);
3888             }
3889
3890           attributes.window_type = GDK_WINDOW_TEMP;
3891           attributes.wclass = GDK_INPUT_OUTPUT;
3892           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
3893           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3894           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
3895           attributes.x = x;
3896           attributes.y = y;
3897           attributes.width = width;
3898           attributes.height = height;
3899           tree_view->priv->drag_highlight_window = gdk_window_new (gtk_widget_get_root_window (widget),
3900                                                                    &attributes, attributes_mask);
3901           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
3902
3903           mask_image = cairo_image_surface_create (CAIRO_FORMAT_A1, width, height);
3904
3905           cr = cairo_create (mask_image);
3906           cairo_move_to (cr, 0, 0);
3907           cairo_line_to (cr, width, 0);
3908           cairo_line_to (cr, width / 2., width / 2);
3909           cairo_move_to (cr, 0, height);
3910           cairo_line_to (cr, width, height);
3911           cairo_line_to (cr, width / 2., height - width / 2.);
3912           cairo_fill (cr);
3913           cairo_destroy (cr);
3914
3915           mask_region = gdk_cairo_region_create_from_surface (mask_image);
3916           gdk_window_shape_combine_region (tree_view->priv->drag_highlight_window,
3917                                            mask_region, 0, 0);
3918
3919           cairo_region_destroy (mask_region);
3920           cairo_surface_destroy (mask_image);
3921         }
3922
3923       tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_ARROW;
3924       gdk_window_move (tree_view->priv->drag_highlight_window, x, y);
3925     }
3926   else if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT ||
3927            arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
3928     {
3929       GtkAllocation allocation;
3930       GtkWidget    *button;
3931
3932       width = tree_view->priv->expander_size;
3933
3934       /* Get x, y, width, height of arrow */
3935       width = width/2; /* remember, the arrow only takes half the available width */
3936       gdk_window_get_origin (gtk_widget_get_window (widget),
3937                              &x, &y);
3938       if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
3939         {
3940           gtk_widget_get_allocation (widget, &allocation);
3941           x += allocation.width - width;
3942         }
3943
3944       if (reorder->left_column)
3945         {
3946           button = gtk_tree_view_column_get_button (reorder->left_column);
3947           gtk_widget_get_allocation (button, &allocation);
3948           height = allocation.height;
3949         }
3950       else
3951         {
3952           button = gtk_tree_view_column_get_button (reorder->right_column);
3953           gtk_widget_get_allocation (button, &allocation);
3954           height = allocation.height;
3955         }
3956
3957       y -= tree_view->priv->expander_size;
3958       height += 2*tree_view->priv->expander_size;
3959
3960       /* Create the new window */
3961       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT &&
3962           tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
3963         {
3964           if (tree_view->priv->drag_highlight_window)
3965             {
3966               gdk_window_set_user_data (tree_view->priv->drag_highlight_window,
3967                                         NULL);
3968               gdk_window_destroy (tree_view->priv->drag_highlight_window);
3969             }
3970
3971           attributes.window_type = GDK_WINDOW_TEMP;
3972           attributes.wclass = GDK_INPUT_OUTPUT;
3973           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
3974           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3975           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
3976           attributes.x = x;
3977           attributes.y = y;
3978           attributes.width = width;
3979           attributes.height = height;
3980           tree_view->priv->drag_highlight_window = gdk_window_new (NULL, &attributes, attributes_mask);
3981           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
3982
3983           mask_image = cairo_image_surface_create (CAIRO_FORMAT_A1, width, height);
3984
3985           cr = cairo_create (mask_image);
3986           /* mirror if we're on the left */
3987           if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT)
3988             {
3989               cairo_translate (cr, width, 0);
3990               cairo_scale (cr, -1, 1);
3991             }
3992           cairo_move_to (cr, 0, 0);
3993           cairo_line_to (cr, width, width);
3994           cairo_line_to (cr, 0, tree_view->priv->expander_size);
3995           cairo_move_to (cr, 0, height);
3996           cairo_line_to (cr, width, height - width);
3997           cairo_line_to (cr, 0, height - tree_view->priv->expander_size);
3998           cairo_fill (cr);
3999           cairo_destroy (cr);
4000
4001           mask_region = gdk_cairo_region_create_from_surface (mask_image);
4002           gdk_window_shape_combine_region (tree_view->priv->drag_highlight_window,
4003                                            mask_region, 0, 0);
4004
4005           cairo_region_destroy (mask_region);
4006           cairo_surface_destroy (mask_image);
4007         }
4008
4009       tree_view->priv->drag_column_window_state = arrow_type;
4010       gdk_window_move (tree_view->priv->drag_highlight_window, x, y);
4011    }
4012   else
4013     {
4014       g_warning (G_STRLOC"Invalid GtkTreeViewColumnReorder struct");
4015       gdk_window_hide (tree_view->priv->drag_highlight_window);
4016       return;
4017     }
4018
4019   gdk_window_show (tree_view->priv->drag_highlight_window);
4020   gdk_window_raise (tree_view->priv->drag_highlight_window);
4021 }
4022
4023 static gboolean
4024 gtk_tree_view_motion_resize_column (GtkWidget      *widget,
4025                                     GdkEventMotion *event)
4026 {
4027   gint x;
4028   gint new_width;
4029   GtkTreeViewColumn *column;
4030   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
4031
4032   column = gtk_tree_view_get_column (tree_view, tree_view->priv->drag_pos);
4033
4034   if (event->is_hint || event->window != gtk_widget_get_window (widget))
4035     gtk_widget_get_pointer (widget, &x, NULL);
4036   else
4037     x = event->x;
4038
4039   if (tree_view->priv->hadjustment)
4040     x += gtk_adjustment_get_value (tree_view->priv->hadjustment);
4041
4042   new_width = gtk_tree_view_new_column_width (tree_view,
4043                                               tree_view->priv->drag_pos, &x);
4044   if (x != tree_view->priv->x_drag &&
4045       (new_width != gtk_tree_view_column_get_fixed_width (column)))
4046     {
4047       _gtk_tree_view_column_set_use_resized_width (column, TRUE);
4048
4049       if (gtk_tree_view_column_get_expand (column))
4050         new_width -= tree_view->priv->last_extra_space_per_column;
4051
4052       _gtk_tree_view_column_set_resized_width (column, new_width);
4053
4054
4055       gtk_widget_queue_resize (widget);
4056     }
4057
4058   return FALSE;
4059 }
4060
4061
4062 static void
4063 gtk_tree_view_update_current_reorder (GtkTreeView *tree_view)
4064 {
4065   GtkTreeViewColumnReorder *reorder = NULL;
4066   GList *list;
4067   gint mouse_x;
4068
4069   gdk_window_get_pointer (tree_view->priv->header_window, &mouse_x, NULL, NULL);
4070   for (list = tree_view->priv->column_drag_info; list; list = list->next)
4071     {
4072       reorder = (GtkTreeViewColumnReorder *) list->data;
4073       if (mouse_x >= reorder->left_align && mouse_x < reorder->right_align)
4074         break;
4075       reorder = NULL;
4076     }
4077
4078   /*  if (reorder && reorder == tree_view->priv->cur_reorder)
4079       return;*/
4080
4081   tree_view->priv->cur_reorder = reorder;
4082   gtk_tree_view_motion_draw_column_motion_arrow (tree_view);
4083 }
4084
4085 static void
4086 gtk_tree_view_vertical_autoscroll (GtkTreeView *tree_view)
4087 {
4088   GdkRectangle visible_rect;
4089   gint y;
4090   gint offset;
4091
4092   gdk_window_get_pointer (tree_view->priv->bin_window, NULL, &y, NULL);
4093   y += tree_view->priv->dy;
4094
4095   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
4096
4097   /* see if we are near the edge. */
4098   offset = y - (visible_rect.y + 2 * SCROLL_EDGE_SIZE);
4099   if (offset > 0)
4100     {
4101       offset = y - (visible_rect.y + visible_rect.height - 2 * SCROLL_EDGE_SIZE);
4102       if (offset < 0)
4103         return;
4104     }
4105
4106   gtk_adjustment_set_value (tree_view->priv->vadjustment,
4107                             MAX (gtk_adjustment_get_value (tree_view->priv->vadjustment) + offset, 0.0));
4108 }
4109
4110 static gboolean
4111 gtk_tree_view_horizontal_autoscroll (GtkTreeView *tree_view)
4112 {
4113   GdkRectangle visible_rect;
4114   gint x;
4115   gint offset;
4116
4117   gdk_window_get_pointer (tree_view->priv->bin_window, &x, NULL, NULL);
4118
4119   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
4120
4121   /* See if we are near the edge. */
4122   offset = x - (visible_rect.x + SCROLL_EDGE_SIZE);
4123   if (offset > 0)
4124     {
4125       offset = x - (visible_rect.x + visible_rect.width - SCROLL_EDGE_SIZE);
4126       if (offset < 0)
4127         return TRUE;
4128     }
4129   offset = offset/3;
4130
4131   gtk_adjustment_set_value (tree_view->priv->hadjustment,
4132                             MAX (gtk_adjustment_get_value (tree_view->priv->hadjustment) + offset, 0.0));
4133
4134   return TRUE;
4135
4136 }
4137
4138 static gboolean
4139 gtk_tree_view_motion_drag_column (GtkWidget      *widget,
4140                                   GdkEventMotion *event)
4141 {
4142   GtkAllocation allocation, button_allocation;
4143   GtkTreeView *tree_view = (GtkTreeView *) widget;
4144   GtkTreeViewColumn *column = tree_view->priv->drag_column;
4145   GtkWidget *button;
4146   gint x, y;
4147
4148   /* Sanity Check */
4149   if ((column == NULL) ||
4150       (event->window != tree_view->priv->drag_window))
4151     return FALSE;
4152
4153   button = gtk_tree_view_column_get_button (column);
4154
4155   /* Handle moving the header */
4156   gdk_window_get_position (tree_view->priv->drag_window, &x, &y);
4157   gtk_widget_get_allocation (widget, &allocation);
4158   gtk_widget_get_allocation (button, &button_allocation);
4159   x = CLAMP (x + (gint)event->x - _gtk_tree_view_column_get_drag_x (column), 0,
4160              MAX (tree_view->priv->width, allocation.width) - button_allocation.width);
4161   gdk_window_move (tree_view->priv->drag_window, x, y);
4162   
4163   /* autoscroll, if needed */
4164   gtk_tree_view_horizontal_autoscroll (tree_view);
4165   /* Update the current reorder position and arrow; */
4166   gtk_tree_view_update_current_reorder (tree_view);
4167
4168   return TRUE;
4169 }
4170
4171 static void
4172 gtk_tree_view_stop_rubber_band (GtkTreeView *tree_view)
4173 {
4174   remove_scroll_timeout (tree_view);
4175   gtk_grab_remove (GTK_WIDGET (tree_view));
4176
4177   if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
4178     {
4179       GtkTreePath *tmp_path;
4180
4181       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
4182
4183       /* The anchor path should be set to the start path */
4184       tmp_path = _gtk_tree_view_find_path (tree_view,
4185                                            tree_view->priv->rubber_band_start_tree,
4186                                            tree_view->priv->rubber_band_start_node);
4187
4188       if (tree_view->priv->anchor)
4189         gtk_tree_row_reference_free (tree_view->priv->anchor);
4190
4191       tree_view->priv->anchor =
4192         gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
4193                                           tree_view->priv->model,
4194                                           tmp_path);
4195
4196       gtk_tree_path_free (tmp_path);
4197
4198       /* ... and the cursor to the end path */
4199       tmp_path = _gtk_tree_view_find_path (tree_view,
4200                                            tree_view->priv->rubber_band_end_tree,
4201                                            tree_view->priv->rubber_band_end_node);
4202       gtk_tree_view_real_set_cursor (GTK_TREE_VIEW (tree_view), tmp_path, FALSE, FALSE);
4203       gtk_tree_path_free (tmp_path);
4204
4205       _gtk_tree_selection_emit_changed (tree_view->priv->selection);
4206     }
4207
4208   /* Clear status variables */
4209   tree_view->priv->rubber_band_status = RUBBER_BAND_OFF;
4210   tree_view->priv->rubber_band_shift = 0;
4211   tree_view->priv->rubber_band_ctrl = 0;
4212
4213   tree_view->priv->rubber_band_start_node = NULL;
4214   tree_view->priv->rubber_band_start_tree = NULL;
4215   tree_view->priv->rubber_band_end_node = NULL;
4216   tree_view->priv->rubber_band_end_tree = NULL;
4217 }
4218
4219 static void
4220 gtk_tree_view_update_rubber_band_selection_range (GtkTreeView *tree_view,
4221                                                  GtkRBTree   *start_tree,
4222                                                  GtkRBNode   *start_node,
4223                                                  GtkRBTree   *end_tree,
4224                                                  GtkRBNode   *end_node,
4225                                                  gboolean     select,
4226                                                  gboolean     skip_start,
4227                                                  gboolean     skip_end)
4228 {
4229   if (start_node == end_node)
4230     return;
4231
4232   /* We skip the first node and jump inside the loop */
4233   if (skip_start)
4234     goto skip_first;
4235
4236   do
4237     {
4238       /* Small optimization by assuming insensitive nodes are never
4239        * selected.
4240        */
4241       if (!GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
4242         {
4243           GtkTreePath *path;
4244           gboolean selectable;
4245
4246           path = _gtk_tree_view_find_path (tree_view, start_tree, start_node);
4247           selectable = _gtk_tree_selection_row_is_selectable (tree_view->priv->selection, start_node, path);
4248           gtk_tree_path_free (path);
4249
4250           if (!selectable)
4251             goto node_not_selectable;
4252         }
4253
4254       if (select)
4255         {
4256           if (tree_view->priv->rubber_band_shift)
4257             GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4258           else if (tree_view->priv->rubber_band_ctrl)
4259             {
4260               /* Toggle the selection state */
4261               if (GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
4262                 GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4263               else
4264                 GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4265             }
4266           else
4267             GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4268         }
4269       else
4270         {
4271           /* Mirror the above */
4272           if (tree_view->priv->rubber_band_shift)
4273             GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4274           else if (tree_view->priv->rubber_band_ctrl)
4275             {
4276               /* Toggle the selection state */
4277               if (GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
4278                 GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4279               else
4280                 GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4281             }
4282           else
4283             GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4284         }
4285
4286       _gtk_tree_view_queue_draw_node (tree_view, start_tree, start_node, NULL);
4287
4288 node_not_selectable:
4289       if (start_node == end_node)
4290         break;
4291
4292 skip_first:
4293
4294       if (start_node->children)
4295         {
4296           start_tree = start_node->children;
4297           start_node = start_tree->root;
4298           while (start_node->left != start_tree->nil)
4299             start_node = start_node->left;
4300         }
4301       else
4302         {
4303           _gtk_rbtree_next_full (start_tree, start_node, &start_tree, &start_node);
4304
4305           if (!start_tree)
4306             /* Ran out of tree */
4307             break;
4308         }
4309
4310       if (skip_end && start_node == end_node)
4311         break;
4312     }
4313   while (TRUE);
4314 }
4315
4316 static void
4317 gtk_tree_view_update_rubber_band_selection (GtkTreeView *tree_view)
4318 {
4319   GtkRBTree *start_tree, *end_tree;
4320   GtkRBNode *start_node, *end_node;
4321
4322   _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);
4323   _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);
4324
4325   /* Handle the start area first */
4326   if (!tree_view->priv->rubber_band_start_node)
4327     {
4328       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4329                                                        start_tree,
4330                                                        start_node,
4331                                                        end_tree,
4332                                                        end_node,
4333                                                        TRUE,
4334                                                        FALSE,
4335                                                        FALSE);
4336     }
4337   else if (_gtk_rbtree_node_find_offset (start_tree, start_node) <
4338            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_start_tree, tree_view->priv->rubber_band_start_node))
4339     {
4340       /* New node is above the old one; selection became bigger */
4341       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4342                                                        start_tree,
4343                                                        start_node,
4344                                                        tree_view->priv->rubber_band_start_tree,
4345                                                        tree_view->priv->rubber_band_start_node,
4346                                                        TRUE,
4347                                                        FALSE,
4348                                                        TRUE);
4349     }
4350   else if (_gtk_rbtree_node_find_offset (start_tree, start_node) >
4351            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_start_tree, tree_view->priv->rubber_band_start_node))
4352     {
4353       /* New node is below the old one; selection became smaller */
4354       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4355                                                        tree_view->priv->rubber_band_start_tree,
4356                                                        tree_view->priv->rubber_band_start_node,
4357                                                        start_tree,
4358                                                        start_node,
4359                                                        FALSE,
4360                                                        FALSE,
4361                                                        TRUE);
4362     }
4363
4364   tree_view->priv->rubber_band_start_tree = start_tree;
4365   tree_view->priv->rubber_band_start_node = start_node;
4366
4367   /* Next, handle the end area */
4368   if (!tree_view->priv->rubber_band_end_node)
4369     {
4370       /* In the event this happens, start_node was also NULL; this case is
4371        * handled above.
4372        */
4373     }
4374   else if (!end_node)
4375     {
4376       /* Find the last node in the tree */
4377       _gtk_rbtree_find_offset (tree_view->priv->tree, tree_view->priv->height - 1,
4378                                &end_tree, &end_node);
4379
4380       /* Selection reached end of the tree */
4381       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4382                                                        tree_view->priv->rubber_band_end_tree,
4383                                                        tree_view->priv->rubber_band_end_node,
4384                                                        end_tree,
4385                                                        end_node,
4386                                                        TRUE,
4387                                                        TRUE,
4388                                                        FALSE);
4389     }
4390   else if (_gtk_rbtree_node_find_offset (end_tree, end_node) >
4391            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_end_tree, tree_view->priv->rubber_band_end_node))
4392     {
4393       /* New node is below the old one; selection became bigger */
4394       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4395                                                        tree_view->priv->rubber_band_end_tree,
4396                                                        tree_view->priv->rubber_band_end_node,
4397                                                        end_tree,
4398                                                        end_node,
4399                                                        TRUE,
4400                                                        TRUE,
4401                                                        FALSE);
4402     }
4403   else if (_gtk_rbtree_node_find_offset (end_tree, end_node) <
4404            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_end_tree, tree_view->priv->rubber_band_end_node))
4405     {
4406       /* New node is above the old one; selection became smaller */
4407       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4408                                                        end_tree,
4409                                                        end_node,
4410                                                        tree_view->priv->rubber_band_end_tree,
4411                                                        tree_view->priv->rubber_band_end_node,
4412                                                        FALSE,
4413                                                        TRUE,
4414                                                        FALSE);
4415     }
4416
4417   tree_view->priv->rubber_band_end_tree = end_tree;
4418   tree_view->priv->rubber_band_end_node = end_node;
4419 }
4420
4421 static void
4422 gtk_tree_view_update_rubber_band (GtkTreeView *tree_view)
4423 {
4424   gint x, y;
4425   GdkRectangle old_area;
4426   GdkRectangle new_area;
4427   GdkRectangle common;
4428   cairo_region_t *invalid_region;
4429
4430   old_area.x = MIN (tree_view->priv->press_start_x, tree_view->priv->rubber_band_x);
4431   old_area.y = MIN (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y) - tree_view->priv->dy;
4432   old_area.width = ABS (tree_view->priv->rubber_band_x - tree_view->priv->press_start_x) + 1;
4433   old_area.height = ABS (tree_view->priv->rubber_band_y - tree_view->priv->press_start_y) + 1;
4434
4435   gdk_window_get_pointer (tree_view->priv->bin_window, &x, &y, NULL);
4436
4437   x = MAX (x, 0);
4438   y = MAX (y, 0) + tree_view->priv->dy;
4439
4440   new_area.x = MIN (tree_view->priv->press_start_x, x);
4441   new_area.y = MIN (tree_view->priv->press_start_y, y) - tree_view->priv->dy;
4442   new_area.width = ABS (x - tree_view->priv->press_start_x) + 1;
4443   new_area.height = ABS (y - tree_view->priv->press_start_y) + 1;
4444
4445   invalid_region = cairo_region_create_rectangle (&old_area);
4446   cairo_region_union_rectangle (invalid_region, &new_area);
4447
4448   gdk_rectangle_intersect (&old_area, &new_area, &common);
4449   if (common.width > 2 && common.height > 2)
4450     {
4451       cairo_region_t *common_region;
4452
4453       /* make sure the border is invalidated */
4454       common.x += 1;
4455       common.y += 1;
4456       common.width -= 2;
4457       common.height -= 2;
4458
4459       common_region = cairo_region_create_rectangle (&common);
4460
4461       cairo_region_subtract (invalid_region, common_region);
4462       cairo_region_destroy (common_region);
4463     }
4464
4465   gdk_window_invalidate_region (tree_view->priv->bin_window, invalid_region, TRUE);
4466
4467   cairo_region_destroy (invalid_region);
4468
4469   tree_view->priv->rubber_band_x = x;
4470   tree_view->priv->rubber_band_y = y;
4471
4472   gtk_tree_view_update_rubber_band_selection (tree_view);
4473 }
4474
4475 static void
4476 gtk_tree_view_paint_rubber_band (GtkTreeView  *tree_view,
4477                                  cairo_t      *cr)
4478 {
4479   GdkRectangle rect;
4480   GtkStyleContext *context;
4481
4482   cairo_save (cr);
4483
4484   context = gtk_widget_get_style_context (GTK_WIDGET (tree_view));
4485
4486   gtk_style_context_save (context);
4487   gtk_style_context_add_class (context, GTK_STYLE_CLASS_RUBBERBAND);
4488
4489   rect.x = MIN (tree_view->priv->press_start_x, tree_view->priv->rubber_band_x);
4490   rect.y = MIN (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y) - tree_view->priv->dy;
4491   rect.width = ABS (tree_view->priv->press_start_x - tree_view->priv->rubber_band_x) + 1;
4492   rect.height = ABS (tree_view->priv->press_start_y - tree_view->priv->rubber_band_y) + 1;
4493
4494   gdk_cairo_rectangle (cr, &rect);
4495   cairo_clip (cr);
4496
4497   gtk_render_background (context, cr,
4498                          rect.x, rect.y,
4499                          rect.width, rect.height);
4500   gtk_render_frame (context, cr,
4501                     rect.x, rect.y,
4502                     rect.width, rect.height);
4503
4504   gtk_style_context_restore (context);
4505   cairo_restore (cr);
4506 }
4507
4508 static gboolean
4509 gtk_tree_view_motion_bin_window (GtkWidget      *widget,
4510                                  GdkEventMotion *event)
4511 {
4512   GtkTreeView *tree_view;
4513   GtkRBTree *tree;
4514   GtkRBNode *node;
4515   gint new_y;
4516
4517   tree_view = (GtkTreeView *) widget;
4518
4519   if (tree_view->priv->tree == NULL)
4520     return FALSE;
4521
4522   if (tree_view->priv->rubber_band_status == RUBBER_BAND_MAYBE_START)
4523     {
4524       gtk_grab_add (GTK_WIDGET (tree_view));
4525       gtk_tree_view_update_rubber_band (tree_view);
4526
4527       tree_view->priv->rubber_band_status = RUBBER_BAND_ACTIVE;
4528     }
4529   else if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
4530     {
4531       gtk_tree_view_update_rubber_band (tree_view);
4532
4533       add_scroll_timeout (tree_view);
4534     }
4535
4536   /* only check for an initiated drag when a button is pressed */
4537   if (tree_view->priv->pressed_button >= 0
4538       && !tree_view->priv->rubber_band_status)
4539     gtk_tree_view_maybe_begin_dragging_row (tree_view, event);
4540
4541   new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
4542   if (new_y < 0)
4543     new_y = 0;
4544
4545   _gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
4546
4547   /* If we are currently pressing down a button, we don't want to prelight anything else. */
4548   if ((tree_view->priv->button_pressed_node != NULL) &&
4549       (tree_view->priv->button_pressed_node != node))
4550     node = NULL;
4551
4552   tree_view->priv->event_last_x = event->x;
4553   tree_view->priv->event_last_y = event->y;
4554
4555   prelight_or_select (tree_view, tree, node, event->x, event->y);
4556
4557   return TRUE;
4558 }
4559
4560 static gboolean
4561 gtk_tree_view_motion (GtkWidget      *widget,
4562                       GdkEventMotion *event)
4563 {
4564   GtkTreeView *tree_view;
4565
4566   tree_view = (GtkTreeView *) widget;
4567
4568   /* Resizing a column */
4569   if (tree_view->priv->in_column_resize)
4570     return gtk_tree_view_motion_resize_column (widget, event);
4571
4572   /* Drag column */
4573   if (tree_view->priv->in_column_drag)
4574     return gtk_tree_view_motion_drag_column (widget, event);
4575
4576   /* Sanity check it */
4577   if (event->window == tree_view->priv->bin_window)
4578     return gtk_tree_view_motion_bin_window (widget, event);
4579
4580   return FALSE;
4581 }
4582
4583 /* Invalidate the focus rectangle near the edge of the bin_window; used when
4584  * the tree is empty.
4585  */
4586 static void
4587 invalidate_empty_focus (GtkTreeView *tree_view)
4588 {
4589   GdkRectangle area;
4590
4591   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
4592     return;
4593
4594   area.x = 0;
4595   area.y = 0;
4596   area.width = gdk_window_get_width (tree_view->priv->bin_window);
4597   area.height = gdk_window_get_height (tree_view->priv->bin_window);
4598   gdk_window_invalidate_rect (tree_view->priv->bin_window, &area, FALSE);
4599 }
4600
4601 /* Draws a focus rectangle near the edge of the bin_window; used when the tree
4602  * is empty.
4603  */
4604 static void
4605 draw_empty_focus (GtkTreeView *tree_view, cairo_t *cr)
4606 {
4607   GtkWidget *widget = GTK_WIDGET (tree_view);
4608   gint w, h;
4609
4610   if (!gtk_widget_has_focus (widget))
4611     return;
4612
4613   w = gdk_window_get_width (tree_view->priv->bin_window) - 2;
4614   h = gdk_window_get_height (tree_view->priv->bin_window) - 2;
4615
4616   if (w > 0 && h > 0)
4617     {
4618       GtkStyleContext *context;
4619       GtkStateFlags state;
4620
4621       context = gtk_widget_get_style_context (widget);
4622       state = gtk_widget_get_state_flags (widget);
4623
4624       gtk_style_context_save (context);
4625       gtk_style_context_set_state (context, state);
4626
4627       gtk_render_focus (context, cr, 1, 1, w, h);
4628
4629       gtk_style_context_restore (context);
4630     }
4631 }
4632
4633 typedef enum {
4634   GTK_TREE_VIEW_GRID_LINE,
4635   GTK_TREE_VIEW_TREE_LINE,
4636   GTK_TREE_VIEW_FOREGROUND_LINE
4637 } GtkTreeViewLineType;
4638
4639 static void
4640 gtk_tree_view_draw_line (GtkTreeView         *tree_view,
4641                          cairo_t             *cr,
4642                          GtkTreeViewLineType  type,
4643                          int                  x1,
4644                          int                  y1,
4645                          int                  x2,
4646                          int                  y2)
4647 {
4648   cairo_save (cr);
4649
4650   switch (type)
4651     {
4652     case GTK_TREE_VIEW_TREE_LINE:
4653       cairo_set_source_rgb (cr, 0, 0, 0);
4654       cairo_set_line_width (cr, tree_view->priv->tree_line_width);
4655       if (tree_view->priv->tree_line_dashes[0])
4656         cairo_set_dash (cr, 
4657                         tree_view->priv->tree_line_dashes,
4658                         2, 0.5);
4659       break;
4660     case GTK_TREE_VIEW_GRID_LINE:
4661       cairo_set_source_rgb (cr, 0, 0, 0);
4662       cairo_set_line_width (cr, tree_view->priv->grid_line_width);
4663       if (tree_view->priv->grid_line_dashes[0])
4664         cairo_set_dash (cr, 
4665                         tree_view->priv->grid_line_dashes,
4666                         2, 0.5);
4667       break;
4668     default:
4669       g_assert_not_reached ();
4670       /* fall through */
4671     case GTK_TREE_VIEW_FOREGROUND_LINE:
4672       {
4673         GtkStyleContext *context;
4674         GtkStateFlags state;
4675         GdkRGBA color;
4676
4677         context = gtk_widget_get_style_context (GTK_WIDGET (tree_view));
4678         state = gtk_widget_get_state_flags (GTK_WIDGET (tree_view));
4679
4680         cairo_set_line_width (cr, 1.0);
4681         gtk_style_context_get_color (context, state, &color);
4682         gdk_cairo_set_source_rgba (cr, &color);
4683       }
4684
4685       break;
4686     }
4687
4688   cairo_move_to (cr, x1 + 0.5, y1 + 0.5);
4689   cairo_line_to (cr, x2 + 0.5, y2 + 0.5);
4690   cairo_stroke (cr);
4691
4692   cairo_restore (cr);
4693 }
4694                          
4695 static void
4696 gtk_tree_view_draw_grid_lines (GtkTreeView    *tree_view,
4697                                cairo_t        *cr,
4698                                gint            n_visible_columns)
4699 {
4700   GList *list = tree_view->priv->columns;
4701   gint i = 0;
4702   gint current_x = 0;
4703
4704   if (tree_view->priv->grid_lines != GTK_TREE_VIEW_GRID_LINES_VERTICAL
4705       && tree_view->priv->grid_lines != GTK_TREE_VIEW_GRID_LINES_BOTH)
4706     return;
4707
4708   /* Only draw the lines for visible rows and columns */
4709   for (list = tree_view->priv->columns; list; list = list->next, i++)
4710     {
4711       GtkTreeViewColumn *column = list->data;
4712
4713       /* We don't want a line for the last column */
4714       if (i == n_visible_columns - 1)
4715         break;
4716
4717       if (!gtk_tree_view_column_get_visible (column))
4718         continue;
4719
4720       current_x += gtk_tree_view_column_get_width (column);
4721
4722       gtk_tree_view_draw_line (tree_view, cr,
4723                                GTK_TREE_VIEW_GRID_LINE,
4724                                current_x - 1, 0,
4725                                current_x - 1, tree_view->priv->height);
4726     }
4727 }
4728
4729 /* Warning: Very scary function.
4730  * Modify at your own risk
4731  *
4732  * KEEP IN SYNC WITH gtk_tree_view_create_row_drag_icon()!
4733  * FIXME: It's not...
4734  */
4735 static gboolean
4736 gtk_tree_view_bin_draw (GtkWidget      *widget,
4737                         cairo_t        *cr)
4738 {
4739   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
4740   GtkTreePath *path;
4741   GtkRBTree *tree;
4742   GList *list;
4743   GtkRBNode *node;
4744   GtkRBNode *cursor = NULL;
4745   GtkRBTree *cursor_tree = NULL;
4746   GtkRBNode *drag_highlight = NULL;
4747   GtkRBTree *drag_highlight_tree = NULL;
4748   GtkTreeIter iter;
4749   gint new_y;
4750   gint y_offset, cell_offset;
4751   gint max_height;
4752   gint depth;
4753   GdkRectangle background_area;
4754   GdkRectangle cell_area;
4755   GdkRectangle clip;
4756   guint flags;
4757   gint highlight_x;
4758   gint expander_cell_width;
4759   gint bin_window_width;
4760   gint bin_window_height;
4761   GtkTreePath *cursor_path;
4762   GtkTreePath *drag_dest_path;
4763   GList *first_column, *last_column;
4764   gint vertical_separator;
4765   gint horizontal_separator;
4766   gint focus_line_width;
4767   gboolean allow_rules;
4768   gboolean has_can_focus_cell;
4769   gboolean rtl;
4770   gint n_visible_columns;
4771   gint pointer_x, pointer_y;
4772   gint grid_line_width;
4773   gboolean got_pointer = FALSE;
4774   gboolean draw_vgrid_lines, draw_hgrid_lines;
4775   GtkStyleContext *context;
4776   GtkStateFlags state;
4777
4778   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
4779   context = gtk_widget_get_style_context (widget);
4780   state = gtk_widget_get_state_flags (widget);
4781
4782   gtk_widget_style_get (widget,
4783                         "horizontal-separator", &horizontal_separator,
4784                         "vertical-separator", &vertical_separator,
4785                         "allow-rules", &allow_rules,
4786                         "focus-line-width", &focus_line_width,
4787                         NULL);
4788
4789   if (tree_view->priv->tree == NULL)
4790     {
4791       draw_empty_focus (tree_view, cr);
4792       return TRUE;
4793     }
4794
4795   bin_window_width = gdk_window_get_width (tree_view->priv->bin_window);
4796   bin_window_height = gdk_window_get_height (tree_view->priv->bin_window);
4797   cairo_rectangle (cr, 0, 0, bin_window_width, bin_window_height);
4798   cairo_clip (cr);
4799   if (!gdk_cairo_get_clip_rectangle (cr, &clip))
4800     return TRUE;
4801
4802   new_y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, clip.y);
4803
4804   if (new_y < 0)
4805     new_y = 0;
4806   y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
4807
4808   if (tree_view->priv->height < bin_window_height)
4809     {
4810       gtk_style_context_save (context);
4811       gtk_style_context_set_state (context, state);
4812       gtk_style_context_add_class (context, GTK_STYLE_CLASS_CELL);
4813
4814       gtk_render_background (context, cr,
4815                              0, tree_view->priv->height,
4816                              bin_window_width,
4817                              bin_window_height - tree_view->priv->height);
4818
4819       gtk_style_context_restore (context);
4820     }
4821
4822   if (node == NULL)
4823     return TRUE;
4824
4825   /* find the path for the node */
4826   path = _gtk_tree_view_find_path ((GtkTreeView *)widget,
4827                                    tree,
4828                                    node);
4829   gtk_tree_model_get_iter (tree_view->priv->model,
4830                            &iter,
4831                            path);
4832   depth = gtk_tree_path_get_depth (path);
4833   gtk_tree_path_free (path);
4834   
4835   cursor_path = NULL;
4836   drag_dest_path = NULL;
4837
4838   if (tree_view->priv->cursor)
4839     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
4840
4841   if (cursor_path)
4842     _gtk_tree_view_find_node (tree_view, cursor_path,
4843                               &cursor_tree, &cursor);
4844
4845   if (tree_view->priv->drag_dest_row)
4846     drag_dest_path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
4847
4848   if (drag_dest_path)
4849     _gtk_tree_view_find_node (tree_view, drag_dest_path,
4850                               &drag_highlight_tree, &drag_highlight);
4851
4852   draw_vgrid_lines =
4853     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_VERTICAL
4854     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
4855   draw_hgrid_lines =
4856     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_HORIZONTAL
4857     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
4858
4859   if (draw_vgrid_lines || draw_hgrid_lines)
4860     gtk_widget_style_get (widget, "grid-line-width", &grid_line_width, NULL);
4861   
4862   n_visible_columns = 0;
4863   for (list = tree_view->priv->columns; list; list = list->next)
4864     {
4865       if (!gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (list->data)))
4866         continue;
4867       n_visible_columns ++;
4868     }
4869
4870   /* Find the last column */
4871   for (last_column = g_list_last (tree_view->priv->columns);
4872        last_column &&
4873        !(gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (last_column->data)));
4874        last_column = last_column->prev)
4875     ;
4876
4877   /* and the first */
4878   for (first_column = g_list_first (tree_view->priv->columns);
4879        first_column &&
4880        !(gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (first_column->data)));
4881        first_column = first_column->next)
4882     ;
4883
4884   /* Actually process the expose event.  To do this, we want to
4885    * start at the first node of the event, and walk the tree in
4886    * order, drawing each successive node.
4887    */
4888
4889   do
4890     {
4891       gboolean parity;
4892       gboolean is_separator = FALSE;
4893       gboolean is_first = FALSE;
4894       gboolean is_last = FALSE;
4895       gint n_col = 0;
4896
4897       is_separator = row_is_separator (tree_view, &iter, NULL);
4898
4899       max_height = gtk_tree_view_get_row_height (tree_view, node);
4900
4901       cell_offset = 0;
4902       highlight_x = 0; /* should match x coord of first cell */
4903       expander_cell_width = 0;
4904
4905       background_area.y = y_offset + clip.y;
4906       background_area.height = max_height;
4907
4908       flags = 0;
4909
4910       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PRELIT))
4911         flags |= GTK_CELL_RENDERER_PRELIT;
4912
4913       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
4914         flags |= GTK_CELL_RENDERER_SELECTED;
4915
4916       parity = _gtk_rbtree_node_find_parity (tree, node);
4917
4918       /* we *need* to set cell data on all cells before the call
4919        * to _has_can_focus_cell, else _has_can_focus_cell() does not
4920        * return a correct value.
4921        */
4922       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
4923            list;
4924            list = (rtl ? list->prev : list->next))
4925         {
4926           GtkTreeViewColumn *column = list->data;
4927           gtk_tree_view_column_cell_set_cell_data (column,
4928                                                    tree_view->priv->model,
4929                                                    &iter,
4930                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
4931                                                    node->children?TRUE:FALSE);
4932         }
4933
4934       has_can_focus_cell = gtk_tree_view_has_can_focus_cell (tree_view);
4935
4936       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
4937            list;
4938            list = (rtl ? list->prev : list->next))
4939         {
4940           GtkTreeViewColumn *column = list->data;
4941           GtkRegionFlags row_flags = 0, column_flags = 0;
4942           GtkStateFlags state = 0;
4943           gint width;
4944           gboolean draw_focus;
4945
4946           if (!gtk_tree_view_column_get_visible (column))
4947             continue;
4948
4949           n_col++;
4950           width = gtk_tree_view_column_get_width (column);
4951
4952           if (cell_offset > clip.x + clip.width ||
4953               cell_offset + width < clip.x)
4954             {
4955               cell_offset += width;
4956               continue;
4957             }
4958
4959           if (gtk_tree_view_column_get_sort_indicator (column))
4960             flags |= GTK_CELL_RENDERER_SORTED;
4961           else
4962             flags &= ~GTK_CELL_RENDERER_SORTED;
4963
4964           if (cursor == node)
4965             flags |= GTK_CELL_RENDERER_FOCUSED;
4966           else
4967             flags &= ~GTK_CELL_RENDERER_FOCUSED;
4968
4969           background_area.x = cell_offset;
4970           background_area.width = width;
4971
4972           cell_area = background_area;
4973           cell_area.y += vertical_separator / 2;
4974           cell_area.x += horizontal_separator / 2;
4975           cell_area.height -= vertical_separator;
4976           cell_area.width -= horizontal_separator;
4977
4978           if (draw_vgrid_lines)
4979             {
4980               if (list == first_column)
4981                 {
4982                   cell_area.width -= grid_line_width / 2;
4983                 }
4984               else if (list == last_column)
4985                 {
4986                   cell_area.x += grid_line_width / 2;
4987                   cell_area.width -= grid_line_width / 2;
4988                 }
4989               else
4990                 {
4991                   cell_area.x += grid_line_width / 2;
4992                   cell_area.width -= grid_line_width;
4993                 }
4994             }
4995
4996           if (draw_hgrid_lines)
4997             {
4998               cell_area.y += grid_line_width / 2;
4999               cell_area.height -= grid_line_width;
5000             }
5001
5002           if (!gdk_rectangle_intersect (&clip, &background_area, NULL))
5003             {
5004               cell_offset += gtk_tree_view_column_get_width (column);
5005               continue;
5006             }
5007
5008           gtk_tree_view_column_cell_set_cell_data (column,
5009                                                    tree_view->priv->model,
5010                                                    &iter,
5011                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
5012                                                    node->children?TRUE:FALSE);
5013
5014           /* Select the detail for drawing the cell.  relevant
5015            * factors are parity, sortedness, and whether to
5016            * display rules.
5017            */
5018           if (allow_rules && tree_view->priv->has_rules)
5019             {
5020               if (parity)
5021                 row_flags |= GTK_REGION_ODD;
5022               else
5023                 row_flags |= GTK_REGION_EVEN;
5024             }
5025
5026           if ((flags & GTK_CELL_RENDERER_SORTED) &&
5027               n_visible_columns >= 3)
5028             column_flags |= GTK_REGION_SORTED;
5029
5030           is_first = (rtl ? !list->next : !list->prev);
5031           is_last = (rtl ? !list->prev : !list->next);
5032
5033           if (is_first)
5034             column_flags |= GTK_REGION_FIRST;
5035
5036           if (is_last)
5037             column_flags |= GTK_REGION_LAST;
5038
5039           if ((n_col % 2) == 0)
5040             column_flags |= GTK_REGION_EVEN;
5041           else
5042             column_flags |= GTK_REGION_ODD;
5043
5044           gtk_style_context_save (context);
5045
5046           state = gtk_cell_renderer_get_state (NULL, widget, flags);
5047           gtk_style_context_set_state (context, state);
5048
5049           gtk_style_context_add_class (context, GTK_STYLE_CLASS_CELL);
5050           gtk_style_context_add_region (context, GTK_STYLE_REGION_ROW, row_flags);
5051           gtk_style_context_add_region (context, GTK_STYLE_REGION_COLUMN, column_flags);
5052
5053           if (node == cursor && has_can_focus_cell
5054               && ((column == tree_view->priv->focus_column
5055                    && tree_view->priv->draw_keyfocus &&
5056                    gtk_widget_has_focus (widget))
5057                   || (column == tree_view->priv->edited_column)))
5058             draw_focus = TRUE;
5059           else
5060             draw_focus = FALSE;
5061
5062           /* Draw background */
5063           gtk_render_background (context, cr,
5064                                  background_area.x,
5065                                  background_area.y,
5066                                  background_area.width,
5067                                  background_area.height);
5068
5069           if (gtk_tree_view_is_expander_column (tree_view, column))
5070             {
5071               if (!rtl)
5072                 cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
5073               cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
5074
5075               if (gtk_tree_view_draw_expanders (tree_view))
5076                 {
5077                   if (!rtl)
5078                     cell_area.x += depth * tree_view->priv->expander_size;
5079                   cell_area.width -= depth * tree_view->priv->expander_size;
5080                 }
5081
5082               /* If we have an expander column, the highlight underline
5083                * starts with that column, so that it indicates which
5084                * level of the tree we're dropping at.
5085                */
5086               highlight_x = cell_area.x;
5087               expander_cell_width = cell_area.width;
5088
5089               if (is_separator)
5090                 gtk_render_line (context, cr,
5091                                  cell_area.x,
5092                                  cell_area.y + cell_area.height / 2,
5093                                  cell_area.x + cell_area.width,
5094                                  cell_area.y + cell_area.height / 2);
5095               else
5096                 _gtk_tree_view_column_cell_render (column,
5097                                                    cr,
5098                                                    &background_area,
5099                                                    &cell_area,
5100                                                    flags,
5101                                                    draw_focus);
5102               if (gtk_tree_view_draw_expanders (tree_view)
5103                   && (node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT)
5104                 {
5105                   if (!got_pointer)
5106                     {
5107                       gdk_window_get_pointer (tree_view->priv->bin_window, 
5108                                               &pointer_x, &pointer_y, NULL);
5109                       got_pointer = TRUE;
5110                     }
5111
5112                   gtk_tree_view_draw_arrow (GTK_TREE_VIEW (widget),
5113                                             cr,
5114                                             tree,
5115                                             node,
5116                                             pointer_x, pointer_y);
5117                 }
5118             }
5119           else
5120             {
5121               if (is_separator)
5122                 gtk_render_line (context, cr,
5123                                  cell_area.x,
5124                                  cell_area.y + cell_area.height / 2,
5125                                  cell_area.x + cell_area.width,
5126                                  cell_area.y + cell_area.height / 2);
5127               else
5128                 _gtk_tree_view_column_cell_render (column,
5129                                                    cr,
5130                                                    &background_area,
5131                                                    &cell_area,
5132                                                    flags,
5133                                                    draw_focus);
5134             }
5135
5136           if (draw_hgrid_lines)
5137             {
5138               if (background_area.y > 0)
5139                 gtk_tree_view_draw_line (tree_view, cr,
5140                                          GTK_TREE_VIEW_GRID_LINE,
5141                                          background_area.x, background_area.y,
5142                                          background_area.x + background_area.width,
5143                                          background_area.y);
5144
5145               if (y_offset + max_height >= clip.height)
5146                 gtk_tree_view_draw_line (tree_view, cr,
5147                                          GTK_TREE_VIEW_GRID_LINE,
5148                                          background_area.x, background_area.y + max_height,
5149                                          background_area.x + background_area.width,
5150                                          background_area.y + max_height);
5151             }
5152
5153           if (gtk_tree_view_is_expander_column (tree_view, column) &&
5154               tree_view->priv->tree_lines_enabled)
5155             {
5156               gint x = background_area.x;
5157               gint mult = rtl ? -1 : 1;
5158               gint y0 = background_area.y;
5159               gint y1 = background_area.y + background_area.height/2;
5160               gint y2 = background_area.y + background_area.height;
5161
5162               if (rtl)
5163                 x += background_area.width - 1;
5164
5165               if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT
5166                   && depth > 1)
5167                 {
5168                   gtk_tree_view_draw_line (tree_view, cr,
5169                                            GTK_TREE_VIEW_TREE_LINE,
5170                                            x + tree_view->priv->expander_size * (depth - 1.5) * mult,
5171                                            y1,
5172                                            x + tree_view->priv->expander_size * (depth - 1.1) * mult,
5173                                            y1);
5174                 }
5175               else if (depth > 1)
5176                 {
5177                   gtk_tree_view_draw_line (tree_view, cr,
5178                                            GTK_TREE_VIEW_TREE_LINE,
5179                                            x + tree_view->priv->expander_size * (depth - 1.5) * mult,
5180                                            y1,
5181                                            x + tree_view->priv->expander_size * (depth - 0.5) * mult,
5182                                            y1);
5183                 }
5184
5185               if (depth > 1)
5186                 {
5187                   gint i;
5188                   GtkRBNode *tmp_node;
5189                   GtkRBTree *tmp_tree;
5190
5191                   if (!_gtk_rbtree_next (tree, node))
5192                     gtk_tree_view_draw_line (tree_view, cr,
5193                                              GTK_TREE_VIEW_TREE_LINE,
5194                                              x + tree_view->priv->expander_size * (depth - 1.5) * mult,
5195                                              y0,
5196                                              x + tree_view->priv->expander_size * (depth - 1.5) * mult,
5197                                              y1);
5198                   else
5199                     gtk_tree_view_draw_line (tree_view, cr,
5200                                              GTK_TREE_VIEW_TREE_LINE,
5201                                              x + tree_view->priv->expander_size * (depth - 1.5) * mult,
5202                                              y0,
5203                                              x + tree_view->priv->expander_size * (depth - 1.5) * mult,
5204                                              y2);
5205
5206                   tmp_node = tree->parent_node;
5207                   tmp_tree = tree->parent_tree;
5208
5209                   for (i = depth - 2; i > 0; i--)
5210                     {
5211                       if (_gtk_rbtree_next (tmp_tree, tmp_node))
5212                         gtk_tree_view_draw_line (tree_view, cr,
5213                                                  GTK_TREE_VIEW_TREE_LINE,
5214                                                  x + tree_view->priv->expander_size * (i - 0.5) * mult,
5215                                                  y0,
5216                                                  x + tree_view->priv->expander_size * (i - 0.5) * mult,
5217                                                  y2);
5218
5219                       tmp_node = tmp_tree->parent_node;
5220                       tmp_tree = tmp_tree->parent_tree;
5221                     }
5222                 }
5223             }
5224
5225           gtk_style_context_restore (context);
5226           cell_offset += gtk_tree_view_column_get_width (column);
5227         }
5228
5229       if (node == drag_highlight)
5230         {
5231           /* Draw indicator for the drop
5232            */
5233           gint highlight_y = -1;
5234           GtkRBTree *tree = NULL;
5235           GtkRBNode *node = NULL;
5236
5237           switch (tree_view->priv->drag_dest_pos)
5238             {
5239             case GTK_TREE_VIEW_DROP_BEFORE:
5240               highlight_y = background_area.y - 1;
5241               if (highlight_y < 0)
5242                       highlight_y = 0;
5243               break;
5244
5245             case GTK_TREE_VIEW_DROP_AFTER:
5246               highlight_y = background_area.y + background_area.height - 1;
5247               break;
5248
5249             case GTK_TREE_VIEW_DROP_INTO_OR_BEFORE:
5250             case GTK_TREE_VIEW_DROP_INTO_OR_AFTER:
5251               _gtk_tree_view_find_node (tree_view, drag_dest_path, &tree, &node);
5252
5253               if (tree == NULL)
5254                 break;
5255
5256               gtk_render_focus (context, cr,
5257                                 0, gtk_tree_view_get_row_y_offset (tree_view, tree, node)
5258                                    - focus_line_width / 2,
5259                                 gdk_window_get_width (tree_view->priv->bin_window),
5260                                 gtk_tree_view_get_row_height (tree_view, node)
5261                                    - focus_line_width + 1);
5262               break;
5263             }
5264
5265           if (highlight_y >= 0)
5266             {
5267               gtk_tree_view_draw_line (tree_view, cr,
5268                                        GTK_TREE_VIEW_FOREGROUND_LINE,
5269                                        rtl ? highlight_x + expander_cell_width : highlight_x,
5270                                        highlight_y,
5271                                        rtl ? 0 : bin_window_width,
5272                                        highlight_y);
5273             }
5274         }
5275
5276       /* draw the big row-spanning focus rectangle, if needed */
5277       if (!has_can_focus_cell && node == cursor &&
5278           tree_view->priv->draw_keyfocus &&
5279           gtk_widget_has_focus (widget))
5280         {
5281           gint tmp_y, tmp_height;
5282           GtkStateFlags focus_rect_state = 0;
5283
5284           gtk_style_context_save (context);
5285
5286           focus_rect_state = gtk_cell_renderer_get_state (NULL, widget, flags);
5287           gtk_style_context_set_state (context, focus_rect_state);
5288
5289           if (draw_hgrid_lines)
5290             {
5291               tmp_y = gtk_tree_view_get_row_y_offset (tree_view, tree, node) + grid_line_width / 2;
5292               tmp_height = gtk_tree_view_get_row_height (tree_view, node) - grid_line_width;
5293             }
5294           else
5295             {
5296               tmp_y = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
5297               tmp_height = gtk_tree_view_get_row_height (tree_view, node);
5298             }
5299
5300           gtk_render_focus (context, cr,
5301                             0, tmp_y,
5302                             gdk_window_get_width (tree_view->priv->bin_window),
5303                             tmp_height);
5304
5305           gtk_style_context_restore (context);
5306         }
5307
5308       y_offset += max_height;
5309       if (node->children)
5310         {
5311           GtkTreeIter parent = iter;
5312           gboolean has_child;
5313
5314           tree = node->children;
5315           node = tree->root;
5316
5317           g_assert (node != tree->nil);
5318
5319           while (node->left != tree->nil)
5320             node = node->left;
5321           has_child = gtk_tree_model_iter_children (tree_view->priv->model,
5322                                                     &iter,
5323                                                     &parent);
5324           depth++;
5325
5326           /* Sanity Check! */
5327           TREE_VIEW_INTERNAL_ASSERT (has_child, FALSE);
5328         }
5329       else
5330         {
5331           gboolean done = FALSE;
5332
5333           do
5334             {
5335               node = _gtk_rbtree_next (tree, node);
5336               if (node != NULL)
5337                 {
5338                   gboolean has_next = gtk_tree_model_iter_next (tree_view->priv->model, &iter);
5339                   done = TRUE;
5340
5341                   /* Sanity Check! */
5342                   TREE_VIEW_INTERNAL_ASSERT (has_next, FALSE);
5343                 }
5344               else
5345                 {
5346                   GtkTreeIter parent_iter = iter;
5347                   gboolean has_parent;
5348
5349                   node = tree->parent_node;
5350                   tree = tree->parent_tree;
5351                   if (tree == NULL)
5352                     /* we should go to done to free some memory */
5353                     goto done;
5354                   has_parent = gtk_tree_model_iter_parent (tree_view->priv->model,
5355                                                            &iter,
5356                                                            &parent_iter);
5357                   depth--;
5358
5359                   /* Sanity check */
5360                   TREE_VIEW_INTERNAL_ASSERT (has_parent, FALSE);
5361                 }
5362             }
5363           while (!done);
5364         }
5365     }
5366   while (y_offset < clip.height);
5367
5368 done:
5369   gtk_tree_view_draw_grid_lines (tree_view, cr, n_visible_columns);
5370
5371   if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
5372     gtk_tree_view_paint_rubber_band (tree_view, cr);
5373
5374   if (cursor_path)
5375     gtk_tree_path_free (cursor_path);
5376
5377   if (drag_dest_path)
5378     gtk_tree_path_free (drag_dest_path);
5379
5380   return FALSE;
5381 }
5382
5383 static gboolean
5384 gtk_tree_view_draw (GtkWidget *widget,
5385                     cairo_t   *cr)
5386 {
5387   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
5388   GtkWidget   *button;
5389
5390   if (gtk_cairo_should_draw_window (cr, tree_view->priv->bin_window))
5391     {
5392       GtkStyleContext *context;
5393       GList *tmp_list;
5394
5395       context = gtk_widget_get_style_context (widget);
5396
5397       cairo_save (cr);
5398
5399       gtk_style_context_save (context);
5400       gtk_style_context_add_class (context, GTK_STYLE_CLASS_VIEW);
5401
5402       gtk_cairo_transform_to_window (cr, widget, tree_view->priv->bin_window);
5403
5404       gtk_tree_view_bin_draw (widget, cr);
5405
5406       gtk_style_context_restore (context);
5407       cairo_restore (cr);
5408
5409       /* We can't just chain up to Container::draw as it will try to send the
5410        * event to the headers, so we handle propagating it to our children
5411        * (eg. widgets being edited) ourselves.
5412        */
5413       tmp_list = tree_view->priv->children;
5414       while (tmp_list)
5415         {
5416           GtkTreeViewChild *child = tmp_list->data;
5417           tmp_list = tmp_list->next;
5418
5419           gtk_container_propagate_draw (GTK_CONTAINER (tree_view), child->widget, cr);
5420         }
5421     }
5422
5423   if (gtk_cairo_should_draw_window (cr, tree_view->priv->header_window))
5424     {
5425       GList *list;
5426       
5427       for (list = tree_view->priv->columns; list != NULL; list = list->next)
5428         {
5429           GtkTreeViewColumn *column = list->data;
5430
5431           if (column == tree_view->priv->drag_column)
5432             continue;
5433
5434           if (gtk_tree_view_column_get_visible (column))
5435             {
5436               button = gtk_tree_view_column_get_button (column);
5437               gtk_container_propagate_draw (GTK_CONTAINER (tree_view),
5438                                             button, cr);
5439             }
5440         }
5441     }
5442   
5443   if (tree_view->priv->drag_window &&
5444       gtk_cairo_should_draw_window (cr, tree_view->priv->drag_window))
5445     {
5446       button = gtk_tree_view_column_get_button (tree_view->priv->drag_column);
5447       gtk_container_propagate_draw (GTK_CONTAINER (tree_view),
5448                                     button, cr);
5449     }
5450
5451   return TRUE;
5452 }
5453
5454 enum
5455 {
5456   DROP_HOME,
5457   DROP_RIGHT,
5458   DROP_LEFT,
5459   DROP_END
5460 };
5461
5462 /* returns 0x1 when no column has been found -- yes it's hackish */
5463 static GtkTreeViewColumn *
5464 gtk_tree_view_get_drop_column (GtkTreeView       *tree_view,
5465                                GtkTreeViewColumn *column,
5466                                gint               drop_position)
5467 {
5468   GtkTreeViewColumn *left_column = NULL;
5469   GtkTreeViewColumn *cur_column = NULL;
5470   GList *tmp_list;
5471
5472   if (!gtk_tree_view_column_get_reorderable (column))
5473     return (GtkTreeViewColumn *)0x1;
5474
5475   switch (drop_position)
5476     {
5477       case DROP_HOME:
5478         /* find first column where we can drop */
5479         tmp_list = tree_view->priv->columns;
5480         if (column == GTK_TREE_VIEW_COLUMN (tmp_list->data))
5481           return (GtkTreeViewColumn *)0x1;
5482
5483         while (tmp_list)
5484           {
5485             g_assert (tmp_list);
5486
5487             cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5488             tmp_list = tmp_list->next;
5489
5490             if (left_column &&
5491                 gtk_tree_view_column_get_visible (left_column) == FALSE)
5492               continue;
5493
5494             if (!tree_view->priv->column_drop_func)
5495               return left_column;
5496
5497             if (!tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5498               {
5499                 left_column = cur_column;
5500                 continue;
5501               }
5502
5503             return left_column;
5504           }
5505
5506         if (!tree_view->priv->column_drop_func)
5507           return left_column;
5508
5509         if (tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data))
5510           return left_column;
5511         else
5512           return (GtkTreeViewColumn *)0x1;
5513         break;
5514
5515       case DROP_RIGHT:
5516         /* find first column after column where we can drop */
5517         tmp_list = tree_view->priv->columns;
5518
5519         for (; tmp_list; tmp_list = tmp_list->next)
5520           if (GTK_TREE_VIEW_COLUMN (tmp_list->data) == column)
5521             break;
5522
5523         if (!tmp_list || !tmp_list->next)
5524           return (GtkTreeViewColumn *)0x1;
5525
5526         tmp_list = tmp_list->next;
5527         left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5528         tmp_list = tmp_list->next;
5529
5530         while (tmp_list)
5531           {
5532             g_assert (tmp_list);
5533
5534             cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5535             tmp_list = tmp_list->next;
5536
5537             if (left_column &&
5538                 gtk_tree_view_column_get_visible (left_column) == FALSE)
5539               {
5540                 left_column = cur_column;
5541                 if (tmp_list)
5542                   tmp_list = tmp_list->next;
5543                 continue;
5544               }
5545
5546             if (!tree_view->priv->column_drop_func)
5547               return left_column;
5548
5549             if (!tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5550               {
5551                 left_column = cur_column;
5552                 continue;
5553               }
5554
5555             return left_column;
5556           }
5557
5558         if (!tree_view->priv->column_drop_func)
5559           return left_column;
5560
5561         if (tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data))
5562           return left_column;
5563         else
5564           return (GtkTreeViewColumn *)0x1;
5565         break;
5566
5567       case DROP_LEFT:
5568         /* find first column before column where we can drop */
5569         tmp_list = tree_view->priv->columns;
5570
5571         for (; tmp_list; tmp_list = tmp_list->next)
5572           if (GTK_TREE_VIEW_COLUMN (tmp_list->data) == column)
5573             break;
5574
5575         if (!tmp_list || !tmp_list->prev)
5576           return (GtkTreeViewColumn *)0x1;
5577
5578         tmp_list = tmp_list->prev;
5579         cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5580         tmp_list = tmp_list->prev;
5581
5582         while (tmp_list)
5583           {
5584             g_assert (tmp_list);
5585
5586             left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5587
5588             if (left_column &&
5589                 gtk_tree_view_column_get_visible (left_column) == FALSE)
5590               {
5591                 /*if (!tmp_list->prev)
5592                   return (GtkTreeViewColumn *)0x1;
5593                   */
5594 /*
5595                 cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->prev->data);
5596                 tmp_list = tmp_list->prev->prev;
5597                 continue;*/
5598
5599                 cur_column = left_column;
5600                 if (tmp_list)
5601                   tmp_list = tmp_list->prev;
5602                 continue;
5603               }
5604
5605             if (!tree_view->priv->column_drop_func)
5606               return left_column;
5607
5608             if (tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5609               return left_column;
5610
5611             cur_column = left_column;
5612             tmp_list = tmp_list->prev;
5613           }
5614
5615         if (!tree_view->priv->column_drop_func)
5616           return NULL;
5617
5618         if (tree_view->priv->column_drop_func (tree_view, column, NULL, cur_column, tree_view->priv->column_drop_func_data))
5619           return NULL;
5620         else
5621           return (GtkTreeViewColumn *)0x1;
5622         break;
5623
5624       case DROP_END:
5625         /* same as DROP_HOME case, but doing it backwards */
5626         tmp_list = g_list_last (tree_view->priv->columns);
5627         cur_column = NULL;
5628
5629         if (column == GTK_TREE_VIEW_COLUMN (tmp_list->data))
5630           return (GtkTreeViewColumn *)0x1;
5631
5632         while (tmp_list)
5633           {
5634             g_assert (tmp_list);
5635
5636             left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5637
5638             if (left_column &&
5639                 gtk_tree_view_column_get_visible (left_column) == FALSE)
5640               {
5641                 cur_column = left_column;
5642                 tmp_list = tmp_list->prev;
5643               }
5644
5645             if (!tree_view->priv->column_drop_func)
5646               return left_column;
5647
5648             if (tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5649               return left_column;
5650
5651             cur_column = left_column;
5652             tmp_list = tmp_list->prev;
5653           }
5654
5655         if (!tree_view->priv->column_drop_func)
5656           return NULL;
5657
5658         if (tree_view->priv->column_drop_func (tree_view, column, NULL, cur_column, tree_view->priv->column_drop_func_data))
5659           return NULL;
5660         else
5661           return (GtkTreeViewColumn *)0x1;
5662         break;
5663     }
5664
5665   return (GtkTreeViewColumn *)0x1;
5666 }
5667
5668 static gboolean
5669 gtk_tree_view_key_press (GtkWidget   *widget,
5670                          GdkEventKey *event)
5671 {
5672   GtkTreeView *tree_view = (GtkTreeView *) widget;
5673   GtkWidget   *button;
5674
5675   if (tree_view->priv->rubber_band_status)
5676     {
5677       if (event->keyval == GDK_KEY_Escape)
5678         gtk_tree_view_stop_rubber_band (tree_view);
5679
5680       return TRUE;
5681     }
5682
5683   if (tree_view->priv->in_column_drag)
5684     {
5685       if (event->keyval == GDK_KEY_Escape)
5686         {
5687           tree_view->priv->cur_reorder = NULL;
5688           gtk_tree_view_button_release_drag_column (widget, NULL);
5689         }
5690       return TRUE;
5691     }
5692
5693   if (tree_view->priv->headers_visible)
5694     {
5695       GList *focus_column;
5696       gboolean rtl;
5697
5698       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
5699
5700       for (focus_column = tree_view->priv->columns;
5701            focus_column;
5702            focus_column = focus_column->next)
5703         {
5704           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
5705           
5706           button = gtk_tree_view_column_get_button (column);
5707           if (gtk_widget_has_focus (button))
5708             break;
5709         }
5710
5711       if (focus_column &&
5712           (event->state & GDK_SHIFT_MASK) && (event->state & GDK_MOD1_MASK) &&
5713           (event->keyval == GDK_KEY_Left || event->keyval == GDK_KEY_KP_Left
5714            || event->keyval == GDK_KEY_Right || event->keyval == GDK_KEY_KP_Right))
5715         {
5716           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
5717           gint max_width, min_width;
5718
5719           if (!gtk_tree_view_column_get_resizable (column))
5720             {
5721               gtk_widget_error_bell (widget);
5722               return TRUE;
5723             }
5724
5725           if (event->keyval == (rtl ? GDK_KEY_Right : GDK_KEY_Left)
5726               || event->keyval == (rtl ? GDK_KEY_KP_Right : GDK_KEY_KP_Left))
5727             {
5728               GtkRequisition button_req;
5729               gint old_width = _gtk_tree_view_column_get_resized_width (column);
5730               gint new_width;
5731
5732               button = gtk_tree_view_column_get_button (column);
5733
5734               gtk_widget_get_preferred_size (button, &button_req, NULL);
5735
5736               new_width = MAX (old_width, gtk_tree_view_column_get_width (column));
5737               new_width -= 2;
5738               if (new_width < 0)
5739                 new_width = 0;
5740
5741               _gtk_tree_view_column_set_resized_width (column, new_width);
5742
5743               min_width = gtk_tree_view_column_get_min_width (column);
5744               if (min_width == -1)
5745                 new_width = MAX (button_req.width, new_width);
5746               else
5747                 {
5748                   new_width = MAX (min_width, new_width);
5749                 }
5750
5751               max_width = gtk_tree_view_column_get_max_width (column);
5752               if (max_width != -1)
5753                 new_width = MIN (new_width, max_width);
5754
5755               _gtk_tree_view_column_set_use_resized_width (column, TRUE);
5756
5757               if (new_width != old_width)
5758                 {
5759                   _gtk_tree_view_column_set_resized_width (column, new_width);
5760                   gtk_widget_queue_resize (widget);
5761                 }
5762               else
5763                 gtk_widget_error_bell (widget);
5764             }
5765           else if (event->keyval == (rtl ? GDK_KEY_Left : GDK_KEY_Right)
5766                    || event->keyval == (rtl ? GDK_KEY_KP_Left : GDK_KEY_KP_Right))
5767             {
5768               gint old_width = _gtk_tree_view_column_get_resized_width (column);
5769               gint new_width;
5770
5771               new_width = MAX (old_width, gtk_tree_view_column_get_width (column));
5772               new_width += 2;
5773
5774               max_width = gtk_tree_view_column_get_max_width (column);
5775               if (max_width != -1)
5776                 new_width = MIN (new_width, max_width);
5777
5778               _gtk_tree_view_column_set_use_resized_width (column, TRUE);
5779
5780               if (new_width != old_width)
5781                 {
5782                   _gtk_tree_view_column_set_resized_width (column, new_width);
5783                   gtk_widget_queue_resize (widget);
5784                 }
5785               else
5786                 gtk_widget_error_bell (widget);
5787             }
5788
5789           return TRUE;
5790         }
5791
5792       if (focus_column &&
5793           (event->state & GDK_MOD1_MASK) &&
5794           (event->keyval == GDK_KEY_Left || event->keyval == GDK_KEY_KP_Left
5795            || event->keyval == GDK_KEY_Right || event->keyval == GDK_KEY_KP_Right
5796            || event->keyval == GDK_KEY_Home || event->keyval == GDK_KEY_KP_Home
5797            || event->keyval == GDK_KEY_End || event->keyval == GDK_KEY_KP_End))
5798         {
5799           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
5800
5801           if (event->keyval == (rtl ? GDK_KEY_Right : GDK_KEY_Left)
5802               || event->keyval == (rtl ? GDK_KEY_KP_Right : GDK_KEY_KP_Left))
5803             {
5804               GtkTreeViewColumn *col;
5805               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_LEFT);
5806               if (col != (GtkTreeViewColumn *)0x1)
5807                 gtk_tree_view_move_column_after (tree_view, column, col);
5808               else
5809                 gtk_widget_error_bell (widget);
5810             }
5811           else if (event->keyval == (rtl ? GDK_KEY_Left : GDK_KEY_Right)
5812                    || event->keyval == (rtl ? GDK_KEY_KP_Left : GDK_KEY_KP_Right))
5813             {
5814               GtkTreeViewColumn *col;
5815               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_RIGHT);
5816               if (col != (GtkTreeViewColumn *)0x1)
5817                 gtk_tree_view_move_column_after (tree_view, column, col);
5818               else
5819                 gtk_widget_error_bell (widget);
5820             }
5821           else if (event->keyval == GDK_KEY_Home || event->keyval == GDK_KEY_KP_Home)
5822             {
5823               GtkTreeViewColumn *col;
5824               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_HOME);
5825               if (col != (GtkTreeViewColumn *)0x1)
5826                 gtk_tree_view_move_column_after (tree_view, column, col);
5827               else
5828                 gtk_widget_error_bell (widget);
5829             }
5830           else if (event->keyval == GDK_KEY_End || event->keyval == GDK_KEY_KP_End)
5831             {
5832               GtkTreeViewColumn *col;
5833               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_END);
5834               if (col != (GtkTreeViewColumn *)0x1)
5835                 gtk_tree_view_move_column_after (tree_view, column, col);
5836               else
5837                 gtk_widget_error_bell (widget);
5838             }
5839
5840           return TRUE;
5841         }
5842     }
5843
5844   /* Chain up to the parent class.  It handles the keybindings. */
5845   if (GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->key_press_event (widget, event))
5846     return TRUE;
5847
5848   if (tree_view->priv->search_entry_avoid_unhandled_binding)
5849     {
5850       tree_view->priv->search_entry_avoid_unhandled_binding = FALSE;
5851       return FALSE;
5852     }
5853
5854   /* We pass the event to the search_entry.  If its text changes, then we start
5855    * the typeahead find capabilities. */
5856   if (gtk_widget_has_focus (GTK_WIDGET (tree_view))
5857       && tree_view->priv->enable_search
5858       && !tree_view->priv->search_custom_entry_set)
5859     {
5860       GdkEvent *new_event;
5861       char *old_text;
5862       const char *new_text;
5863       gboolean retval;
5864       GdkScreen *screen;
5865       gboolean text_modified;
5866       gulong popup_menu_id;
5867
5868       gtk_tree_view_ensure_interactive_directory (tree_view);
5869
5870       /* Make a copy of the current text */
5871       old_text = g_strdup (gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry)));
5872       new_event = gdk_event_copy ((GdkEvent *) event);
5873       g_object_unref (((GdkEventKey *) new_event)->window);
5874       ((GdkEventKey *) new_event)->window = g_object_ref (gtk_widget_get_window (tree_view->priv->search_window));
5875       gtk_widget_realize (tree_view->priv->search_window);
5876
5877       popup_menu_id = g_signal_connect (tree_view->priv->search_entry, 
5878                                         "popup-menu", G_CALLBACK (gtk_true),
5879                                         NULL);
5880
5881       /* Move the entry off screen */
5882       screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
5883       gtk_window_move (GTK_WINDOW (tree_view->priv->search_window),
5884                        gdk_screen_get_width (screen) + 1,
5885                        gdk_screen_get_height (screen) + 1);
5886       gtk_widget_show (tree_view->priv->search_window);
5887
5888       /* Send the event to the window.  If the preedit_changed signal is emitted
5889        * during this event, we will set priv->imcontext_changed  */
5890       tree_view->priv->imcontext_changed = FALSE;
5891       retval = gtk_widget_event (tree_view->priv->search_window, new_event);
5892       gdk_event_free (new_event);
5893       gtk_widget_hide (tree_view->priv->search_window);
5894
5895       g_signal_handler_disconnect (tree_view->priv->search_entry, 
5896                                    popup_menu_id);
5897
5898       /* We check to make sure that the entry tried to handle the text, and that
5899        * the text has changed.
5900        */
5901       new_text = gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry));
5902       text_modified = strcmp (old_text, new_text) != 0;
5903       g_free (old_text);
5904       if (tree_view->priv->imcontext_changed ||    /* we're in a preedit */
5905           (retval && text_modified))               /* ...or the text was modified */
5906         {
5907           if (gtk_tree_view_real_start_interactive_search (tree_view,
5908                                                            gdk_event_get_device ((GdkEvent *) event),
5909                                                            FALSE))
5910             {
5911               gtk_widget_grab_focus (GTK_WIDGET (tree_view));
5912               return TRUE;
5913             }
5914           else
5915             {
5916               gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
5917               return FALSE;
5918             }
5919         }
5920     }
5921
5922   return FALSE;
5923 }
5924
5925 static gboolean
5926 gtk_tree_view_key_release (GtkWidget   *widget,
5927                            GdkEventKey *event)
5928 {
5929   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
5930
5931   if (tree_view->priv->rubber_band_status)
5932     return TRUE;
5933
5934   return GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->key_release_event (widget, event);
5935 }
5936
5937 /* FIXME Is this function necessary? Can I get an enter_notify event
5938  * w/o either an expose event or a mouse motion event?
5939  */
5940 static gboolean
5941 gtk_tree_view_enter_notify (GtkWidget        *widget,
5942                             GdkEventCrossing *event)
5943 {
5944   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
5945   GtkRBTree *tree;
5946   GtkRBNode *node;
5947   gint new_y;
5948
5949   /* Sanity check it */
5950   if (event->window != tree_view->priv->bin_window)
5951     return FALSE;
5952
5953   if (tree_view->priv->tree == NULL)
5954     return FALSE;
5955
5956   if (event->mode == GDK_CROSSING_GRAB ||
5957       event->mode == GDK_CROSSING_GTK_GRAB ||
5958       event->mode == GDK_CROSSING_GTK_UNGRAB ||
5959       event->mode == GDK_CROSSING_STATE_CHANGED)
5960     return TRUE;
5961
5962   /* find the node internally */
5963   new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
5964   if (new_y < 0)
5965     new_y = 0;
5966   _gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
5967
5968   tree_view->priv->event_last_x = event->x;
5969   tree_view->priv->event_last_y = event->y;
5970
5971   if ((tree_view->priv->button_pressed_node == NULL) ||
5972       (tree_view->priv->button_pressed_node == node))
5973     prelight_or_select (tree_view, tree, node, event->x, event->y);
5974
5975   return TRUE;
5976 }
5977
5978 static gboolean
5979 gtk_tree_view_leave_notify (GtkWidget        *widget,
5980                             GdkEventCrossing *event)
5981 {
5982   GtkTreeView *tree_view;
5983
5984   if (event->mode == GDK_CROSSING_GRAB)
5985     return TRUE;
5986
5987   tree_view = GTK_TREE_VIEW (widget);
5988
5989   if (tree_view->priv->prelight_node)
5990     _gtk_tree_view_queue_draw_node (tree_view,
5991                                    tree_view->priv->prelight_tree,
5992                                    tree_view->priv->prelight_node,
5993                                    NULL);
5994
5995   tree_view->priv->event_last_x = -10000;
5996   tree_view->priv->event_last_y = -10000;
5997
5998   prelight_or_select (tree_view,
5999                       NULL, NULL,
6000                       -1000, -1000); /* coords not possibly over an arrow */
6001
6002   return TRUE;
6003 }
6004
6005
6006 static gint
6007 gtk_tree_view_focus_out (GtkWidget     *widget,
6008                          GdkEventFocus *event)
6009 {
6010   GtkTreeView *tree_view;
6011
6012   tree_view = GTK_TREE_VIEW (widget);
6013
6014   gtk_widget_queue_draw (widget);
6015
6016   /* destroy interactive search dialog */
6017   if (tree_view->priv->search_window)
6018     gtk_tree_view_search_dialog_hide (tree_view->priv->search_window, tree_view,
6019                                       gdk_event_get_device ((GdkEvent *) event));
6020
6021   return FALSE;
6022 }
6023
6024
6025 /* Incremental Reflow
6026  */
6027
6028 static void
6029 gtk_tree_view_node_queue_redraw (GtkTreeView *tree_view,
6030                                  GtkRBTree   *tree,
6031                                  GtkRBNode   *node)
6032 {
6033   GtkAllocation allocation;
6034   gint y;
6035
6036   y = _gtk_rbtree_node_find_offset (tree, node)
6037     - gtk_adjustment_get_value (tree_view->priv->vadjustment)
6038     + gtk_tree_view_get_effective_header_height (tree_view);
6039
6040   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
6041   gtk_widget_queue_draw_area (GTK_WIDGET (tree_view),
6042                               0, y,
6043                               allocation.width,
6044                               GTK_RBNODE_GET_HEIGHT (node));
6045 }
6046
6047 static gboolean
6048 node_is_visible (GtkTreeView *tree_view,
6049                  GtkRBTree   *tree,
6050                  GtkRBNode   *node)
6051 {
6052   int y;
6053   int height;
6054
6055   y = _gtk_rbtree_node_find_offset (tree, node);
6056   height = gtk_tree_view_get_row_height (tree_view, node);
6057
6058   if (y >= gtk_adjustment_get_value (tree_view->priv->vadjustment) &&
6059       y + height <= (gtk_adjustment_get_value (tree_view->priv->vadjustment)
6060                      + gtk_adjustment_get_page_size (tree_view->priv->vadjustment)))
6061     return TRUE;
6062
6063   return FALSE;
6064 }
6065
6066 /* Returns TRUE if it updated the size
6067  */
6068 static gboolean
6069 validate_row (GtkTreeView *tree_view,
6070               GtkRBTree   *tree,
6071               GtkRBNode   *node,
6072               GtkTreeIter *iter,
6073               GtkTreePath *path)
6074 {
6075   GtkTreeViewColumn *column;
6076   GList *list, *first_column, *last_column;
6077   gint height = 0;
6078   gint horizontal_separator;
6079   gint vertical_separator;
6080   gint depth = gtk_tree_path_get_depth (path);
6081   gboolean retval = FALSE;
6082   gboolean is_separator = FALSE;
6083   gboolean draw_vgrid_lines, draw_hgrid_lines;
6084   gint focus_pad;
6085   gint grid_line_width;
6086   gboolean wide_separators;
6087   gint separator_height;
6088
6089   /* double check the row needs validating */
6090   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) &&
6091       ! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6092     return FALSE;
6093
6094   is_separator = row_is_separator (tree_view, iter, NULL);
6095
6096   gtk_widget_style_get (GTK_WIDGET (tree_view),
6097                         "focus-padding", &focus_pad,
6098                         "horizontal-separator", &horizontal_separator,
6099                         "vertical-separator", &vertical_separator,
6100                         "grid-line-width", &grid_line_width,
6101                         "wide-separators",  &wide_separators,
6102                         "separator-height", &separator_height,
6103                         NULL);
6104   
6105   draw_vgrid_lines =
6106     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_VERTICAL
6107     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
6108   draw_hgrid_lines =
6109     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_HORIZONTAL
6110     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
6111
6112   for (last_column = g_list_last (tree_view->priv->columns);
6113        last_column &&
6114        !(gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (last_column->data)));
6115        last_column = last_column->prev)
6116     ;
6117
6118   for (first_column = g_list_first (tree_view->priv->columns);
6119        first_column &&
6120        !(gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (first_column->data)));
6121        first_column = first_column->next)
6122     ;
6123
6124   for (list = tree_view->priv->columns; list; list = list->next)
6125     {
6126       gint padding = 0;
6127       gint original_width;
6128       gint new_width;
6129       gint row_height;
6130
6131       column = list->data;
6132
6133       if (!gtk_tree_view_column_get_visible (column))
6134         continue;
6135
6136       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID) && 
6137           !_gtk_tree_view_column_cell_get_dirty (column))
6138         continue;
6139
6140       original_width = _gtk_tree_view_column_get_requested_width (column);
6141
6142       gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, iter,
6143                                                GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
6144                                                node->children?TRUE:FALSE);
6145       gtk_tree_view_column_cell_get_size (column,
6146                                           NULL, NULL, NULL,
6147                                           NULL, &row_height);
6148
6149       if (!is_separator)
6150         {
6151           row_height += vertical_separator;
6152           height = MAX (height, row_height);
6153           height = MAX (height, tree_view->priv->expander_size);
6154         }
6155       else
6156         {
6157           if (wide_separators)
6158             height = separator_height + 2 * focus_pad;
6159           else
6160             height = 2 + 2 * focus_pad;
6161         }
6162
6163       if (gtk_tree_view_is_expander_column (tree_view, column))
6164         {
6165           padding += horizontal_separator + (depth - 1) * tree_view->priv->level_indentation;
6166
6167           if (gtk_tree_view_draw_expanders (tree_view))
6168             padding += depth * tree_view->priv->expander_size;
6169         }
6170       else
6171         padding += horizontal_separator;
6172
6173       if (draw_vgrid_lines)
6174         {
6175           if (list->data == first_column || list->data == last_column)
6176             padding += grid_line_width / 2.0;
6177           else
6178             padding += grid_line_width;
6179         }
6180
6181       /* Update the padding for the column */
6182       _gtk_tree_view_column_push_padding (column, padding);
6183       new_width = _gtk_tree_view_column_get_requested_width (column);
6184
6185       if (new_width > original_width)
6186         retval = TRUE;
6187     }
6188
6189   if (draw_hgrid_lines)
6190     height += grid_line_width;
6191
6192   if (height != GTK_RBNODE_GET_HEIGHT (node))
6193     {
6194       retval = TRUE;
6195       _gtk_rbtree_node_set_height (tree, node, height);
6196     }
6197   _gtk_rbtree_node_mark_valid (tree, node);
6198   tree_view->priv->post_validation_flag = TRUE;
6199
6200   return retval;
6201 }
6202
6203
6204 static void
6205 validate_visible_area (GtkTreeView *tree_view)
6206 {
6207   GtkAllocation allocation;
6208   GtkTreePath *path = NULL;
6209   GtkTreePath *above_path = NULL;
6210   GtkTreeIter iter;
6211   GtkRBTree *tree = NULL;
6212   GtkRBNode *node = NULL;
6213   gboolean need_redraw = FALSE;
6214   gboolean size_changed = FALSE;
6215   gint total_height;
6216   gint area_above = 0;
6217   gint area_below = 0;
6218
6219   if (tree_view->priv->tree == NULL)
6220     return;
6221
6222   if (! GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID) &&
6223       tree_view->priv->scroll_to_path == NULL)
6224     return;
6225
6226   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
6227   total_height = allocation.height - gtk_tree_view_get_effective_header_height (tree_view);
6228
6229   if (total_height == 0)
6230     return;
6231
6232   /* First, we check to see if we need to scroll anywhere
6233    */
6234   if (tree_view->priv->scroll_to_path)
6235     {
6236       path = gtk_tree_row_reference_get_path (tree_view->priv->scroll_to_path);
6237       if (path && !_gtk_tree_view_find_node (tree_view, path, &tree, &node))
6238         {
6239           /* we are going to scroll, and will update dy */
6240           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6241           if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6242               GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6243             {
6244               _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
6245               if (validate_row (tree_view, tree, node, &iter, path))
6246                 size_changed = TRUE;
6247             }
6248
6249           if (tree_view->priv->scroll_to_use_align)
6250             {
6251               gint height = gtk_tree_view_get_row_height (tree_view, node);
6252               area_above = (total_height - height) *
6253                 tree_view->priv->scroll_to_row_align;
6254               area_below = total_height - area_above - height;
6255               area_above = MAX (area_above, 0);
6256               area_below = MAX (area_below, 0);
6257             }
6258           else
6259             {
6260               /* two cases:
6261                * 1) row not visible
6262                * 2) row visible
6263                */
6264               gint dy;
6265               gint height = gtk_tree_view_get_row_height (tree_view, node);
6266
6267               dy = _gtk_rbtree_node_find_offset (tree, node);
6268
6269               if (dy >= gtk_adjustment_get_value (tree_view->priv->vadjustment) &&
6270                   dy + height <= (gtk_adjustment_get_value (tree_view->priv->vadjustment)
6271                                   + gtk_adjustment_get_page_size (tree_view->priv->vadjustment)))
6272                 {
6273                   /* row visible: keep the row at the same position */
6274                   area_above = dy - gtk_adjustment_get_value (tree_view->priv->vadjustment);
6275                   area_below = (gtk_adjustment_get_value (tree_view->priv->vadjustment) +
6276                                 gtk_adjustment_get_page_size (tree_view->priv->vadjustment))
6277                                - dy - height;
6278                 }
6279               else
6280                 {
6281                   /* row not visible */
6282                   if (dy >= 0
6283                       && dy + height <= gtk_adjustment_get_page_size (tree_view->priv->vadjustment))
6284                     {
6285                       /* row at the beginning -- fixed */
6286                       area_above = dy;
6287                       area_below = gtk_adjustment_get_page_size (tree_view->priv->vadjustment)
6288                                    - area_above - height;
6289                     }
6290                   else if (dy >= (gtk_adjustment_get_upper (tree_view->priv->vadjustment) -
6291                                   gtk_adjustment_get_page_size (tree_view->priv->vadjustment)))
6292                     {
6293                       /* row at the end -- fixed */
6294                       area_above = dy - (gtk_adjustment_get_upper (tree_view->priv->vadjustment) -
6295                                    gtk_adjustment_get_page_size (tree_view->priv->vadjustment));
6296                       area_below = gtk_adjustment_get_page_size (tree_view->priv->vadjustment) -
6297                                    area_above - height;
6298
6299                       if (area_below < 0)
6300                         {
6301                           area_above = gtk_adjustment_get_page_size (tree_view->priv->vadjustment) - height;
6302                           area_below = 0;
6303                         }
6304                     }
6305                   else
6306                     {
6307                       /* row somewhere in the middle, bring it to the top
6308                        * of the view
6309                        */
6310                       area_above = 0;
6311                       area_below = total_height - height;
6312                     }
6313                 }
6314             }
6315         }
6316       else
6317         /* the scroll to isn't valid; ignore it.
6318          */
6319         {
6320           if (tree_view->priv->scroll_to_path && !path)
6321             {
6322               gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
6323               tree_view->priv->scroll_to_path = NULL;
6324             }
6325           if (path)
6326             gtk_tree_path_free (path);
6327           path = NULL;
6328         }      
6329     }
6330
6331   /* We didn't have a scroll_to set, so we just handle things normally
6332    */
6333   if (path == NULL)
6334     {
6335       gint offset;
6336
6337       offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
6338                                         TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, 0),
6339                                         &tree, &node);
6340       if (node == NULL)
6341         {
6342           /* In this case, nothing has been validated */
6343           path = gtk_tree_path_new_first ();
6344           _gtk_tree_view_find_node (tree_view, path, &tree, &node);
6345         }
6346       else
6347         {
6348           path = _gtk_tree_view_find_path (tree_view, tree, node);
6349           total_height += offset;
6350         }
6351
6352       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6353
6354       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6355           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6356         {
6357           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
6358           if (validate_row (tree_view, tree, node, &iter, path))
6359             size_changed = TRUE;
6360         }
6361       area_above = 0;
6362       area_below = total_height - gtk_tree_view_get_row_height (tree_view, node);
6363     }
6364
6365   above_path = gtk_tree_path_copy (path);
6366
6367   /* if we do not validate any row above the new top_row, we will make sure
6368    * that the row immediately above top_row has been validated. (if we do not
6369    * do this, _gtk_rbtree_find_offset will find the row above top_row, because
6370    * when invalidated that row's height will be zero. and this will mess up
6371    * scrolling).
6372    */
6373   if (area_above == 0)
6374     {
6375       GtkRBTree *tmptree;
6376       GtkRBNode *tmpnode;
6377
6378       _gtk_tree_view_find_node (tree_view, above_path, &tmptree, &tmpnode);
6379       _gtk_rbtree_prev_full (tmptree, tmpnode, &tmptree, &tmpnode);
6380
6381       if (tmpnode)
6382         {
6383           GtkTreePath *tmppath;
6384           GtkTreeIter tmpiter;
6385
6386           tmppath = _gtk_tree_view_find_path (tree_view, tmptree, tmpnode);
6387           gtk_tree_model_get_iter (tree_view->priv->model, &tmpiter, tmppath);
6388
6389           if (GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_INVALID) ||
6390               GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_COLUMN_INVALID))
6391             {
6392               _gtk_tree_view_queue_draw_node (tree_view, tmptree, tmpnode, NULL);
6393               if (validate_row (tree_view, tmptree, tmpnode, &tmpiter, tmppath))
6394                 size_changed = TRUE;
6395             }
6396
6397           gtk_tree_path_free (tmppath);
6398         }
6399     }
6400
6401   /* Now, we walk forwards and backwards, measuring rows. Unfortunately,
6402    * backwards is much slower then forward, as there is no iter_prev function.
6403    * We go forwards first in case we run out of tree.  Then we go backwards to
6404    * fill out the top.
6405    */
6406   while (node && area_below > 0)
6407     {
6408       if (node->children)
6409         {
6410           GtkTreeIter parent = iter;
6411           gboolean has_child;
6412
6413           tree = node->children;
6414           node = tree->root;
6415
6416           g_assert (node != tree->nil);
6417
6418           while (node->left != tree->nil)
6419             node = node->left;
6420           has_child = gtk_tree_model_iter_children (tree_view->priv->model,
6421                                                     &iter,
6422                                                     &parent);
6423           TREE_VIEW_INTERNAL_ASSERT_VOID (has_child);
6424           gtk_tree_path_down (path);
6425         }
6426       else
6427         {
6428           gboolean done = FALSE;
6429           do
6430             {
6431               node = _gtk_rbtree_next (tree, node);
6432               if (node != NULL)
6433                 {
6434                   gboolean has_next = gtk_tree_model_iter_next (tree_view->priv->model, &iter);
6435                   done = TRUE;
6436                   gtk_tree_path_next (path);
6437
6438                   /* Sanity Check! */
6439                   TREE_VIEW_INTERNAL_ASSERT_VOID (has_next);
6440                 }
6441               else
6442                 {
6443                   GtkTreeIter parent_iter = iter;
6444                   gboolean has_parent;
6445
6446                   node = tree->parent_node;
6447                   tree = tree->parent_tree;
6448                   if (tree == NULL)
6449                     break;
6450                   has_parent = gtk_tree_model_iter_parent (tree_view->priv->model,
6451                                                            &iter,
6452                                                            &parent_iter);
6453                   gtk_tree_path_up (path);
6454
6455                   /* Sanity check */
6456                   TREE_VIEW_INTERNAL_ASSERT_VOID (has_parent);
6457                 }
6458             }
6459           while (!done);
6460         }
6461
6462       if (!node)
6463         break;
6464
6465       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6466           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6467         {
6468           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
6469           if (validate_row (tree_view, tree, node, &iter, path))
6470               size_changed = TRUE;
6471         }
6472
6473       area_below -= gtk_tree_view_get_row_height (tree_view, node);
6474     }
6475   gtk_tree_path_free (path);
6476
6477   /* If we ran out of tree, and have extra area_below left, we need to add it
6478    * to area_above */
6479   if (area_below > 0)
6480     area_above += area_below;
6481
6482   _gtk_tree_view_find_node (tree_view, above_path, &tree, &node);
6483
6484   /* We walk backwards */
6485   while (area_above > 0)
6486     {
6487       _gtk_rbtree_prev_full (tree, node, &tree, &node);
6488
6489       /* Always find the new path in the tree.  We cannot just assume
6490        * a gtk_tree_path_prev() is enough here, as there might be children
6491        * in between this node and the previous sibling node.  If this
6492        * appears to be a performance hotspot in profiles, we can look into
6493        * intrigate logic for keeping path, node and iter in sync like
6494        * we do for forward walks.  (Which will be hard because of the lacking
6495        * iter_prev).
6496        */
6497
6498       if (node == NULL)
6499         break;
6500
6501       gtk_tree_path_free (above_path);
6502       above_path = _gtk_tree_view_find_path (tree_view, tree, node);
6503
6504       gtk_tree_model_get_iter (tree_view->priv->model, &iter, above_path);
6505
6506       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6507           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6508         {
6509           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
6510           if (validate_row (tree_view, tree, node, &iter, above_path))
6511             size_changed = TRUE;
6512         }
6513       area_above -= gtk_tree_view_get_row_height (tree_view, node);
6514     }
6515
6516   /* if we scrolled to a path, we need to set the dy here,
6517    * and sync the top row accordingly
6518    */
6519   if (tree_view->priv->scroll_to_path)
6520     {
6521       gtk_tree_view_set_top_row (tree_view, above_path, -area_above);
6522       gtk_tree_view_top_row_to_dy (tree_view);
6523
6524       need_redraw = TRUE;
6525     }
6526   else if (tree_view->priv->height <= gtk_adjustment_get_page_size (tree_view->priv->vadjustment))
6527     {
6528       /* when we are not scrolling, we should never set dy to something
6529        * else than zero. we update top_row to be in sync with dy = 0.
6530        */
6531       gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
6532       gtk_tree_view_dy_to_top_row (tree_view);
6533     }
6534   else if (gtk_adjustment_get_value (tree_view->priv->vadjustment) + gtk_adjustment_get_page_size (tree_view->priv->vadjustment) > tree_view->priv->height)
6535     {
6536       gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), tree_view->priv->height - gtk_adjustment_get_page_size (tree_view->priv->vadjustment));
6537       gtk_tree_view_dy_to_top_row (tree_view);
6538     }
6539   else
6540     gtk_tree_view_top_row_to_dy (tree_view);
6541
6542   /* update width/height and queue a resize */
6543   if (size_changed)
6544     {
6545       GtkRequisition requisition;
6546
6547       /* We temporarily guess a size, under the assumption that it will be the
6548        * same when we get our next size_allocate.  If we don't do this, we'll be
6549        * in an inconsistent state if we call top_row_to_dy. */
6550
6551       gtk_widget_get_preferred_size (GTK_WIDGET (tree_view),
6552                                      &requisition, NULL);
6553       gtk_adjustment_set_upper (tree_view->priv->hadjustment,
6554                                 MAX (gtk_adjustment_get_upper (tree_view->priv->hadjustment), requisition.width));
6555       gtk_adjustment_set_upper (tree_view->priv->vadjustment,
6556                                 MAX (gtk_adjustment_get_upper (tree_view->priv->vadjustment), requisition.height));
6557       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6558     }
6559
6560   if (tree_view->priv->scroll_to_path)
6561     {
6562       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
6563       tree_view->priv->scroll_to_path = NULL;
6564     }
6565
6566   if (above_path)
6567     gtk_tree_path_free (above_path);
6568
6569   if (tree_view->priv->scroll_to_column)
6570     {
6571       tree_view->priv->scroll_to_column = NULL;
6572     }
6573   if (need_redraw)
6574     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
6575 }
6576
6577 static void
6578 initialize_fixed_height_mode (GtkTreeView *tree_view)
6579 {
6580   if (!tree_view->priv->tree)
6581     return;
6582
6583   if (tree_view->priv->fixed_height < 0)
6584     {
6585       GtkTreeIter iter;
6586       GtkTreePath *path;
6587
6588       GtkRBTree *tree = NULL;
6589       GtkRBNode *node = NULL;
6590
6591       tree = tree_view->priv->tree;
6592       node = tree->root;
6593
6594       path = _gtk_tree_view_find_path (tree_view, tree, node);
6595       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6596
6597       validate_row (tree_view, tree, node, &iter, path);
6598
6599       gtk_tree_path_free (path);
6600
6601       tree_view->priv->fixed_height = gtk_tree_view_get_row_height (tree_view, node);
6602     }
6603
6604    _gtk_rbtree_set_fixed_height (tree_view->priv->tree,
6605                                  tree_view->priv->fixed_height, TRUE);
6606 }
6607
6608 /* Our strategy for finding nodes to validate is a little convoluted.  We find
6609  * the left-most uninvalidated node.  We then try walking right, validating
6610  * nodes.  Once we find a valid node, we repeat the previous process of finding
6611  * the first invalid node.
6612  */
6613
6614 static gboolean
6615 do_validate_rows (GtkTreeView *tree_view, gboolean queue_resize)
6616 {
6617   GtkRBTree *tree = NULL;
6618   GtkRBNode *node = NULL;
6619   gboolean validated_area = FALSE;
6620   gint retval = TRUE;
6621   GtkTreePath *path = NULL;
6622   GtkTreeIter iter;
6623   GTimer *timer;
6624   gint i = 0;
6625
6626   gint prev_height = -1;
6627   gboolean fixed_height = TRUE;
6628
6629   g_assert (tree_view);
6630
6631   if (tree_view->priv->tree == NULL)
6632       return FALSE;
6633
6634   if (tree_view->priv->fixed_height_mode)
6635     {
6636       if (tree_view->priv->fixed_height < 0)
6637         initialize_fixed_height_mode (tree_view);
6638
6639       return FALSE;
6640     }
6641
6642   timer = g_timer_new ();
6643   g_timer_start (timer);
6644
6645   do
6646     {
6647       if (! GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID))
6648         {
6649           retval = FALSE;
6650           goto done;
6651         }
6652
6653       if (path != NULL)
6654         {
6655           node = _gtk_rbtree_next (tree, node);
6656           if (node != NULL)
6657             {
6658               TREE_VIEW_INTERNAL_ASSERT (gtk_tree_model_iter_next (tree_view->priv->model, &iter), FALSE);
6659               gtk_tree_path_next (path);
6660             }
6661           else
6662             {
6663               gtk_tree_path_free (path);
6664               path = NULL;
6665             }
6666         }
6667
6668       if (path == NULL)
6669         {
6670           tree = tree_view->priv->tree;
6671           node = tree_view->priv->tree->root;
6672
6673           g_assert (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_DESCENDANTS_INVALID));
6674
6675           do
6676             {
6677               if (node->left != tree->nil &&
6678                   GTK_RBNODE_FLAG_SET (node->left, GTK_RBNODE_DESCENDANTS_INVALID))
6679                 {
6680                   node = node->left;
6681                 }
6682               else if (node->right != tree->nil &&
6683                        GTK_RBNODE_FLAG_SET (node->right, GTK_RBNODE_DESCENDANTS_INVALID))
6684                 {
6685                   node = node->right;
6686                 }
6687               else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6688                        GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6689                 {
6690                   break;
6691                 }
6692               else if (node->children != NULL)
6693                 {
6694                   tree = node->children;
6695                   node = tree->root;
6696                 }
6697               else
6698                 /* RBTree corruption!  All bad */
6699                 g_assert_not_reached ();
6700             }
6701           while (TRUE);
6702           path = _gtk_tree_view_find_path (tree_view, tree, node);
6703           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6704         }
6705
6706       validated_area = validate_row (tree_view, tree, node, &iter, path) ||
6707                        validated_area;
6708
6709       if (!tree_view->priv->fixed_height_check)
6710         {
6711           gint height;
6712
6713           height = gtk_tree_view_get_row_height (tree_view, node);
6714           if (prev_height < 0)
6715             prev_height = height;
6716           else if (prev_height != height)
6717             fixed_height = FALSE;
6718         }
6719
6720       i++;
6721     }
6722   while (g_timer_elapsed (timer, NULL) < GTK_TREE_VIEW_TIME_MS_PER_IDLE / 1000.);
6723
6724   if (!tree_view->priv->fixed_height_check)
6725    {
6726      if (fixed_height)
6727        _gtk_rbtree_set_fixed_height (tree_view->priv->tree, prev_height, FALSE);
6728
6729      tree_view->priv->fixed_height_check = 1;
6730    }
6731   
6732  done:
6733   if (validated_area)
6734     {
6735       GtkRequisition requisition;
6736
6737       /* We temporarily guess a size, under the assumption that it will be the
6738        * same when we get our next size_allocate.  If we don't do this, we'll be
6739        * in an inconsistent state when we call top_row_to_dy. */
6740
6741       /* FIXME: This is called from size_request, for some reason it is not infinitely
6742        * recursing, we cannot call gtk_widget_get_preferred_size() here because that's
6743        * not allowed (from inside ->get_preferred_width/height() implementations, one
6744        * should call the vfuncs directly). However what is desired here is the full
6745        * size including any margins and limited by any alignment (i.e. after 
6746        * GtkWidget:adjust_size_request() is called).
6747        *
6748        * Currently bypassing this but the real solution is to not update the scroll adjustments
6749        * untill we've recieved an allocation (never update scroll adjustments from size-requests).
6750        */
6751       gtk_tree_view_size_request (GTK_WIDGET (tree_view), &requisition, FALSE);
6752
6753       gtk_adjustment_set_upper (tree_view->priv->hadjustment,
6754                                 MAX (gtk_adjustment_get_upper (tree_view->priv->hadjustment), requisition.width));
6755       gtk_adjustment_set_upper (tree_view->priv->vadjustment,
6756                                 MAX (gtk_adjustment_get_upper (tree_view->priv->vadjustment), requisition.height));
6757
6758       if (queue_resize)
6759         gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6760     }
6761
6762   if (path) gtk_tree_path_free (path);
6763   g_timer_destroy (timer);
6764
6765   return retval;
6766 }
6767
6768 static gboolean
6769 validate_rows (GtkTreeView *tree_view)
6770 {
6771   gboolean retval;
6772   
6773   retval = do_validate_rows (tree_view, TRUE);
6774   
6775   if (! retval && tree_view->priv->validate_rows_timer)
6776     {
6777       g_source_remove (tree_view->priv->validate_rows_timer);
6778       tree_view->priv->validate_rows_timer = 0;
6779     }
6780
6781   return retval;
6782 }
6783
6784 static gboolean
6785 validate_rows_handler (GtkTreeView *tree_view)
6786 {
6787   gboolean retval;
6788
6789   retval = do_validate_rows (tree_view, TRUE);
6790   if (! retval && tree_view->priv->validate_rows_timer)
6791     {
6792       g_source_remove (tree_view->priv->validate_rows_timer);
6793       tree_view->priv->validate_rows_timer = 0;
6794     }
6795
6796   return retval;
6797 }
6798
6799 static gboolean
6800 do_presize_handler (GtkTreeView *tree_view)
6801 {
6802   if (tree_view->priv->mark_rows_col_dirty)
6803     {
6804       if (tree_view->priv->tree)
6805         _gtk_rbtree_column_invalid (tree_view->priv->tree);
6806       tree_view->priv->mark_rows_col_dirty = FALSE;
6807     }
6808   validate_visible_area (tree_view);
6809   tree_view->priv->presize_handler_timer = 0;
6810
6811   if (tree_view->priv->fixed_height_mode)
6812     {
6813       GtkRequisition requisition;
6814
6815       gtk_widget_get_preferred_size (GTK_WIDGET (tree_view),
6816                                      &requisition, NULL);
6817
6818       gtk_adjustment_set_upper (tree_view->priv->hadjustment,
6819                                 MAX (gtk_adjustment_get_upper (tree_view->priv->hadjustment), requisition.width));
6820       gtk_adjustment_set_upper (tree_view->priv->vadjustment,
6821                                 MAX (gtk_adjustment_get_upper (tree_view->priv->vadjustment), requisition.height));
6822       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6823     }
6824                    
6825   return FALSE;
6826 }
6827
6828 static gboolean
6829 presize_handler_callback (gpointer data)
6830 {
6831   do_presize_handler (GTK_TREE_VIEW (data));
6832                    
6833   return FALSE;
6834 }
6835
6836 static void
6837 install_presize_handler (GtkTreeView *tree_view)
6838 {
6839   if (! gtk_widget_get_realized (GTK_WIDGET (tree_view)))
6840     return;
6841
6842   if (! tree_view->priv->presize_handler_timer)
6843     {
6844       tree_view->priv->presize_handler_timer =
6845         gdk_threads_add_idle_full (GTK_PRIORITY_RESIZE - 2, presize_handler_callback, tree_view, NULL);
6846     }
6847   if (! tree_view->priv->validate_rows_timer)
6848     {
6849       tree_view->priv->validate_rows_timer =
6850         gdk_threads_add_idle_full (GTK_TREE_VIEW_PRIORITY_VALIDATE, (GSourceFunc) validate_rows_handler, tree_view, NULL);
6851     }
6852 }
6853
6854 static void
6855 gtk_tree_view_bin_process_updates (GtkTreeView *tree_view)
6856 {
6857   /* Prior to drawing, we make sure the visible area is validated. */
6858   if (tree_view->priv->presize_handler_timer)
6859     {
6860       g_source_remove (tree_view->priv->presize_handler_timer);
6861       tree_view->priv->presize_handler_timer = 0;
6862
6863       do_presize_handler (tree_view);
6864     }
6865
6866   gdk_window_process_updates (tree_view->priv->bin_window, TRUE);
6867 }
6868
6869 static gboolean
6870 scroll_sync_handler (GtkTreeView *tree_view)
6871 {
6872   if (tree_view->priv->height <= gtk_adjustment_get_page_size (tree_view->priv->vadjustment))
6873     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
6874   else if (gtk_tree_row_reference_valid (tree_view->priv->top_row))
6875     gtk_tree_view_top_row_to_dy (tree_view);
6876   else
6877     gtk_tree_view_dy_to_top_row (tree_view);
6878
6879   tree_view->priv->scroll_sync_timer = 0;
6880
6881   return FALSE;
6882 }
6883
6884 static void
6885 install_scroll_sync_handler (GtkTreeView *tree_view)
6886 {
6887   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
6888     return;
6889
6890   if (!tree_view->priv->scroll_sync_timer)
6891     {
6892       tree_view->priv->scroll_sync_timer =
6893         gdk_threads_add_idle_full (GTK_TREE_VIEW_PRIORITY_SCROLL_SYNC, (GSourceFunc) scroll_sync_handler, tree_view, NULL);
6894     }
6895 }
6896
6897 static void
6898 gtk_tree_view_set_top_row (GtkTreeView *tree_view,
6899                            GtkTreePath *path,
6900                            gint         offset)
6901 {
6902   gtk_tree_row_reference_free (tree_view->priv->top_row);
6903
6904   if (!path)
6905     {
6906       tree_view->priv->top_row = NULL;
6907       tree_view->priv->top_row_dy = 0;
6908     }
6909   else
6910     {
6911       tree_view->priv->top_row = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
6912       tree_view->priv->top_row_dy = offset;
6913     }
6914 }
6915
6916 /* Always call this iff dy is in the visible range.  If the tree is empty, then
6917  * it's set to be NULL, and top_row_dy is 0;
6918  */
6919 static void
6920 gtk_tree_view_dy_to_top_row (GtkTreeView *tree_view)
6921 {
6922   gint offset;
6923   GtkTreePath *path;
6924   GtkRBTree *tree;
6925   GtkRBNode *node;
6926
6927   if (tree_view->priv->tree == NULL)
6928     {
6929       gtk_tree_view_set_top_row (tree_view, NULL, 0);
6930     }
6931   else
6932     {
6933       offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
6934                                         tree_view->priv->dy,
6935                                         &tree, &node);
6936
6937       if (tree == NULL)
6938         {
6939           gtk_tree_view_set_top_row (tree_view, NULL, 0);
6940         }
6941       else
6942         {
6943           path = _gtk_tree_view_find_path (tree_view, tree, node);
6944           gtk_tree_view_set_top_row (tree_view, path, offset);
6945           gtk_tree_path_free (path);
6946         }
6947     }
6948 }
6949
6950 static void
6951 gtk_tree_view_top_row_to_dy (GtkTreeView *tree_view)
6952 {
6953   GtkTreePath *path;
6954   GtkRBTree *tree;
6955   GtkRBNode *node;
6956   int new_dy;
6957
6958   /* Avoid recursive calls */
6959   if (tree_view->priv->in_top_row_to_dy)
6960     return;
6961
6962   if (tree_view->priv->top_row)
6963     path = gtk_tree_row_reference_get_path (tree_view->priv->top_row);
6964   else
6965     path = NULL;
6966
6967   if (!path)
6968     tree = NULL;
6969   else
6970     _gtk_tree_view_find_node (tree_view, path, &tree, &node);
6971
6972   if (path)
6973     gtk_tree_path_free (path);
6974
6975   if (tree == NULL)
6976     {
6977       /* keep dy and set new toprow */
6978       gtk_tree_row_reference_free (tree_view->priv->top_row);
6979       tree_view->priv->top_row = NULL;
6980       tree_view->priv->top_row_dy = 0;
6981       /* DO NOT install the idle handler */
6982       gtk_tree_view_dy_to_top_row (tree_view);
6983       return;
6984     }
6985
6986   if (gtk_tree_view_get_row_height (tree_view, node)
6987       < tree_view->priv->top_row_dy)
6988     {
6989       /* new top row -- do NOT install the idle handler */
6990       gtk_tree_view_dy_to_top_row (tree_view);
6991       return;
6992     }
6993
6994   new_dy = _gtk_rbtree_node_find_offset (tree, node);
6995   new_dy += tree_view->priv->top_row_dy;
6996
6997   if (new_dy + gtk_adjustment_get_page_size (tree_view->priv->vadjustment) > tree_view->priv->height)
6998     new_dy = tree_view->priv->height - gtk_adjustment_get_page_size (tree_view->priv->vadjustment);
6999
7000   new_dy = MAX (0, new_dy);
7001
7002   tree_view->priv->in_top_row_to_dy = TRUE;
7003   gtk_adjustment_set_value (tree_view->priv->vadjustment, (gdouble)new_dy);
7004   tree_view->priv->in_top_row_to_dy = FALSE;
7005 }
7006
7007
7008 void
7009 _gtk_tree_view_install_mark_rows_col_dirty (GtkTreeView *tree_view,
7010                                             gboolean     install_handler)
7011 {
7012   tree_view->priv->mark_rows_col_dirty = TRUE;
7013
7014   if (install_handler)
7015     install_presize_handler (tree_view);
7016 }
7017
7018 /*
7019  * This function works synchronously (due to the while (validate_rows...)
7020  * loop).
7021  *
7022  * There was a check for column_type != GTK_TREE_VIEW_COLUMN_AUTOSIZE
7023  * here. You now need to check that yourself.
7024  */
7025 void
7026 _gtk_tree_view_column_autosize (GtkTreeView *tree_view,
7027                                 GtkTreeViewColumn *column)
7028 {
7029   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
7030   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (column));
7031
7032   _gtk_tree_view_column_cell_set_dirty (column, FALSE);
7033
7034   do_presize_handler (tree_view);
7035   while (validate_rows (tree_view));
7036
7037   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
7038 }
7039
7040 /* Drag-and-drop */
7041
7042 static void
7043 set_source_row (GdkDragContext *context,
7044                 GtkTreeModel   *model,
7045                 GtkTreePath    *source_row)
7046 {
7047   g_object_set_data_full (G_OBJECT (context),
7048                           I_("gtk-tree-view-source-row"),
7049                           source_row ? gtk_tree_row_reference_new (model, source_row) : NULL,
7050                           (GDestroyNotify) (source_row ? gtk_tree_row_reference_free : NULL));
7051 }
7052
7053 static GtkTreePath*
7054 get_source_row (GdkDragContext *context)
7055 {
7056   GtkTreeRowReference *ref =
7057     g_object_get_data (G_OBJECT (context), "gtk-tree-view-source-row");
7058
7059   if (ref)
7060     return gtk_tree_row_reference_get_path (ref);
7061   else
7062     return NULL;
7063 }
7064
7065 typedef struct
7066 {
7067   GtkTreeRowReference *dest_row;
7068   guint                path_down_mode   : 1;
7069   guint                empty_view_drop  : 1;
7070   guint                drop_append_mode : 1;
7071 }
7072 DestRow;
7073
7074 static void
7075 dest_row_free (gpointer data)
7076 {
7077   DestRow *dr = (DestRow *)data;
7078
7079   gtk_tree_row_reference_free (dr->dest_row);
7080   g_slice_free (DestRow, dr);
7081 }
7082
7083 static void
7084 set_dest_row (GdkDragContext *context,
7085               GtkTreeModel   *model,
7086               GtkTreePath    *dest_row,
7087               gboolean        path_down_mode,
7088               gboolean        empty_view_drop,
7089               gboolean        drop_append_mode)
7090 {
7091   DestRow *dr;
7092
7093   if (!dest_row)
7094     {
7095       g_object_set_data_full (G_OBJECT (context), I_("gtk-tree-view-dest-row"),
7096                               NULL, NULL);
7097       return;
7098     }
7099
7100   dr = g_slice_new (DestRow);
7101
7102   dr->dest_row = gtk_tree_row_reference_new (model, dest_row);
7103   dr->path_down_mode = path_down_mode != FALSE;
7104   dr->empty_view_drop = empty_view_drop != FALSE;
7105   dr->drop_append_mode = drop_append_mode != FALSE;
7106
7107   g_object_set_data_full (G_OBJECT (context), I_("gtk-tree-view-dest-row"),
7108                           dr, (GDestroyNotify) dest_row_free);
7109 }
7110
7111 static GtkTreePath*
7112 get_dest_row (GdkDragContext *context,
7113               gboolean       *path_down_mode)
7114 {
7115   DestRow *dr =
7116     g_object_get_data (G_OBJECT (context), "gtk-tree-view-dest-row");
7117
7118   if (dr)
7119     {
7120       GtkTreePath *path = NULL;
7121
7122       if (path_down_mode)
7123         *path_down_mode = dr->path_down_mode;
7124
7125       if (dr->dest_row)
7126         path = gtk_tree_row_reference_get_path (dr->dest_row);
7127       else if (dr->empty_view_drop)
7128         path = gtk_tree_path_new_from_indices (0, -1);
7129       else
7130         path = NULL;
7131
7132       if (path && dr->drop_append_mode)
7133         gtk_tree_path_next (path);
7134
7135       return path;
7136     }
7137   else
7138     return NULL;
7139 }
7140
7141 /* Get/set whether drag_motion requested the drag data and
7142  * drag_data_received should thus not actually insert the data,
7143  * since the data doesn't result from a drop.
7144  */
7145 static void
7146 set_status_pending (GdkDragContext *context,
7147                     GdkDragAction   suggested_action)
7148 {
7149   g_object_set_data (G_OBJECT (context),
7150                      I_("gtk-tree-view-status-pending"),
7151                      GINT_TO_POINTER (suggested_action));
7152 }
7153
7154 static GdkDragAction
7155 get_status_pending (GdkDragContext *context)
7156 {
7157   return GPOINTER_TO_INT (g_object_get_data (G_OBJECT (context),
7158                                              "gtk-tree-view-status-pending"));
7159 }
7160
7161 static TreeViewDragInfo*
7162 get_info (GtkTreeView *tree_view)
7163 {
7164   return g_object_get_data (G_OBJECT (tree_view), "gtk-tree-view-drag-info");
7165 }
7166
7167 static void
7168 destroy_info (TreeViewDragInfo *di)
7169 {
7170   g_slice_free (TreeViewDragInfo, di);
7171 }
7172
7173 static TreeViewDragInfo*
7174 ensure_info (GtkTreeView *tree_view)
7175 {
7176   TreeViewDragInfo *di;
7177
7178   di = get_info (tree_view);
7179
7180   if (di == NULL)
7181     {
7182       di = g_slice_new0 (TreeViewDragInfo);
7183
7184       g_object_set_data_full (G_OBJECT (tree_view),
7185                               I_("gtk-tree-view-drag-info"),
7186                               di,
7187                               (GDestroyNotify) destroy_info);
7188     }
7189
7190   return di;
7191 }
7192
7193 static void
7194 remove_info (GtkTreeView *tree_view)
7195 {
7196   g_object_set_data (G_OBJECT (tree_view), I_("gtk-tree-view-drag-info"), NULL);
7197 }
7198
7199 #if 0
7200 static gint
7201 drag_scan_timeout (gpointer data)
7202 {
7203   GtkTreeView *tree_view;
7204   gint x, y;
7205   GdkModifierType state;
7206   GtkTreePath *path = NULL;
7207   GtkTreeViewColumn *column = NULL;
7208   GdkRectangle visible_rect;
7209
7210   GDK_THREADS_ENTER ();
7211
7212   tree_view = GTK_TREE_VIEW (data);
7213
7214   gdk_window_get_pointer (tree_view->priv->bin_window,
7215                           &x, &y, &state);
7216
7217   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
7218
7219   /* See if we are near the edge. */
7220   if ((x - visible_rect.x) < SCROLL_EDGE_SIZE ||
7221       (visible_rect.x + visible_rect.width - x) < SCROLL_EDGE_SIZE ||
7222       (y - visible_rect.y) < SCROLL_EDGE_SIZE ||
7223       (visible_rect.y + visible_rect.height - y) < SCROLL_EDGE_SIZE)
7224     {
7225       gtk_tree_view_get_path_at_pos (tree_view,
7226                                      tree_view->priv->bin_window,
7227                                      x, y,
7228                                      &path,
7229                                      &column,
7230                                      NULL,
7231                                      NULL);
7232
7233       if (path != NULL)
7234         {
7235           gtk_tree_view_scroll_to_cell (tree_view,
7236                                         path,
7237                                         column,
7238                                         TRUE,
7239                                         0.5, 0.5);
7240
7241           gtk_tree_path_free (path);
7242         }
7243     }
7244
7245   GDK_THREADS_LEAVE ();
7246
7247   return TRUE;
7248 }
7249 #endif /* 0 */
7250
7251 static void
7252 add_scroll_timeout (GtkTreeView *tree_view)
7253 {
7254   if (tree_view->priv->scroll_timeout == 0)
7255     {
7256       tree_view->priv->scroll_timeout =
7257         gdk_threads_add_timeout (150, scroll_row_timeout, tree_view);
7258     }
7259 }
7260
7261 static void
7262 remove_scroll_timeout (GtkTreeView *tree_view)
7263 {
7264   if (tree_view->priv->scroll_timeout != 0)
7265     {
7266       g_source_remove (tree_view->priv->scroll_timeout);
7267       tree_view->priv->scroll_timeout = 0;
7268     }
7269 }
7270
7271 static gboolean
7272 check_model_dnd (GtkTreeModel *model,
7273                  GType         required_iface,
7274                  const gchar  *signal)
7275 {
7276   if (model == NULL || !G_TYPE_CHECK_INSTANCE_TYPE ((model), required_iface))
7277     {
7278       g_warning ("You must override the default '%s' handler "
7279                  "on GtkTreeView when using models that don't support "
7280                  "the %s interface and enabling drag-and-drop. The simplest way to do this "
7281                  "is to connect to '%s' and call "
7282                  "g_signal_stop_emission_by_name() in your signal handler to prevent "
7283                  "the default handler from running. Look at the source code "
7284                  "for the default handler in gtktreeview.c to get an idea what "
7285                  "your handler should do. (gtktreeview.c is in the GTK source "
7286                  "code.) If you're using GTK from a language other than C, "
7287                  "there may be a more natural way to override default handlers, e.g. via derivation.",
7288                  signal, g_type_name (required_iface), signal);
7289       return FALSE;
7290     }
7291   else
7292     return TRUE;
7293 }
7294
7295 static void
7296 remove_open_timeout (GtkTreeView *tree_view)
7297 {
7298   if (tree_view->priv->open_dest_timeout != 0)
7299     {
7300       g_source_remove (tree_view->priv->open_dest_timeout);
7301       tree_view->priv->open_dest_timeout = 0;
7302     }
7303 }
7304
7305
7306 static gint
7307 open_row_timeout (gpointer data)
7308 {
7309   GtkTreeView *tree_view = data;
7310   GtkTreePath *dest_path = NULL;
7311   GtkTreeViewDropPosition pos;
7312   gboolean result = FALSE;
7313
7314   gtk_tree_view_get_drag_dest_row (tree_view,
7315                                    &dest_path,
7316                                    &pos);
7317
7318   if (dest_path &&
7319       (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
7320        pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
7321     {
7322       gtk_tree_view_expand_row (tree_view, dest_path, FALSE);
7323       tree_view->priv->open_dest_timeout = 0;
7324
7325       gtk_tree_path_free (dest_path);
7326     }
7327   else
7328     {
7329       if (dest_path)
7330         gtk_tree_path_free (dest_path);
7331
7332       result = TRUE;
7333     }
7334
7335   return result;
7336 }
7337
7338 static gboolean
7339 scroll_row_timeout (gpointer data)
7340 {
7341   GtkTreeView *tree_view = data;
7342
7343   gtk_tree_view_vertical_autoscroll (tree_view);
7344
7345   if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
7346     gtk_tree_view_update_rubber_band (tree_view);
7347
7348   return TRUE;
7349 }
7350
7351 /* Returns TRUE if event should not be propagated to parent widgets */
7352 static gboolean
7353 set_destination_row (GtkTreeView    *tree_view,
7354                      GdkDragContext *context,
7355                      /* coordinates relative to the widget */
7356                      gint            x,
7357                      gint            y,
7358                      GdkDragAction  *suggested_action,
7359                      GdkAtom        *target)
7360 {
7361   GtkTreePath *path = NULL;
7362   GtkTreeViewDropPosition pos;
7363   GtkTreeViewDropPosition old_pos;
7364   TreeViewDragInfo *di;
7365   GtkWidget *widget;
7366   GtkTreePath *old_dest_path = NULL;
7367   gboolean can_drop = FALSE;
7368
7369   *suggested_action = 0;
7370   *target = GDK_NONE;
7371
7372   widget = GTK_WIDGET (tree_view);
7373
7374   di = get_info (tree_view);
7375
7376   if (di == NULL || y - gtk_tree_view_get_effective_header_height (tree_view) < 0)
7377     {
7378       /* someone unset us as a drag dest, note that if
7379        * we return FALSE drag_leave isn't called
7380        */
7381
7382       gtk_tree_view_set_drag_dest_row (tree_view,
7383                                        NULL,
7384                                        GTK_TREE_VIEW_DROP_BEFORE);
7385
7386       remove_scroll_timeout (GTK_TREE_VIEW (widget));
7387       remove_open_timeout (GTK_TREE_VIEW (widget));
7388
7389       return FALSE; /* no longer a drop site */
7390     }
7391
7392   *target = gtk_drag_dest_find_target (widget, context,
7393                                        gtk_drag_dest_get_target_list (widget));
7394   if (*target == GDK_NONE)
7395     {
7396       return FALSE;
7397     }
7398
7399   if (!gtk_tree_view_get_dest_row_at_pos (tree_view,
7400                                           x, y,
7401                                           &path,
7402                                           &pos))
7403     {
7404       gint n_children;
7405       GtkTreeModel *model;
7406
7407       remove_open_timeout (tree_view);
7408
7409       /* the row got dropped on empty space, let's setup a special case
7410        */
7411
7412       if (path)
7413         gtk_tree_path_free (path);
7414
7415       model = gtk_tree_view_get_model (tree_view);
7416
7417       n_children = gtk_tree_model_iter_n_children (model, NULL);
7418       if (n_children)
7419         {
7420           pos = GTK_TREE_VIEW_DROP_AFTER;
7421           path = gtk_tree_path_new_from_indices (n_children - 1, -1);
7422         }
7423       else
7424         {
7425           pos = GTK_TREE_VIEW_DROP_BEFORE;
7426           path = gtk_tree_path_new_from_indices (0, -1);
7427         }
7428
7429       can_drop = TRUE;
7430
7431       goto out;
7432     }
7433
7434   g_assert (path);
7435
7436   /* If we left the current row's "open" zone, unset the timeout for
7437    * opening the row
7438    */
7439   gtk_tree_view_get_drag_dest_row (tree_view,
7440                                    &old_dest_path,
7441                                    &old_pos);
7442
7443   if (old_dest_path &&
7444       (gtk_tree_path_compare (path, old_dest_path) != 0 ||
7445        !(pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
7446          pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE)))
7447     remove_open_timeout (tree_view);
7448
7449   if (old_dest_path)
7450     gtk_tree_path_free (old_dest_path);
7451
7452   if (TRUE /* FIXME if the location droppable predicate */)
7453     {
7454       can_drop = TRUE;
7455     }
7456
7457 out:
7458   if (can_drop)
7459     {
7460       GtkWidget *source_widget;
7461
7462       *suggested_action = gdk_drag_context_get_suggested_action (context);
7463       source_widget = gtk_drag_get_source_widget (context);
7464
7465       if (source_widget == widget)
7466         {
7467           /* Default to MOVE, unless the user has
7468            * pressed ctrl or shift to affect available actions
7469            */
7470           if ((gdk_drag_context_get_actions (context) & GDK_ACTION_MOVE) != 0)
7471             *suggested_action = GDK_ACTION_MOVE;
7472         }
7473
7474       gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7475                                        path, pos);
7476     }
7477   else
7478     {
7479       /* can't drop here */
7480       remove_open_timeout (tree_view);
7481
7482       gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7483                                        NULL,
7484                                        GTK_TREE_VIEW_DROP_BEFORE);
7485     }
7486
7487   if (path)
7488     gtk_tree_path_free (path);
7489
7490   return TRUE;
7491 }
7492
7493 static GtkTreePath*
7494 get_logical_dest_row (GtkTreeView *tree_view,
7495                       gboolean    *path_down_mode,
7496                       gboolean    *drop_append_mode)
7497 {
7498   /* adjust path to point to the row the drop goes in front of */
7499   GtkTreePath *path = NULL;
7500   GtkTreeViewDropPosition pos;
7501
7502   g_return_val_if_fail (path_down_mode != NULL, NULL);
7503   g_return_val_if_fail (drop_append_mode != NULL, NULL);
7504
7505   *path_down_mode = FALSE;
7506   *drop_append_mode = 0;
7507
7508   gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
7509
7510   if (path == NULL)
7511     return NULL;
7512
7513   if (pos == GTK_TREE_VIEW_DROP_BEFORE)
7514     ; /* do nothing */
7515   else if (pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE ||
7516            pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER)
7517     *path_down_mode = TRUE;
7518   else
7519     {
7520       GtkTreeIter iter;
7521       GtkTreeModel *model = gtk_tree_view_get_model (tree_view);
7522
7523       g_assert (pos == GTK_TREE_VIEW_DROP_AFTER);
7524
7525       if (!gtk_tree_model_get_iter (model, &iter, path) ||
7526           !gtk_tree_model_iter_next (model, &iter))
7527         *drop_append_mode = 1;
7528       else
7529         {
7530           *drop_append_mode = 0;
7531           gtk_tree_path_next (path);
7532         }
7533     }
7534
7535   return path;
7536 }
7537
7538 static gboolean
7539 gtk_tree_view_maybe_begin_dragging_row (GtkTreeView      *tree_view,
7540                                         GdkEventMotion   *event)
7541 {
7542   GtkWidget *widget = GTK_WIDGET (tree_view);
7543   GdkDragContext *context;
7544   TreeViewDragInfo *di;
7545   GtkTreePath *path = NULL;
7546   gint button;
7547   gint cell_x, cell_y;
7548   GtkTreeModel *model;
7549   gboolean retval = FALSE;
7550
7551   di = get_info (tree_view);
7552
7553   if (di == NULL || !di->source_set)
7554     goto out;
7555
7556   if (tree_view->priv->pressed_button < 0)
7557     goto out;
7558
7559   if (!gtk_drag_check_threshold (widget,
7560                                  tree_view->priv->press_start_x,
7561                                  tree_view->priv->press_start_y,
7562                                  event->x, event->y))
7563     goto out;
7564
7565   model = gtk_tree_view_get_model (tree_view);
7566
7567   if (model == NULL)
7568     goto out;
7569
7570   button = tree_view->priv->pressed_button;
7571   tree_view->priv->pressed_button = -1;
7572
7573   gtk_tree_view_get_path_at_pos (tree_view,
7574                                  tree_view->priv->press_start_x,
7575                                  tree_view->priv->press_start_y,
7576                                  &path,
7577                                  NULL,
7578                                  &cell_x,
7579                                  &cell_y);
7580
7581   if (path == NULL)
7582     goto out;
7583
7584   if (!GTK_IS_TREE_DRAG_SOURCE (model) ||
7585       !gtk_tree_drag_source_row_draggable (GTK_TREE_DRAG_SOURCE (model),
7586                                            path))
7587     goto out;
7588
7589   if (!(GDK_BUTTON1_MASK << (button - 1) & di->start_button_mask))
7590     goto out;
7591
7592   /* Now we can begin the drag */
7593
7594   retval = TRUE;
7595
7596   context = gtk_drag_begin (widget,
7597                             gtk_drag_source_get_target_list (widget),
7598                             di->source_actions,
7599                             button,
7600                             (GdkEvent*)event);
7601
7602   set_source_row (context, model, path);
7603
7604  out:
7605   if (path)
7606     gtk_tree_path_free (path);
7607
7608   return retval;
7609 }
7610
7611
7612 static void
7613 gtk_tree_view_drag_begin (GtkWidget      *widget,
7614                           GdkDragContext *context)
7615 {
7616   GtkTreeView *tree_view;
7617   GtkTreePath *path = NULL;
7618   gint cell_x, cell_y;
7619   cairo_surface_t *row_pix;
7620   TreeViewDragInfo *di;
7621
7622   tree_view = GTK_TREE_VIEW (widget);
7623
7624   /* if the user uses a custom DND source impl, we don't set the icon here */
7625   di = get_info (tree_view);
7626
7627   if (di == NULL || !di->source_set)
7628     return;
7629
7630   gtk_tree_view_get_path_at_pos (tree_view,
7631                                  tree_view->priv->press_start_x,
7632                                  tree_view->priv->press_start_y,
7633                                  &path,
7634                                  NULL,
7635                                  &cell_x,
7636                                  &cell_y);
7637
7638   g_return_if_fail (path != NULL);
7639
7640   row_pix = gtk_tree_view_create_row_drag_icon (tree_view,
7641                                                 path);
7642   cairo_surface_set_device_offset (row_pix,
7643                                    /* the + 1 is for the black border in the icon */
7644                                    - (tree_view->priv->press_start_x + 1),
7645                                    - (cell_y + 1));
7646
7647   gtk_drag_set_icon_surface (context, row_pix);
7648
7649   cairo_surface_destroy (row_pix);
7650   gtk_tree_path_free (path);
7651 }
7652
7653 static void
7654 gtk_tree_view_drag_end (GtkWidget      *widget,
7655                         GdkDragContext *context)
7656 {
7657   /* do nothing */
7658 }
7659
7660 /* Default signal implementations for the drag signals */
7661 static void
7662 gtk_tree_view_drag_data_get (GtkWidget        *widget,
7663                              GdkDragContext   *context,
7664                              GtkSelectionData *selection_data,
7665                              guint             info,
7666                              guint             time)
7667 {
7668   GtkTreeView *tree_view;
7669   GtkTreeModel *model;
7670   TreeViewDragInfo *di;
7671   GtkTreePath *source_row;
7672
7673   tree_view = GTK_TREE_VIEW (widget);
7674
7675   model = gtk_tree_view_get_model (tree_view);
7676
7677   if (model == NULL)
7678     return;
7679
7680   di = get_info (GTK_TREE_VIEW (widget));
7681
7682   if (di == NULL)
7683     return;
7684
7685   source_row = get_source_row (context);
7686
7687   if (source_row == NULL)
7688     return;
7689
7690   /* We can implement the GTK_TREE_MODEL_ROW target generically for
7691    * any model; for DragSource models there are some other targets
7692    * we also support.
7693    */
7694
7695   if (GTK_IS_TREE_DRAG_SOURCE (model) &&
7696       gtk_tree_drag_source_drag_data_get (GTK_TREE_DRAG_SOURCE (model),
7697                                           source_row,
7698                                           selection_data))
7699     goto done;
7700
7701   /* If drag_data_get does nothing, try providing row data. */
7702   if (gtk_selection_data_get_target (selection_data) == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
7703     {
7704       gtk_tree_set_row_drag_data (selection_data,
7705                                   model,
7706                                   source_row);
7707     }
7708
7709  done:
7710   gtk_tree_path_free (source_row);
7711 }
7712
7713
7714 static void
7715 gtk_tree_view_drag_data_delete (GtkWidget      *widget,
7716                                 GdkDragContext *context)
7717 {
7718   TreeViewDragInfo *di;
7719   GtkTreeModel *model;
7720   GtkTreeView *tree_view;
7721   GtkTreePath *source_row;
7722
7723   tree_view = GTK_TREE_VIEW (widget);
7724   model = gtk_tree_view_get_model (tree_view);
7725
7726   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_SOURCE, "drag_data_delete"))
7727     return;
7728
7729   di = get_info (tree_view);
7730
7731   if (di == NULL)
7732     return;
7733
7734   source_row = get_source_row (context);
7735
7736   if (source_row == NULL)
7737     return;
7738
7739   gtk_tree_drag_source_drag_data_delete (GTK_TREE_DRAG_SOURCE (model),
7740                                          source_row);
7741
7742   gtk_tree_path_free (source_row);
7743
7744   set_source_row (context, NULL, NULL);
7745 }
7746
7747 static void
7748 gtk_tree_view_drag_leave (GtkWidget      *widget,
7749                           GdkDragContext *context,
7750                           guint             time)
7751 {
7752   /* unset any highlight row */
7753   gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7754                                    NULL,
7755                                    GTK_TREE_VIEW_DROP_BEFORE);
7756
7757   remove_scroll_timeout (GTK_TREE_VIEW (widget));
7758   remove_open_timeout (GTK_TREE_VIEW (widget));
7759 }
7760
7761
7762 static gboolean
7763 gtk_tree_view_drag_motion (GtkWidget        *widget,
7764                            GdkDragContext   *context,
7765                            /* coordinates relative to the widget */
7766                            gint              x,
7767                            gint              y,
7768                            guint             time)
7769 {
7770   gboolean empty;
7771   GtkTreePath *path = NULL;
7772   GtkTreeViewDropPosition pos;
7773   GtkTreeView *tree_view;
7774   GdkDragAction suggested_action = 0;
7775   GdkAtom target;
7776
7777   tree_view = GTK_TREE_VIEW (widget);
7778
7779   if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
7780     return FALSE;
7781
7782   gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
7783
7784   /* we only know this *after* set_desination_row */
7785   empty = tree_view->priv->empty_view_drop;
7786
7787   if (path == NULL && !empty)
7788     {
7789       /* Can't drop here. */
7790       gdk_drag_status (context, 0, time);
7791     }
7792   else
7793     {
7794       if (tree_view->priv->open_dest_timeout == 0 &&
7795           (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
7796            pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
7797         {
7798           tree_view->priv->open_dest_timeout =
7799             gdk_threads_add_timeout (AUTO_EXPAND_TIMEOUT, open_row_timeout, tree_view);
7800         }
7801       else
7802         {
7803           add_scroll_timeout (tree_view);
7804         }
7805
7806       if (target == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
7807         {
7808           /* Request data so we can use the source row when
7809            * determining whether to accept the drop
7810            */
7811           set_status_pending (context, suggested_action);
7812           gtk_drag_get_data (widget, context, target, time);
7813         }
7814       else
7815         {
7816           set_status_pending (context, 0);
7817           gdk_drag_status (context, suggested_action, time);
7818         }
7819     }
7820
7821   if (path)
7822     gtk_tree_path_free (path);
7823
7824   return TRUE;
7825 }
7826
7827
7828 static gboolean
7829 gtk_tree_view_drag_drop (GtkWidget        *widget,
7830                          GdkDragContext   *context,
7831                          /* coordinates relative to the widget */
7832                          gint              x,
7833                          gint              y,
7834                          guint             time)
7835 {
7836   GtkTreeView *tree_view;
7837   GtkTreePath *path;
7838   GdkDragAction suggested_action = 0;
7839   GdkAtom target = GDK_NONE;
7840   TreeViewDragInfo *di;
7841   GtkTreeModel *model;
7842   gboolean path_down_mode;
7843   gboolean drop_append_mode;
7844
7845   tree_view = GTK_TREE_VIEW (widget);
7846
7847   model = gtk_tree_view_get_model (tree_view);
7848
7849   remove_scroll_timeout (GTK_TREE_VIEW (widget));
7850   remove_open_timeout (GTK_TREE_VIEW (widget));
7851
7852   di = get_info (tree_view);
7853
7854   if (di == NULL)
7855     return FALSE;
7856
7857   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_drop"))
7858     return FALSE;
7859
7860   if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
7861     return FALSE;
7862
7863   path = get_logical_dest_row (tree_view, &path_down_mode, &drop_append_mode);
7864
7865   if (target != GDK_NONE && path != NULL)
7866     {
7867       /* in case a motion had requested drag data, change things so we
7868        * treat drag data receives as a drop.
7869        */
7870       set_status_pending (context, 0);
7871       set_dest_row (context, model, path,
7872                     path_down_mode, tree_view->priv->empty_view_drop,
7873                     drop_append_mode);
7874     }
7875
7876   if (path)
7877     gtk_tree_path_free (path);
7878
7879   /* Unset this thing */
7880   gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7881                                    NULL,
7882                                    GTK_TREE_VIEW_DROP_BEFORE);
7883
7884   if (target != GDK_NONE)
7885     {
7886       gtk_drag_get_data (widget, context, target, time);
7887       return TRUE;
7888     }
7889   else
7890     return FALSE;
7891 }
7892
7893 static void
7894 gtk_tree_view_drag_data_received (GtkWidget        *widget,
7895                                   GdkDragContext   *context,
7896                                   /* coordinates relative to the widget */
7897                                   gint              x,
7898                                   gint              y,
7899                                   GtkSelectionData *selection_data,
7900                                   guint             info,
7901                                   guint             time)
7902 {
7903   GtkTreePath *path;
7904   TreeViewDragInfo *di;
7905   gboolean accepted = FALSE;
7906   GtkTreeModel *model;
7907   GtkTreeView *tree_view;
7908   GtkTreePath *dest_row;
7909   GdkDragAction suggested_action;
7910   gboolean path_down_mode;
7911   gboolean drop_append_mode;
7912
7913   tree_view = GTK_TREE_VIEW (widget);
7914
7915   model = gtk_tree_view_get_model (tree_view);
7916
7917   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_data_received"))
7918     return;
7919
7920   di = get_info (tree_view);
7921
7922   if (di == NULL)
7923     return;
7924
7925   suggested_action = get_status_pending (context);
7926
7927   if (suggested_action)
7928     {
7929       /* We are getting this data due to a request in drag_motion,
7930        * rather than due to a request in drag_drop, so we are just
7931        * supposed to call drag_status, not actually paste in the
7932        * data.
7933        */
7934       path = get_logical_dest_row (tree_view, &path_down_mode,
7935                                    &drop_append_mode);
7936
7937       if (path == NULL)
7938         suggested_action = 0;
7939       else if (path_down_mode)
7940         gtk_tree_path_down (path);
7941
7942       if (suggested_action)
7943         {
7944           if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
7945                                                      path,
7946                                                      selection_data))
7947             {
7948               if (path_down_mode)
7949                 {
7950                   path_down_mode = FALSE;
7951                   gtk_tree_path_up (path);
7952
7953                   if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
7954                                                              path,
7955                                                              selection_data))
7956                     suggested_action = 0;
7957                 }
7958               else
7959                 suggested_action = 0;
7960             }
7961         }
7962
7963       gdk_drag_status (context, suggested_action, time);
7964
7965       if (path)
7966         gtk_tree_path_free (path);
7967
7968       /* If you can't drop, remove user drop indicator until the next motion */
7969       if (suggested_action == 0)
7970         gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7971                                          NULL,
7972                                          GTK_TREE_VIEW_DROP_BEFORE);
7973
7974       return;
7975     }
7976
7977   dest_row = get_dest_row (context, &path_down_mode);
7978
7979   if (dest_row == NULL)
7980     return;
7981
7982   if (gtk_selection_data_get_length (selection_data) >= 0)
7983     {
7984       if (path_down_mode)
7985         {
7986           gtk_tree_path_down (dest_row);
7987           if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
7988                                                      dest_row, selection_data))
7989             gtk_tree_path_up (dest_row);
7990         }
7991     }
7992
7993   if (gtk_selection_data_get_length (selection_data) >= 0)
7994     {
7995       if (gtk_tree_drag_dest_drag_data_received (GTK_TREE_DRAG_DEST (model),
7996                                                  dest_row,
7997                                                  selection_data))
7998         accepted = TRUE;
7999     }
8000
8001   gtk_drag_finish (context,
8002                    accepted,
8003                    (gdk_drag_context_get_selected_action (context) == GDK_ACTION_MOVE),
8004                    time);
8005
8006   if (gtk_tree_path_get_depth (dest_row) == 1
8007       && gtk_tree_path_get_indices (dest_row)[0] == 0)
8008     {
8009       /* special special case drag to "0", scroll to first item */
8010       if (!tree_view->priv->scroll_to_path)
8011         gtk_tree_view_scroll_to_cell (tree_view, dest_row, NULL, FALSE, 0.0, 0.0);
8012     }
8013
8014   gtk_tree_path_free (dest_row);
8015
8016   /* drop dest_row */
8017   set_dest_row (context, NULL, NULL, FALSE, FALSE, FALSE);
8018 }
8019
8020
8021
8022 /* GtkContainer Methods
8023  */
8024
8025
8026 static void
8027 gtk_tree_view_remove (GtkContainer *container,
8028                       GtkWidget    *widget)
8029 {
8030   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
8031   GtkTreeViewChild *child = NULL;
8032   GList *tmp_list;
8033
8034   tmp_list = tree_view->priv->children;
8035   while (tmp_list)
8036     {
8037       child = tmp_list->data;
8038       if (child->widget == widget)
8039         {
8040           gtk_widget_unparent (widget);
8041
8042           tree_view->priv->children = g_list_remove_link (tree_view->priv->children, tmp_list);
8043           g_list_free_1 (tmp_list);
8044           g_slice_free (GtkTreeViewChild, child);
8045           return;
8046         }
8047
8048       tmp_list = tmp_list->next;
8049     }
8050
8051   tmp_list = tree_view->priv->columns;
8052
8053   while (tmp_list)
8054     {
8055       GtkTreeViewColumn *column;
8056       GtkWidget         *button;
8057
8058       column = tmp_list->data;
8059       button = gtk_tree_view_column_get_button (column);
8060
8061       if (button == widget)
8062         {
8063           gtk_widget_unparent (widget);
8064           return;
8065         }
8066       tmp_list = tmp_list->next;
8067     }
8068 }
8069
8070 static void
8071 gtk_tree_view_forall (GtkContainer *container,
8072                       gboolean      include_internals,
8073                       GtkCallback   callback,
8074                       gpointer      callback_data)
8075 {
8076   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
8077   GtkTreeViewChild *child = NULL;
8078   GtkTreeViewColumn *column;
8079   GtkWidget *button;
8080   GList *tmp_list;
8081
8082   tmp_list = tree_view->priv->children;
8083   while (tmp_list)
8084     {
8085       child = tmp_list->data;
8086       tmp_list = tmp_list->next;
8087
8088       (* callback) (child->widget, callback_data);
8089     }
8090   if (include_internals == FALSE)
8091     return;
8092
8093   for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
8094     {
8095       column = tmp_list->data;
8096       button = gtk_tree_view_column_get_button (column);
8097
8098       if (button)
8099         (* callback) (button, callback_data);
8100     }
8101 }
8102
8103 /* Returns TRUE is any of the columns contains a cell that can-focus.
8104  * If this is not the case, a column-spanning focus rectangle will be
8105  * drawn.
8106  */
8107 static gboolean
8108 gtk_tree_view_has_can_focus_cell (GtkTreeView *tree_view)
8109 {
8110   GList *list;
8111
8112   for (list = tree_view->priv->columns; list; list = list->next)
8113     {
8114       GtkTreeViewColumn *column = list->data;
8115
8116       if (!gtk_tree_view_column_get_visible (column))
8117         continue;
8118       if (gtk_cell_area_is_activatable (gtk_cell_layout_get_area (GTK_CELL_LAYOUT (column))))
8119         return TRUE;
8120     }
8121
8122   return FALSE;
8123 }
8124
8125 static void
8126 column_sizing_notify (GObject    *object,
8127                       GParamSpec *pspec,
8128                       gpointer    data)
8129 {
8130   GtkTreeViewColumn *c = GTK_TREE_VIEW_COLUMN (object);
8131
8132   if (gtk_tree_view_column_get_sizing (c) != GTK_TREE_VIEW_COLUMN_FIXED)
8133     /* disable fixed height mode */
8134     g_object_set (data, "fixed-height-mode", FALSE, NULL);
8135 }
8136
8137 /**
8138  * gtk_tree_view_set_fixed_height_mode:
8139  * @tree_view: a #GtkTreeView 
8140  * @enable: %TRUE to enable fixed height mode
8141  * 
8142  * Enables or disables the fixed height mode of @tree_view. 
8143  * Fixed height mode speeds up #GtkTreeView by assuming that all 
8144  * rows have the same height. 
8145  * Only enable this option if all rows are the same height and all
8146  * columns are of type %GTK_TREE_VIEW_COLUMN_FIXED.
8147  *
8148  * Since: 2.6 
8149  **/
8150 void
8151 gtk_tree_view_set_fixed_height_mode (GtkTreeView *tree_view,
8152                                      gboolean     enable)
8153 {
8154   GList *l;
8155   
8156   enable = enable != FALSE;
8157
8158   if (enable == tree_view->priv->fixed_height_mode)
8159     return;
8160
8161   if (!enable)
8162     {
8163       tree_view->priv->fixed_height_mode = 0;
8164       tree_view->priv->fixed_height = -1;
8165
8166       /* force a revalidation */
8167       install_presize_handler (tree_view);
8168     }
8169   else 
8170     {
8171       /* make sure all columns are of type FIXED */
8172       for (l = tree_view->priv->columns; l; l = l->next)
8173         {
8174           GtkTreeViewColumn *c = l->data;
8175           
8176           g_return_if_fail (gtk_tree_view_column_get_sizing (c) == GTK_TREE_VIEW_COLUMN_FIXED);
8177         }
8178       
8179       /* yes, we really have to do this is in a separate loop */
8180       for (l = tree_view->priv->columns; l; l = l->next)
8181         g_signal_connect (l->data, "notify::sizing",
8182                           G_CALLBACK (column_sizing_notify), tree_view);
8183       
8184       tree_view->priv->fixed_height_mode = 1;
8185       tree_view->priv->fixed_height = -1;
8186       
8187       if (tree_view->priv->tree)
8188         initialize_fixed_height_mode (tree_view);
8189     }
8190
8191   g_object_notify (G_OBJECT (tree_view), "fixed-height-mode");
8192 }
8193
8194 /**
8195  * gtk_tree_view_get_fixed_height_mode:
8196  * @tree_view: a #GtkTreeView
8197  * 
8198  * Returns whether fixed height mode is turned on for @tree_view.
8199  * 
8200  * Return value: %TRUE if @tree_view is in fixed height mode
8201  * 
8202  * Since: 2.6
8203  **/
8204 gboolean
8205 gtk_tree_view_get_fixed_height_mode (GtkTreeView *tree_view)
8206 {
8207   return tree_view->priv->fixed_height_mode;
8208 }
8209
8210 /* Returns TRUE if the focus is within the headers, after the focus operation is
8211  * done
8212  */
8213 static gboolean
8214 gtk_tree_view_header_focus (GtkTreeView      *tree_view,
8215                             GtkDirectionType  dir,
8216                             gboolean          clamp_column_visible)
8217 {
8218   GtkTreeViewColumn *column;
8219   GtkWidget *focus_child;
8220   GtkWidget *button;
8221   GList *last_column, *first_column;
8222   GList *tmp_list;
8223   gboolean rtl;
8224
8225   if (! tree_view->priv->headers_visible)
8226     return FALSE;
8227
8228   focus_child = gtk_container_get_focus_child (GTK_CONTAINER (tree_view));
8229
8230   first_column = tree_view->priv->columns;
8231   while (first_column)
8232     {
8233       column = GTK_TREE_VIEW_COLUMN (first_column->data);
8234       button = gtk_tree_view_column_get_button (column);
8235
8236       if (gtk_widget_get_can_focus (button) &&
8237           gtk_tree_view_column_get_visible (column) &&
8238           (gtk_tree_view_column_get_clickable (column) ||
8239            gtk_tree_view_column_get_reorderable (column)))
8240         break;
8241       first_column = first_column->next;
8242     }
8243
8244   /* No headers are visible, or are focusable.  We can't focus in or out.
8245    */
8246   if (first_column == NULL)
8247     return FALSE;
8248
8249   last_column = g_list_last (tree_view->priv->columns);
8250   while (last_column)
8251     {
8252       column = GTK_TREE_VIEW_COLUMN (last_column->data);
8253       button = gtk_tree_view_column_get_button (column);
8254
8255       if (gtk_widget_get_can_focus (button) &&
8256           gtk_tree_view_column_get_visible (column) &&
8257           (gtk_tree_view_column_get_clickable (column) ||
8258            gtk_tree_view_column_get_reorderable (column)))
8259         break;
8260       last_column = last_column->prev;
8261     }
8262
8263
8264   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
8265
8266   switch (dir)
8267     {
8268     case GTK_DIR_TAB_BACKWARD:
8269     case GTK_DIR_TAB_FORWARD:
8270     case GTK_DIR_UP:
8271     case GTK_DIR_DOWN:
8272       if (focus_child == NULL)
8273         {
8274           if (tree_view->priv->focus_column != NULL)
8275             button = gtk_tree_view_column_get_button (tree_view->priv->focus_column);
8276           else 
8277             button = NULL;
8278
8279           if (button && gtk_widget_get_can_focus (button))
8280             focus_child = button;
8281           else
8282             focus_child = gtk_tree_view_column_get_button (GTK_TREE_VIEW_COLUMN (first_column->data));
8283
8284           gtk_widget_grab_focus (focus_child);
8285           break;
8286         }
8287       return FALSE;
8288
8289     case GTK_DIR_LEFT:
8290     case GTK_DIR_RIGHT:
8291       if (focus_child == NULL)
8292         {
8293           if (tree_view->priv->focus_column != NULL)
8294             focus_child = gtk_tree_view_column_get_button (tree_view->priv->focus_column);
8295           else if (dir == GTK_DIR_LEFT)
8296             focus_child = gtk_tree_view_column_get_button (GTK_TREE_VIEW_COLUMN (last_column->data));
8297           else
8298             focus_child = gtk_tree_view_column_get_button (GTK_TREE_VIEW_COLUMN (first_column->data));
8299
8300           gtk_widget_grab_focus (focus_child);
8301           break;
8302         }
8303
8304       if (gtk_widget_child_focus (focus_child, dir))
8305         {
8306           /* The focus moves inside the button. */
8307           /* This is probably a great example of bad UI */
8308           break;
8309         }
8310
8311       /* We need to move the focus among the row of buttons. */
8312       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
8313         if (gtk_tree_view_column_get_button (GTK_TREE_VIEW_COLUMN (tmp_list->data)) == focus_child)
8314           break;
8315
8316       if ((tmp_list == first_column && dir == (rtl ? GTK_DIR_RIGHT : GTK_DIR_LEFT))
8317           || (tmp_list == last_column && dir == (rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT)))
8318         {
8319           gtk_widget_error_bell (GTK_WIDGET (tree_view));
8320           break;
8321         }
8322
8323       while (tmp_list)
8324         {
8325           GtkTreeViewColumn *column;
8326           GtkWidget         *button;
8327
8328           if (dir == (rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT))
8329             tmp_list = tmp_list->next;
8330           else
8331             tmp_list = tmp_list->prev;
8332
8333           if (tmp_list == NULL)
8334             {
8335               g_warning ("Internal button not found");
8336               break;
8337             }
8338           column = tmp_list->data;
8339           button = gtk_tree_view_column_get_button (column);
8340           if (button &&
8341               gtk_tree_view_column_get_visible (column) &&
8342               gtk_widget_get_can_focus (button))
8343             {
8344               focus_child = button;
8345               gtk_widget_grab_focus (button);
8346               break;
8347             }
8348         }
8349       break;
8350     default:
8351       g_assert_not_reached ();
8352       break;
8353     }
8354
8355   /* if focus child is non-null, we assume it's been set to the current focus child
8356    */
8357   if (focus_child)
8358     {
8359       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
8360         if (gtk_tree_view_column_get_button (GTK_TREE_VIEW_COLUMN (tmp_list->data)) == focus_child)
8361           {
8362             tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
8363             break;
8364           }
8365
8366       if (clamp_column_visible)
8367         {
8368           gtk_tree_view_clamp_column_visible (tree_view,
8369                                               tree_view->priv->focus_column,
8370                                               FALSE);
8371         }
8372     }
8373
8374   return (focus_child != NULL);
8375 }
8376
8377 /* This function returns in 'path' the first focusable path, if the given path
8378  * is already focusable, it's the returned one.
8379  */
8380 static gboolean
8381 search_first_focusable_path (GtkTreeView  *tree_view,
8382                              GtkTreePath **path,
8383                              gboolean      search_forward,
8384                              GtkRBTree   **new_tree,
8385                              GtkRBNode   **new_node)
8386 {
8387   GtkRBTree *tree = NULL;
8388   GtkRBNode *node = NULL;
8389
8390   if (!path || !*path)
8391     return FALSE;
8392
8393   _gtk_tree_view_find_node (tree_view, *path, &tree, &node);
8394
8395   if (!tree || !node)
8396     return FALSE;
8397
8398   while (node && row_is_separator (tree_view, NULL, *path))
8399     {
8400       if (search_forward)
8401         _gtk_rbtree_next_full (tree, node, &tree, &node);
8402       else
8403         _gtk_rbtree_prev_full (tree, node, &tree, &node);
8404
8405       if (*path)
8406         gtk_tree_path_free (*path);
8407
8408       if (node)
8409         *path = _gtk_tree_view_find_path (tree_view, tree, node);
8410       else
8411         *path = NULL;
8412     }
8413
8414   if (new_tree)
8415     *new_tree = tree;
8416
8417   if (new_node)
8418     *new_node = node;
8419
8420   return (*path != NULL);
8421 }
8422
8423 static gint
8424 gtk_tree_view_focus (GtkWidget        *widget,
8425                      GtkDirectionType  direction)
8426 {
8427   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
8428   GtkContainer *container = GTK_CONTAINER (widget);
8429   GtkWidget *focus_child;
8430
8431   if (!gtk_widget_is_sensitive (widget) || !gtk_widget_get_can_focus (widget))
8432     return FALSE;
8433
8434   focus_child = gtk_container_get_focus_child (container);
8435
8436   gtk_tree_view_stop_editing (GTK_TREE_VIEW (widget), FALSE);
8437   /* Case 1.  Headers currently have focus. */
8438   if (focus_child)
8439     {
8440       switch (direction)
8441         {
8442         case GTK_DIR_LEFT:
8443         case GTK_DIR_RIGHT:
8444           gtk_tree_view_header_focus (tree_view, direction, TRUE);
8445           return TRUE;
8446         case GTK_DIR_TAB_BACKWARD:
8447         case GTK_DIR_UP:
8448           return FALSE;
8449         case GTK_DIR_TAB_FORWARD:
8450         case GTK_DIR_DOWN:
8451           gtk_widget_grab_focus (widget);
8452           return TRUE;
8453         default:
8454           g_assert_not_reached ();
8455           return FALSE;
8456         }
8457     }
8458
8459   /* Case 2. We don't have focus at all. */
8460   if (!gtk_widget_has_focus (widget))
8461     {
8462       gtk_widget_grab_focus (widget);
8463       return TRUE;
8464     }
8465
8466   /* Case 3. We have focus already. */
8467   if (direction == GTK_DIR_TAB_BACKWARD)
8468     return (gtk_tree_view_header_focus (tree_view, direction, FALSE));
8469   else if (direction == GTK_DIR_TAB_FORWARD)
8470     return FALSE;
8471
8472   /* Other directions caught by the keybindings */
8473   gtk_widget_grab_focus (widget);
8474   return TRUE;
8475 }
8476
8477 static void
8478 gtk_tree_view_grab_focus (GtkWidget *widget)
8479 {
8480   GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->grab_focus (widget);
8481
8482   gtk_tree_view_focus_to_cursor (GTK_TREE_VIEW (widget));
8483 }
8484
8485 static void
8486 gtk_tree_view_style_updated (GtkWidget *widget)
8487 {
8488   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
8489   GList *list;
8490   GtkTreeViewColumn *column;
8491
8492   GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->style_updated (widget);
8493
8494   if (gtk_widget_get_realized (widget))
8495     {
8496       GtkStyleContext *context;
8497
8498       context = gtk_widget_get_style_context (widget);
8499
8500       gtk_style_context_save (context);
8501       gtk_style_context_add_class (context, GTK_STYLE_CLASS_VIEW);
8502       gtk_style_context_set_background (context, tree_view->priv->bin_window);
8503       gtk_style_context_restore (context);
8504
8505       gtk_style_context_set_background (context, tree_view->priv->header_window);
8506
8507       gtk_tree_view_set_grid_lines (tree_view, tree_view->priv->grid_lines);
8508       gtk_tree_view_set_enable_tree_lines (tree_view, tree_view->priv->tree_lines_enabled);
8509     }
8510
8511   gtk_widget_style_get (widget,
8512                         "expander-size", &tree_view->priv->expander_size,
8513                         NULL);
8514   tree_view->priv->expander_size += EXPANDER_EXTRA_PADDING;
8515
8516   for (list = tree_view->priv->columns; list; list = list->next)
8517     {
8518       column = list->data;
8519       _gtk_tree_view_column_cell_set_dirty (column, TRUE);
8520     }
8521
8522   tree_view->priv->fixed_height = -1;
8523   _gtk_rbtree_mark_invalid (tree_view->priv->tree);
8524
8525   gtk_widget_queue_resize (widget);
8526 }
8527
8528
8529 static void
8530 gtk_tree_view_set_focus_child (GtkContainer *container,
8531                                GtkWidget    *child)
8532 {
8533   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
8534   GList *list;
8535
8536   for (list = tree_view->priv->columns; list; list = list->next)
8537     {
8538       if (gtk_tree_view_column_get_button (GTK_TREE_VIEW_COLUMN (list->data)) == child)
8539         {
8540           tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (list->data);
8541           break;
8542         }
8543     }
8544
8545   GTK_CONTAINER_CLASS (gtk_tree_view_parent_class)->set_focus_child (container, child);
8546 }
8547
8548 static GtkWidgetPath *
8549 gtk_tree_view_get_path_for_child (GtkContainer *container,
8550                                   GtkWidget    *child)
8551 {
8552   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
8553   GtkWidgetPath *path;
8554   gboolean rtl;
8555   GList *list;
8556   gint n_col = 0;
8557
8558   path = GTK_CONTAINER_CLASS (gtk_tree_view_parent_class)->get_path_for_child (container, child);
8559   rtl = (gtk_widget_get_direction (GTK_WIDGET (container)) == GTK_TEXT_DIR_RTL);
8560
8561   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
8562        list;
8563        list = (rtl ? list->prev : list->next))
8564     {
8565       GtkTreeViewColumn *column = list->data;
8566       GtkRegionFlags flags = 0;
8567
8568       if (!gtk_tree_view_column_get_visible (column))
8569         continue;
8570
8571       n_col++;
8572
8573       if (gtk_tree_view_column_get_widget (column) != child &&
8574           gtk_tree_view_column_get_button (column) != child)
8575         continue;
8576
8577       if ((n_col % 2) == 0)
8578         flags |= GTK_REGION_EVEN;
8579       else
8580         flags |= GTK_REGION_ODD;
8581
8582       if (n_col == 1)
8583         flags |= GTK_REGION_FIRST;
8584
8585       if ((rtl && !list->prev) ||
8586           (!rtl && !list->next))
8587         flags |= GTK_REGION_LAST;
8588
8589       gtk_widget_path_iter_add_region (path, -1, GTK_STYLE_REGION_COLUMN_HEADER, flags);
8590       break;
8591     }
8592
8593   return path;
8594 }
8595
8596 static gboolean
8597 gtk_tree_view_real_move_cursor (GtkTreeView       *tree_view,
8598                                 GtkMovementStep    step,
8599                                 gint               count)
8600 {
8601   GdkModifierType state;
8602
8603   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
8604   g_return_val_if_fail (step == GTK_MOVEMENT_LOGICAL_POSITIONS ||
8605                         step == GTK_MOVEMENT_VISUAL_POSITIONS ||
8606                         step == GTK_MOVEMENT_DISPLAY_LINES ||
8607                         step == GTK_MOVEMENT_PAGES ||
8608                         step == GTK_MOVEMENT_BUFFER_ENDS, FALSE);
8609
8610   if (tree_view->priv->tree == NULL)
8611     return FALSE;
8612   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
8613     return FALSE;
8614
8615   gtk_tree_view_stop_editing (tree_view, FALSE);
8616   tree_view->priv->draw_keyfocus = TRUE;
8617   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
8618
8619   if (gtk_get_current_event_state (&state))
8620     {
8621       if ((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
8622         tree_view->priv->ctrl_pressed = TRUE;
8623       if ((state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
8624         tree_view->priv->shift_pressed = TRUE;
8625     }
8626   /* else we assume not pressed */
8627
8628   switch (step)
8629     {
8630       /* currently we make no distinction.  When we go bi-di, we need to */
8631     case GTK_MOVEMENT_LOGICAL_POSITIONS:
8632     case GTK_MOVEMENT_VISUAL_POSITIONS:
8633       gtk_tree_view_move_cursor_left_right (tree_view, count);
8634       break;
8635     case GTK_MOVEMENT_DISPLAY_LINES:
8636       gtk_tree_view_move_cursor_up_down (tree_view, count);
8637       break;
8638     case GTK_MOVEMENT_PAGES:
8639       gtk_tree_view_move_cursor_page_up_down (tree_view, count);
8640       break;
8641     case GTK_MOVEMENT_BUFFER_ENDS:
8642       gtk_tree_view_move_cursor_start_end (tree_view, count);
8643       break;
8644     default:
8645       g_assert_not_reached ();
8646     }
8647
8648   tree_view->priv->ctrl_pressed = FALSE;
8649   tree_view->priv->shift_pressed = FALSE;
8650
8651   return TRUE;
8652 }
8653
8654 static void
8655 gtk_tree_view_put (GtkTreeView *tree_view,
8656                    GtkWidget   *child_widget,
8657                    /* in bin_window coordinates */
8658                    gint         x,
8659                    gint         y,
8660                    gint         width,
8661                    gint         height)
8662 {
8663   GtkTreeViewChild *child;
8664   
8665   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8666   g_return_if_fail (GTK_IS_WIDGET (child_widget));
8667
8668   child = g_slice_new (GtkTreeViewChild);
8669
8670   child->widget = child_widget;
8671   child->x = x;
8672   child->y = y;
8673   child->width = width;
8674   child->height = height;
8675
8676   tree_view->priv->children = g_list_append (tree_view->priv->children, child);
8677
8678   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
8679     gtk_widget_set_parent_window (child->widget, tree_view->priv->bin_window);
8680   
8681   gtk_widget_set_parent (child_widget, GTK_WIDGET (tree_view));
8682 }
8683
8684 void
8685 _gtk_tree_view_child_move_resize (GtkTreeView *tree_view,
8686                                   GtkWidget   *widget,
8687                                   /* in tree coordinates */
8688                                   gint         x,
8689                                   gint         y,
8690                                   gint         width,
8691                                   gint         height)
8692 {
8693   GtkTreeViewChild *child = NULL;
8694   GList *list;
8695   GdkRectangle allocation;
8696
8697   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8698   g_return_if_fail (GTK_IS_WIDGET (widget));
8699
8700   for (list = tree_view->priv->children; list; list = list->next)
8701     {
8702       if (((GtkTreeViewChild *)list->data)->widget == widget)
8703         {
8704           child = list->data;
8705           break;
8706         }
8707     }
8708   if (child == NULL)
8709     return;
8710
8711   allocation.x = child->x = x;
8712   allocation.y = child->y = y;
8713   allocation.width = child->width = width;
8714   allocation.height = child->height = height;
8715
8716   if (gtk_widget_get_realized (widget))
8717     gtk_widget_size_allocate (widget, &allocation);
8718 }
8719
8720
8721 /* TreeModel Callbacks
8722  */
8723
8724 static void
8725 gtk_tree_view_row_changed (GtkTreeModel *model,
8726                            GtkTreePath  *path,
8727                            GtkTreeIter  *iter,
8728                            gpointer      data)
8729 {
8730   GtkTreeView *tree_view = (GtkTreeView *)data;
8731   GtkRBTree *tree;
8732   GtkRBNode *node;
8733   gboolean free_path = FALSE;
8734   GList *list;
8735   GtkTreePath *cursor_path;
8736
8737   g_return_if_fail (path != NULL || iter != NULL);
8738
8739   if (tree_view->priv->cursor != NULL)
8740     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
8741   else
8742     cursor_path = NULL;
8743
8744   if (tree_view->priv->edited_column &&
8745       (cursor_path == NULL || gtk_tree_path_compare (cursor_path, path) == 0))
8746     gtk_tree_view_stop_editing (tree_view, TRUE);
8747
8748   if (cursor_path != NULL)
8749     gtk_tree_path_free (cursor_path);
8750
8751   if (path == NULL)
8752     {
8753       path = gtk_tree_model_get_path (model, iter);
8754       free_path = TRUE;
8755     }
8756   else if (iter == NULL)
8757     gtk_tree_model_get_iter (model, iter, path);
8758
8759   if (_gtk_tree_view_find_node (tree_view,
8760                                 path,
8761                                 &tree,
8762                                 &node))
8763     /* We aren't actually showing the node */
8764     goto done;
8765
8766   if (tree == NULL)
8767     goto done;
8768
8769   if (tree_view->priv->fixed_height_mode
8770       && tree_view->priv->fixed_height >= 0)
8771     {
8772       _gtk_rbtree_node_set_height (tree, node, tree_view->priv->fixed_height);
8773       if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
8774         gtk_tree_view_node_queue_redraw (tree_view, tree, node);
8775     }
8776   else
8777     {
8778       _gtk_rbtree_node_mark_invalid (tree, node);
8779       for (list = tree_view->priv->columns; list; list = list->next)
8780         {
8781           GtkTreeViewColumn *column;
8782
8783           column = list->data;
8784           if (!gtk_tree_view_column_get_visible (column))
8785             continue;
8786
8787           if (gtk_tree_view_column_get_sizing (column) == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
8788             {
8789               _gtk_tree_view_column_cell_set_dirty (column, TRUE);
8790             }
8791         }
8792     }
8793
8794  done:
8795   if (!tree_view->priv->fixed_height_mode &&
8796       gtk_widget_get_realized (GTK_WIDGET (tree_view)))
8797     install_presize_handler (tree_view);
8798   if (free_path)
8799     gtk_tree_path_free (path);
8800 }
8801
8802 static void
8803 gtk_tree_view_row_inserted (GtkTreeModel *model,
8804                             GtkTreePath  *path,
8805                             GtkTreeIter  *iter,
8806                             gpointer      data)
8807 {
8808   GtkTreeView *tree_view = (GtkTreeView *) data;
8809   gint *indices;
8810   GtkRBTree *tmptree, *tree;
8811   GtkRBNode *tmpnode = NULL;
8812   gint depth;
8813   gint i = 0;
8814   gint height;
8815   gboolean free_path = FALSE;
8816   gboolean node_visible = TRUE;
8817
8818   g_return_if_fail (path != NULL || iter != NULL);
8819
8820   if (tree_view->priv->fixed_height_mode
8821       && tree_view->priv->fixed_height >= 0)
8822     height = tree_view->priv->fixed_height;
8823   else
8824     height = 0;
8825
8826   if (path == NULL)
8827     {
8828       path = gtk_tree_model_get_path (model, iter);
8829       free_path = TRUE;
8830     }
8831   else if (iter == NULL)
8832     gtk_tree_model_get_iter (model, iter, path);
8833
8834   if (tree_view->priv->tree == NULL)
8835     tree_view->priv->tree = _gtk_rbtree_new ();
8836
8837   tmptree = tree = tree_view->priv->tree;
8838
8839   /* Update all row-references */
8840   gtk_tree_row_reference_inserted (G_OBJECT (data), path);
8841   depth = gtk_tree_path_get_depth (path);
8842   indices = gtk_tree_path_get_indices (path);
8843
8844   /* First, find the parent tree */
8845   while (i < depth - 1)
8846     {
8847       if (tmptree == NULL)
8848         {
8849           /* We aren't showing the node */
8850           node_visible = FALSE;
8851           goto done;
8852         }
8853
8854       tmpnode = _gtk_rbtree_find_count (tmptree, indices[i] + 1);
8855       if (tmpnode == NULL)
8856         {
8857           g_warning ("A node was inserted with a parent that's not in the tree.\n" \
8858                      "This possibly means that a GtkTreeModel inserted a child node\n" \
8859                      "before the parent was inserted.");
8860           goto done;
8861         }
8862       else if (!GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_IS_PARENT))
8863         {
8864           /* FIXME enforce correct behavior on model, probably */
8865           /* In theory, the model should have emitted has_child_toggled here.  We
8866            * try to catch it anyway, just to be safe, in case the model hasn't.
8867            */
8868           GtkTreePath *tmppath = _gtk_tree_view_find_path (tree_view,
8869                                                            tree,
8870                                                            tmpnode);
8871           gtk_tree_view_row_has_child_toggled (model, tmppath, NULL, data);
8872           gtk_tree_path_free (tmppath);
8873           goto done;
8874         }
8875
8876       tmptree = tmpnode->children;
8877       tree = tmptree;
8878       i++;
8879     }
8880
8881   if (tree == NULL)
8882     {
8883       node_visible = FALSE;
8884       goto done;
8885     }
8886
8887   /* ref the node */
8888   gtk_tree_model_ref_node (tree_view->priv->model, iter);
8889   if (indices[depth - 1] == 0)
8890     {
8891       tmpnode = _gtk_rbtree_find_count (tree, 1);
8892       tmpnode = _gtk_rbtree_insert_before (tree, tmpnode, height, FALSE);
8893     }
8894   else
8895     {
8896       tmpnode = _gtk_rbtree_find_count (tree, indices[depth - 1]);
8897       tmpnode = _gtk_rbtree_insert_after (tree, tmpnode, height, FALSE);
8898     }
8899
8900  done:
8901   if (height > 0)
8902     {
8903       if (tree)
8904         _gtk_rbtree_node_mark_valid (tree, tmpnode);
8905
8906       if (node_visible && node_is_visible (tree_view, tree, tmpnode))
8907         gtk_widget_queue_resize (GTK_WIDGET (tree_view));
8908       else
8909         gtk_widget_queue_resize_no_redraw (GTK_WIDGET (tree_view));
8910     }
8911   else
8912     install_presize_handler (tree_view);
8913   if (free_path)
8914     gtk_tree_path_free (path);
8915 }
8916
8917 static void
8918 gtk_tree_view_row_has_child_toggled (GtkTreeModel *model,
8919                                      GtkTreePath  *path,
8920                                      GtkTreeIter  *iter,
8921                                      gpointer      data)
8922 {
8923   GtkTreeView *tree_view = (GtkTreeView *)data;
8924   GtkTreeIter real_iter;
8925   gboolean has_child;
8926   GtkRBTree *tree;
8927   GtkRBNode *node;
8928   gboolean free_path = FALSE;
8929
8930   g_return_if_fail (path != NULL || iter != NULL);
8931
8932   if (iter)
8933     real_iter = *iter;
8934
8935   if (path == NULL)
8936     {
8937       path = gtk_tree_model_get_path (model, iter);
8938       free_path = TRUE;
8939     }
8940   else if (iter == NULL)
8941     gtk_tree_model_get_iter (model, &real_iter, path);
8942
8943   if (_gtk_tree_view_find_node (tree_view,
8944                                 path,
8945                                 &tree,
8946                                 &node))
8947     /* We aren't actually showing the node */
8948     goto done;
8949
8950   if (tree == NULL)
8951     goto done;
8952
8953   has_child = gtk_tree_model_iter_has_child (model, &real_iter);
8954   /* Sanity check.
8955    */
8956   if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT) == has_child)
8957     goto done;
8958
8959   if (has_child)
8960     GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_PARENT);
8961   else
8962     GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_PARENT);
8963
8964   if (has_child && tree_view->priv->is_list)
8965     {
8966       tree_view->priv->is_list = FALSE;
8967       if (tree_view->priv->show_expanders)
8968         {
8969           GList *list;
8970
8971           for (list = tree_view->priv->columns; list; list = list->next)
8972             if (gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (list->data)))
8973               {
8974                 _gtk_tree_view_column_cell_set_dirty (GTK_TREE_VIEW_COLUMN (list->data), TRUE);
8975                 break;
8976               }
8977         }
8978       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
8979     }
8980   else
8981     {
8982       _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
8983     }
8984
8985  done:
8986   if (free_path)
8987     gtk_tree_path_free (path);
8988 }
8989
8990 static void
8991 count_children_helper (GtkRBTree *tree,
8992                        GtkRBNode *node,
8993                        gpointer   data)
8994 {
8995   if (node->children)
8996     _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, data);
8997   (*((gint *)data))++;
8998 }
8999
9000 static void
9001 check_selection_helper (GtkRBTree *tree,
9002                         GtkRBNode *node,
9003                         gpointer   data)
9004 {
9005   gint *value = (gint *)data;
9006
9007   *value = GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED);
9008
9009   if (node->children && !*value)
9010     _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, check_selection_helper, data);
9011 }
9012
9013 static void
9014 gtk_tree_view_row_deleted (GtkTreeModel *model,
9015                            GtkTreePath  *path,
9016                            gpointer      data)
9017 {
9018   GtkTreeView *tree_view = (GtkTreeView *)data;
9019   GtkRBTree *tree;
9020   GtkRBNode *node;
9021   GList *list;
9022   gint selection_changed = FALSE;
9023   GtkStyleContext *context;
9024
9025   g_return_if_fail (path != NULL);
9026
9027   gtk_tree_row_reference_deleted (G_OBJECT (data), path);
9028
9029   if (_gtk_tree_view_find_node (tree_view, path, &tree, &node))
9030     return;
9031
9032   if (tree == NULL)
9033     return;
9034
9035   /* check if the selection has been changed */
9036   _gtk_rbtree_traverse (tree, node, G_POST_ORDER,
9037                         check_selection_helper, &selection_changed);
9038
9039   for (list = tree_view->priv->columns; list; list = list->next)
9040     if (gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (list->data)) &&
9041         gtk_tree_view_column_get_sizing (GTK_TREE_VIEW_COLUMN (list->data)) == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
9042       _gtk_tree_view_column_cell_set_dirty ((GtkTreeViewColumn *)list->data, TRUE);
9043
9044   /* Ensure we don't have a dangling pointer to a dead node */
9045   ensure_unprelighted (tree_view);
9046
9047   /* Cancel editting if we've started */
9048   gtk_tree_view_stop_editing (tree_view, TRUE);
9049
9050   if (tree_view->priv->destroy_count_func)
9051     {
9052       gint child_count = 0;
9053       if (node->children)
9054         _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, &child_count);
9055       tree_view->priv->destroy_count_func (tree_view, path, child_count, tree_view->priv->destroy_count_data);
9056     }
9057
9058   if (tree->root->count == 1)
9059     {
9060       if (tree_view->priv->tree == tree)
9061         tree_view->priv->tree = NULL;
9062
9063       _gtk_rbtree_remove (tree);
9064     }
9065   else
9066     {
9067       _gtk_rbtree_remove_node (tree, node);
9068     }
9069
9070   if (! gtk_tree_row_reference_valid (tree_view->priv->top_row))
9071     {
9072       gtk_tree_row_reference_free (tree_view->priv->top_row);
9073       tree_view->priv->top_row = NULL;
9074     }
9075
9076   /* Cancel any ongoing animation happening within the row */
9077   context = gtk_widget_get_style_context (GTK_WIDGET (tree_view));
9078   gtk_style_context_cancel_animations (context, node);
9079
9080   install_scroll_sync_handler (tree_view);
9081
9082   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
9083
9084   if (selection_changed)
9085     g_signal_emit_by_name (tree_view->priv->selection, "changed");
9086 }
9087
9088 static void
9089 gtk_tree_view_rows_reordered (GtkTreeModel *model,
9090                               GtkTreePath  *parent,
9091                               GtkTreeIter  *iter,
9092                               gint         *new_order,
9093                               gpointer      data)
9094 {
9095   GtkTreeView *tree_view = GTK_TREE_VIEW (data);
9096   GtkRBTree *tree;
9097   GtkRBNode *node;
9098   gint len;
9099
9100   len = gtk_tree_model_iter_n_children (model, iter);
9101
9102   if (len < 2)
9103     return;
9104
9105   gtk_tree_row_reference_reordered (G_OBJECT (data),
9106                                     parent,
9107                                     iter,
9108                                     new_order);
9109
9110   if (_gtk_tree_view_find_node (tree_view,
9111                                 parent,
9112                                 &tree,
9113                                 &node))
9114     return;
9115
9116   /* We need to special case the parent path */
9117   if (tree == NULL)
9118     tree = tree_view->priv->tree;
9119   else
9120     tree = node->children;
9121
9122   if (tree == NULL)
9123     return;
9124
9125   if (tree_view->priv->edited_column)
9126     gtk_tree_view_stop_editing (tree_view, TRUE);
9127
9128   /* we need to be unprelighted */
9129   ensure_unprelighted (tree_view);
9130
9131   _gtk_rbtree_reorder (tree, new_order, len);
9132
9133   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
9134
9135   gtk_tree_view_dy_to_top_row (tree_view);
9136 }
9137
9138
9139 /* Internal tree functions
9140  */
9141
9142
9143 static void
9144 gtk_tree_view_get_background_xrange (GtkTreeView       *tree_view,
9145                                      GtkRBTree         *tree,
9146                                      GtkTreeViewColumn *column,
9147                                      gint              *x1,
9148                                      gint              *x2)
9149 {
9150   GtkTreeViewColumn *tmp_column = NULL;
9151   gint total_width;
9152   GList *list;
9153   gboolean rtl;
9154
9155   if (x1)
9156     *x1 = 0;
9157
9158   if (x2)
9159     *x2 = 0;
9160
9161   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
9162
9163   total_width = 0;
9164   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
9165        list;
9166        list = (rtl ? list->prev : list->next))
9167     {
9168       tmp_column = list->data;
9169
9170       if (tmp_column == column)
9171         break;
9172
9173       if (gtk_tree_view_column_get_visible (tmp_column))
9174         total_width += gtk_tree_view_column_get_width (tmp_column);
9175     }
9176
9177   if (tmp_column != column)
9178     {
9179       g_warning (G_STRLOC": passed-in column isn't in the tree");
9180       return;
9181     }
9182
9183   if (x1)
9184     *x1 = total_width;
9185
9186   if (x2)
9187     {
9188       if (gtk_tree_view_column_get_visible (column))
9189         *x2 = total_width + gtk_tree_view_column_get_width (column);
9190       else
9191         *x2 = total_width; /* width of 0 */
9192     }
9193 }
9194
9195 static void
9196 gtk_tree_view_get_arrow_xrange (GtkTreeView *tree_view,
9197                                 GtkRBTree   *tree,
9198                                 gint        *x1,
9199                                 gint        *x2)
9200 {
9201   gint x_offset = 0;
9202   GList *list;
9203   GtkTreeViewColumn *tmp_column = NULL;
9204   gint total_width;
9205   gboolean indent_expanders;
9206   gboolean rtl;
9207
9208   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
9209
9210   total_width = 0;
9211   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
9212        list;
9213        list = (rtl ? list->prev : list->next))
9214     {
9215       tmp_column = list->data;
9216
9217       if (gtk_tree_view_is_expander_column (tree_view, tmp_column))
9218         {
9219           if (rtl)
9220             x_offset = total_width + gtk_tree_view_column_get_width (tmp_column) - tree_view->priv->expander_size;
9221           else
9222             x_offset = total_width;
9223           break;
9224         }
9225
9226       if (gtk_tree_view_column_get_visible (tmp_column))
9227         total_width += gtk_tree_view_column_get_width (tmp_column);
9228     }
9229
9230   gtk_widget_style_get (GTK_WIDGET (tree_view),
9231                         "indent-expanders", &indent_expanders,
9232                         NULL);
9233
9234   if (indent_expanders)
9235     {
9236       if (rtl)
9237         x_offset -= tree_view->priv->expander_size * _gtk_rbtree_get_depth (tree);
9238       else
9239         x_offset += tree_view->priv->expander_size * _gtk_rbtree_get_depth (tree);
9240     }
9241
9242   *x1 = x_offset;
9243
9244   if (tmp_column &&
9245       gtk_tree_view_column_get_visible (tmp_column))
9246     /* +1 because x2 isn't included in the range. */
9247     *x2 = *x1 + tree_view->priv->expander_size + 1;
9248   else
9249     *x2 = *x1;
9250 }
9251
9252 static void
9253 gtk_tree_view_build_tree (GtkTreeView *tree_view,
9254                           GtkRBTree   *tree,
9255                           GtkTreeIter *iter,
9256                           gint         depth,
9257                           gboolean     recurse)
9258 {
9259   GtkRBNode *temp = NULL;
9260   GtkTreePath *path = NULL;
9261
9262   do
9263     {
9264       gtk_tree_model_ref_node (tree_view->priv->model, iter);
9265       temp = _gtk_rbtree_insert_after (tree, temp, 0, FALSE);
9266
9267       if (tree_view->priv->fixed_height > 0)
9268         {
9269           if (GTK_RBNODE_FLAG_SET (temp, GTK_RBNODE_INVALID))
9270             {
9271               _gtk_rbtree_node_set_height (tree, temp, tree_view->priv->fixed_height);
9272               _gtk_rbtree_node_mark_valid (tree, temp);
9273             }
9274         }
9275
9276       if (tree_view->priv->is_list)
9277         continue;
9278
9279       if (recurse)
9280         {
9281           GtkTreeIter child;
9282
9283           if (!path)
9284             path = gtk_tree_model_get_path (tree_view->priv->model, iter);
9285           else
9286             gtk_tree_path_next (path);
9287
9288           if (gtk_tree_model_iter_children (tree_view->priv->model, &child, iter))
9289             {
9290               gboolean expand;
9291
9292               g_signal_emit (tree_view, tree_view_signals[TEST_EXPAND_ROW], 0, iter, path, &expand);
9293
9294               if (gtk_tree_model_iter_has_child (tree_view->priv->model, iter)
9295                   && !expand)
9296                 {
9297                   temp->children = _gtk_rbtree_new ();
9298                   temp->children->parent_tree = tree;
9299                   temp->children->parent_node = temp;
9300                   gtk_tree_view_build_tree (tree_view, temp->children, &child, depth + 1, recurse);
9301                 }
9302             }
9303         }
9304
9305       if (gtk_tree_model_iter_has_child (tree_view->priv->model, iter))
9306         {
9307           if ((temp->flags&GTK_RBNODE_IS_PARENT) != GTK_RBNODE_IS_PARENT)
9308             temp->flags ^= GTK_RBNODE_IS_PARENT;
9309         }
9310     }
9311   while (gtk_tree_model_iter_next (tree_view->priv->model, iter));
9312
9313   if (path)
9314     gtk_tree_path_free (path);
9315 }
9316
9317 /* Make sure the node is visible vertically */
9318 static void
9319 gtk_tree_view_clamp_node_visible (GtkTreeView *tree_view,
9320                                   GtkRBTree   *tree,
9321                                   GtkRBNode   *node)
9322 {
9323   gint node_dy, height;
9324   GtkTreePath *path = NULL;
9325
9326   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
9327     return;
9328
9329   /* just return if the node is visible, avoiding a costly expose */
9330   node_dy = _gtk_rbtree_node_find_offset (tree, node);
9331   height = gtk_tree_view_get_row_height (tree_view, node);
9332   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID)
9333       && node_dy >= gtk_adjustment_get_value (tree_view->priv->vadjustment)
9334       && node_dy + height <= (gtk_adjustment_get_value (tree_view->priv->vadjustment)
9335                               + gtk_adjustment_get_page_size (tree_view->priv->vadjustment)))
9336     return;
9337
9338   path = _gtk_tree_view_find_path (tree_view, tree, node);
9339   if (path)
9340     {
9341       /* We process updates because we want to clear old selected items when we scroll.
9342        * if this is removed, we get a "selection streak" at the bottom. */
9343       gtk_tree_view_bin_process_updates (tree_view);
9344
9345       gtk_tree_view_scroll_to_cell (tree_view, path, NULL, FALSE, 0.0, 0.0);
9346       gtk_tree_path_free (path);
9347     }
9348 }
9349
9350 static void
9351 gtk_tree_view_clamp_column_visible (GtkTreeView       *tree_view,
9352                                     GtkTreeViewColumn *column,
9353                                     gboolean           focus_to_cell)
9354 {
9355   GtkAllocation allocation;
9356   gint x, width;
9357
9358   if (column == NULL)
9359     return;
9360
9361   gtk_widget_get_allocation (gtk_tree_view_column_get_button (column), &allocation);
9362   x = allocation.x;
9363   width = allocation.width;
9364
9365   if (width > gtk_adjustment_get_page_size (tree_view->priv->hadjustment))
9366     {
9367       /* The column is larger than the horizontal page size.  If the
9368        * column has cells which can be focussed individually, then we make
9369        * sure the cell which gets focus is fully visible (if even the
9370        * focus cell is bigger than the page size, we make sure the
9371        * left-hand side of the cell is visible).
9372        *
9373        * If the column does not have an activatable cell, we
9374        * make sure the left-hand side of the column is visible.
9375        */
9376
9377       if (focus_to_cell && gtk_tree_view_has_can_focus_cell (tree_view))
9378         {
9379           GtkCellArea *cell_area;
9380           GtkCellRenderer *focus_cell;
9381
9382           cell_area = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (column));
9383           focus_cell = gtk_cell_area_get_focus_cell (cell_area);
9384
9385           if (gtk_tree_view_column_cell_get_position (column, focus_cell,
9386                                                       &x, &width))
9387             {
9388               if (width < gtk_adjustment_get_page_size (tree_view->priv->hadjustment))
9389                 {
9390                   if (gtk_adjustment_get_value (tree_view->priv->hadjustment) + gtk_adjustment_get_page_size (tree_view->priv->hadjustment) < x + width)
9391                     gtk_adjustment_set_value (tree_view->priv->hadjustment,
9392                                               x + width - gtk_adjustment_get_page_size (tree_view->priv->hadjustment));
9393                   else if (gtk_adjustment_get_value (tree_view->priv->hadjustment) > x)
9394                     gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
9395                 }
9396             }
9397         }
9398
9399       gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
9400     }
9401   else
9402     {
9403       if ((gtk_adjustment_get_value (tree_view->priv->hadjustment) + gtk_adjustment_get_page_size (tree_view->priv->hadjustment)) < (x + width))
9404           gtk_adjustment_set_value (tree_view->priv->hadjustment,
9405                                     x + width - gtk_adjustment_get_page_size (tree_view->priv->hadjustment));
9406       else if (gtk_adjustment_get_value (tree_view->priv->hadjustment) > x)
9407         gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
9408   }
9409 }
9410
9411 /* This function could be more efficient.  I'll optimize it if profiling seems
9412  * to imply that it is important */
9413 GtkTreePath *
9414 _gtk_tree_view_find_path (GtkTreeView *tree_view,
9415                           GtkRBTree   *tree,
9416                           GtkRBNode   *node)
9417 {
9418   GtkTreePath *path;
9419   GtkRBTree *tmp_tree;
9420   GtkRBNode *tmp_node, *last;
9421   gint count;
9422
9423   path = gtk_tree_path_new ();
9424
9425   g_return_val_if_fail (node != NULL, path);
9426   g_return_val_if_fail (node != tree->nil, path);
9427
9428   count = 1 + node->left->count;
9429
9430   last = node;
9431   tmp_node = node->parent;
9432   tmp_tree = tree;
9433   while (tmp_tree)
9434     {
9435       while (tmp_node != tmp_tree->nil)
9436         {
9437           if (tmp_node->right == last)
9438             count += 1 + tmp_node->left->count;
9439           last = tmp_node;
9440           tmp_node = tmp_node->parent;
9441         }
9442       gtk_tree_path_prepend_index (path, count - 1);
9443       last = tmp_tree->parent_node;
9444       tmp_tree = tmp_tree->parent_tree;
9445       if (last)
9446         {
9447           count = 1 + last->left->count;
9448           tmp_node = last->parent;
9449         }
9450     }
9451   return path;
9452 }
9453
9454 /* Returns TRUE if we ran out of tree before finding the path.  If the path is
9455  * invalid (ie. points to a node that's not in the tree), *tree and *node are
9456  * both set to NULL.
9457  */
9458 gboolean
9459 _gtk_tree_view_find_node (GtkTreeView  *tree_view,
9460                           GtkTreePath  *path,
9461                           GtkRBTree   **tree,
9462                           GtkRBNode   **node)
9463 {
9464   GtkRBNode *tmpnode = NULL;
9465   GtkRBTree *tmptree = tree_view->priv->tree;
9466   gint *indices = gtk_tree_path_get_indices (path);
9467   gint depth = gtk_tree_path_get_depth (path);
9468   gint i = 0;
9469
9470   *node = NULL;
9471   *tree = NULL;
9472
9473   if (depth == 0 || tmptree == NULL)
9474     return FALSE;
9475   do
9476     {
9477       tmpnode = _gtk_rbtree_find_count (tmptree, indices[i] + 1);
9478       ++i;
9479       if (tmpnode == NULL)
9480         {
9481           *tree = NULL;
9482           *node = NULL;
9483           return FALSE;
9484         }
9485       if (i >= depth)
9486         {
9487           *tree = tmptree;
9488           *node = tmpnode;
9489           return FALSE;
9490         }
9491       *tree = tmptree;
9492       *node = tmpnode;
9493       tmptree = tmpnode->children;
9494       if (tmptree == NULL)
9495         return TRUE;
9496     }
9497   while (1);
9498 }
9499
9500 static gboolean
9501 gtk_tree_view_is_expander_column (GtkTreeView       *tree_view,
9502                                   GtkTreeViewColumn *column)
9503 {
9504   GList *list;
9505
9506   if (tree_view->priv->is_list)
9507     return FALSE;
9508
9509   if (tree_view->priv->expander_column != NULL)
9510     {
9511       if (tree_view->priv->expander_column == column)
9512         return TRUE;
9513       return FALSE;
9514     }
9515   else
9516     {
9517       for (list = tree_view->priv->columns;
9518            list;
9519            list = list->next)
9520         if (gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (list->data)))
9521           break;
9522       if (list && list->data == column)
9523         return TRUE;
9524     }
9525   return FALSE;
9526 }
9527
9528 static inline gboolean
9529 gtk_tree_view_draw_expanders (GtkTreeView *tree_view)
9530 {
9531   if (!tree_view->priv->is_list && tree_view->priv->show_expanders)
9532     return TRUE;
9533   /* else */
9534   return FALSE;
9535 }
9536
9537 static void
9538 gtk_tree_view_add_move_binding (GtkBindingSet  *binding_set,
9539                                 guint           keyval,
9540                                 guint           modmask,
9541                                 gboolean        add_shifted_binding,
9542                                 GtkMovementStep step,
9543                                 gint            count)
9544 {
9545   
9546   gtk_binding_entry_add_signal (binding_set, keyval, modmask,
9547                                 "move-cursor", 2,
9548                                 G_TYPE_ENUM, step,
9549                                 G_TYPE_INT, count);
9550
9551   if (add_shifted_binding)
9552     gtk_binding_entry_add_signal (binding_set, keyval, GDK_SHIFT_MASK,
9553                                   "move-cursor", 2,
9554                                   G_TYPE_ENUM, step,
9555                                   G_TYPE_INT, count);
9556
9557   if ((modmask & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
9558    return;
9559
9560   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK | GDK_SHIFT_MASK,
9561                                 "move-cursor", 2,
9562                                 G_TYPE_ENUM, step,
9563                                 G_TYPE_INT, count);
9564
9565   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK,
9566                                 "move-cursor", 2,
9567                                 G_TYPE_ENUM, step,
9568                                 G_TYPE_INT, count);
9569 }
9570
9571 static gint
9572 gtk_tree_view_unref_tree_helper (GtkTreeModel *model,
9573                                  GtkTreeIter  *iter,
9574                                  GtkRBTree    *tree,
9575                                  GtkRBNode    *node)
9576 {
9577   gint retval = FALSE;
9578   do
9579     {
9580       g_return_val_if_fail (node != NULL, FALSE);
9581
9582       if (node->children)
9583         {
9584           GtkTreeIter child;
9585           GtkRBTree *new_tree;
9586           GtkRBNode *new_node;
9587
9588           new_tree = node->children;
9589           new_node = new_tree->root;
9590
9591           while (new_node && new_node->left != new_tree->nil)
9592             new_node = new_node->left;
9593
9594           if (!gtk_tree_model_iter_children (model, &child, iter))
9595             return FALSE;
9596
9597           retval = retval || gtk_tree_view_unref_tree_helper (model, &child, new_tree, new_node);
9598         }
9599
9600       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
9601         retval = TRUE;
9602       gtk_tree_model_unref_node (model, iter);
9603       node = _gtk_rbtree_next (tree, node);
9604     }
9605   while (gtk_tree_model_iter_next (model, iter));
9606
9607   return retval;
9608 }
9609
9610 static gint
9611 gtk_tree_view_unref_and_check_selection_tree (GtkTreeView *tree_view,
9612                                               GtkRBTree   *tree)
9613 {
9614   GtkTreeIter iter;
9615   GtkTreePath *path;
9616   GtkRBNode *node;
9617   gint retval;
9618
9619   if (!tree)
9620     return FALSE;
9621
9622   node = tree->root;
9623   while (node && node->left != tree->nil)
9624     node = node->left;
9625
9626   g_return_val_if_fail (node != NULL, FALSE);
9627   path = _gtk_tree_view_find_path (tree_view, tree, node);
9628   gtk_tree_model_get_iter (GTK_TREE_MODEL (tree_view->priv->model),
9629                            &iter, path);
9630   retval = gtk_tree_view_unref_tree_helper (GTK_TREE_MODEL (tree_view->priv->model), &iter, tree, node);
9631   gtk_tree_path_free (path);
9632
9633   return retval;
9634 }
9635
9636 static void
9637 gtk_tree_view_set_column_drag_info (GtkTreeView       *tree_view,
9638                                     GtkTreeViewColumn *column)
9639 {
9640   GtkTreeViewColumn *left_column;
9641   GtkTreeViewColumn *cur_column = NULL;
9642   GtkTreeViewColumnReorder *reorder;
9643   gboolean rtl;
9644   GList *tmp_list;
9645   gint left;
9646
9647   /* We want to precalculate the motion list such that we know what column slots
9648    * are available.
9649    */
9650   left_column = NULL;
9651   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
9652
9653   /* First, identify all possible drop spots */
9654   if (rtl)
9655     tmp_list = g_list_last (tree_view->priv->columns);
9656   else
9657     tmp_list = g_list_first (tree_view->priv->columns);
9658
9659   while (tmp_list)
9660     {
9661       cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
9662       tmp_list = rtl?g_list_previous (tmp_list):g_list_next (tmp_list);
9663
9664       if (gtk_tree_view_column_get_visible (cur_column) == FALSE)
9665         continue;
9666
9667       /* If it's not the column moving and func tells us to skip over the column, we continue. */
9668       if (left_column != column && cur_column != column &&
9669           tree_view->priv->column_drop_func &&
9670           ! tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
9671         {
9672           left_column = cur_column;
9673           continue;
9674         }
9675       reorder = g_slice_new0 (GtkTreeViewColumnReorder);
9676       reorder->left_column = left_column;
9677       left_column = reorder->right_column = cur_column;
9678
9679       tree_view->priv->column_drag_info = g_list_append (tree_view->priv->column_drag_info, reorder);
9680     }
9681
9682   /* Add the last one */
9683   if (tree_view->priv->column_drop_func == NULL ||
9684       ((left_column != column) &&
9685        tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data)))
9686     {
9687       reorder = g_slice_new0 (GtkTreeViewColumnReorder);
9688       reorder->left_column = left_column;
9689       reorder->right_column = NULL;
9690       tree_view->priv->column_drag_info = g_list_append (tree_view->priv->column_drag_info, reorder);
9691     }
9692
9693   /* We quickly check to see if it even makes sense to reorder columns. */
9694   /* If there is nothing that can be moved, then we return */
9695
9696   if (tree_view->priv->column_drag_info == NULL)
9697     return;
9698
9699   /* We know there are always 2 slots possbile, as you can always return column. */
9700   /* If that's all there is, return */
9701   if (tree_view->priv->column_drag_info->next == NULL || 
9702       (tree_view->priv->column_drag_info->next->next == NULL &&
9703        ((GtkTreeViewColumnReorder *)tree_view->priv->column_drag_info->data)->right_column == column &&
9704        ((GtkTreeViewColumnReorder *)tree_view->priv->column_drag_info->next->data)->left_column == column))
9705     {
9706       for (tmp_list = tree_view->priv->column_drag_info; tmp_list; tmp_list = tmp_list->next)
9707         g_slice_free (GtkTreeViewColumnReorder, tmp_list->data);
9708       g_list_free (tree_view->priv->column_drag_info);
9709       tree_view->priv->column_drag_info = NULL;
9710       return;
9711     }
9712   /* We fill in the ranges for the columns, now that we've isolated them */
9713   left = - TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER (tree_view);
9714
9715   for (tmp_list = tree_view->priv->column_drag_info; tmp_list; tmp_list = tmp_list->next)
9716     {
9717       reorder = (GtkTreeViewColumnReorder *) tmp_list->data;
9718
9719       reorder->left_align = left;
9720       if (tmp_list->next != NULL)
9721         {
9722           GtkAllocation right_allocation, left_allocation;
9723           GtkWidget    *left_button, *right_button;
9724
9725           g_assert (tmp_list->next->data);
9726
9727           right_button = gtk_tree_view_column_get_button (reorder->right_column);
9728           left_button  = gtk_tree_view_column_get_button
9729             (((GtkTreeViewColumnReorder *)tmp_list->next->data)->left_column);
9730
9731           gtk_widget_get_allocation (right_button, &right_allocation);
9732           gtk_widget_get_allocation (left_button, &left_allocation);
9733           left = reorder->right_align = (right_allocation.x + right_allocation.width + left_allocation.x) / 2;
9734         }
9735       else
9736         {
9737           reorder->right_align = gdk_window_get_width (tree_view->priv->header_window)
9738                                  + TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER (tree_view);
9739         }
9740     }
9741 }
9742
9743 void
9744 _gtk_tree_view_column_start_drag (GtkTreeView       *tree_view,
9745                                   GtkTreeViewColumn *column,
9746                                   GdkDevice         *device)
9747 {
9748   GdkEvent *send_event;
9749   GtkAllocation allocation;
9750   GtkAllocation button_allocation;
9751   GdkScreen *screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
9752   GtkWidget *button;
9753   GdkDevice *pointer, *keyboard;
9754
9755   g_return_if_fail (tree_view->priv->column_drag_info == NULL);
9756   g_return_if_fail (tree_view->priv->cur_reorder == NULL);
9757
9758   gtk_tree_view_set_column_drag_info (tree_view, column);
9759
9760   if (tree_view->priv->column_drag_info == NULL)
9761     return;
9762
9763   button = gtk_tree_view_column_get_button (column);
9764
9765   if (tree_view->priv->drag_window == NULL)
9766     {
9767       GdkWindowAttr attributes;
9768       guint attributes_mask;
9769
9770       gtk_widget_get_allocation (button, &button_allocation);
9771
9772       attributes.window_type = GDK_WINDOW_CHILD;
9773       attributes.wclass = GDK_INPUT_OUTPUT;
9774       attributes.x = button_allocation.x;
9775       attributes.y = 0;
9776       attributes.width = button_allocation.width;
9777       attributes.height = button_allocation.height;
9778       attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
9779       attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
9780       attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
9781
9782       tree_view->priv->drag_window = gdk_window_new (tree_view->priv->bin_window,
9783                                                      &attributes,
9784                                                      attributes_mask);
9785       gdk_window_set_user_data (tree_view->priv->drag_window, GTK_WIDGET (tree_view));
9786     }
9787
9788   if (gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD)
9789     {
9790       keyboard = device;
9791       pointer = gdk_device_get_associated_device (device);
9792     }
9793   else
9794     {
9795       pointer = device;
9796       keyboard = gdk_device_get_associated_device (device);
9797     }
9798
9799   gdk_device_ungrab (pointer, GDK_CURRENT_TIME);
9800   gdk_device_ungrab (keyboard, GDK_CURRENT_TIME);
9801
9802   gtk_grab_remove (button);
9803
9804   send_event = gdk_event_new (GDK_LEAVE_NOTIFY);
9805   send_event->crossing.send_event = TRUE;
9806   send_event->crossing.window = g_object_ref (gtk_button_get_event_window (GTK_BUTTON (button)));
9807   send_event->crossing.subwindow = NULL;
9808   send_event->crossing.detail = GDK_NOTIFY_ANCESTOR;
9809   send_event->crossing.time = GDK_CURRENT_TIME;
9810   gdk_event_set_device (send_event, device);
9811
9812   gtk_propagate_event (button, send_event);
9813   gdk_event_free (send_event);
9814
9815   send_event = gdk_event_new (GDK_BUTTON_RELEASE);
9816   send_event->button.window = g_object_ref (gdk_screen_get_root_window (screen));
9817   send_event->button.send_event = TRUE;
9818   send_event->button.time = GDK_CURRENT_TIME;
9819   send_event->button.x = -1;
9820   send_event->button.y = -1;
9821   send_event->button.axes = NULL;
9822   send_event->button.state = 0;
9823   send_event->button.button = 1;
9824   send_event->button.x_root = 0;
9825   send_event->button.y_root = 0;
9826   gdk_event_set_device (send_event, device);
9827
9828   gtk_propagate_event (button, send_event);
9829   gdk_event_free (send_event);
9830
9831   /* Kids, don't try this at home */
9832   g_object_ref (button);
9833   gtk_container_remove (GTK_CONTAINER (tree_view), button);
9834   gtk_widget_set_parent_window (button, tree_view->priv->drag_window);
9835   gtk_widget_set_parent (button, GTK_WIDGET (tree_view));
9836   g_object_unref (button);
9837
9838   gtk_widget_get_allocation (button, &button_allocation);
9839   tree_view->priv->drag_column_x = button_allocation.x;
9840   allocation = button_allocation;
9841   allocation.x = 0;
9842   gtk_widget_size_allocate (button, &allocation);
9843   gtk_widget_set_parent_window (button, tree_view->priv->drag_window);
9844
9845   tree_view->priv->drag_column = column;
9846   gdk_window_show (tree_view->priv->drag_window);
9847
9848   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
9849   while (gtk_events_pending ())
9850     gtk_main_iteration ();
9851
9852   tree_view->priv->in_column_drag = TRUE;
9853
9854   gdk_device_grab (pointer,
9855                    tree_view->priv->drag_window,
9856                    GDK_OWNERSHIP_NONE,
9857                    FALSE,
9858                    GDK_POINTER_MOTION_MASK|GDK_BUTTON_RELEASE_MASK,
9859                    NULL,
9860                    GDK_CURRENT_TIME);
9861   gdk_device_grab (keyboard,
9862                    tree_view->priv->drag_window,
9863                    GDK_OWNERSHIP_NONE,
9864                    FALSE,
9865                    GDK_KEY_PRESS_MASK|GDK_KEY_RELEASE_MASK,
9866                    NULL,
9867                    GDK_CURRENT_TIME);
9868 }
9869
9870 static void
9871 gtk_tree_view_queue_draw_arrow (GtkTreeView        *tree_view,
9872                                 GtkRBTree          *tree,
9873                                 GtkRBNode          *node)
9874 {
9875   GtkAllocation allocation;
9876   GdkRectangle rect;
9877
9878   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
9879     return;
9880
9881   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
9882   rect.x = 0;
9883   rect.width = MAX (tree_view->priv->expander_size, MAX (tree_view->priv->width, allocation.width));
9884
9885   rect.y = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
9886   rect.height = gtk_tree_view_get_row_height (tree_view, node);
9887
9888   gdk_window_invalidate_rect (tree_view->priv->bin_window, &rect, TRUE);
9889 }
9890
9891 void
9892 _gtk_tree_view_queue_draw_node (GtkTreeView        *tree_view,
9893                                 GtkRBTree          *tree,
9894                                 GtkRBNode          *node,
9895                                 const GdkRectangle *clip_rect)
9896 {
9897   GtkAllocation allocation;
9898   GdkRectangle rect;
9899
9900   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
9901     return;
9902
9903   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
9904   rect.x = 0;
9905   rect.width = MAX (tree_view->priv->width, allocation.width);
9906
9907   rect.y = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
9908   rect.height = gtk_tree_view_get_row_height (tree_view, node);
9909
9910   if (clip_rect)
9911     {
9912       GdkRectangle new_rect;
9913
9914       gdk_rectangle_intersect (clip_rect, &rect, &new_rect);
9915
9916       gdk_window_invalidate_rect (tree_view->priv->bin_window, &new_rect, TRUE);
9917     }
9918   else
9919     {
9920       gdk_window_invalidate_rect (tree_view->priv->bin_window, &rect, TRUE);
9921     }
9922 }
9923
9924 static inline gint
9925 gtk_tree_view_get_effective_header_height (GtkTreeView *tree_view)
9926 {
9927   if (tree_view->priv->headers_visible)
9928     return tree_view->priv->header_height;
9929   /* else */
9930   return 0;
9931 }
9932
9933 gint
9934 _gtk_tree_view_get_header_height (GtkTreeView *tree_view)
9935 {
9936   return tree_view->priv->header_height;
9937 }
9938
9939 void
9940 _gtk_tree_view_get_row_separator_func (GtkTreeView                 *tree_view,
9941                                        GtkTreeViewRowSeparatorFunc *func,
9942                                        gpointer                    *data)
9943 {
9944   *func = tree_view->priv->row_separator_func;
9945   *data = tree_view->priv->row_separator_data;
9946 }
9947
9948 GtkTreePath *
9949 _gtk_tree_view_get_anchor_path (GtkTreeView *tree_view)
9950 {
9951   if (tree_view->priv->anchor)
9952     return gtk_tree_row_reference_get_path (tree_view->priv->anchor);
9953
9954   return NULL;
9955 }
9956
9957 void
9958 _gtk_tree_view_set_anchor_path (GtkTreeView *tree_view,
9959                                 GtkTreePath *anchor_path)
9960 {
9961   if (tree_view->priv->anchor)
9962     {
9963       gtk_tree_row_reference_free (tree_view->priv->anchor);
9964       tree_view->priv->anchor = NULL;
9965     }
9966
9967   if (anchor_path && tree_view->priv->model)
9968     tree_view->priv->anchor =
9969       gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), 
9970                                         tree_view->priv->model, anchor_path);
9971 }
9972
9973 GtkRBTree *
9974 _gtk_tree_view_get_rbtree (GtkTreeView *tree_view)
9975 {
9976   return tree_view->priv->tree;
9977 }
9978
9979 GdkWindow *
9980 _gtk_tree_view_get_header_window (GtkTreeView *tree_view)
9981 {
9982   return tree_view->priv->header_window;
9983 }
9984
9985 void
9986 _gtk_tree_view_set_focus_column (GtkTreeView       *tree_view,
9987                                  GtkTreeViewColumn *column)
9988 {
9989   tree_view->priv->focus_column = column;
9990 }
9991
9992
9993 static void
9994 gtk_tree_view_queue_draw_path (GtkTreeView        *tree_view,
9995                                GtkTreePath        *path,
9996                                const GdkRectangle *clip_rect)
9997 {
9998   GtkRBTree *tree = NULL;
9999   GtkRBNode *node = NULL;
10000
10001   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
10002
10003   if (tree)
10004     _gtk_tree_view_queue_draw_node (tree_view, tree, node, clip_rect);
10005 }
10006
10007 /* x and y are the mouse position
10008  */
10009 static void
10010 gtk_tree_view_draw_arrow (GtkTreeView *tree_view,
10011                           cairo_t     *cr,
10012                           GtkRBTree   *tree,
10013                           GtkRBNode   *node,
10014                           /* in bin_window coordinates */
10015                           gint         x,
10016                           gint         y)
10017 {
10018   GdkRectangle area;
10019   GtkStateFlags state = 0;
10020   GtkStyleContext *context;
10021   GtkWidget *widget;
10022   gint x_offset = 0;
10023   gint x2;
10024   gint vertical_separator;
10025   gint expander_size;
10026
10027   widget = GTK_WIDGET (tree_view);
10028   context = gtk_widget_get_style_context (widget);
10029
10030   gtk_widget_style_get (widget,
10031                         "vertical-separator", &vertical_separator,
10032                         NULL);
10033   expander_size = tree_view->priv->expander_size - EXPANDER_EXTRA_PADDING;
10034
10035   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
10036     return;
10037
10038   gtk_tree_view_get_arrow_xrange (tree_view, tree, &x_offset, &x2);
10039
10040   area.x = x_offset;
10041   area.y = gtk_tree_view_get_cell_area_y_offset (tree_view, tree, node,
10042                                                  vertical_separator);
10043   area.width = expander_size + 2;
10044   area.height = gtk_tree_view_get_cell_area_height (tree_view, node,
10045                                                     vertical_separator);
10046
10047   if (!gtk_widget_get_sensitive (widget))
10048     state |= GTK_STATE_FLAG_INSENSITIVE;
10049   else
10050     {
10051       if (node == tree_view->priv->button_pressed_node &&
10052           x >= area.x && x <= (area.x + area.width) &&
10053           y >= area.y && y <= (area.y + area.height))
10054         state |= GTK_STATE_FLAG_SELECTED;
10055
10056       if (node == tree_view->priv->prelight_node &&
10057           tree_view->priv->arrow_prelit)
10058         state |= GTK_STATE_FLAG_PRELIGHT;
10059     }
10060
10061   if (node->children != NULL)
10062     state |= GTK_STATE_FLAG_ACTIVE;
10063
10064   gtk_style_context_save (context);
10065
10066   gtk_style_context_set_state (context, state);
10067   gtk_style_context_add_class (context, GTK_STYLE_CLASS_EXPANDER);
10068
10069   gtk_style_context_push_animatable_region (context, node);
10070
10071   gtk_render_expander (context, cr,
10072                        area.x, area.y,
10073                        area.width, area.height);
10074
10075   gtk_style_context_pop_animatable_region (context);
10076   gtk_style_context_restore (context);
10077 }
10078
10079 static void
10080 gtk_tree_view_focus_to_cursor (GtkTreeView *tree_view)
10081
10082 {
10083   GtkTreePath *cursor_path;
10084
10085   if ((tree_view->priv->tree == NULL) ||
10086       (! gtk_widget_get_realized (GTK_WIDGET (tree_view))))
10087     return;
10088
10089   cursor_path = NULL;
10090   if (tree_view->priv->cursor)
10091     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10092
10093   if (cursor_path == NULL)
10094     {
10095       /* Consult the selection before defaulting to the
10096        * first focusable element
10097        */
10098       GList *selected_rows;
10099       GtkTreeModel *model;
10100       GtkTreeSelection *selection;
10101
10102       selection = gtk_tree_view_get_selection (tree_view);
10103       selected_rows = gtk_tree_selection_get_selected_rows (selection, &model);
10104
10105       if (selected_rows)
10106         {
10107           cursor_path = gtk_tree_path_copy((const GtkTreePath *)(selected_rows->data));
10108           g_list_foreach (selected_rows, (GFunc)gtk_tree_path_free, NULL);
10109           g_list_free (selected_rows);
10110         }
10111       else
10112         {
10113           cursor_path = gtk_tree_path_new_first ();
10114           search_first_focusable_path (tree_view, &cursor_path,
10115                                        TRUE, NULL, NULL);
10116         }
10117
10118       gtk_tree_row_reference_free (tree_view->priv->cursor);
10119       tree_view->priv->cursor = NULL;
10120
10121       if (cursor_path)
10122         {
10123           if (gtk_tree_selection_get_mode (tree_view->priv->selection) == GTK_SELECTION_MULTIPLE)
10124             gtk_tree_view_real_set_cursor (tree_view, cursor_path, FALSE, FALSE);
10125           else
10126             gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE);
10127         }
10128     }
10129
10130   if (cursor_path)
10131     {
10132       tree_view->priv->draw_keyfocus = TRUE;
10133
10134       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10135       gtk_tree_path_free (cursor_path);
10136
10137       if (tree_view->priv->focus_column == NULL)
10138         {
10139           GList *list;
10140           for (list = tree_view->priv->columns; list; list = list->next)
10141             {
10142               if (gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (list->data)))
10143                 {
10144                   GtkCellArea *cell_area;
10145
10146                   tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (list->data);
10147
10148                   /* This happens when the treeview initially grabs focus and there
10149                    * is no column in focus, here we explicitly focus into the first cell */
10150                   cell_area = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (tree_view->priv->focus_column));
10151                   if (!gtk_cell_area_get_focus_cell (cell_area))
10152                     {
10153                       gboolean rtl;
10154
10155                       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
10156                       gtk_cell_area_focus (cell_area,
10157                                            rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT);
10158                     }
10159
10160                   break;
10161                 }
10162             }
10163         }
10164     }
10165 }
10166
10167 static void
10168 gtk_tree_view_move_cursor_up_down (GtkTreeView *tree_view,
10169                                    gint         count)
10170 {
10171   gint selection_count;
10172   GtkRBTree *cursor_tree = NULL;
10173   GtkRBNode *cursor_node = NULL;
10174   GtkRBTree *new_cursor_tree = NULL;
10175   GtkRBNode *new_cursor_node = NULL;
10176   GtkTreePath *cursor_path = NULL;
10177   gboolean grab_focus = TRUE;
10178   gboolean selectable;
10179   GtkDirectionType direction;
10180   GtkCellArea *cell_area = NULL;
10181   GtkCellRenderer *last_focus_cell = NULL;
10182   GtkTreeIter iter;
10183
10184   if (! gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10185     return;
10186
10187   cursor_path = NULL;
10188   if (!gtk_tree_row_reference_valid (tree_view->priv->cursor))
10189     /* FIXME: we lost the cursor; should we get the first? */
10190     return;
10191
10192   cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10193   _gtk_tree_view_find_node (tree_view, cursor_path,
10194                             &cursor_tree, &cursor_node);
10195
10196   if (cursor_tree == NULL)
10197     /* FIXME: we lost the cursor; should we get the first? */
10198     return;
10199
10200   direction = count < 0 ? GTK_DIR_UP : GTK_DIR_DOWN;
10201
10202   if (tree_view->priv->focus_column)
10203     cell_area = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (tree_view->priv->focus_column));
10204
10205   /* If focus stays in the area for this row, then just return for this round */
10206   if (cell_area && (count == -1 || count == 1) &&
10207       gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path))
10208     {
10209       gtk_tree_view_column_cell_set_cell_data (tree_view->priv->focus_column,
10210                                                tree_view->priv->model,
10211                                                &iter,
10212                                                GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_PARENT),
10213                                                cursor_node->children?TRUE:FALSE);
10214
10215       /* Save the last cell that had focus, if we hit the end of the view we'll give
10216        * focus back to it. */
10217       last_focus_cell = gtk_cell_area_get_focus_cell (cell_area);
10218
10219       /* If focus stays in the area, no need to change the cursor row */
10220       if (gtk_cell_area_focus (cell_area, direction))
10221         return;
10222     }
10223
10224   selection_count = gtk_tree_selection_count_selected_rows (tree_view->priv->selection);
10225   selectable = _gtk_tree_selection_row_is_selectable (tree_view->priv->selection,
10226                                                       cursor_node,
10227                                                       cursor_path);
10228
10229   if (selection_count == 0
10230       && gtk_tree_selection_get_mode (tree_view->priv->selection) != GTK_SELECTION_NONE
10231       && !tree_view->priv->ctrl_pressed
10232       && selectable)
10233     {
10234       /* Don't move the cursor, but just select the current node */
10235       new_cursor_tree = cursor_tree;
10236       new_cursor_node = cursor_node;
10237     }
10238   else
10239     {
10240       if (count == -1)
10241         _gtk_rbtree_prev_full (cursor_tree, cursor_node,
10242                                &new_cursor_tree, &new_cursor_node);
10243       else
10244         _gtk_rbtree_next_full (cursor_tree, cursor_node,
10245                                &new_cursor_tree, &new_cursor_node);
10246     }
10247
10248   gtk_tree_path_free (cursor_path);
10249
10250   if (new_cursor_node)
10251     {
10252       cursor_path = _gtk_tree_view_find_path (tree_view,
10253                                               new_cursor_tree, new_cursor_node);
10254
10255       search_first_focusable_path (tree_view, &cursor_path,
10256                                    (count != -1),
10257                                    &new_cursor_tree,
10258                                    &new_cursor_node);
10259
10260       if (cursor_path)
10261         gtk_tree_path_free (cursor_path);
10262     }
10263
10264   /*
10265    * If the list has only one item and multi-selection is set then select
10266    * the row (if not yet selected).
10267    */
10268   if (gtk_tree_selection_get_mode (tree_view->priv->selection) == GTK_SELECTION_MULTIPLE &&
10269       new_cursor_node == NULL)
10270     {
10271       if (count == -1)
10272         _gtk_rbtree_next_full (cursor_tree, cursor_node,
10273                                &new_cursor_tree, &new_cursor_node);
10274       else
10275         _gtk_rbtree_prev_full (cursor_tree, cursor_node,
10276                                &new_cursor_tree, &new_cursor_node);
10277
10278       if (new_cursor_node == NULL
10279           && !GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_SELECTED))
10280         {
10281           new_cursor_node = cursor_node;
10282           new_cursor_tree = cursor_tree;
10283         }
10284       else
10285         {
10286           new_cursor_node = NULL;
10287         }
10288     }
10289
10290   if (new_cursor_node)
10291     {
10292       cursor_path = _gtk_tree_view_find_path (tree_view, new_cursor_tree, new_cursor_node);
10293       gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, TRUE);
10294       gtk_tree_path_free (cursor_path);
10295
10296       /* Give focus to the area in the new row */
10297       if (cell_area)
10298         gtk_cell_area_focus (cell_area, direction);
10299     }
10300   else
10301     {
10302       gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10303
10304       if (!tree_view->priv->shift_pressed)
10305         {
10306           if (! gtk_widget_keynav_failed (GTK_WIDGET (tree_view),
10307                                           count < 0 ?
10308                                           GTK_DIR_UP : GTK_DIR_DOWN))
10309             {
10310               GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (tree_view));
10311
10312               if (toplevel)
10313                 gtk_widget_child_focus (toplevel,
10314                                         count < 0 ?
10315                                         GTK_DIR_TAB_BACKWARD :
10316                                         GTK_DIR_TAB_FORWARD);
10317
10318               grab_focus = FALSE;
10319             }
10320         }
10321       else
10322         {
10323           gtk_widget_error_bell (GTK_WIDGET (tree_view));
10324         }
10325
10326       if (cell_area)
10327         gtk_cell_area_set_focus_cell (cell_area, last_focus_cell);
10328     }
10329
10330   if (grab_focus)
10331     gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10332 }
10333
10334 static void
10335 gtk_tree_view_move_cursor_page_up_down (GtkTreeView *tree_view,
10336                                         gint         count)
10337 {
10338   GtkRBTree *cursor_tree = NULL;
10339   GtkRBNode *cursor_node = NULL;
10340   GtkTreePath *old_cursor_path = NULL;
10341   GtkTreePath *cursor_path = NULL;
10342   GtkRBTree *start_cursor_tree = NULL;
10343   GtkRBNode *start_cursor_node = NULL;
10344   gint y;
10345   gint window_y;
10346   gint vertical_separator;
10347
10348   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10349     return;
10350
10351   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
10352     old_cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10353   else
10354     /* This is sorta weird.  Focus in should give us a cursor */
10355     return;
10356
10357   gtk_widget_style_get (GTK_WIDGET (tree_view), "vertical-separator", &vertical_separator, NULL);
10358   _gtk_tree_view_find_node (tree_view, old_cursor_path,
10359                             &cursor_tree, &cursor_node);
10360
10361   if (cursor_tree == NULL)
10362     {
10363       /* FIXME: we lost the cursor.  Should we try to get one? */
10364       gtk_tree_path_free (old_cursor_path);
10365       return;
10366     }
10367   g_return_if_fail (cursor_node != NULL);
10368
10369   y = _gtk_rbtree_node_find_offset (cursor_tree, cursor_node);
10370   window_y = RBTREE_Y_TO_TREE_WINDOW_Y (tree_view, y);
10371   y += tree_view->priv->cursor_offset;
10372   y += count * (int)gtk_adjustment_get_page_increment (tree_view->priv->vadjustment);
10373   y = CLAMP (y, (gint)gtk_adjustment_get_lower (tree_view->priv->vadjustment),  (gint)gtk_adjustment_get_upper (tree_view->priv->vadjustment) - vertical_separator);
10374
10375   if (y >= tree_view->priv->height)
10376     y = tree_view->priv->height - 1;
10377
10378   tree_view->priv->cursor_offset =
10379     _gtk_rbtree_find_offset (tree_view->priv->tree, y,
10380                              &cursor_tree, &cursor_node);
10381
10382   if (cursor_tree == NULL)
10383     {
10384       /* FIXME: we lost the cursor.  Should we try to get one? */
10385       gtk_tree_path_free (old_cursor_path);
10386       return;
10387     }
10388
10389   if (tree_view->priv->cursor_offset
10390       > gtk_tree_view_get_row_height (tree_view, cursor_node))
10391     {
10392       _gtk_rbtree_next_full (cursor_tree, cursor_node,
10393                              &cursor_tree, &cursor_node);
10394       tree_view->priv->cursor_offset -= gtk_tree_view_get_row_height (tree_view, cursor_node);
10395     }
10396
10397   y -= tree_view->priv->cursor_offset;
10398   cursor_path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
10399
10400   start_cursor_tree = cursor_tree;
10401   start_cursor_node = cursor_node;
10402
10403   if (! search_first_focusable_path (tree_view, &cursor_path,
10404                                      (count != -1),
10405                                      &cursor_tree, &cursor_node))
10406     {
10407       /* It looks like we reached the end of the view without finding
10408        * a focusable row.  We will step backwards to find the last
10409        * focusable row.
10410        */
10411       cursor_tree = start_cursor_tree;
10412       cursor_node = start_cursor_node;
10413       cursor_path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
10414
10415       search_first_focusable_path (tree_view, &cursor_path,
10416                                    (count == -1),
10417                                    &cursor_tree, &cursor_node);
10418     }
10419
10420   if (!cursor_path)
10421     goto cleanup;
10422
10423   /* update y */
10424   y = _gtk_rbtree_node_find_offset (cursor_tree, cursor_node);
10425
10426   gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE);
10427
10428   y -= window_y;
10429   gtk_tree_view_scroll_to_point (tree_view, -1, y);
10430   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10431   _gtk_tree_view_queue_draw_node (tree_view, cursor_tree, cursor_node, NULL);
10432
10433   if (!gtk_tree_path_compare (old_cursor_path, cursor_path))
10434     gtk_widget_error_bell (GTK_WIDGET (tree_view));
10435
10436   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10437
10438 cleanup:
10439   gtk_tree_path_free (old_cursor_path);
10440   gtk_tree_path_free (cursor_path);
10441 }
10442
10443 static void
10444 gtk_tree_view_move_cursor_left_right (GtkTreeView *tree_view,
10445                                       gint         count)
10446 {
10447   GtkRBTree *cursor_tree = NULL;
10448   GtkRBNode *cursor_node = NULL;
10449   GtkTreePath *cursor_path = NULL;
10450   GtkTreeViewColumn *column;
10451   GtkTreeIter iter;
10452   GList *list;
10453   gboolean found_column = FALSE;
10454   gboolean rtl;
10455   GtkDirectionType direction;
10456   GtkCellArea     *cell_area;
10457   GtkCellRenderer *last_focus_cell = NULL;
10458   GtkCellArea     *last_focus_area = NULL;
10459
10460   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
10461
10462   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10463     return;
10464
10465   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
10466     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10467   else
10468     return;
10469
10470   _gtk_tree_view_find_node (tree_view, cursor_path, &cursor_tree, &cursor_node);
10471   if (cursor_tree == NULL)
10472     return;
10473   if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path) == FALSE)
10474     {
10475       gtk_tree_path_free (cursor_path);
10476       return;
10477     }
10478   gtk_tree_path_free (cursor_path);
10479
10480   list = rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns);
10481   if (tree_view->priv->focus_column)
10482     {
10483       /* Save the cell/area we are moving focus from, if moving the cursor
10484        * by one step hits the end we'll set focus back here */
10485       last_focus_area = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (tree_view->priv->focus_column));
10486       last_focus_cell = gtk_cell_area_get_focus_cell (last_focus_area);
10487
10488       for (; list; list = (rtl ? list->prev : list->next))
10489         {
10490           if (list->data == tree_view->priv->focus_column)
10491             break;
10492         }
10493     }
10494
10495   direction = count > 0 ? GTK_DIR_RIGHT : GTK_DIR_LEFT;
10496
10497   while (list)
10498     {
10499       column = list->data;
10500       if (gtk_tree_view_column_get_visible (column) == FALSE)
10501         goto loop_end;
10502
10503       gtk_tree_view_column_cell_set_cell_data (column,
10504                                                tree_view->priv->model,
10505                                                &iter,
10506                                                GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_PARENT),
10507                                                cursor_node->children?TRUE:FALSE);
10508
10509       cell_area = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (column));
10510       if (gtk_cell_area_focus (cell_area, direction))
10511         {
10512           tree_view->priv->focus_column = column;
10513           found_column = TRUE;
10514           break;
10515         }
10516
10517     loop_end:
10518       if (count == 1)
10519         list = rtl ? list->prev : list->next;
10520       else
10521         list = rtl ? list->next : list->prev;
10522     }
10523
10524   if (found_column)
10525     {
10526       if (!gtk_tree_view_has_can_focus_cell (tree_view))
10527         _gtk_tree_view_queue_draw_node (tree_view,
10528                                         cursor_tree,
10529                                         cursor_node,
10530                                         NULL);
10531       g_signal_emit (tree_view, tree_view_signals[CURSOR_CHANGED], 0);
10532       gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10533     }
10534   else
10535     {
10536       gtk_widget_error_bell (GTK_WIDGET (tree_view));
10537
10538       if (last_focus_area)
10539         gtk_cell_area_set_focus_cell (last_focus_area, last_focus_cell);
10540     }
10541
10542   gtk_tree_view_clamp_column_visible (tree_view,
10543                                       tree_view->priv->focus_column, TRUE);
10544 }
10545
10546 static void
10547 gtk_tree_view_move_cursor_start_end (GtkTreeView *tree_view,
10548                                      gint         count)
10549 {
10550   GtkRBTree *cursor_tree;
10551   GtkRBNode *cursor_node;
10552   GtkTreePath *path;
10553   GtkTreePath *old_path;
10554
10555   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10556     return;
10557
10558   g_return_if_fail (tree_view->priv->tree != NULL);
10559
10560   gtk_tree_view_get_cursor (tree_view, &old_path, NULL);
10561
10562   cursor_tree = tree_view->priv->tree;
10563   cursor_node = cursor_tree->root;
10564
10565   if (count == -1)
10566     {
10567       while (cursor_node && cursor_node->left != cursor_tree->nil)
10568         cursor_node = cursor_node->left;
10569
10570       /* Now go forward to find the first focusable row. */
10571       path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
10572       search_first_focusable_path (tree_view, &path,
10573                                    TRUE, &cursor_tree, &cursor_node);
10574     }
10575   else
10576     {
10577       do
10578         {
10579           while (cursor_node && cursor_node->right != cursor_tree->nil)
10580             cursor_node = cursor_node->right;
10581           if (cursor_node->children == NULL)
10582             break;
10583
10584           cursor_tree = cursor_node->children;
10585           cursor_node = cursor_tree->root;
10586         }
10587       while (1);
10588
10589       /* Now go backwards to find last focusable row. */
10590       path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
10591       search_first_focusable_path (tree_view, &path,
10592                                    FALSE, &cursor_tree, &cursor_node);
10593     }
10594
10595   if (!path)
10596     goto cleanup;
10597
10598   if (gtk_tree_path_compare (old_path, path))
10599     {
10600       gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
10601       gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10602     }
10603   else
10604     {
10605       gtk_widget_error_bell (GTK_WIDGET (tree_view));
10606     }
10607
10608 cleanup:
10609   gtk_tree_path_free (old_path);
10610   gtk_tree_path_free (path);
10611 }
10612
10613 static gboolean
10614 gtk_tree_view_real_select_all (GtkTreeView *tree_view)
10615 {
10616   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10617     return FALSE;
10618
10619   if (gtk_tree_selection_get_mode (tree_view->priv->selection) != GTK_SELECTION_MULTIPLE)
10620     return FALSE;
10621
10622   gtk_tree_selection_select_all (tree_view->priv->selection);
10623
10624   return TRUE;
10625 }
10626
10627 static gboolean
10628 gtk_tree_view_real_unselect_all (GtkTreeView *tree_view)
10629 {
10630   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10631     return FALSE;
10632
10633   if (gtk_tree_selection_get_mode (tree_view->priv->selection) != GTK_SELECTION_MULTIPLE)
10634     return FALSE;
10635
10636   gtk_tree_selection_unselect_all (tree_view->priv->selection);
10637
10638   return TRUE;
10639 }
10640
10641 static gboolean
10642 gtk_tree_view_real_select_cursor_row (GtkTreeView *tree_view,
10643                                       gboolean     start_editing)
10644 {
10645   GtkRBTree *new_tree = NULL;
10646   GtkRBNode *new_node = NULL;
10647   GtkRBTree *cursor_tree = NULL;
10648   GtkRBNode *cursor_node = NULL;
10649   GtkTreePath *cursor_path = NULL;
10650   GtkTreeSelectMode mode = 0;
10651
10652   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10653     return FALSE;
10654
10655   if (tree_view->priv->cursor)
10656     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10657
10658   if (cursor_path == NULL)
10659     return FALSE;
10660
10661   _gtk_tree_view_find_node (tree_view, cursor_path,
10662                             &cursor_tree, &cursor_node);
10663
10664   if (cursor_tree == NULL)
10665     {
10666       gtk_tree_path_free (cursor_path);
10667       return FALSE;
10668     }
10669
10670   if (!tree_view->priv->shift_pressed && start_editing &&
10671       tree_view->priv->focus_column)
10672     {
10673       if (gtk_tree_view_start_editing (tree_view, cursor_path, FALSE))
10674         {
10675           gtk_tree_path_free (cursor_path);
10676           return TRUE;
10677         }
10678     }
10679
10680   if (tree_view->priv->ctrl_pressed)
10681     mode |= GTK_TREE_SELECT_MODE_TOGGLE;
10682   if (tree_view->priv->shift_pressed)
10683     mode |= GTK_TREE_SELECT_MODE_EXTEND;
10684
10685   _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
10686                                             cursor_node,
10687                                             cursor_tree,
10688                                             cursor_path,
10689                                             mode,
10690                                             FALSE);
10691
10692   /* We bail out if the original (tree, node) don't exist anymore after
10693    * handling the selection-changed callback.  We do return TRUE because
10694    * the key press has been handled at this point.
10695    */
10696   _gtk_tree_view_find_node (tree_view, cursor_path, &new_tree, &new_node);
10697
10698   if (cursor_tree != new_tree || cursor_node != new_node)
10699     return FALSE;
10700
10701   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10702
10703   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10704   _gtk_tree_view_queue_draw_node (tree_view, cursor_tree, cursor_node, NULL);
10705
10706   if (!tree_view->priv->shift_pressed)
10707     gtk_tree_view_row_activated (tree_view, cursor_path,
10708                                  tree_view->priv->focus_column);
10709     
10710   gtk_tree_path_free (cursor_path);
10711
10712   return TRUE;
10713 }
10714
10715 static gboolean
10716 gtk_tree_view_real_toggle_cursor_row (GtkTreeView *tree_view)
10717 {
10718   GtkRBTree *new_tree = NULL;
10719   GtkRBNode *new_node = NULL;
10720   GtkRBTree *cursor_tree = NULL;
10721   GtkRBNode *cursor_node = NULL;
10722   GtkTreePath *cursor_path = NULL;
10723
10724   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10725     return FALSE;
10726
10727   cursor_path = NULL;
10728   if (tree_view->priv->cursor)
10729     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10730
10731   if (cursor_path == NULL)
10732     return FALSE;
10733
10734   _gtk_tree_view_find_node (tree_view, cursor_path,
10735                             &cursor_tree, &cursor_node);
10736   if (cursor_tree == NULL)
10737     {
10738       gtk_tree_path_free (cursor_path);
10739       return FALSE;
10740     }
10741
10742   _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
10743                                             cursor_node,
10744                                             cursor_tree,
10745                                             cursor_path,
10746                                             GTK_TREE_SELECT_MODE_TOGGLE,
10747                                             FALSE);
10748
10749   /* We bail out if the original (tree, node) don't exist anymore after
10750    * handling the selection-changed callback.  We do return TRUE because
10751    * the key press has been handled at this point.
10752    */
10753   _gtk_tree_view_find_node (tree_view, cursor_path, &new_tree, &new_node);
10754
10755   if (cursor_tree != new_tree || cursor_node != new_node)
10756     return FALSE;
10757
10758   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10759
10760   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10761   gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10762   gtk_tree_path_free (cursor_path);
10763
10764   return TRUE;
10765 }
10766
10767 static gboolean
10768 gtk_tree_view_real_expand_collapse_cursor_row (GtkTreeView *tree_view,
10769                                                gboolean     logical,
10770                                                gboolean     expand,
10771                                                gboolean     open_all)
10772 {
10773   GtkTreePath *cursor_path = NULL;
10774   GtkRBTree *tree;
10775   GtkRBNode *node;
10776
10777   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10778     return FALSE;
10779
10780   cursor_path = NULL;
10781   if (tree_view->priv->cursor)
10782     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10783
10784   if (cursor_path == NULL)
10785     return FALSE;
10786
10787   if (_gtk_tree_view_find_node (tree_view, cursor_path, &tree, &node))
10788     return FALSE;
10789
10790   /* Don't handle the event if we aren't an expander */
10791   if (!((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT))
10792     return FALSE;
10793
10794   if (!logical
10795       && gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL)
10796     expand = !expand;
10797
10798   if (expand)
10799     gtk_tree_view_real_expand_row (tree_view, cursor_path, tree, node, open_all, TRUE);
10800   else
10801     gtk_tree_view_real_collapse_row (tree_view, cursor_path, tree, node, TRUE);
10802
10803   gtk_tree_path_free (cursor_path);
10804
10805   return TRUE;
10806 }
10807
10808 static gboolean
10809 gtk_tree_view_real_select_cursor_parent (GtkTreeView *tree_view)
10810 {
10811   GtkRBTree *cursor_tree = NULL;
10812   GtkRBNode *cursor_node = NULL;
10813   GtkTreePath *cursor_path = NULL;
10814   GdkModifierType state;
10815
10816   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10817     goto out;
10818
10819   cursor_path = NULL;
10820   if (tree_view->priv->cursor)
10821     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10822
10823   if (cursor_path == NULL)
10824     goto out;
10825
10826   _gtk_tree_view_find_node (tree_view, cursor_path,
10827                             &cursor_tree, &cursor_node);
10828   if (cursor_tree == NULL)
10829     {
10830       gtk_tree_path_free (cursor_path);
10831       goto out;
10832     }
10833
10834   if (cursor_tree->parent_node)
10835     {
10836       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10837       cursor_node = cursor_tree->parent_node;
10838       cursor_tree = cursor_tree->parent_tree;
10839
10840       gtk_tree_path_up (cursor_path);
10841
10842       if (gtk_get_current_event_state (&state))
10843         {
10844           if ((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
10845             tree_view->priv->ctrl_pressed = TRUE;
10846         }
10847
10848       gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE);
10849       gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10850
10851       gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10852       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10853       gtk_tree_path_free (cursor_path);
10854
10855       tree_view->priv->ctrl_pressed = FALSE;
10856
10857       return TRUE;
10858     }
10859
10860  out:
10861
10862   tree_view->priv->search_entry_avoid_unhandled_binding = TRUE;
10863   return FALSE;
10864 }
10865
10866 static gboolean
10867 gtk_tree_view_search_entry_flush_timeout (GtkTreeView *tree_view)
10868 {
10869   gtk_tree_view_search_dialog_hide (tree_view->priv->search_window, tree_view, NULL);
10870   tree_view->priv->typeselect_flush_timeout = 0;
10871
10872   return FALSE;
10873 }
10874
10875 /* Cut and paste from gtkwindow.c */
10876 static void
10877 send_focus_change (GtkWidget *widget,
10878                    GdkDevice *device,
10879                    gboolean   in)
10880 {
10881   GdkDeviceManager *device_manager;
10882   GList *devices, *d;
10883
10884   device_manager = gdk_display_get_device_manager (gtk_widget_get_display (widget));
10885   devices = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER);
10886   devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_SLAVE));
10887   devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_FLOATING));
10888
10889   for (d = devices; d; d = d->next)
10890     {
10891       GdkDevice *dev = d->data;
10892       GdkEvent *fevent;
10893       GdkWindow *window;
10894
10895       if (gdk_device_get_source (dev) != GDK_SOURCE_KEYBOARD)
10896         continue;
10897
10898       window = gtk_widget_get_window (widget);
10899
10900       /* Skip non-master keyboards that haven't
10901        * selected for events from this window
10902        */
10903       if (gdk_device_get_device_type (dev) != GDK_DEVICE_TYPE_MASTER &&
10904           !gdk_window_get_device_events (window, dev))
10905         continue;
10906
10907       fevent = gdk_event_new (GDK_FOCUS_CHANGE);
10908
10909       fevent->focus_change.type = GDK_FOCUS_CHANGE;
10910       fevent->focus_change.window = g_object_ref (window);
10911       fevent->focus_change.in = in;
10912       gdk_event_set_device (fevent, device);
10913
10914       gtk_widget_send_focus_change (widget, fevent);
10915
10916       gdk_event_free (fevent);
10917     }
10918 }
10919
10920 static void
10921 gtk_tree_view_ensure_interactive_directory (GtkTreeView *tree_view)
10922 {
10923   GtkWidget *frame, *vbox, *toplevel;
10924   GdkScreen *screen;
10925
10926   if (tree_view->priv->search_custom_entry_set)
10927     return;
10928
10929   toplevel = gtk_widget_get_toplevel (GTK_WIDGET (tree_view));
10930   screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
10931
10932    if (tree_view->priv->search_window != NULL)
10933      {
10934        if (gtk_window_has_group (GTK_WINDOW (toplevel)))
10935          gtk_window_group_add_window (gtk_window_get_group (GTK_WINDOW (toplevel)),
10936                                       GTK_WINDOW (tree_view->priv->search_window));
10937        else if (gtk_window_has_group (GTK_WINDOW (tree_view->priv->search_window)))
10938          gtk_window_group_remove_window (gtk_window_get_group (GTK_WINDOW (tree_view->priv->search_window)),
10939                                          GTK_WINDOW (tree_view->priv->search_window));
10940
10941        gtk_window_set_screen (GTK_WINDOW (tree_view->priv->search_window), screen);
10942
10943        return;
10944      }
10945    
10946   tree_view->priv->search_window = gtk_window_new (GTK_WINDOW_POPUP);
10947   gtk_window_set_screen (GTK_WINDOW (tree_view->priv->search_window), screen);
10948
10949   if (gtk_window_has_group (GTK_WINDOW (toplevel)))
10950     gtk_window_group_add_window (gtk_window_get_group (GTK_WINDOW (toplevel)),
10951                                  GTK_WINDOW (tree_view->priv->search_window));
10952
10953   gtk_window_set_type_hint (GTK_WINDOW (tree_view->priv->search_window),
10954                             GDK_WINDOW_TYPE_HINT_UTILITY);
10955   gtk_window_set_modal (GTK_WINDOW (tree_view->priv->search_window), TRUE);
10956   g_signal_connect (tree_view->priv->search_window, "delete-event",
10957                     G_CALLBACK (gtk_tree_view_search_delete_event),
10958                     tree_view);
10959   g_signal_connect (tree_view->priv->search_window, "key-press-event",
10960                     G_CALLBACK (gtk_tree_view_search_key_press_event),
10961                     tree_view);
10962   g_signal_connect (tree_view->priv->search_window, "button-press-event",
10963                     G_CALLBACK (gtk_tree_view_search_button_press_event),
10964                     tree_view);
10965   g_signal_connect (tree_view->priv->search_window, "scroll-event",
10966                     G_CALLBACK (gtk_tree_view_search_scroll_event),
10967                     tree_view);
10968
10969   frame = gtk_frame_new (NULL);
10970   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
10971   gtk_widget_show (frame);
10972   gtk_container_add (GTK_CONTAINER (tree_view->priv->search_window), frame);
10973
10974   vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
10975   gtk_widget_show (vbox);
10976   gtk_container_add (GTK_CONTAINER (frame), vbox);
10977   gtk_container_set_border_width (GTK_CONTAINER (vbox), 3);
10978
10979   /* add entry */
10980   tree_view->priv->search_entry = gtk_entry_new ();
10981   gtk_widget_show (tree_view->priv->search_entry);
10982   g_signal_connect (tree_view->priv->search_entry, "populate-popup",
10983                     G_CALLBACK (gtk_tree_view_search_disable_popdown),
10984                     tree_view);
10985   g_signal_connect (tree_view->priv->search_entry,
10986                     "activate", G_CALLBACK (gtk_tree_view_search_activate),
10987                     tree_view);
10988
10989   g_signal_connect (_gtk_entry_get_im_context (GTK_ENTRY (tree_view->priv->search_entry)),
10990                     "preedit-changed",
10991                     G_CALLBACK (gtk_tree_view_search_preedit_changed),
10992                     tree_view);
10993
10994   gtk_container_add (GTK_CONTAINER (vbox),
10995                      tree_view->priv->search_entry);
10996
10997   gtk_widget_realize (tree_view->priv->search_entry);
10998 }
10999
11000 /* Pops up the interactive search entry.  If keybinding is TRUE then the user
11001  * started this by typing the start_interactive_search keybinding.  Otherwise, it came from 
11002  */
11003 static gboolean
11004 gtk_tree_view_real_start_interactive_search (GtkTreeView *tree_view,
11005                                              GdkDevice   *device,
11006                                              gboolean     keybinding)
11007 {
11008   /* We only start interactive search if we have focus or the columns
11009    * have focus.  If one of our children have focus, we don't want to
11010    * start the search.
11011    */
11012   GList *list;
11013   gboolean found_focus = FALSE;
11014   GtkWidgetClass *entry_parent_class;
11015   
11016   if (!tree_view->priv->enable_search && !keybinding)
11017     return FALSE;
11018
11019   if (tree_view->priv->search_custom_entry_set)
11020     return FALSE;
11021
11022   if (tree_view->priv->search_window != NULL &&
11023       gtk_widget_get_visible (tree_view->priv->search_window))
11024     return TRUE;
11025
11026   for (list = tree_view->priv->columns; list; list = list->next)
11027     {
11028       GtkTreeViewColumn *column;
11029       GtkWidget         *button;
11030
11031       column = list->data;
11032       if (!gtk_tree_view_column_get_visible (column))
11033         continue;
11034
11035       button = gtk_tree_view_column_get_button (column);
11036       if (gtk_widget_has_focus (button))
11037         {
11038           found_focus = TRUE;
11039           break;
11040         }
11041     }
11042   
11043   if (gtk_widget_has_focus (GTK_WIDGET (tree_view)))
11044     found_focus = TRUE;
11045
11046   if (!found_focus)
11047     return FALSE;
11048
11049   if (tree_view->priv->search_column < 0)
11050     return FALSE;
11051
11052   gtk_tree_view_ensure_interactive_directory (tree_view);
11053
11054   if (keybinding)
11055     gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
11056
11057   /* done, show it */
11058   tree_view->priv->search_position_func (tree_view, tree_view->priv->search_window, tree_view->priv->search_position_user_data);
11059   gtk_widget_show (tree_view->priv->search_window);
11060   if (tree_view->priv->search_entry_changed_id == 0)
11061     {
11062       tree_view->priv->search_entry_changed_id =
11063         g_signal_connect (tree_view->priv->search_entry, "changed",
11064                           G_CALLBACK (gtk_tree_view_search_init),
11065                           tree_view);
11066     }
11067
11068   tree_view->priv->typeselect_flush_timeout =
11069     gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
11070                    (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
11071                    tree_view);
11072
11073   /* Grab focus will select all the text.  We don't want that to happen, so we
11074    * call the parent instance and bypass the selection change.  This is probably
11075    * really non-kosher. */
11076   entry_parent_class = g_type_class_peek_parent (GTK_ENTRY_GET_CLASS (tree_view->priv->search_entry));
11077   (entry_parent_class->grab_focus) (tree_view->priv->search_entry);
11078
11079   /* send focus-in event */
11080   send_focus_change (tree_view->priv->search_entry, device, TRUE);
11081
11082   /* search first matching iter */
11083   gtk_tree_view_search_init (tree_view->priv->search_entry, tree_view);
11084
11085   return TRUE;
11086 }
11087
11088 static gboolean
11089 gtk_tree_view_start_interactive_search (GtkTreeView *tree_view)
11090 {
11091   return gtk_tree_view_real_start_interactive_search (tree_view,
11092                                                       gtk_get_current_event_device (),
11093                                                       TRUE);
11094 }
11095
11096 /* this function returns the new width of the column being resized given
11097  * the column and x position of the cursor; the x cursor position is passed
11098  * in as a pointer and automagicly corrected if it's beyond min/max limits
11099  */
11100 static gint
11101 gtk_tree_view_new_column_width (GtkTreeView *tree_view,
11102                                 gint       i,
11103                                 gint      *x)
11104 {
11105   GtkAllocation allocation;
11106   GtkTreeViewColumn *column;
11107   GtkRequisition button_req;
11108   gint max_width, min_width;
11109   gint width;
11110   gboolean rtl;
11111
11112   /* first translate the x position from widget->window
11113    * to clist->clist_window
11114    */
11115   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
11116   column = g_list_nth (tree_view->priv->columns, i)->data;
11117   gtk_widget_get_allocation (gtk_tree_view_column_get_button (column), &allocation);
11118   width = rtl ? (allocation.x + allocation.width - *x) : (*x - allocation.x);
11119
11120   /* Clamp down the value */
11121   min_width = gtk_tree_view_column_get_min_width (column);
11122   if (min_width == -1)
11123     {
11124       gtk_widget_get_preferred_size (gtk_tree_view_column_get_button (column), &button_req, NULL);
11125       width = MAX (button_req.width, width);
11126     }
11127   else
11128     width = MAX (min_width, width);
11129
11130   max_width = gtk_tree_view_column_get_max_width (column);
11131   if (max_width != -1)
11132     width = MIN (width, max_width);
11133
11134   *x = rtl ? (allocation.x + allocation.width - width) : (allocation.x + width);
11135
11136   return width;
11137 }
11138
11139
11140 /* FIXME this adjust_allocation is a big cut-and-paste from
11141  * GtkCList, needs to be some "official" way to do this
11142  * factored out.
11143  */
11144 typedef struct
11145 {
11146   GdkWindow *window;
11147   int dx;
11148   int dy;
11149 } ScrollData;
11150
11151 /* The window to which widget->window is relative */
11152 #define ALLOCATION_WINDOW(widget)               \
11153    (!gtk_widget_get_has_window (widget) ?                   \
11154     gtk_widget_get_window (widget) :                        \
11155     gdk_window_get_parent (gtk_widget_get_window (widget)))
11156
11157 static void
11158 adjust_allocation_recurse (GtkWidget *widget,
11159                            gpointer   data)
11160 {
11161   GtkAllocation allocation;
11162   ScrollData *scroll_data = data;
11163
11164   /* Need to really size allocate instead of just poking
11165    * into widget->allocation if the widget is not realized.
11166    * FIXME someone figure out why this was.
11167    */
11168   gtk_widget_get_allocation (widget, &allocation);
11169   if (!gtk_widget_get_realized (widget))
11170     {
11171       if (gtk_widget_get_visible (widget))
11172         {
11173           GdkRectangle tmp_rectangle = allocation;
11174           tmp_rectangle.x += scroll_data->dx;
11175           tmp_rectangle.y += scroll_data->dy;
11176           
11177           gtk_widget_size_allocate (widget, &tmp_rectangle);
11178         }
11179     }
11180   else
11181     {
11182       if (ALLOCATION_WINDOW (widget) == scroll_data->window)
11183         {
11184           allocation.x += scroll_data->dx;
11185           allocation.y += scroll_data->dy;
11186           gtk_widget_set_allocation (widget, &allocation);
11187
11188           if (GTK_IS_CONTAINER (widget))
11189             gtk_container_forall (GTK_CONTAINER (widget),
11190                                   adjust_allocation_recurse,
11191                                   data);
11192         }
11193     }
11194 }
11195
11196 static void
11197 adjust_allocation (GtkWidget *widget,
11198                    int        dx,
11199                    int        dy)
11200 {
11201   ScrollData scroll_data;
11202
11203   if (gtk_widget_get_realized (widget))
11204     scroll_data.window = ALLOCATION_WINDOW (widget);
11205   else
11206     scroll_data.window = NULL;
11207     
11208   scroll_data.dx = dx;
11209   scroll_data.dy = dy;
11210   
11211   adjust_allocation_recurse (widget, &scroll_data);
11212 }
11213
11214 /* Callbacks */
11215 static void
11216 gtk_tree_view_adjustment_changed (GtkAdjustment *adjustment,
11217                                   GtkTreeView   *tree_view)
11218 {
11219   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11220     {
11221       GtkStyleContext *context;
11222       gint dy;
11223         
11224       gdk_window_move (tree_view->priv->bin_window,
11225                        - gtk_adjustment_get_value (tree_view->priv->hadjustment),
11226                        gtk_tree_view_get_effective_header_height (tree_view));
11227       gdk_window_move (tree_view->priv->header_window,
11228                        - gtk_adjustment_get_value (tree_view->priv->hadjustment),
11229                        0);
11230       dy = tree_view->priv->dy - (int) gtk_adjustment_get_value (tree_view->priv->vadjustment);
11231       if (dy)
11232         {
11233           update_prelight (tree_view,
11234                            tree_view->priv->event_last_x,
11235                            tree_view->priv->event_last_y - dy);
11236
11237           if (tree_view->priv->edited_column)
11238             {
11239               GList *list;
11240               GtkTreeViewChild *child = NULL;
11241               GtkCellEditable *edit_widget;
11242               GtkCellArea *area;
11243
11244               area        = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (tree_view->priv->edited_column));
11245               edit_widget = gtk_cell_area_get_edit_widget (area);
11246               if (GTK_IS_WIDGET (edit_widget))
11247                 {
11248                   adjust_allocation (GTK_WIDGET (edit_widget), 0, dy);
11249
11250                   for (list = tree_view->priv->children; list; list = list->next)
11251                     {
11252                       child = (GtkTreeViewChild *)list->data;
11253                       if (child->widget == GTK_WIDGET (edit_widget))
11254                         {
11255                           child->y += dy;
11256                           break;
11257                         }
11258                     }
11259                 }
11260             }
11261         }
11262       gdk_window_scroll (tree_view->priv->bin_window, 0, dy);
11263
11264       context = gtk_widget_get_style_context (GTK_WIDGET (tree_view));
11265       gtk_style_context_scroll_animations (context, tree_view->priv->bin_window, 0, dy);
11266
11267       if (tree_view->priv->dy != (int) gtk_adjustment_get_value (tree_view->priv->vadjustment))
11268         {
11269           /* update our dy and top_row */
11270           tree_view->priv->dy = (int) gtk_adjustment_get_value (tree_view->priv->vadjustment);
11271
11272           if (!tree_view->priv->in_top_row_to_dy)
11273             gtk_tree_view_dy_to_top_row (tree_view);
11274         }
11275
11276       gdk_window_process_updates (tree_view->priv->header_window, TRUE);
11277       gtk_tree_view_bin_process_updates (tree_view);
11278     }
11279 }
11280
11281 \f
11282
11283 /* Public methods
11284  */
11285
11286 /**
11287  * gtk_tree_view_new:
11288  *
11289  * Creates a new #GtkTreeView widget.
11290  *
11291  * Return value: A newly created #GtkTreeView widget.
11292  **/
11293 GtkWidget *
11294 gtk_tree_view_new (void)
11295 {
11296   return g_object_new (GTK_TYPE_TREE_VIEW, NULL);
11297 }
11298
11299 /**
11300  * gtk_tree_view_new_with_model:
11301  * @model: the model.
11302  *
11303  * Creates a new #GtkTreeView widget with the model initialized to @model.
11304  *
11305  * Return value: A newly created #GtkTreeView widget.
11306  **/
11307 GtkWidget *
11308 gtk_tree_view_new_with_model (GtkTreeModel *model)
11309 {
11310   return g_object_new (GTK_TYPE_TREE_VIEW, "model", model, NULL);
11311 }
11312
11313 /* Public Accessors
11314  */
11315
11316 /**
11317  * gtk_tree_view_get_model:
11318  * @tree_view: a #GtkTreeView
11319  *
11320  * Returns the model the #GtkTreeView is based on.  Returns %NULL if the
11321  * model is unset.
11322  *
11323  * Return value: (transfer none): A #GtkTreeModel, or %NULL if none is currently being used.
11324  **/
11325 GtkTreeModel *
11326 gtk_tree_view_get_model (GtkTreeView *tree_view)
11327 {
11328   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11329
11330   return tree_view->priv->model;
11331 }
11332
11333 /**
11334  * gtk_tree_view_set_model:
11335  * @tree_view: A #GtkTreeNode.
11336  * @model: (allow-none): The model.
11337  *
11338  * Sets the model for a #GtkTreeView.  If the @tree_view already has a model
11339  * set, it will remove it before setting the new model.  If @model is %NULL,
11340  * then it will unset the old model.
11341  **/
11342 void
11343 gtk_tree_view_set_model (GtkTreeView  *tree_view,
11344                          GtkTreeModel *model)
11345 {
11346   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11347   g_return_if_fail (model == NULL || GTK_IS_TREE_MODEL (model));
11348
11349   if (model == tree_view->priv->model)
11350     return;
11351
11352   if (tree_view->priv->scroll_to_path)
11353     {
11354       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
11355       tree_view->priv->scroll_to_path = NULL;
11356     }
11357
11358   if (tree_view->priv->model)
11359     {
11360       GList *tmplist = tree_view->priv->columns;
11361       GtkStyleContext *context;
11362
11363       gtk_tree_view_unref_and_check_selection_tree (tree_view, tree_view->priv->tree);
11364       gtk_tree_view_stop_editing (tree_view, TRUE);
11365
11366       context = gtk_widget_get_style_context (GTK_WIDGET (tree_view));
11367       gtk_style_context_cancel_animations (context, NULL);
11368
11369       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
11370                                             gtk_tree_view_row_changed,
11371                                             tree_view);
11372       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
11373                                             gtk_tree_view_row_inserted,
11374                                             tree_view);
11375       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
11376                                             gtk_tree_view_row_has_child_toggled,
11377                                             tree_view);
11378       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
11379                                             gtk_tree_view_row_deleted,
11380                                             tree_view);
11381       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
11382                                             gtk_tree_view_rows_reordered,
11383                                             tree_view);
11384
11385       for (; tmplist; tmplist = tmplist->next)
11386         _gtk_tree_view_column_unset_model (tmplist->data,
11387                                            tree_view->priv->model);
11388
11389       if (tree_view->priv->tree)
11390         gtk_tree_view_free_rbtree (tree_view);
11391
11392       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
11393       tree_view->priv->drag_dest_row = NULL;
11394       gtk_tree_row_reference_free (tree_view->priv->cursor);
11395       tree_view->priv->cursor = NULL;
11396       gtk_tree_row_reference_free (tree_view->priv->anchor);
11397       tree_view->priv->anchor = NULL;
11398       gtk_tree_row_reference_free (tree_view->priv->top_row);
11399       tree_view->priv->top_row = NULL;
11400       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
11401       tree_view->priv->scroll_to_path = NULL;
11402
11403       tree_view->priv->scroll_to_column = NULL;
11404
11405       g_object_unref (tree_view->priv->model);
11406
11407       tree_view->priv->search_column = -1;
11408       tree_view->priv->fixed_height_check = 0;
11409       tree_view->priv->fixed_height = -1;
11410       tree_view->priv->dy = tree_view->priv->top_row_dy = 0;
11411       tree_view->priv->last_button_x = -1;
11412       tree_view->priv->last_button_y = -1;
11413     }
11414
11415   tree_view->priv->model = model;
11416
11417   if (tree_view->priv->model)
11418     {
11419       gint i;
11420       GtkTreePath *path;
11421       GtkTreeIter iter;
11422       GtkTreeModelFlags flags;
11423
11424       if (tree_view->priv->search_column == -1)
11425         {
11426           for (i = 0; i < gtk_tree_model_get_n_columns (model); i++)
11427             {
11428               GType type = gtk_tree_model_get_column_type (model, i);
11429
11430               if (g_value_type_transformable (type, G_TYPE_STRING))
11431                 {
11432                   tree_view->priv->search_column = i;
11433                   break;
11434                 }
11435             }
11436         }
11437
11438       g_object_ref (tree_view->priv->model);
11439       g_signal_connect (tree_view->priv->model,
11440                         "row-changed",
11441                         G_CALLBACK (gtk_tree_view_row_changed),
11442                         tree_view);
11443       g_signal_connect (tree_view->priv->model,
11444                         "row-inserted",
11445                         G_CALLBACK (gtk_tree_view_row_inserted),
11446                         tree_view);
11447       g_signal_connect (tree_view->priv->model,
11448                         "row-has-child-toggled",
11449                         G_CALLBACK (gtk_tree_view_row_has_child_toggled),
11450                         tree_view);
11451       g_signal_connect (tree_view->priv->model,
11452                         "row-deleted",
11453                         G_CALLBACK (gtk_tree_view_row_deleted),
11454                         tree_view);
11455       g_signal_connect (tree_view->priv->model,
11456                         "rows-reordered",
11457                         G_CALLBACK (gtk_tree_view_rows_reordered),
11458                         tree_view);
11459
11460       flags = gtk_tree_model_get_flags (tree_view->priv->model);
11461       if ((flags & GTK_TREE_MODEL_LIST_ONLY) == GTK_TREE_MODEL_LIST_ONLY)
11462         tree_view->priv->is_list = TRUE;
11463       else
11464         tree_view->priv->is_list = FALSE;
11465
11466       path = gtk_tree_path_new_first ();
11467       if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, path))
11468         {
11469           tree_view->priv->tree = _gtk_rbtree_new ();
11470           gtk_tree_view_build_tree (tree_view, tree_view->priv->tree, &iter, 1, FALSE);
11471         }
11472       gtk_tree_path_free (path);
11473
11474       /*  FIXME: do I need to do this? gtk_tree_view_create_buttons (tree_view); */
11475       install_presize_handler (tree_view);
11476     }
11477
11478   g_object_notify (G_OBJECT (tree_view), "model");
11479
11480   if (tree_view->priv->selection)
11481   _gtk_tree_selection_emit_changed (tree_view->priv->selection);
11482
11483   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11484     gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11485 }
11486
11487 /**
11488  * gtk_tree_view_get_selection:
11489  * @tree_view: A #GtkTreeView.
11490  *
11491  * Gets the #GtkTreeSelection associated with @tree_view.
11492  *
11493  * Return value: (transfer none): A #GtkTreeSelection object.
11494  **/
11495 GtkTreeSelection *
11496 gtk_tree_view_get_selection (GtkTreeView *tree_view)
11497 {
11498   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11499
11500   return tree_view->priv->selection;
11501 }
11502
11503 /**
11504  * gtk_tree_view_get_hadjustment:
11505  * @tree_view: A #GtkTreeView
11506  *
11507  * Gets the #GtkAdjustment currently being used for the horizontal aspect.
11508  *
11509  * Return value: (transfer none): A #GtkAdjustment object, or %NULL
11510  *     if none is currently being used.
11511  *
11512  * Deprecated: 3.0: Use gtk_scrollable_get_hadjustment()
11513  **/
11514 GtkAdjustment *
11515 gtk_tree_view_get_hadjustment (GtkTreeView *tree_view)
11516 {
11517   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11518
11519   return tree_view->priv->hadjustment;
11520 }
11521
11522 /**
11523  * gtk_tree_view_set_hadjustment:
11524  * @tree_view: A #GtkTreeView
11525  * @adjustment: (allow-none): The #GtkAdjustment to set, or %NULL
11526  *
11527  * Sets the #GtkAdjustment for the current horizontal aspect.
11528  *
11529  * Deprecated: 3.0: Use gtk_scrollable_set_hadjustment()
11530  **/
11531 void
11532 gtk_tree_view_set_hadjustment (GtkTreeView   *tree_view,
11533                                GtkAdjustment *adjustment)
11534 {
11535   GtkTreeViewPrivate *priv = tree_view->priv;
11536
11537   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11538   g_return_if_fail (adjustment == NULL || GTK_IS_ADJUSTMENT (adjustment));
11539
11540   if (adjustment && priv->hadjustment == adjustment)
11541     return;
11542
11543   if (priv->hadjustment != NULL)
11544     {
11545       g_signal_handlers_disconnect_by_func (priv->hadjustment,
11546                                             gtk_tree_view_adjustment_changed,
11547                                             tree_view);
11548       g_object_unref (priv->hadjustment);
11549     }
11550
11551   if (adjustment == NULL)
11552     adjustment = gtk_adjustment_new (0.0, 0.0, 0.0,
11553                                      0.0, 0.0, 0.0);
11554
11555   g_signal_connect (adjustment, "value-changed",
11556                     G_CALLBACK (gtk_tree_view_adjustment_changed), tree_view);
11557   priv->hadjustment = g_object_ref_sink (adjustment);
11558   /* FIXME: Adjustment should probably be populated here with fresh values, but
11559    * internal details are too complicated for me to decipher right now.
11560    */
11561   gtk_tree_view_adjustment_changed (NULL, tree_view);
11562
11563   g_object_notify (G_OBJECT (tree_view), "hadjustment");
11564 }
11565
11566 /**
11567  * gtk_tree_view_get_vadjustment:
11568  * @tree_view: A #GtkTreeView
11569  *
11570  * Gets the #GtkAdjustment currently being used for the vertical aspect.
11571  *
11572  * Return value: (transfer none): A #GtkAdjustment object, or %NULL
11573  *     if none is currently being used.
11574  *
11575  * Deprecated: 3.0: Use gtk_scrollable_get_vadjustment()
11576  **/
11577 GtkAdjustment *
11578 gtk_tree_view_get_vadjustment (GtkTreeView *tree_view)
11579 {
11580   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11581
11582   return tree_view->priv->vadjustment;
11583 }
11584
11585 /**
11586  * gtk_tree_view_set_vadjustment:
11587  * @tree_view: A #GtkTreeView
11588  * @adjustment: (allow-none): The #GtkAdjustment to set, or %NULL
11589  *
11590  * Sets the #GtkAdjustment for the current vertical aspect.
11591  *
11592  * Deprecated: 3.0: Use gtk_scrollable_set_vadjustment()
11593  **/
11594 void
11595 gtk_tree_view_set_vadjustment (GtkTreeView   *tree_view,
11596                                GtkAdjustment *adjustment)
11597 {
11598   GtkTreeViewPrivate *priv = tree_view->priv;
11599
11600   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11601   g_return_if_fail (adjustment == NULL || GTK_IS_ADJUSTMENT (adjustment));
11602
11603   if (adjustment && priv->vadjustment == adjustment)
11604     return;
11605
11606   if (priv->vadjustment != NULL)
11607     {
11608       g_signal_handlers_disconnect_by_func (priv->vadjustment,
11609                                             gtk_tree_view_adjustment_changed,
11610                                             tree_view);
11611       g_object_unref (priv->vadjustment);
11612     }
11613
11614   if (adjustment == NULL)
11615     adjustment = gtk_adjustment_new (0.0, 0.0, 0.0,
11616                                      0.0, 0.0, 0.0);
11617
11618   g_signal_connect (adjustment, "value-changed",
11619                     G_CALLBACK (gtk_tree_view_adjustment_changed), tree_view);
11620   priv->vadjustment = g_object_ref_sink (adjustment);
11621   /* FIXME: Adjustment should probably be populated here with fresh values, but
11622    * internal details are too complicated for me to decipher right now.
11623    */
11624   gtk_tree_view_adjustment_changed (NULL, tree_view);
11625   g_object_notify (G_OBJECT (tree_view), "vadjustment");
11626 }
11627
11628 /* Column and header operations */
11629
11630 /**
11631  * gtk_tree_view_get_headers_visible:
11632  * @tree_view: A #GtkTreeView.
11633  *
11634  * Returns %TRUE if the headers on the @tree_view are visible.
11635  *
11636  * Return value: Whether the headers are visible or not.
11637  **/
11638 gboolean
11639 gtk_tree_view_get_headers_visible (GtkTreeView *tree_view)
11640 {
11641   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
11642
11643   return tree_view->priv->headers_visible;
11644 }
11645
11646 /**
11647  * gtk_tree_view_set_headers_visible:
11648  * @tree_view: A #GtkTreeView.
11649  * @headers_visible: %TRUE if the headers are visible
11650  *
11651  * Sets the visibility state of the headers.
11652  **/
11653 void
11654 gtk_tree_view_set_headers_visible (GtkTreeView *tree_view,
11655                                    gboolean     headers_visible)
11656 {
11657   gint x, y;
11658   GList *list;
11659   GtkTreeViewColumn *column;
11660   GtkAllocation allocation;
11661   GtkWidget *button;
11662
11663   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11664
11665   headers_visible = !! headers_visible;
11666
11667   if (tree_view->priv->headers_visible == headers_visible)
11668     return;
11669
11670   tree_view->priv->headers_visible = headers_visible == TRUE;
11671
11672   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11673     {
11674       gdk_window_get_position (tree_view->priv->bin_window, &x, &y);
11675       if (headers_visible)
11676         {
11677           gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
11678           gdk_window_move_resize (tree_view->priv->bin_window,
11679                                   x, y  + gtk_tree_view_get_effective_header_height (tree_view),
11680                                   tree_view->priv->width, allocation.height -  + gtk_tree_view_get_effective_header_height (tree_view));
11681
11682           if (gtk_widget_get_mapped (GTK_WIDGET (tree_view)))
11683             gtk_tree_view_map_buttons (tree_view);
11684         }
11685       else
11686         {
11687           gdk_window_move_resize (tree_view->priv->bin_window, x, y, tree_view->priv->width, tree_view->priv->height);
11688
11689           for (list = tree_view->priv->columns; list; list = list->next)
11690             {
11691               column = list->data;
11692               button = gtk_tree_view_column_get_button (column);
11693
11694               gtk_widget_hide (button);
11695               gtk_widget_unmap (button);
11696             }
11697           gdk_window_hide (tree_view->priv->header_window);
11698         }
11699     }
11700
11701   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
11702   gtk_adjustment_configure (tree_view->priv->vadjustment,
11703                             gtk_adjustment_get_value (tree_view->priv->vadjustment),
11704                             0,
11705                             tree_view->priv->height,
11706                             gtk_adjustment_get_step_increment (tree_view->priv->vadjustment),
11707                             (allocation.height - gtk_tree_view_get_effective_header_height (tree_view)) / 2,
11708                             allocation.height - gtk_tree_view_get_effective_header_height (tree_view));
11709
11710   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11711
11712   g_object_notify (G_OBJECT (tree_view), "headers-visible");
11713 }
11714
11715 /**
11716  * gtk_tree_view_columns_autosize:
11717  * @tree_view: A #GtkTreeView.
11718  *
11719  * Resizes all columns to their optimal width. Only works after the
11720  * treeview has been realized.
11721  **/
11722 void
11723 gtk_tree_view_columns_autosize (GtkTreeView *tree_view)
11724 {
11725   gboolean dirty = FALSE;
11726   GList *list;
11727   GtkTreeViewColumn *column;
11728
11729   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11730
11731   for (list = tree_view->priv->columns; list; list = list->next)
11732     {
11733       column = list->data;
11734       if (gtk_tree_view_column_get_sizing (column) == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
11735         continue;
11736       _gtk_tree_view_column_cell_set_dirty (column, TRUE);
11737       dirty = TRUE;
11738     }
11739
11740   if (dirty)
11741     gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11742 }
11743
11744 /**
11745  * gtk_tree_view_set_headers_clickable:
11746  * @tree_view: A #GtkTreeView.
11747  * @setting: %TRUE if the columns are clickable.
11748  *
11749  * Allow the column title buttons to be clicked.
11750  **/
11751 void
11752 gtk_tree_view_set_headers_clickable (GtkTreeView *tree_view,
11753                                      gboolean   setting)
11754 {
11755   GList *list;
11756
11757   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11758
11759   for (list = tree_view->priv->columns; list; list = list->next)
11760     gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (list->data), setting);
11761
11762   g_object_notify (G_OBJECT (tree_view), "headers-clickable");
11763 }
11764
11765
11766 /**
11767  * gtk_tree_view_get_headers_clickable:
11768  * @tree_view: A #GtkTreeView.
11769  *
11770  * Returns whether all header columns are clickable.
11771  *
11772  * Return value: %TRUE if all header columns are clickable, otherwise %FALSE
11773  *
11774  * Since: 2.10
11775  **/
11776 gboolean 
11777 gtk_tree_view_get_headers_clickable (GtkTreeView *tree_view)
11778 {
11779   GList *list;
11780   
11781   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
11782
11783   for (list = tree_view->priv->columns; list; list = list->next)
11784     if (!gtk_tree_view_column_get_clickable (GTK_TREE_VIEW_COLUMN (list->data)))
11785       return FALSE;
11786
11787   return TRUE;
11788 }
11789
11790 /**
11791  * gtk_tree_view_set_rules_hint
11792  * @tree_view: a #GtkTreeView
11793  * @setting: %TRUE if the tree requires reading across rows
11794  *
11795  * This function tells GTK+ that the user interface for your
11796  * application requires users to read across tree rows and associate
11797  * cells with one another. By default, GTK+ will then render the tree
11798  * with alternating row colors. Do <emphasis>not</emphasis> use it
11799  * just because you prefer the appearance of the ruled tree; that's a
11800  * question for the theme. Some themes will draw tree rows in
11801  * alternating colors even when rules are turned off, and users who
11802  * prefer that appearance all the time can choose those themes. You
11803  * should call this function only as a <emphasis>semantic</emphasis>
11804  * hint to the theme engine that your tree makes alternating colors
11805  * useful from a functional standpoint (since it has lots of columns,
11806  * generally).
11807  *
11808  **/
11809 void
11810 gtk_tree_view_set_rules_hint (GtkTreeView  *tree_view,
11811                               gboolean      setting)
11812 {
11813   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11814
11815   setting = setting != FALSE;
11816
11817   if (tree_view->priv->has_rules != setting)
11818     {
11819       tree_view->priv->has_rules = setting;
11820       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
11821     }
11822
11823   g_object_notify (G_OBJECT (tree_view), "rules-hint");
11824 }
11825
11826 /**
11827  * gtk_tree_view_get_rules_hint
11828  * @tree_view: a #GtkTreeView
11829  *
11830  * Gets the setting set by gtk_tree_view_set_rules_hint().
11831  *
11832  * Return value: %TRUE if rules are useful for the user of this tree
11833  **/
11834 gboolean
11835 gtk_tree_view_get_rules_hint (GtkTreeView  *tree_view)
11836 {
11837   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
11838
11839   return tree_view->priv->has_rules;
11840 }
11841
11842 /* Public Column functions
11843  */
11844
11845 /**
11846  * gtk_tree_view_append_column:
11847  * @tree_view: A #GtkTreeView.
11848  * @column: The #GtkTreeViewColumn to add.
11849  *
11850  * Appends @column to the list of columns. If @tree_view has "fixed_height"
11851  * mode enabled, then @column must have its "sizing" property set to be
11852  * GTK_TREE_VIEW_COLUMN_FIXED.
11853  *
11854  * Return value: The number of columns in @tree_view after appending.
11855  **/
11856 gint
11857 gtk_tree_view_append_column (GtkTreeView       *tree_view,
11858                              GtkTreeViewColumn *column)
11859 {
11860   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11861   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
11862   g_return_val_if_fail (gtk_tree_view_column_get_tree_view (column) == NULL, -1);
11863
11864   return gtk_tree_view_insert_column (tree_view, column, -1);
11865 }
11866
11867 void
11868 _gtk_tree_view_reset_header_styles (GtkTreeView *tree_view)
11869 {
11870   GList *columns;
11871
11872   for (columns = tree_view->priv->columns; columns; columns = columns->next)
11873     {
11874       GtkTreeViewColumn *column = columns->data;
11875       GtkWidget *header_widget;
11876
11877       if (gtk_tree_view_column_get_visible (column))
11878         continue;
11879
11880       header_widget = gtk_tree_view_column_get_widget (column);
11881
11882       if (!header_widget)
11883         header_widget = gtk_tree_view_column_get_button (column);
11884
11885       gtk_widget_reset_style (header_widget);
11886     }
11887 }
11888
11889
11890 /**
11891  * gtk_tree_view_remove_column:
11892  * @tree_view: A #GtkTreeView.
11893  * @column: The #GtkTreeViewColumn to remove.
11894  *
11895  * Removes @column from @tree_view.
11896  *
11897  * Return value: The number of columns in @tree_view after removing.
11898  **/
11899 gint
11900 gtk_tree_view_remove_column (GtkTreeView       *tree_view,
11901                              GtkTreeViewColumn *column)
11902 {
11903   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11904   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
11905   g_return_val_if_fail (gtk_tree_view_column_get_tree_view (column) == GTK_WIDGET (tree_view), -1);
11906
11907   if (tree_view->priv->focus_column == column)
11908     tree_view->priv->focus_column = NULL;
11909
11910   if (tree_view->priv->edited_column == column)
11911     {
11912       gtk_tree_view_stop_editing (tree_view, TRUE);
11913
11914       /* no need to, but just to be sure ... */
11915       tree_view->priv->edited_column = NULL;
11916     }
11917
11918   if (tree_view->priv->expander_column == column)
11919     tree_view->priv->expander_column = NULL;
11920
11921   g_signal_handlers_disconnect_by_func (column,
11922                                         G_CALLBACK (column_sizing_notify),
11923                                         tree_view);
11924
11925   _gtk_tree_view_column_unset_tree_view (column);
11926
11927   tree_view->priv->columns = g_list_remove (tree_view->priv->columns, column);
11928   tree_view->priv->n_columns--;
11929
11930   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11931     {
11932       GList *list;
11933
11934       _gtk_tree_view_column_unrealize_button (column);
11935       for (list = tree_view->priv->columns; list; list = list->next)
11936         {
11937           GtkTreeViewColumn *tmp_column;
11938
11939           tmp_column = GTK_TREE_VIEW_COLUMN (list->data);
11940           if (gtk_tree_view_column_get_visible (tmp_column))
11941             _gtk_tree_view_column_cell_set_dirty (tmp_column, TRUE);
11942         }
11943
11944       if (tree_view->priv->n_columns == 0 &&
11945           gtk_tree_view_get_headers_visible (tree_view))
11946         gdk_window_hide (tree_view->priv->header_window);
11947
11948       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11949     }
11950
11951   _gtk_tree_view_reset_header_styles (tree_view);
11952
11953   g_object_unref (column);
11954   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
11955
11956   return tree_view->priv->n_columns;
11957 }
11958
11959 /**
11960  * gtk_tree_view_insert_column:
11961  * @tree_view: A #GtkTreeView.
11962  * @column: The #GtkTreeViewColumn to be inserted.
11963  * @position: The position to insert @column in.
11964  *
11965  * This inserts the @column into the @tree_view at @position.  If @position is
11966  * -1, then the column is inserted at the end. If @tree_view has
11967  * "fixed_height" mode enabled, then @column must have its "sizing" property
11968  * set to be GTK_TREE_VIEW_COLUMN_FIXED.
11969  *
11970  * Return value: The number of columns in @tree_view after insertion.
11971  **/
11972 gint
11973 gtk_tree_view_insert_column (GtkTreeView       *tree_view,
11974                              GtkTreeViewColumn *column,
11975                              gint               position)
11976 {
11977   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11978   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
11979   g_return_val_if_fail (gtk_tree_view_column_get_tree_view (column) == NULL, -1);
11980
11981   if (tree_view->priv->fixed_height_mode)
11982     g_return_val_if_fail (gtk_tree_view_column_get_sizing (column)
11983                           == GTK_TREE_VIEW_COLUMN_FIXED, -1);
11984
11985   g_object_ref_sink (column);
11986
11987   if (tree_view->priv->n_columns == 0 &&
11988       gtk_widget_get_realized (GTK_WIDGET (tree_view)) &&
11989       gtk_tree_view_get_headers_visible (tree_view))
11990     {
11991       gdk_window_show (tree_view->priv->header_window);
11992     }
11993
11994   g_signal_connect (column, "notify::sizing",
11995                     G_CALLBACK (column_sizing_notify), tree_view);
11996
11997   tree_view->priv->columns = g_list_insert (tree_view->priv->columns,
11998                                             column, position);
11999   tree_view->priv->n_columns++;
12000
12001   _gtk_tree_view_column_set_tree_view (column, tree_view);
12002
12003   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
12004     {
12005       GList *list;
12006
12007       _gtk_tree_view_column_realize_button (column);
12008
12009       for (list = tree_view->priv->columns; list; list = list->next)
12010         {
12011           column = GTK_TREE_VIEW_COLUMN (list->data);
12012           if (gtk_tree_view_column_get_visible (column))
12013             _gtk_tree_view_column_cell_set_dirty (column, TRUE);
12014         }
12015       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
12016     }
12017
12018   _gtk_tree_view_reset_header_styles (tree_view);
12019   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
12020
12021   return tree_view->priv->n_columns;
12022 }
12023
12024 /**
12025  * gtk_tree_view_insert_column_with_attributes:
12026  * @tree_view: A #GtkTreeView
12027  * @position: The position to insert the new column in.
12028  * @title: The title to set the header to.
12029  * @cell: The #GtkCellRenderer.
12030  * @Varargs: A %NULL-terminated list of attributes.
12031  *
12032  * Creates a new #GtkTreeViewColumn and inserts it into the @tree_view at
12033  * @position.  If @position is -1, then the newly created column is inserted at
12034  * the end.  The column is initialized with the attributes given. If @tree_view
12035  * has "fixed_height" mode enabled, then the new column will have its sizing
12036  * property set to be GTK_TREE_VIEW_COLUMN_FIXED.
12037  *
12038  * Return value: The number of columns in @tree_view after insertion.
12039  **/
12040 gint
12041 gtk_tree_view_insert_column_with_attributes (GtkTreeView     *tree_view,
12042                                              gint             position,
12043                                              const gchar     *title,
12044                                              GtkCellRenderer *cell,
12045                                              ...)
12046 {
12047   GtkTreeViewColumn *column;
12048   gchar *attribute;
12049   va_list args;
12050   gint column_id;
12051
12052   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
12053
12054   column = gtk_tree_view_column_new ();
12055   if (tree_view->priv->fixed_height_mode)
12056     gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
12057
12058   gtk_tree_view_column_set_title (column, title);
12059   gtk_tree_view_column_pack_start (column, cell, TRUE);
12060
12061   va_start (args, cell);
12062
12063   attribute = va_arg (args, gchar *);
12064
12065   while (attribute != NULL)
12066     {
12067       column_id = va_arg (args, gint);
12068       gtk_tree_view_column_add_attribute (column, cell, attribute, column_id);
12069       attribute = va_arg (args, gchar *);
12070     }
12071
12072   va_end (args);
12073
12074   gtk_tree_view_insert_column (tree_view, column, position);
12075
12076   return tree_view->priv->n_columns;
12077 }
12078
12079 /**
12080  * gtk_tree_view_insert_column_with_data_func:
12081  * @tree_view: a #GtkTreeView
12082  * @position: Position to insert, -1 for append
12083  * @title: column title
12084  * @cell: cell renderer for column
12085  * @func: function to set attributes of cell renderer
12086  * @data: data for @func
12087  * @dnotify: destroy notifier for @data
12088  *
12089  * Convenience function that inserts a new column into the #GtkTreeView
12090  * with the given cell renderer and a #GtkCellDataFunc to set cell renderer
12091  * attributes (normally using data from the model). See also
12092  * gtk_tree_view_column_set_cell_data_func(), gtk_tree_view_column_pack_start().
12093  * If @tree_view has "fixed_height" mode enabled, then the new column will have its
12094  * "sizing" property set to be GTK_TREE_VIEW_COLUMN_FIXED.
12095  *
12096  * Return value: number of columns in the tree view post-insert
12097  **/
12098 gint
12099 gtk_tree_view_insert_column_with_data_func  (GtkTreeView               *tree_view,
12100                                              gint                       position,
12101                                              const gchar               *title,
12102                                              GtkCellRenderer           *cell,
12103                                              GtkTreeCellDataFunc        func,
12104                                              gpointer                   data,
12105                                              GDestroyNotify             dnotify)
12106 {
12107   GtkTreeViewColumn *column;
12108
12109   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
12110
12111   column = gtk_tree_view_column_new ();
12112   if (tree_view->priv->fixed_height_mode)
12113     gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
12114
12115   gtk_tree_view_column_set_title (column, title);
12116   gtk_tree_view_column_pack_start (column, cell, TRUE);
12117   gtk_tree_view_column_set_cell_data_func (column, cell, func, data, dnotify);
12118
12119   gtk_tree_view_insert_column (tree_view, column, position);
12120
12121   return tree_view->priv->n_columns;
12122 }
12123
12124 /**
12125  * gtk_tree_view_get_column:
12126  * @tree_view: A #GtkTreeView.
12127  * @n: The position of the column, counting from 0.
12128  *
12129  * Gets the #GtkTreeViewColumn at the given position in the #tree_view.
12130  *
12131  * Return value: (transfer none): The #GtkTreeViewColumn, or %NULL if the
12132  *     position is outside the range of columns.
12133  **/
12134 GtkTreeViewColumn *
12135 gtk_tree_view_get_column (GtkTreeView *tree_view,
12136                           gint         n)
12137 {
12138   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
12139
12140   if (n < 0 || n >= tree_view->priv->n_columns)
12141     return NULL;
12142
12143   if (tree_view->priv->columns == NULL)
12144     return NULL;
12145
12146   return GTK_TREE_VIEW_COLUMN (g_list_nth (tree_view->priv->columns, n)->data);
12147 }
12148
12149 /**
12150  * gtk_tree_view_get_columns:
12151  * @tree_view: A #GtkTreeView
12152  *
12153  * Returns a #GList of all the #GtkTreeViewColumn s currently in @tree_view.
12154  * The returned list must be freed with g_list_free ().
12155  *
12156  * Return value: (element-type GtkTreeViewColumn) (transfer container): A list of #GtkTreeViewColumn s
12157  **/
12158 GList *
12159 gtk_tree_view_get_columns (GtkTreeView *tree_view)
12160 {
12161   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
12162
12163   return g_list_copy (tree_view->priv->columns);
12164 }
12165
12166 /**
12167  * gtk_tree_view_move_column_after:
12168  * @tree_view: A #GtkTreeView
12169  * @column: The #GtkTreeViewColumn to be moved.
12170  * @base_column: (allow-none): The #GtkTreeViewColumn to be moved relative to, or %NULL.
12171  *
12172  * Moves @column to be after to @base_column.  If @base_column is %NULL, then
12173  * @column is placed in the first position.
12174  **/
12175 void
12176 gtk_tree_view_move_column_after (GtkTreeView       *tree_view,
12177                                  GtkTreeViewColumn *column,
12178                                  GtkTreeViewColumn *base_column)
12179 {
12180   GList *column_list_el, *base_el = NULL;
12181
12182   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12183
12184   column_list_el = g_list_find (tree_view->priv->columns, column);
12185   g_return_if_fail (column_list_el != NULL);
12186
12187   if (base_column)
12188     {
12189       base_el = g_list_find (tree_view->priv->columns, base_column);
12190       g_return_if_fail (base_el != NULL);
12191     }
12192
12193   if (column_list_el->prev == base_el)
12194     return;
12195
12196   tree_view->priv->columns = g_list_remove_link (tree_view->priv->columns, column_list_el);
12197   if (base_el == NULL)
12198     {
12199       column_list_el->prev = NULL;
12200       column_list_el->next = tree_view->priv->columns;
12201       if (column_list_el->next)
12202         column_list_el->next->prev = column_list_el;
12203       tree_view->priv->columns = column_list_el;
12204     }
12205   else
12206     {
12207       column_list_el->prev = base_el;
12208       column_list_el->next = base_el->next;
12209       if (column_list_el->next)
12210         column_list_el->next->prev = column_list_el;
12211       base_el->next = column_list_el;
12212     }
12213
12214   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
12215     {
12216       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
12217       gtk_tree_view_size_allocate_columns (GTK_WIDGET (tree_view), NULL);
12218     }
12219
12220   _gtk_tree_view_reset_header_styles (tree_view);
12221   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
12222 }
12223
12224 /**
12225  * gtk_tree_view_set_expander_column:
12226  * @tree_view: A #GtkTreeView
12227  * @column: %NULL, or the column to draw the expander arrow at.
12228  *
12229  * Sets the column to draw the expander arrow at. It must be in @tree_view.  
12230  * If @column is %NULL, then the expander arrow is always at the first 
12231  * visible column.
12232  *
12233  * If you do not want expander arrow to appear in your tree, set the 
12234  * expander column to a hidden column.
12235  **/
12236 void
12237 gtk_tree_view_set_expander_column (GtkTreeView       *tree_view,
12238                                    GtkTreeViewColumn *column)
12239 {
12240   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12241   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
12242
12243   if (tree_view->priv->expander_column != column)
12244     {
12245       GList *list;
12246
12247       if (column)
12248         {
12249           /* Confirm that column is in tree_view */
12250           for (list = tree_view->priv->columns; list; list = list->next)
12251             if (list->data == column)
12252               break;
12253           g_return_if_fail (list != NULL);
12254         }
12255
12256       tree_view->priv->expander_column = column;
12257       g_object_notify (G_OBJECT (tree_view), "expander-column");
12258     }
12259 }
12260
12261 /**
12262  * gtk_tree_view_get_expander_column:
12263  * @tree_view: A #GtkTreeView
12264  *
12265  * Returns the column that is the current expander column.
12266  * This column has the expander arrow drawn next to it.
12267  *
12268  * Return value: (transfer none): The expander column.
12269  **/
12270 GtkTreeViewColumn *
12271 gtk_tree_view_get_expander_column (GtkTreeView *tree_view)
12272 {
12273   GList *list;
12274
12275   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
12276
12277   for (list = tree_view->priv->columns; list; list = list->next)
12278     if (gtk_tree_view_is_expander_column (tree_view, GTK_TREE_VIEW_COLUMN (list->data)))
12279       return (GtkTreeViewColumn *) list->data;
12280   return NULL;
12281 }
12282
12283
12284 /**
12285  * gtk_tree_view_set_column_drag_function:
12286  * @tree_view: A #GtkTreeView.
12287  * @func: (allow-none): A function to determine which columns are reorderable, or %NULL.
12288  * @user_data: (allow-none): User data to be passed to @func, or %NULL
12289  * @destroy: (allow-none): Destroy notifier for @user_data, or %NULL
12290  *
12291  * Sets a user function for determining where a column may be dropped when
12292  * dragged.  This function is called on every column pair in turn at the
12293  * beginning of a column drag to determine where a drop can take place.  The
12294  * arguments passed to @func are: the @tree_view, the #GtkTreeViewColumn being
12295  * dragged, the two #GtkTreeViewColumn s determining the drop spot, and
12296  * @user_data.  If either of the #GtkTreeViewColumn arguments for the drop spot
12297  * are %NULL, then they indicate an edge.  If @func is set to be %NULL, then
12298  * @tree_view reverts to the default behavior of allowing all columns to be
12299  * dropped everywhere.
12300  **/
12301 void
12302 gtk_tree_view_set_column_drag_function (GtkTreeView               *tree_view,
12303                                         GtkTreeViewColumnDropFunc  func,
12304                                         gpointer                   user_data,
12305                                         GDestroyNotify             destroy)
12306 {
12307   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12308
12309   if (tree_view->priv->column_drop_func_data_destroy)
12310     tree_view->priv->column_drop_func_data_destroy (tree_view->priv->column_drop_func_data);
12311
12312   tree_view->priv->column_drop_func = func;
12313   tree_view->priv->column_drop_func_data = user_data;
12314   tree_view->priv->column_drop_func_data_destroy = destroy;
12315 }
12316
12317 /**
12318  * gtk_tree_view_scroll_to_point:
12319  * @tree_view: a #GtkTreeView
12320  * @tree_x: X coordinate of new top-left pixel of visible area, or -1
12321  * @tree_y: Y coordinate of new top-left pixel of visible area, or -1
12322  *
12323  * Scrolls the tree view such that the top-left corner of the visible
12324  * area is @tree_x, @tree_y, where @tree_x and @tree_y are specified
12325  * in tree coordinates.  The @tree_view must be realized before
12326  * this function is called.  If it isn't, you probably want to be
12327  * using gtk_tree_view_scroll_to_cell().
12328  *
12329  * If either @tree_x or @tree_y are -1, then that direction isn't scrolled.
12330  **/
12331 void
12332 gtk_tree_view_scroll_to_point (GtkTreeView *tree_view,
12333                                gint         tree_x,
12334                                gint         tree_y)
12335 {
12336   GtkAdjustment *hadj;
12337   GtkAdjustment *vadj;
12338
12339   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12340   g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (tree_view)));
12341
12342   hadj = tree_view->priv->hadjustment;
12343   vadj = tree_view->priv->vadjustment;
12344
12345   if (tree_x != -1)
12346     gtk_adjustment_set_value (hadj, tree_x);
12347   if (tree_y != -1)
12348     gtk_adjustment_set_value (vadj, tree_y);
12349 }
12350
12351 /**
12352  * gtk_tree_view_scroll_to_cell:
12353  * @tree_view: A #GtkTreeView.
12354  * @path: (allow-none): The path of the row to move to, or %NULL.
12355  * @column: (allow-none): The #GtkTreeViewColumn to move horizontally to, or %NULL.
12356  * @use_align: whether to use alignment arguments, or %FALSE.
12357  * @row_align: The vertical alignment of the row specified by @path.
12358  * @col_align: The horizontal alignment of the column specified by @column.
12359  *
12360  * Moves the alignments of @tree_view to the position specified by @column and
12361  * @path.  If @column is %NULL, then no horizontal scrolling occurs.  Likewise,
12362  * if @path is %NULL no vertical scrolling occurs.  At a minimum, one of @column
12363  * or @path need to be non-%NULL.  @row_align determines where the row is
12364  * placed, and @col_align determines where @column is placed.  Both are expected
12365  * to be between 0.0 and 1.0. 0.0 means left/top alignment, 1.0 means
12366  * right/bottom alignment, 0.5 means center.
12367  *
12368  * If @use_align is %FALSE, then the alignment arguments are ignored, and the
12369  * tree does the minimum amount of work to scroll the cell onto the screen.
12370  * This means that the cell will be scrolled to the edge closest to its current
12371  * position.  If the cell is currently visible on the screen, nothing is done.
12372  *
12373  * This function only works if the model is set, and @path is a valid row on the
12374  * model.  If the model changes before the @tree_view is realized, the centered
12375  * path will be modified to reflect this change.
12376  **/
12377 void
12378 gtk_tree_view_scroll_to_cell (GtkTreeView       *tree_view,
12379                               GtkTreePath       *path,
12380                               GtkTreeViewColumn *column,
12381                               gboolean           use_align,
12382                               gfloat             row_align,
12383                               gfloat             col_align)
12384 {
12385   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12386   g_return_if_fail (tree_view->priv->model != NULL);
12387   g_return_if_fail (tree_view->priv->tree != NULL);
12388   g_return_if_fail (row_align >= 0.0 && row_align <= 1.0);
12389   g_return_if_fail (col_align >= 0.0 && col_align <= 1.0);
12390   g_return_if_fail (path != NULL || column != NULL);
12391
12392 #if 0
12393   g_print ("gtk_tree_view_scroll_to_cell:\npath: %s\ncolumn: %s\nuse_align: %d\nrow_align: %f\ncol_align: %f\n",
12394            gtk_tree_path_to_string (path), column?"non-null":"null", use_align, row_align, col_align);
12395 #endif
12396   row_align = CLAMP (row_align, 0.0, 1.0);
12397   col_align = CLAMP (col_align, 0.0, 1.0);
12398
12399
12400   /* Note: Despite the benefits that come from having one code path for the
12401    * scrolling code, we short-circuit validate_visible_area's immplementation as
12402    * it is much slower than just going to the point.
12403    */
12404   if (!gtk_widget_get_visible (GTK_WIDGET (tree_view)) ||
12405       !gtk_widget_get_realized (GTK_WIDGET (tree_view)) ||
12406       _gtk_widget_get_alloc_needed (GTK_WIDGET (tree_view)) ||
12407       GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID))
12408     {
12409       if (tree_view->priv->scroll_to_path)
12410         gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
12411
12412       tree_view->priv->scroll_to_path = NULL;
12413       tree_view->priv->scroll_to_column = NULL;
12414
12415       if (path)
12416         tree_view->priv->scroll_to_path = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
12417       if (column)
12418         tree_view->priv->scroll_to_column = column;
12419       tree_view->priv->scroll_to_use_align = use_align;
12420       tree_view->priv->scroll_to_row_align = row_align;
12421       tree_view->priv->scroll_to_col_align = col_align;
12422
12423       install_presize_handler (tree_view);
12424     }
12425   else
12426     {
12427       GdkRectangle cell_rect;
12428       GdkRectangle vis_rect;
12429       gint dest_x, dest_y;
12430
12431       gtk_tree_view_get_background_area (tree_view, path, column, &cell_rect);
12432       gtk_tree_view_get_visible_rect (tree_view, &vis_rect);
12433
12434       cell_rect.y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, cell_rect.y);
12435
12436       dest_x = vis_rect.x;
12437       dest_y = vis_rect.y;
12438
12439       if (column)
12440         {
12441           if (use_align)
12442             {
12443               dest_x = cell_rect.x - ((vis_rect.width - cell_rect.width) * col_align);
12444             }
12445           else
12446             {
12447               if (cell_rect.x < vis_rect.x)
12448                 dest_x = cell_rect.x;
12449               if (cell_rect.x + cell_rect.width > vis_rect.x + vis_rect.width)
12450                 dest_x = cell_rect.x + cell_rect.width - vis_rect.width;
12451             }
12452         }
12453
12454       if (path)
12455         {
12456           if (use_align)
12457             {
12458               dest_y = cell_rect.y - ((vis_rect.height - cell_rect.height) * row_align);
12459               dest_y = MAX (dest_y, 0);
12460             }
12461           else
12462             {
12463               if (cell_rect.y < vis_rect.y)
12464                 dest_y = cell_rect.y;
12465               if (cell_rect.y + cell_rect.height > vis_rect.y + vis_rect.height)
12466                 dest_y = cell_rect.y + cell_rect.height - vis_rect.height;
12467             }
12468         }
12469
12470       gtk_tree_view_scroll_to_point (tree_view, dest_x, dest_y);
12471     }
12472 }
12473
12474 /**
12475  * gtk_tree_view_row_activated:
12476  * @tree_view: A #GtkTreeView
12477  * @path: The #GtkTreePath to be activated.
12478  * @column: The #GtkTreeViewColumn to be activated.
12479  *
12480  * Activates the cell determined by @path and @column.
12481  **/
12482 void
12483 gtk_tree_view_row_activated (GtkTreeView       *tree_view,
12484                              GtkTreePath       *path,
12485                              GtkTreeViewColumn *column)
12486 {
12487   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12488
12489   g_signal_emit (tree_view, tree_view_signals[ROW_ACTIVATED], 0, path, column);
12490 }
12491
12492
12493 static void
12494 gtk_tree_view_expand_all_emission_helper (GtkRBTree *tree,
12495                                           GtkRBNode *node,
12496                                           gpointer   data)
12497 {
12498   GtkTreeView *tree_view = data;
12499
12500   if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT &&
12501       node->children)
12502     {
12503       GtkTreePath *path;
12504       GtkTreeIter iter;
12505
12506       path = _gtk_tree_view_find_path (tree_view, tree, node);
12507       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
12508
12509       g_signal_emit (tree_view, tree_view_signals[ROW_EXPANDED], 0, &iter, path);
12510
12511       gtk_tree_path_free (path);
12512     }
12513
12514   if (node->children)
12515     _gtk_rbtree_traverse (node->children,
12516                           node->children->root,
12517                           G_PRE_ORDER,
12518                           gtk_tree_view_expand_all_emission_helper,
12519                           tree_view);
12520 }
12521
12522 /**
12523  * gtk_tree_view_expand_all:
12524  * @tree_view: A #GtkTreeView.
12525  *
12526  * Recursively expands all nodes in the @tree_view.
12527  **/
12528 void
12529 gtk_tree_view_expand_all (GtkTreeView *tree_view)
12530 {
12531   GtkTreePath *path;
12532   GtkRBTree *tree;
12533   GtkRBNode *node;
12534
12535   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12536
12537   if (tree_view->priv->tree == NULL)
12538     return;
12539
12540   path = gtk_tree_path_new_first ();
12541   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
12542
12543   while (node)
12544     {
12545       gtk_tree_view_real_expand_row (tree_view, path, tree, node, TRUE, FALSE);
12546       node = _gtk_rbtree_next (tree, node);
12547       gtk_tree_path_next (path);
12548   }
12549
12550   gtk_tree_path_free (path);
12551 }
12552
12553 /**
12554  * gtk_tree_view_collapse_all:
12555  * @tree_view: A #GtkTreeView.
12556  *
12557  * Recursively collapses all visible, expanded nodes in @tree_view.
12558  **/
12559 void
12560 gtk_tree_view_collapse_all (GtkTreeView *tree_view)
12561 {
12562   GtkRBTree *tree;
12563   GtkRBNode *node;
12564   GtkTreePath *path;
12565   gint *indices;
12566
12567   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12568
12569   if (tree_view->priv->tree == NULL)
12570     return;
12571
12572   path = gtk_tree_path_new ();
12573   gtk_tree_path_down (path);
12574   indices = gtk_tree_path_get_indices (path);
12575
12576   tree = tree_view->priv->tree;
12577   node = tree->root;
12578   while (node && node->left != tree->nil)
12579     node = node->left;
12580
12581   while (node)
12582     {
12583       if (node->children)
12584         gtk_tree_view_real_collapse_row (tree_view, path, tree, node, FALSE);
12585       indices[0]++;
12586       node = _gtk_rbtree_next (tree, node);
12587     }
12588
12589   gtk_tree_path_free (path);
12590 }
12591
12592 /**
12593  * gtk_tree_view_expand_to_path:
12594  * @tree_view: A #GtkTreeView.
12595  * @path: path to a row.
12596  *
12597  * Expands the row at @path. This will also expand all parent rows of
12598  * @path as necessary.
12599  *
12600  * Since: 2.2
12601  **/
12602 void
12603 gtk_tree_view_expand_to_path (GtkTreeView *tree_view,
12604                               GtkTreePath *path)
12605 {
12606   gint i, depth;
12607   gint *indices;
12608   GtkTreePath *tmp;
12609
12610   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12611   g_return_if_fail (path != NULL);
12612
12613   depth = gtk_tree_path_get_depth (path);
12614   indices = gtk_tree_path_get_indices (path);
12615
12616   tmp = gtk_tree_path_new ();
12617   g_return_if_fail (tmp != NULL);
12618
12619   for (i = 0; i < depth; i++)
12620     {
12621       gtk_tree_path_append_index (tmp, indices[i]);
12622       gtk_tree_view_expand_row (tree_view, tmp, FALSE);
12623     }
12624
12625   gtk_tree_path_free (tmp);
12626 }
12627
12628 /* FIXME the bool return values for expand_row and collapse_row are
12629  * not analagous; they should be TRUE if the row had children and
12630  * was not already in the requested state.
12631  */
12632
12633
12634 static gboolean
12635 gtk_tree_view_real_expand_row (GtkTreeView *tree_view,
12636                                GtkTreePath *path,
12637                                GtkRBTree   *tree,
12638                                GtkRBNode   *node,
12639                                gboolean     open_all,
12640                                gboolean     animate)
12641 {
12642   GtkTreeIter iter;
12643   GtkTreeIter temp;
12644   gboolean expand;
12645
12646   if (animate)
12647     g_object_get (gtk_widget_get_settings (GTK_WIDGET (tree_view)),
12648                   "gtk-enable-animations", &animate,
12649                   NULL);
12650
12651   remove_auto_expand_timeout (tree_view);
12652
12653   if (node->children && !open_all)
12654     return FALSE;
12655
12656   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
12657     return FALSE;
12658
12659   gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
12660   if (! gtk_tree_model_iter_has_child (tree_view->priv->model, &iter))
12661     return FALSE;
12662
12663
12664    if (node->children && open_all)
12665     {
12666       gboolean retval = FALSE;
12667       GtkTreePath *tmp_path = gtk_tree_path_copy (path);
12668
12669       gtk_tree_path_append_index (tmp_path, 0);
12670       tree = node->children;
12671       node = tree->root;
12672       while (node->left != tree->nil)
12673         node = node->left;
12674       /* try to expand the children */
12675       do
12676         {
12677          gboolean t;
12678          t = gtk_tree_view_real_expand_row (tree_view, tmp_path, tree, node,
12679                                             TRUE, animate);
12680          if (t)
12681            retval = TRUE;
12682
12683          gtk_tree_path_next (tmp_path);
12684          node = _gtk_rbtree_next (tree, node);
12685        }
12686       while (node != NULL);
12687
12688       gtk_tree_path_free (tmp_path);
12689
12690       return retval;
12691     }
12692
12693   g_signal_emit (tree_view, tree_view_signals[TEST_EXPAND_ROW], 0, &iter, path, &expand);
12694
12695   if (!gtk_tree_model_iter_has_child (tree_view->priv->model, &iter))
12696     return FALSE;
12697
12698   if (expand)
12699     return FALSE;
12700
12701   node->children = _gtk_rbtree_new ();
12702   node->children->parent_tree = tree;
12703   node->children->parent_node = node;
12704
12705   gtk_tree_model_iter_children (tree_view->priv->model, &temp, &iter);
12706
12707   gtk_tree_view_build_tree (tree_view,
12708                             node->children,
12709                             &temp,
12710                             gtk_tree_path_get_depth (path) + 1,
12711                             open_all);
12712
12713   if (animate)
12714     {
12715       GtkStyleContext *context;
12716
12717       context = gtk_widget_get_style_context (GTK_WIDGET (tree_view));
12718
12719       gtk_style_context_save (context);
12720       gtk_style_context_add_class (context, GTK_STYLE_CLASS_EXPANDER);
12721
12722       gtk_style_context_notify_state_change (context, tree_view->priv->bin_window,
12723                                              node, GTK_STATE_ACTIVE, TRUE);
12724
12725       _gtk_style_context_invalidate_animation_areas (context);
12726       gtk_style_context_restore (context);
12727     }
12728
12729   install_presize_handler (tree_view);
12730
12731   g_signal_emit (tree_view, tree_view_signals[ROW_EXPANDED], 0, &iter, path);
12732   if (open_all && node->children)
12733     {
12734       _gtk_rbtree_traverse (node->children,
12735                             node->children->root,
12736                             G_PRE_ORDER,
12737                             gtk_tree_view_expand_all_emission_helper,
12738                             tree_view);
12739     }
12740   return TRUE;
12741 }
12742
12743
12744 /**
12745  * gtk_tree_view_expand_row:
12746  * @tree_view: a #GtkTreeView
12747  * @path: path to a row
12748  * @open_all: whether to recursively expand, or just expand immediate children
12749  *
12750  * Opens the row so its children are visible.
12751  *
12752  * Return value: %TRUE if the row existed and had children
12753  **/
12754 gboolean
12755 gtk_tree_view_expand_row (GtkTreeView *tree_view,
12756                           GtkTreePath *path,
12757                           gboolean     open_all)
12758 {
12759   GtkRBTree *tree;
12760   GtkRBNode *node;
12761
12762   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12763   g_return_val_if_fail (tree_view->priv->model != NULL, FALSE);
12764   g_return_val_if_fail (path != NULL, FALSE);
12765
12766   if (_gtk_tree_view_find_node (tree_view,
12767                                 path,
12768                                 &tree,
12769                                 &node))
12770     return FALSE;
12771
12772   if (tree != NULL)
12773     return gtk_tree_view_real_expand_row (tree_view, path, tree, node, open_all, FALSE);
12774   else
12775     return FALSE;
12776 }
12777
12778 static gboolean
12779 gtk_tree_view_real_collapse_row (GtkTreeView *tree_view,
12780                                  GtkTreePath *path,
12781                                  GtkRBTree   *tree,
12782                                  GtkRBNode   *node,
12783                                  gboolean     animate)
12784 {
12785   GtkTreeIter iter;
12786   GtkTreeIter children;
12787   gboolean collapse;
12788   gint x, y;
12789   GList *list;
12790   GdkWindow *child, *parent;
12791
12792   if (animate)
12793     g_object_get (gtk_widget_get_settings (GTK_WIDGET (tree_view)),
12794                   "gtk-enable-animations", &animate,
12795                   NULL);
12796
12797   remove_auto_expand_timeout (tree_view);
12798
12799   if (node->children == NULL)
12800     return FALSE;
12801   gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
12802
12803   g_signal_emit (tree_view, tree_view_signals[TEST_COLLAPSE_ROW], 0, &iter, path, &collapse);
12804
12805   if (collapse)
12806     return FALSE;
12807
12808   /* if the prelighted node is a child of us, we want to unprelight it.  We have
12809    * a chance to prelight the correct node below */
12810
12811   if (tree_view->priv->prelight_tree)
12812     {
12813       GtkRBTree *parent_tree;
12814       GtkRBNode *parent_node;
12815
12816       parent_tree = tree_view->priv->prelight_tree->parent_tree;
12817       parent_node = tree_view->priv->prelight_tree->parent_node;
12818       while (parent_tree)
12819         {
12820           if (parent_tree == tree && parent_node == node)
12821             {
12822               ensure_unprelighted (tree_view);
12823               break;
12824             }
12825           parent_node = parent_tree->parent_node;
12826           parent_tree = parent_tree->parent_tree;
12827         }
12828     }
12829
12830   TREE_VIEW_INTERNAL_ASSERT (gtk_tree_model_iter_children (tree_view->priv->model, &children, &iter), FALSE);
12831
12832   for (list = tree_view->priv->columns; list; list = list->next)
12833     {
12834       GtkTreeViewColumn *column = list->data;
12835
12836       if (gtk_tree_view_column_get_visible (column) == FALSE)
12837         continue;
12838       if (gtk_tree_view_column_get_sizing (column) == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
12839         _gtk_tree_view_column_cell_set_dirty (column, TRUE);
12840     }
12841
12842   if (tree_view->priv->destroy_count_func)
12843     {
12844       GtkTreePath *child_path;
12845       gint child_count = 0;
12846       child_path = gtk_tree_path_copy (path);
12847       gtk_tree_path_down (child_path);
12848       if (node->children)
12849         _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, &child_count);
12850       tree_view->priv->destroy_count_func (tree_view, child_path, child_count, tree_view->priv->destroy_count_data);
12851       gtk_tree_path_free (child_path);
12852     }
12853
12854   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
12855     {
12856       GtkTreePath *cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
12857
12858       if (gtk_tree_path_is_ancestor (path, cursor_path))
12859         {
12860           gtk_tree_row_reference_free (tree_view->priv->cursor);
12861           tree_view->priv->cursor = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
12862                                                                       tree_view->priv->model,
12863                                                                       path);
12864         }
12865       gtk_tree_path_free (cursor_path);
12866     }
12867
12868   if (gtk_tree_row_reference_valid (tree_view->priv->anchor))
12869     {
12870       GtkTreePath *anchor_path = gtk_tree_row_reference_get_path (tree_view->priv->anchor);
12871       if (gtk_tree_path_is_ancestor (path, anchor_path))
12872         {
12873           gtk_tree_row_reference_free (tree_view->priv->anchor);
12874           tree_view->priv->anchor = NULL;
12875         }
12876       gtk_tree_path_free (anchor_path);
12877     }
12878
12879   /* Stop a pending double click */
12880   tree_view->priv->last_button_x = -1;
12881   tree_view->priv->last_button_y = -1;
12882
12883   if (gtk_tree_view_unref_and_check_selection_tree (tree_view, node->children))
12884     {
12885       _gtk_rbtree_remove (node->children);
12886       g_signal_emit_by_name (tree_view->priv->selection, "changed");
12887     }
12888   else
12889     _gtk_rbtree_remove (node->children);
12890
12891   if (animate)
12892     {
12893       GtkStyleContext *context;
12894
12895       context = gtk_widget_get_style_context (GTK_WIDGET (tree_view));
12896
12897       gtk_style_context_save (context);
12898       gtk_style_context_add_class (context, GTK_STYLE_CLASS_EXPANDER);
12899
12900       gtk_style_context_notify_state_change (context, tree_view->priv->bin_window,
12901                                              node, GTK_STATE_ACTIVE, FALSE);
12902
12903       _gtk_style_context_invalidate_animation_areas (context);
12904       gtk_style_context_restore (context);
12905     }
12906
12907   if (gtk_widget_get_mapped (GTK_WIDGET (tree_view)))
12908     {
12909       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
12910     }
12911
12912   g_signal_emit (tree_view, tree_view_signals[ROW_COLLAPSED], 0, &iter, path);
12913   
12914   if (gtk_widget_get_mapped (GTK_WIDGET (tree_view)))
12915     {
12916       /* now that we've collapsed all rows, we want to try to set the prelight
12917        * again. To do this, we fake a motion event and send it to ourselves. */
12918
12919       child = tree_view->priv->bin_window;
12920       parent = gdk_window_get_parent (child);
12921
12922       if (gdk_window_get_pointer (parent, &x, &y, NULL) == child)
12923         {
12924           GdkEventMotion event;
12925           gint child_x, child_y;
12926
12927           gdk_window_get_position (child, &child_x, &child_y);
12928
12929           event.window = tree_view->priv->bin_window;
12930           event.x = x - child_x;
12931           event.y = y - child_y;
12932
12933           /* despite the fact this isn't a real event, I'm almost positive it will
12934            * never trigger a drag event.  maybe_drag is the only function that uses
12935            * more than just event.x and event.y. */
12936           gtk_tree_view_motion_bin_window (GTK_WIDGET (tree_view), &event);
12937         }
12938     }
12939
12940   return TRUE;
12941 }
12942
12943 /**
12944  * gtk_tree_view_collapse_row:
12945  * @tree_view: a #GtkTreeView
12946  * @path: path to a row in the @tree_view
12947  *
12948  * Collapses a row (hides its child rows, if they exist).
12949  *
12950  * Return value: %TRUE if the row was collapsed.
12951  **/
12952 gboolean
12953 gtk_tree_view_collapse_row (GtkTreeView *tree_view,
12954                             GtkTreePath *path)
12955 {
12956   GtkRBTree *tree;
12957   GtkRBNode *node;
12958
12959   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12960   g_return_val_if_fail (tree_view->priv->tree != NULL, FALSE);
12961   g_return_val_if_fail (path != NULL, FALSE);
12962
12963   if (_gtk_tree_view_find_node (tree_view,
12964                                 path,
12965                                 &tree,
12966                                 &node))
12967     return FALSE;
12968
12969   if (tree == NULL || node->children == NULL)
12970     return FALSE;
12971
12972   return gtk_tree_view_real_collapse_row (tree_view, path, tree, node, FALSE);
12973 }
12974
12975 static void
12976 gtk_tree_view_map_expanded_rows_helper (GtkTreeView            *tree_view,
12977                                         GtkRBTree              *tree,
12978                                         GtkTreePath            *path,
12979                                         GtkTreeViewMappingFunc  func,
12980                                         gpointer                user_data)
12981 {
12982   GtkRBNode *node;
12983
12984   if (tree == NULL || tree->root == NULL)
12985     return;
12986
12987   node = tree->root;
12988
12989   while (node && node->left != tree->nil)
12990     node = node->left;
12991
12992   while (node)
12993     {
12994       if (node->children)
12995         {
12996           (* func) (tree_view, path, user_data);
12997           gtk_tree_path_down (path);
12998           gtk_tree_view_map_expanded_rows_helper (tree_view, node->children, path, func, user_data);
12999           gtk_tree_path_up (path);
13000         }
13001       gtk_tree_path_next (path);
13002       node = _gtk_rbtree_next (tree, node);
13003     }
13004 }
13005
13006 /**
13007  * gtk_tree_view_map_expanded_rows:
13008  * @tree_view: A #GtkTreeView
13009  * @func: (scope call): A function to be called
13010  * @data: User data to be passed to the function.
13011  *
13012  * Calls @func on all expanded rows.
13013  **/
13014 void
13015 gtk_tree_view_map_expanded_rows (GtkTreeView            *tree_view,
13016                                  GtkTreeViewMappingFunc  func,
13017                                  gpointer                user_data)
13018 {
13019   GtkTreePath *path;
13020
13021   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13022   g_return_if_fail (func != NULL);
13023
13024   path = gtk_tree_path_new_first ();
13025
13026   gtk_tree_view_map_expanded_rows_helper (tree_view,
13027                                           tree_view->priv->tree,
13028                                           path, func, user_data);
13029
13030   gtk_tree_path_free (path);
13031 }
13032
13033 /**
13034  * gtk_tree_view_row_expanded:
13035  * @tree_view: A #GtkTreeView.
13036  * @path: A #GtkTreePath to test expansion state.
13037  *
13038  * Returns %TRUE if the node pointed to by @path is expanded in @tree_view.
13039  *
13040  * Return value: %TRUE if #path is expanded.
13041  **/
13042 gboolean
13043 gtk_tree_view_row_expanded (GtkTreeView *tree_view,
13044                             GtkTreePath *path)
13045 {
13046   GtkRBTree *tree;
13047   GtkRBNode *node;
13048
13049   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
13050   g_return_val_if_fail (path != NULL, FALSE);
13051
13052   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
13053
13054   if (node == NULL)
13055     return FALSE;
13056
13057   return (node->children != NULL);
13058 }
13059
13060 /**
13061  * gtk_tree_view_get_reorderable:
13062  * @tree_view: a #GtkTreeView
13063  *
13064  * Retrieves whether the user can reorder the tree via drag-and-drop. See
13065  * gtk_tree_view_set_reorderable().
13066  *
13067  * Return value: %TRUE if the tree can be reordered.
13068  **/
13069 gboolean
13070 gtk_tree_view_get_reorderable (GtkTreeView *tree_view)
13071 {
13072   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
13073
13074   return tree_view->priv->reorderable;
13075 }
13076
13077 /**
13078  * gtk_tree_view_set_reorderable:
13079  * @tree_view: A #GtkTreeView.
13080  * @reorderable: %TRUE, if the tree can be reordered.
13081  *
13082  * This function is a convenience function to allow you to reorder
13083  * models that support the #GtkDragSourceIface and the
13084  * #GtkDragDestIface.  Both #GtkTreeStore and #GtkListStore support
13085  * these.  If @reorderable is %TRUE, then the user can reorder the
13086  * model by dragging and dropping rows. The developer can listen to
13087  * these changes by connecting to the model's row_inserted and
13088  * row_deleted signals. The reordering is implemented by setting up
13089  * the tree view as a drag source and destination. Therefore, drag and
13090  * drop can not be used in a reorderable view for any other purpose.
13091  *
13092  * This function does not give you any degree of control over the order -- any
13093  * reordering is allowed.  If more control is needed, you should probably
13094  * handle drag and drop manually.
13095  **/
13096 void
13097 gtk_tree_view_set_reorderable (GtkTreeView *tree_view,
13098                                gboolean     reorderable)
13099 {
13100   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13101
13102   reorderable = reorderable != FALSE;
13103
13104   if (tree_view->priv->reorderable == reorderable)
13105     return;
13106
13107   if (reorderable)
13108     {
13109       const GtkTargetEntry row_targets[] = {
13110         { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, 0 }
13111       };
13112
13113       gtk_tree_view_enable_model_drag_source (tree_view,
13114                                               GDK_BUTTON1_MASK,
13115                                               row_targets,
13116                                               G_N_ELEMENTS (row_targets),
13117                                               GDK_ACTION_MOVE);
13118       gtk_tree_view_enable_model_drag_dest (tree_view,
13119                                             row_targets,
13120                                             G_N_ELEMENTS (row_targets),
13121                                             GDK_ACTION_MOVE);
13122     }
13123   else
13124     {
13125       gtk_tree_view_unset_rows_drag_source (tree_view);
13126       gtk_tree_view_unset_rows_drag_dest (tree_view);
13127     }
13128
13129   tree_view->priv->reorderable = reorderable;
13130
13131   g_object_notify (G_OBJECT (tree_view), "reorderable");
13132 }
13133
13134 static void
13135 gtk_tree_view_real_set_cursor (GtkTreeView     *tree_view,
13136                                GtkTreePath     *path,
13137                                gboolean         clear_and_select,
13138                                gboolean         clamp_node)
13139 {
13140   GtkRBTree *tree = NULL;
13141   GtkRBNode *node = NULL;
13142
13143   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
13144     {
13145       GtkTreePath *cursor_path;
13146       cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
13147       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
13148       gtk_tree_path_free (cursor_path);
13149     }
13150
13151   gtk_tree_row_reference_free (tree_view->priv->cursor);
13152   tree_view->priv->cursor = NULL;
13153
13154   /* One cannot set the cursor on a separator.   Also, if
13155    * _gtk_tree_view_find_node returns TRUE, it ran out of tree
13156    * before finding the tree and node belonging to path.  The
13157    * path maps to a non-existing path and we will silently bail out.
13158    * We unset tree and node to avoid further processing.
13159    */
13160   if (!row_is_separator (tree_view, NULL, path)
13161       && _gtk_tree_view_find_node (tree_view, path, &tree, &node) == FALSE)
13162     {
13163       tree_view->priv->cursor =
13164           gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
13165                                             tree_view->priv->model,
13166                                             path);
13167     }
13168   else
13169     {
13170       tree = NULL;
13171       node = NULL;
13172     }
13173
13174   if (tree != NULL)
13175     {
13176       GtkRBTree *new_tree = NULL;
13177       GtkRBNode *new_node = NULL;
13178
13179       if (clear_and_select && !tree_view->priv->ctrl_pressed)
13180         {
13181           GtkTreeSelectMode mode = 0;
13182
13183           if (tree_view->priv->ctrl_pressed)
13184             mode |= GTK_TREE_SELECT_MODE_TOGGLE;
13185           if (tree_view->priv->shift_pressed)
13186             mode |= GTK_TREE_SELECT_MODE_EXTEND;
13187
13188           _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
13189                                                     node, tree, path, mode,
13190                                                     FALSE);
13191         }
13192
13193       /* We have to re-find tree and node here again, somebody might have
13194        * cleared the node or the whole tree in the GtkTreeSelection::changed
13195        * callback. If the nodes differ we bail out here.
13196        */
13197       _gtk_tree_view_find_node (tree_view, path, &new_tree, &new_node);
13198
13199       if (tree != new_tree || node != new_node)
13200         return;
13201
13202       if (clamp_node)
13203         {
13204           gtk_tree_view_clamp_node_visible (tree_view, tree, node);
13205           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
13206         }
13207     }
13208
13209   g_signal_emit (tree_view, tree_view_signals[CURSOR_CHANGED], 0);
13210 }
13211
13212 /**
13213  * gtk_tree_view_get_cursor:
13214  * @tree_view: A #GtkTreeView
13215  * @path: (out) (transfer full) (allow-none): A pointer to be filled with the current cursor path, or %NULL
13216  * @focus_column: (out) (transfer none) (allow-none): A pointer to be filled with the current focus column, or %NULL
13217  *
13218  * Fills in @path and @focus_column with the current path and focus column.  If
13219  * the cursor isn't currently set, then *@path will be %NULL.  If no column
13220  * currently has focus, then *@focus_column will be %NULL.
13221  *
13222  * The returned #GtkTreePath must be freed with gtk_tree_path_free() when
13223  * you are done with it.
13224  **/
13225 void
13226 gtk_tree_view_get_cursor (GtkTreeView        *tree_view,
13227                           GtkTreePath       **path,
13228                           GtkTreeViewColumn **focus_column)
13229 {
13230   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13231
13232   if (path)
13233     {
13234       if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
13235         *path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
13236       else
13237         *path = NULL;
13238     }
13239
13240   if (focus_column)
13241     {
13242       *focus_column = tree_view->priv->focus_column;
13243     }
13244 }
13245
13246 /**
13247  * gtk_tree_view_set_cursor:
13248  * @tree_view: A #GtkTreeView
13249  * @path: A #GtkTreePath
13250  * @focus_column: (allow-none): A #GtkTreeViewColumn, or %NULL
13251  * @start_editing: %TRUE if the specified cell should start being edited.
13252  *
13253  * Sets the current keyboard focus to be at @path, and selects it.  This is
13254  * useful when you want to focus the user's attention on a particular row.  If
13255  * @focus_column is not %NULL, then focus is given to the column specified by 
13256  * it. Additionally, if @focus_column is specified, and @start_editing is 
13257  * %TRUE, then editing should be started in the specified cell.  
13258  * This function is often followed by @gtk_widget_grab_focus (@tree_view) 
13259  * in order to give keyboard focus to the widget.  Please note that editing 
13260  * can only happen when the widget is realized.
13261  *
13262  * If @path is invalid for @model, the current cursor (if any) will be unset
13263  * and the function will return without failing.
13264  **/
13265 void
13266 gtk_tree_view_set_cursor (GtkTreeView       *tree_view,
13267                           GtkTreePath       *path,
13268                           GtkTreeViewColumn *focus_column,
13269                           gboolean           start_editing)
13270 {
13271   gtk_tree_view_set_cursor_on_cell (tree_view, path, focus_column,
13272                                     NULL, start_editing);
13273 }
13274
13275 /**
13276  * gtk_tree_view_set_cursor_on_cell:
13277  * @tree_view: A #GtkTreeView
13278  * @path: A #GtkTreePath
13279  * @focus_column: (allow-none): A #GtkTreeViewColumn, or %NULL
13280  * @focus_cell: (allow-none): A #GtkCellRenderer, or %NULL
13281  * @start_editing: %TRUE if the specified cell should start being edited.
13282  *
13283  * Sets the current keyboard focus to be at @path, and selects it.  This is
13284  * useful when you want to focus the user's attention on a particular row.  If
13285  * @focus_column is not %NULL, then focus is given to the column specified by
13286  * it. If @focus_column and @focus_cell are not %NULL, and @focus_column
13287  * contains 2 or more editable or activatable cells, then focus is given to
13288  * the cell specified by @focus_cell. Additionally, if @focus_column is
13289  * specified, and @start_editing is %TRUE, then editing should be started in
13290  * the specified cell.  This function is often followed by
13291  * @gtk_widget_grab_focus (@tree_view) in order to give keyboard focus to the
13292  * widget.  Please note that editing can only happen when the widget is
13293  * realized.
13294  *
13295  * If @path is invalid for @model, the current cursor (if any) will be unset
13296  * and the function will return without failing.
13297  *
13298  * Since: 2.2
13299  **/
13300 void
13301 gtk_tree_view_set_cursor_on_cell (GtkTreeView       *tree_view,
13302                                   GtkTreePath       *path,
13303                                   GtkTreeViewColumn *focus_column,
13304                                   GtkCellRenderer   *focus_cell,
13305                                   gboolean           start_editing)
13306 {
13307   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13308   g_return_if_fail (path != NULL);
13309   g_return_if_fail (focus_column == NULL || GTK_IS_TREE_VIEW_COLUMN (focus_column));
13310
13311   if (!tree_view->priv->model)
13312     return;
13313
13314   if (focus_cell)
13315     {
13316       g_return_if_fail (focus_column);
13317       g_return_if_fail (GTK_IS_CELL_RENDERER (focus_cell));
13318     }
13319
13320   /* cancel the current editing, if it exists */
13321   if (tree_view->priv->edited_column &&
13322       gtk_cell_area_get_edit_widget
13323       (gtk_cell_layout_get_area (GTK_CELL_LAYOUT (tree_view->priv->edited_column))))
13324     gtk_tree_view_stop_editing (tree_view, TRUE);
13325
13326   gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
13327
13328   if (focus_column &&
13329       gtk_tree_view_column_get_visible (focus_column))
13330     {
13331       GList *list;
13332       gboolean column_in_tree = FALSE;
13333
13334       for (list = tree_view->priv->columns; list; list = list->next)
13335         if (list->data == focus_column)
13336           {
13337             column_in_tree = TRUE;
13338             break;
13339           }
13340       g_return_if_fail (column_in_tree);
13341       tree_view->priv->focus_column = focus_column;
13342       if (focus_cell)
13343         gtk_tree_view_column_focus_cell (focus_column, focus_cell);
13344       if (start_editing)
13345         gtk_tree_view_start_editing (tree_view, path, TRUE);
13346     }
13347 }
13348
13349 /**
13350  * gtk_tree_view_get_bin_window:
13351  * @tree_view: A #GtkTreeView
13352  *
13353  * Returns the window that @tree_view renders to.
13354  * This is used primarily to compare to <literal>event->window</literal>
13355  * to confirm that the event on @tree_view is on the right window.
13356  *
13357  * Return value: (transfer none): A #GdkWindow, or %NULL when @tree_view
13358  *     hasn't been realized yet
13359  **/
13360 GdkWindow *
13361 gtk_tree_view_get_bin_window (GtkTreeView *tree_view)
13362 {
13363   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
13364
13365   return tree_view->priv->bin_window;
13366 }
13367
13368 /**
13369  * gtk_tree_view_get_path_at_pos:
13370  * @tree_view: A #GtkTreeView.
13371  * @x: The x position to be identified (relative to bin_window).
13372  * @y: The y position to be identified (relative to bin_window).
13373  * @path: (out) (allow-none): A pointer to a #GtkTreePath pointer to be filled in, or %NULL
13374  * @column: (out) (transfer none) (allow-none): A pointer to a #GtkTreeViewColumn pointer to be filled in, or %NULL
13375  * @cell_x: (out) (allow-none): A pointer where the X coordinate relative to the cell can be placed, or %NULL
13376  * @cell_y: (out) (allow-none): A pointer where the Y coordinate relative to the cell can be placed, or %NULL
13377  *
13378  * Finds the path at the point (@x, @y), relative to bin_window coordinates
13379  * (please see gtk_tree_view_get_bin_window()).
13380  * That is, @x and @y are relative to an events coordinates. @x and @y must
13381  * come from an event on the @tree_view only where <literal>event->window ==
13382  * gtk_tree_view_get_bin_window (<!-- -->)</literal>. It is primarily for
13383  * things like popup menus. If @path is non-%NULL, then it will be filled
13384  * with the #GtkTreePath at that point.  This path should be freed with
13385  * gtk_tree_path_free().  If @column is non-%NULL, then it will be filled
13386  * with the column at that point.  @cell_x and @cell_y return the coordinates
13387  * relative to the cell background (i.e. the @background_area passed to
13388  * gtk_cell_renderer_render()).  This function is only meaningful if
13389  * @tree_view is realized.  Therefore this function will always return %FALSE
13390  * if @tree_view is not realized or does not have a model.
13391  *
13392  * For converting widget coordinates (eg. the ones you get from
13393  * GtkWidget::query-tooltip), please see
13394  * gtk_tree_view_convert_widget_to_bin_window_coords().
13395  *
13396  * Return value: %TRUE if a row exists at that coordinate.
13397  **/
13398 gboolean
13399 gtk_tree_view_get_path_at_pos (GtkTreeView        *tree_view,
13400                                gint                x,
13401                                gint                y,
13402                                GtkTreePath       **path,
13403                                GtkTreeViewColumn **column,
13404                                gint               *cell_x,
13405                                gint               *cell_y)
13406 {
13407   GtkRBTree *tree;
13408   GtkRBNode *node;
13409   gint y_offset;
13410
13411   g_return_val_if_fail (tree_view != NULL, FALSE);
13412
13413   if (path)
13414     *path = NULL;
13415   if (column)
13416     *column = NULL;
13417
13418   if (tree_view->priv->bin_window == NULL)
13419     return FALSE;
13420
13421   if (tree_view->priv->tree == NULL)
13422     return FALSE;
13423
13424   if (x > gtk_adjustment_get_upper (tree_view->priv->hadjustment))
13425     return FALSE;
13426
13427   if (x < 0 || y < 0)
13428     return FALSE;
13429
13430   if (column || cell_x)
13431     {
13432       GtkTreeViewColumn *tmp_column;
13433       GtkTreeViewColumn *last_column = NULL;
13434       GList *list;
13435       gint remaining_x = x;
13436       gboolean found = FALSE;
13437       gboolean rtl;
13438       gint width;
13439
13440       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
13441       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
13442            list;
13443            list = (rtl ? list->prev : list->next))
13444         {
13445           tmp_column = list->data;
13446
13447           if (gtk_tree_view_column_get_visible (tmp_column) == FALSE)
13448             continue;
13449
13450           last_column = tmp_column;
13451           width = gtk_tree_view_column_get_width (tmp_column);
13452           if (remaining_x <= width)
13453             {
13454               found = TRUE;
13455
13456               if (column)
13457                 *column = tmp_column;
13458
13459               if (cell_x)
13460                 *cell_x = remaining_x;
13461
13462               break;
13463             }
13464           remaining_x -= width;
13465         }
13466
13467       /* If found is FALSE and there is a last_column, then it the remainder
13468        * space is in that area
13469        */
13470       if (!found)
13471         {
13472           if (last_column)
13473             {
13474               if (column)
13475                 *column = last_column;
13476               
13477               if (cell_x)
13478                 *cell_x = gtk_tree_view_column_get_width (last_column) + remaining_x;
13479             }
13480           else
13481             {
13482               return FALSE;
13483             }
13484         }
13485     }
13486
13487   y_offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
13488                                       TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, y),
13489                                       &tree, &node);
13490
13491   if (tree == NULL)
13492     return FALSE;
13493
13494   if (cell_y)
13495     *cell_y = y_offset;
13496
13497   if (path)
13498     *path = _gtk_tree_view_find_path (tree_view, tree, node);
13499
13500   return TRUE;
13501 }
13502
13503
13504 static inline gint
13505 gtk_tree_view_get_cell_area_height (GtkTreeView *tree_view,
13506                                     GtkRBNode   *node,
13507                                     gint         vertical_separator)
13508 {
13509   int height;
13510
13511   /* The "cell" areas are the cell_area passed in to gtk_cell_renderer_render(),
13512    * i.e. just the cells, no spacing.
13513    *
13514    * The cell area height is at least expander_size - vertical_separator.
13515    * For regular nodes, the height is then at least expander_size. We should
13516    * be able to enforce the expander_size minimum here, because this
13517    * function will not be called for irregular (e.g. separator) rows.
13518    */
13519   height = gtk_tree_view_get_row_height (tree_view, node);
13520   if (height < tree_view->priv->expander_size)
13521     height = tree_view->priv->expander_size;
13522
13523   return height - vertical_separator;
13524 }
13525
13526 static inline gint
13527 gtk_tree_view_get_cell_area_y_offset (GtkTreeView *tree_view,
13528                                       GtkRBTree   *tree,
13529                                       GtkRBNode   *node,
13530                                       gint         vertical_separator)
13531 {
13532   int offset;
13533
13534   offset = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
13535   offset += vertical_separator / 2;
13536
13537   return offset;
13538 }
13539
13540 /**
13541  * gtk_tree_view_get_cell_area:
13542  * @tree_view: a #GtkTreeView
13543  * @path: (allow-none): a #GtkTreePath for the row, or %NULL to get only horizontal coordinates
13544  * @column: (allow-none): a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordinates
13545  * @rect: (out): rectangle to fill with cell rect
13546  *
13547  * Fills the bounding rectangle in bin_window coordinates for the cell at the
13548  * row specified by @path and the column specified by @column.  If @path is
13549  * %NULL, or points to a path not currently displayed, the @y and @height fields
13550  * of the rectangle will be filled with 0. If @column is %NULL, the @x and @width
13551  * fields will be filled with 0.  The sum of all cell rects does not cover the
13552  * entire tree; there are extra pixels in between rows, for example. The
13553  * returned rectangle is equivalent to the @cell_area passed to
13554  * gtk_cell_renderer_render().  This function is only valid if @tree_view is
13555  * realized.
13556  **/
13557 void
13558 gtk_tree_view_get_cell_area (GtkTreeView        *tree_view,
13559                              GtkTreePath        *path,
13560                              GtkTreeViewColumn  *column,
13561                              GdkRectangle       *rect)
13562 {
13563   GtkAllocation allocation;
13564   GtkRBTree *tree = NULL;
13565   GtkRBNode *node = NULL;
13566   gint vertical_separator;
13567   gint horizontal_separator;
13568
13569   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13570   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
13571   g_return_if_fail (rect != NULL);
13572   g_return_if_fail (!column || gtk_tree_view_column_get_tree_view (column) == (GtkWidget *) tree_view);
13573   g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (tree_view)));
13574
13575   gtk_widget_style_get (GTK_WIDGET (tree_view),
13576                         "vertical-separator", &vertical_separator,
13577                         "horizontal-separator", &horizontal_separator,
13578                         NULL);
13579
13580   rect->x = 0;
13581   rect->y = 0;
13582   rect->width = 0;
13583   rect->height = 0;
13584
13585   if (column)
13586     {
13587       gtk_widget_get_allocation (gtk_tree_view_column_get_button (column), &allocation);
13588       rect->x = allocation.x + horizontal_separator/2;
13589       rect->width = allocation.width - horizontal_separator;
13590     }
13591
13592   if (path)
13593     {
13594       gboolean ret = _gtk_tree_view_find_node (tree_view, path, &tree, &node);
13595
13596       /* Get vertical coords */
13597       if ((!ret && tree == NULL) || ret)
13598         return;
13599
13600       if (row_is_separator (tree_view, NULL, path))
13601         {
13602           /* There isn't really a "cell area" for separator, so we
13603            * return the y, height values for background area instead.
13604            */
13605           rect->y = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
13606           rect->height = gtk_tree_view_get_row_height (tree_view, node);
13607         }
13608       else
13609         {
13610           rect->y = gtk_tree_view_get_cell_area_y_offset (tree_view, tree, node,
13611                                                           vertical_separator);
13612           rect->height = gtk_tree_view_get_cell_area_height (tree_view, node,
13613                                                              vertical_separator);
13614         }
13615
13616       if (column &&
13617           gtk_tree_view_is_expander_column (tree_view, column))
13618         {
13619           gint depth = gtk_tree_path_get_depth (path);
13620           gboolean rtl;
13621
13622           rtl = gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL;
13623
13624           if (!rtl)
13625             rect->x += (depth - 1) * tree_view->priv->level_indentation;
13626           rect->width -= (depth - 1) * tree_view->priv->level_indentation;
13627
13628           if (gtk_tree_view_draw_expanders (tree_view))
13629             {
13630               if (!rtl)
13631                 rect->x += depth * tree_view->priv->expander_size;
13632               rect->width -= depth * tree_view->priv->expander_size;
13633             }
13634
13635           rect->width = MAX (rect->width, 0);
13636         }
13637     }
13638 }
13639
13640 static inline gint
13641 gtk_tree_view_get_row_height (GtkTreeView *tree_view,
13642                               GtkRBNode   *node)
13643 {
13644   int height;
13645
13646   /* The "background" areas of all rows/cells add up to cover the entire tree.
13647    * The background includes all inter-row and inter-cell spacing.
13648    *
13649    * If the row pointed at by node does not have a height set, we default
13650    * to expander_size, which is the minimum height for regular nodes.
13651    * Non-regular nodes (e.g. separators) can have a height set smaller
13652    * than expander_size and should not be overruled here.
13653    */
13654   height = GTK_RBNODE_GET_HEIGHT (node);
13655   if (height <= 0)
13656     height = tree_view->priv->expander_size;
13657
13658   return height;
13659 }
13660
13661 static inline gint
13662 gtk_tree_view_get_row_y_offset (GtkTreeView *tree_view,
13663                                 GtkRBTree   *tree,
13664                                 GtkRBNode   *node)
13665 {
13666   int offset;
13667
13668   offset = _gtk_rbtree_node_find_offset (tree, node);
13669
13670   return RBTREE_Y_TO_TREE_WINDOW_Y (tree_view, offset);
13671 }
13672
13673 /**
13674  * gtk_tree_view_get_background_area:
13675  * @tree_view: a #GtkTreeView
13676  * @path: (allow-none): a #GtkTreePath for the row, or %NULL to get only horizontal coordinates
13677  * @column: (allow-none): a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordiantes
13678  * @rect: (out): rectangle to fill with cell background rect
13679  *
13680  * Fills the bounding rectangle in bin_window coordinates for the cell at the
13681  * row specified by @path and the column specified by @column.  If @path is
13682  * %NULL, or points to a node not found in the tree, the @y and @height fields of
13683  * the rectangle will be filled with 0. If @column is %NULL, the @x and @width
13684  * fields will be filled with 0.  The returned rectangle is equivalent to the
13685  * @background_area passed to gtk_cell_renderer_render().  These background
13686  * areas tile to cover the entire bin window.  Contrast with the @cell_area,
13687  * returned by gtk_tree_view_get_cell_area(), which returns only the cell
13688  * itself, excluding surrounding borders and the tree expander area.
13689  *
13690  **/
13691 void
13692 gtk_tree_view_get_background_area (GtkTreeView        *tree_view,
13693                                    GtkTreePath        *path,
13694                                    GtkTreeViewColumn  *column,
13695                                    GdkRectangle       *rect)
13696 {
13697   GtkRBTree *tree = NULL;
13698   GtkRBNode *node = NULL;
13699
13700   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13701   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
13702   g_return_if_fail (rect != NULL);
13703
13704   rect->x = 0;
13705   rect->y = 0;
13706   rect->width = 0;
13707   rect->height = 0;
13708
13709   if (path)
13710     {
13711       /* Get vertical coords */
13712
13713       if (!_gtk_tree_view_find_node (tree_view, path, &tree, &node) &&
13714           tree == NULL)
13715         return;
13716
13717       rect->y = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
13718       rect->height = gtk_tree_view_get_row_height (tree_view, node);
13719     }
13720
13721   if (column)
13722     {
13723       gint x2 = 0;
13724
13725       gtk_tree_view_get_background_xrange (tree_view, tree, column, &rect->x, &x2);
13726       rect->width = x2 - rect->x;
13727     }
13728 }
13729
13730 /**
13731  * gtk_tree_view_get_visible_rect:
13732  * @tree_view: a #GtkTreeView
13733  * @visible_rect: (out): rectangle to fill
13734  *
13735  * Fills @visible_rect with the currently-visible region of the
13736  * buffer, in tree coordinates. Convert to bin_window coordinates with
13737  * gtk_tree_view_convert_tree_to_bin_window_coords().
13738  * Tree coordinates start at 0,0 for row 0 of the tree, and cover the entire
13739  * scrollable area of the tree.
13740  **/
13741 void
13742 gtk_tree_view_get_visible_rect (GtkTreeView  *tree_view,
13743                                 GdkRectangle *visible_rect)
13744 {
13745   GtkAllocation allocation;
13746   GtkWidget *widget;
13747
13748   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13749
13750   widget = GTK_WIDGET (tree_view);
13751
13752   if (visible_rect)
13753     {
13754       gtk_widget_get_allocation (widget, &allocation);
13755       visible_rect->x = gtk_adjustment_get_value (tree_view->priv->hadjustment);
13756       visible_rect->y = gtk_adjustment_get_value (tree_view->priv->vadjustment);
13757       visible_rect->width = allocation.width;
13758       visible_rect->height = allocation.height - gtk_tree_view_get_effective_header_height (tree_view);
13759     }
13760 }
13761
13762 /**
13763  * gtk_tree_view_convert_widget_to_tree_coords:
13764  * @tree_view: a #GtkTreeView
13765  * @wx: X coordinate relative to the widget
13766  * @wy: Y coordinate relative to the widget
13767  * @tx: (out): return location for tree X coordinate
13768  * @ty: (out): return location for tree Y coordinate
13769  *
13770  * Converts widget coordinates to coordinates for the
13771  * tree (the full scrollable area of the tree).
13772  *
13773  * Since: 2.12
13774  **/
13775 void
13776 gtk_tree_view_convert_widget_to_tree_coords (GtkTreeView *tree_view,
13777                                              gint         wx,
13778                                              gint         wy,
13779                                              gint        *tx,
13780                                              gint        *ty)
13781 {
13782   gint x, y;
13783
13784   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13785
13786   gtk_tree_view_convert_widget_to_bin_window_coords (tree_view,
13787                                                      wx, wy,
13788                                                      &x, &y);
13789   gtk_tree_view_convert_bin_window_to_tree_coords (tree_view,
13790                                                    x, y,
13791                                                    tx, ty);
13792 }
13793
13794 /**
13795  * gtk_tree_view_convert_tree_to_widget_coords:
13796  * @tree_view: a #GtkTreeView
13797  * @tx: X coordinate relative to the tree
13798  * @ty: Y coordinate relative to the tree
13799  * @wx: (out): return location for widget X coordinate
13800  * @wy: (out): return location for widget Y coordinate
13801  *
13802  * Converts tree coordinates (coordinates in full scrollable area of the tree)
13803  * to widget coordinates.
13804  *
13805  * Since: 2.12
13806  **/
13807 void
13808 gtk_tree_view_convert_tree_to_widget_coords (GtkTreeView *tree_view,
13809                                              gint         tx,
13810                                              gint         ty,
13811                                              gint        *wx,
13812                                              gint        *wy)
13813 {
13814   gint x, y;
13815
13816   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13817
13818   gtk_tree_view_convert_tree_to_bin_window_coords (tree_view,
13819                                                    tx, ty,
13820                                                    &x, &y);
13821   gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
13822                                                      x, y,
13823                                                      wx, wy);
13824 }
13825
13826 /**
13827  * gtk_tree_view_convert_widget_to_bin_window_coords:
13828  * @tree_view: a #GtkTreeView
13829  * @wx: X coordinate relative to the widget
13830  * @wy: Y coordinate relative to the widget
13831  * @bx: (out): return location for bin_window X coordinate
13832  * @by: (out): return location for bin_window Y coordinate
13833  *
13834  * Converts widget coordinates to coordinates for the bin_window
13835  * (see gtk_tree_view_get_bin_window()).
13836  *
13837  * Since: 2.12
13838  **/
13839 void
13840 gtk_tree_view_convert_widget_to_bin_window_coords (GtkTreeView *tree_view,
13841                                                    gint         wx,
13842                                                    gint         wy,
13843                                                    gint        *bx,
13844                                                    gint        *by)
13845 {
13846   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13847
13848   if (bx)
13849     *bx = wx + gtk_adjustment_get_value (tree_view->priv->hadjustment);
13850   if (by)
13851     *by = wy - gtk_tree_view_get_effective_header_height (tree_view);
13852 }
13853
13854 /**
13855  * gtk_tree_view_convert_bin_window_to_widget_coords:
13856  * @tree_view: a #GtkTreeView
13857  * @bx: bin_window X coordinate
13858  * @by: bin_window Y coordinate
13859  * @wx: (out): return location for widget X coordinate
13860  * @wy: (out): return location for widget Y coordinate
13861  *
13862  * Converts bin_window coordinates (see gtk_tree_view_get_bin_window())
13863  * to widget relative coordinates.
13864  *
13865  * Since: 2.12
13866  **/
13867 void
13868 gtk_tree_view_convert_bin_window_to_widget_coords (GtkTreeView *tree_view,
13869                                                    gint         bx,
13870                                                    gint         by,
13871                                                    gint        *wx,
13872                                                    gint        *wy)
13873 {
13874   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13875
13876   if (wx)
13877     *wx = bx - gtk_adjustment_get_value (tree_view->priv->hadjustment);
13878   if (wy)
13879     *wy = by + gtk_tree_view_get_effective_header_height (tree_view);
13880 }
13881
13882 /**
13883  * gtk_tree_view_convert_tree_to_bin_window_coords:
13884  * @tree_view: a #GtkTreeView
13885  * @tx: tree X coordinate
13886  * @ty: tree Y coordinate
13887  * @bx: (out): return location for X coordinate relative to bin_window
13888  * @by: (out): return location for Y coordinate relative to bin_window
13889  *
13890  * Converts tree coordinates (coordinates in full scrollable area of the tree)
13891  * to bin_window coordinates.
13892  *
13893  * Since: 2.12
13894  **/
13895 void
13896 gtk_tree_view_convert_tree_to_bin_window_coords (GtkTreeView *tree_view,
13897                                                  gint         tx,
13898                                                  gint         ty,
13899                                                  gint        *bx,
13900                                                  gint        *by)
13901 {
13902   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13903
13904   if (bx)
13905     *bx = tx;
13906   if (by)
13907     *by = ty - tree_view->priv->dy;
13908 }
13909
13910 /**
13911  * gtk_tree_view_convert_bin_window_to_tree_coords:
13912  * @tree_view: a #GtkTreeView
13913  * @bx: X coordinate relative to bin_window
13914  * @by: Y coordinate relative to bin_window
13915  * @tx: (out): return location for tree X coordinate
13916  * @ty: (out): return location for tree Y coordinate
13917  *
13918  * Converts bin_window coordinates to coordinates for the
13919  * tree (the full scrollable area of the tree).
13920  *
13921  * Since: 2.12
13922  **/
13923 void
13924 gtk_tree_view_convert_bin_window_to_tree_coords (GtkTreeView *tree_view,
13925                                                  gint         bx,
13926                                                  gint         by,
13927                                                  gint        *tx,
13928                                                  gint        *ty)
13929 {
13930   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13931
13932   if (tx)
13933     *tx = bx;
13934   if (ty)
13935     *ty = by + tree_view->priv->dy;
13936 }
13937
13938
13939
13940 /**
13941  * gtk_tree_view_get_visible_range:
13942  * @tree_view: A #GtkTreeView
13943  * @start_path: (out) (allow-none): Return location for start of region,
13944  *              or %NULL.
13945  * @end_path: (out) (allow-none): Return location for end of region, or %NULL.
13946  *
13947  * Sets @start_path and @end_path to be the first and last visible path.
13948  * Note that there may be invisible paths in between.
13949  *
13950  * The paths should be freed with gtk_tree_path_free() after use.
13951  *
13952  * Returns: %TRUE, if valid paths were placed in @start_path and @end_path.
13953  *
13954  * Since: 2.8
13955  **/
13956 gboolean
13957 gtk_tree_view_get_visible_range (GtkTreeView  *tree_view,
13958                                  GtkTreePath **start_path,
13959                                  GtkTreePath **end_path)
13960 {
13961   GtkRBTree *tree;
13962   GtkRBNode *node;
13963   gboolean retval;
13964   
13965   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
13966
13967   if (!tree_view->priv->tree)
13968     return FALSE;
13969
13970   retval = TRUE;
13971
13972   if (start_path)
13973     {
13974       _gtk_rbtree_find_offset (tree_view->priv->tree,
13975                                TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, 0),
13976                                &tree, &node);
13977       if (node)
13978         *start_path = _gtk_tree_view_find_path (tree_view, tree, node);
13979       else
13980         retval = FALSE;
13981     }
13982
13983   if (end_path)
13984     {
13985       gint y;
13986
13987       if (tree_view->priv->height < gtk_adjustment_get_page_size (tree_view->priv->vadjustment))
13988         y = tree_view->priv->height - 1;
13989       else
13990         y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, gtk_adjustment_get_page_size (tree_view->priv->vadjustment)) - 1;
13991
13992       _gtk_rbtree_find_offset (tree_view->priv->tree, y, &tree, &node);
13993       if (node)
13994         *end_path = _gtk_tree_view_find_path (tree_view, tree, node);
13995       else
13996         retval = FALSE;
13997     }
13998
13999   return retval;
14000 }
14001
14002 /**
14003  * gtk_tree_view_is_blank_at_pos:
14004  * @tree_view: A #GtkTreeView
14005  * @x: The x position to be identified (relative to bin_window)
14006  * @y: The y position to be identified (relative to bin_window)
14007  * @path: (out) (allow-none): A pointer to a #GtkTreePath pointer to be filled in, or %NULL
14008  * @column: (out) (allow-none): A pointer to a #GtkTreeViewColumn pointer to be filled in, or %NULL
14009  * @cell_x: (out) (allow-none): A pointer where the X coordinate relative to the cell can be placed, or %NULL
14010  * @cell_y: (out) (allow-none): A pointer where the Y coordinate relative to the cell can be placed, or %NULL
14011  *
14012  * Determine whether the point (@x, @y) in @tree_view is blank, that is no
14013  * cell content nor an expander arrow is drawn at the location. If so, the
14014  * location can be considered as the background. You might wish to take
14015  * special action on clicks on the background, such as clearing a current
14016  * selection, having a custom context menu or starting rubber banding.
14017  *
14018  * The @x and @y coordinate that are provided must be relative to bin_window
14019  * coordinates.  That is, @x and @y must come from an event on @tree_view
14020  * where <literal>event->window == gtk_tree_view_get_bin_window (<!-- -->)</literal>.
14021  *
14022  * For converting widget coordinates (eg. the ones you get from
14023  * GtkWidget::query-tooltip), please see
14024  * gtk_tree_view_convert_widget_to_bin_window_coords().
14025  *
14026  * The @path, @column, @cell_x and @cell_y arguments will be filled in
14027  * likewise as for gtk_tree_view_get_path_at_pos().  Please see
14028  * gtk_tree_view_get_path_at_pos() for more information.
14029  *
14030  * Return value: %TRUE if the area at the given coordinates is blank,
14031  * %FALSE otherwise.
14032  *
14033  * Since: 3.0
14034  */
14035 gboolean
14036 gtk_tree_view_is_blank_at_pos (GtkTreeView       *tree_view,
14037                                gint                x,
14038                                gint                y,
14039                                GtkTreePath       **path,
14040                                GtkTreeViewColumn **column,
14041                                gint               *cell_x,
14042                                gint               *cell_y)
14043 {
14044   GtkRBTree *tree;
14045   GtkRBNode *node;
14046   GtkTreeIter iter;
14047   GtkTreePath *real_path;
14048   GtkTreeViewColumn *real_column;
14049   GdkRectangle cell_area, background_area;
14050
14051   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
14052
14053   if (!gtk_tree_view_get_path_at_pos (tree_view, x, y,
14054                                       &real_path, &real_column,
14055                                       cell_x, cell_y))
14056     /* If there's no path here, it is blank */
14057     return TRUE;
14058
14059   if (path)
14060     *path = real_path;
14061
14062   if (column)
14063     *column = real_column;
14064
14065   gtk_tree_model_get_iter (tree_view->priv->model, &iter, real_path);
14066   _gtk_tree_view_find_node (tree_view, real_path, &tree, &node);
14067
14068   /* Check if there's an expander arrow at (x, y) */
14069   if (real_column == tree_view->priv->expander_column
14070       && gtk_tree_view_draw_expanders (tree_view))
14071     {
14072       gboolean over_arrow;
14073
14074       over_arrow = coords_are_over_arrow (tree_view, tree, node, x, y);
14075
14076       if (over_arrow)
14077         {
14078           if (!path)
14079             gtk_tree_path_free (real_path);
14080           return FALSE;
14081         }
14082     }
14083
14084   /* Otherwise, have the column see if there's a cell at (x, y) */
14085   gtk_tree_view_column_cell_set_cell_data (real_column,
14086                                            tree_view->priv->model,
14087                                            &iter,
14088                                            GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
14089                                            node->children ? TRUE : FALSE);
14090
14091   gtk_tree_view_get_background_area (tree_view, real_path, real_column,
14092                                      &background_area);
14093   gtk_tree_view_get_cell_area (tree_view, real_path, real_column,
14094                                &cell_area);
14095
14096   if (!path)
14097     gtk_tree_path_free (real_path);
14098
14099   return _gtk_tree_view_column_is_blank_at_pos (real_column,
14100                                                 &cell_area,
14101                                                 &background_area,
14102                                                 x, y);
14103 }
14104
14105 static void
14106 unset_reorderable (GtkTreeView *tree_view)
14107 {
14108   if (tree_view->priv->reorderable)
14109     {
14110       tree_view->priv->reorderable = FALSE;
14111       g_object_notify (G_OBJECT (tree_view), "reorderable");
14112     }
14113 }
14114
14115 /**
14116  * gtk_tree_view_enable_model_drag_source:
14117  * @tree_view: a #GtkTreeView
14118  * @start_button_mask: Mask of allowed buttons to start drag
14119  * @targets: (array): the table of targets that the drag will support
14120  * @n_targets: the number of items in @targets
14121  * @actions: the bitmask of possible actions for a drag from this
14122  *    widget
14123  *
14124  * Turns @tree_view into a drag source for automatic DND. Calling this
14125  * method sets #GtkTreeView:reorderable to %FALSE.
14126  **/
14127 void
14128 gtk_tree_view_enable_model_drag_source (GtkTreeView              *tree_view,
14129                                         GdkModifierType           start_button_mask,
14130                                         const GtkTargetEntry     *targets,
14131                                         gint                      n_targets,
14132                                         GdkDragAction             actions)
14133 {
14134   TreeViewDragInfo *di;
14135
14136   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14137
14138   gtk_drag_source_set (GTK_WIDGET (tree_view),
14139                        0,
14140                        targets,
14141                        n_targets,
14142                        actions);
14143
14144   di = ensure_info (tree_view);
14145
14146   di->start_button_mask = start_button_mask;
14147   di->source_actions = actions;
14148   di->source_set = TRUE;
14149
14150   unset_reorderable (tree_view);
14151 }
14152
14153 /**
14154  * gtk_tree_view_enable_model_drag_dest:
14155  * @tree_view: a #GtkTreeView
14156  * @targets: (array length=n_targets): the table of targets that
14157  *           the drag will support
14158  * @n_targets: the number of items in @targets
14159  * @actions: the bitmask of possible actions for a drag from this
14160  *    widget
14161  * 
14162  * Turns @tree_view into a drop destination for automatic DND. Calling
14163  * this method sets #GtkTreeView:reorderable to %FALSE.
14164  **/
14165 void
14166 gtk_tree_view_enable_model_drag_dest (GtkTreeView              *tree_view,
14167                                       const GtkTargetEntry     *targets,
14168                                       gint                      n_targets,
14169                                       GdkDragAction             actions)
14170 {
14171   TreeViewDragInfo *di;
14172
14173   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14174
14175   gtk_drag_dest_set (GTK_WIDGET (tree_view),
14176                      0,
14177                      targets,
14178                      n_targets,
14179                      actions);
14180
14181   di = ensure_info (tree_view);
14182   di->dest_set = TRUE;
14183
14184   unset_reorderable (tree_view);
14185 }
14186
14187 /**
14188  * gtk_tree_view_unset_rows_drag_source:
14189  * @tree_view: a #GtkTreeView
14190  *
14191  * Undoes the effect of
14192  * gtk_tree_view_enable_model_drag_source(). Calling this method sets
14193  * #GtkTreeView:reorderable to %FALSE.
14194  **/
14195 void
14196 gtk_tree_view_unset_rows_drag_source (GtkTreeView *tree_view)
14197 {
14198   TreeViewDragInfo *di;
14199
14200   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14201
14202   di = get_info (tree_view);
14203
14204   if (di)
14205     {
14206       if (di->source_set)
14207         {
14208           gtk_drag_source_unset (GTK_WIDGET (tree_view));
14209           di->source_set = FALSE;
14210         }
14211
14212       if (!di->dest_set && !di->source_set)
14213         remove_info (tree_view);
14214     }
14215   
14216   unset_reorderable (tree_view);
14217 }
14218
14219 /**
14220  * gtk_tree_view_unset_rows_drag_dest:
14221  * @tree_view: a #GtkTreeView
14222  *
14223  * Undoes the effect of
14224  * gtk_tree_view_enable_model_drag_dest(). Calling this method sets
14225  * #GtkTreeView:reorderable to %FALSE.
14226  **/
14227 void
14228 gtk_tree_view_unset_rows_drag_dest (GtkTreeView *tree_view)
14229 {
14230   TreeViewDragInfo *di;
14231
14232   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14233
14234   di = get_info (tree_view);
14235
14236   if (di)
14237     {
14238       if (di->dest_set)
14239         {
14240           gtk_drag_dest_unset (GTK_WIDGET (tree_view));
14241           di->dest_set = FALSE;
14242         }
14243
14244       if (!di->dest_set && !di->source_set)
14245         remove_info (tree_view);
14246     }
14247
14248   unset_reorderable (tree_view);
14249 }
14250
14251 /**
14252  * gtk_tree_view_set_drag_dest_row:
14253  * @tree_view: a #GtkTreeView
14254  * @path: (allow-none): The path of the row to highlight, or %NULL.
14255  * @pos: Specifies whether to drop before, after or into the row
14256  * 
14257  * Sets the row that is highlighted for feedback.
14258  **/
14259 void
14260 gtk_tree_view_set_drag_dest_row (GtkTreeView            *tree_view,
14261                                  GtkTreePath            *path,
14262                                  GtkTreeViewDropPosition pos)
14263 {
14264   GtkTreePath *current_dest;
14265
14266   /* Note; this function is exported to allow a custom DND
14267    * implementation, so it can't touch TreeViewDragInfo
14268    */
14269
14270   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14271
14272   current_dest = NULL;
14273
14274   if (tree_view->priv->drag_dest_row)
14275     {
14276       current_dest = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
14277       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
14278     }
14279
14280   /* special case a drop on an empty model */
14281   tree_view->priv->empty_view_drop = 0;
14282
14283   if (pos == GTK_TREE_VIEW_DROP_BEFORE && path
14284       && gtk_tree_path_get_depth (path) == 1
14285       && gtk_tree_path_get_indices (path)[0] == 0)
14286     {
14287       gint n_children;
14288
14289       n_children = gtk_tree_model_iter_n_children (tree_view->priv->model,
14290                                                    NULL);
14291
14292       if (!n_children)
14293         tree_view->priv->empty_view_drop = 1;
14294     }
14295
14296   tree_view->priv->drag_dest_pos = pos;
14297
14298   if (path)
14299     {
14300       tree_view->priv->drag_dest_row =
14301         gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
14302       gtk_tree_view_queue_draw_path (tree_view, path, NULL);
14303     }
14304   else
14305     tree_view->priv->drag_dest_row = NULL;
14306
14307   if (current_dest)
14308     {
14309       GtkRBTree *tree, *new_tree;
14310       GtkRBNode *node, *new_node;
14311
14312       _gtk_tree_view_find_node (tree_view, current_dest, &tree, &node);
14313       _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
14314
14315       if (tree && node)
14316         {
14317           _gtk_rbtree_next_full (tree, node, &new_tree, &new_node);
14318           if (new_tree && new_node)
14319             _gtk_tree_view_queue_draw_node (tree_view, new_tree, new_node, NULL);
14320
14321           _gtk_rbtree_prev_full (tree, node, &new_tree, &new_node);
14322           if (new_tree && new_node)
14323             _gtk_tree_view_queue_draw_node (tree_view, new_tree, new_node, NULL);
14324         }
14325       gtk_tree_path_free (current_dest);
14326     }
14327 }
14328
14329 /**
14330  * gtk_tree_view_get_drag_dest_row:
14331  * @tree_view: a #GtkTreeView
14332  * @path: (out) (allow-none): Return location for the path of the highlighted row, or %NULL.
14333  * @pos: (out) (allow-none): Return location for the drop position, or %NULL
14334  * 
14335  * Gets information about the row that is highlighted for feedback.
14336  **/
14337 void
14338 gtk_tree_view_get_drag_dest_row (GtkTreeView              *tree_view,
14339                                  GtkTreePath             **path,
14340                                  GtkTreeViewDropPosition  *pos)
14341 {
14342   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14343
14344   if (path)
14345     {
14346       if (tree_view->priv->drag_dest_row)
14347         *path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
14348       else
14349         {
14350           if (tree_view->priv->empty_view_drop)
14351             *path = gtk_tree_path_new_from_indices (0, -1);
14352           else
14353             *path = NULL;
14354         }
14355     }
14356
14357   if (pos)
14358     *pos = tree_view->priv->drag_dest_pos;
14359 }
14360
14361 /**
14362  * gtk_tree_view_get_dest_row_at_pos:
14363  * @tree_view: a #GtkTreeView
14364  * @drag_x: the position to determine the destination row for
14365  * @drag_y: the position to determine the destination row for
14366  * @path: (out) (allow-none): Return location for the path of the highlighted row, or %NULL.
14367  * @pos: (out) (allow-none): Return location for the drop position, or %NULL
14368  * 
14369  * Determines the destination row for a given position.  @drag_x and
14370  * @drag_y are expected to be in widget coordinates.  This function is only
14371  * meaningful if @tree_view is realized.  Therefore this function will always
14372  * return %FALSE if @tree_view is not realized or does not have a model.
14373  * 
14374  * Return value: whether there is a row at the given position, %TRUE if this
14375  * is indeed the case.
14376  **/
14377 gboolean
14378 gtk_tree_view_get_dest_row_at_pos (GtkTreeView             *tree_view,
14379                                    gint                     drag_x,
14380                                    gint                     drag_y,
14381                                    GtkTreePath            **path,
14382                                    GtkTreeViewDropPosition *pos)
14383 {
14384   gint cell_y;
14385   gint bin_x, bin_y;
14386   gdouble offset_into_row;
14387   gdouble third;
14388   GdkRectangle cell;
14389   GtkTreeViewColumn *column = NULL;
14390   GtkTreePath *tmp_path = NULL;
14391
14392   /* Note; this function is exported to allow a custom DND
14393    * implementation, so it can't touch TreeViewDragInfo
14394    */
14395
14396   g_return_val_if_fail (tree_view != NULL, FALSE);
14397   g_return_val_if_fail (drag_x >= 0, FALSE);
14398   g_return_val_if_fail (drag_y >= 0, FALSE);
14399
14400   if (path)
14401     *path = NULL;
14402
14403   if (tree_view->priv->bin_window == NULL)
14404     return FALSE;
14405
14406   if (tree_view->priv->tree == NULL)
14407     return FALSE;
14408
14409   /* If in the top third of a row, we drop before that row; if
14410    * in the bottom third, drop after that row; if in the middle,
14411    * and the row has children, drop into the row.
14412    */
14413   gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, drag_x, drag_y,
14414                                                      &bin_x, &bin_y);
14415
14416   if (!gtk_tree_view_get_path_at_pos (tree_view,
14417                                       bin_x,
14418                                       bin_y,
14419                                       &tmp_path,
14420                                       &column,
14421                                       NULL,
14422                                       &cell_y))
14423     return FALSE;
14424
14425   gtk_tree_view_get_background_area (tree_view, tmp_path, column,
14426                                      &cell);
14427
14428   offset_into_row = cell_y;
14429
14430   if (path)
14431     *path = tmp_path;
14432   else
14433     gtk_tree_path_free (tmp_path);
14434
14435   tmp_path = NULL;
14436
14437   third = cell.height / 3.0;
14438
14439   if (pos)
14440     {
14441       if (offset_into_row < third)
14442         {
14443           *pos = GTK_TREE_VIEW_DROP_BEFORE;
14444         }
14445       else if (offset_into_row < (cell.height / 2.0))
14446         {
14447           *pos = GTK_TREE_VIEW_DROP_INTO_OR_BEFORE;
14448         }
14449       else if (offset_into_row < third * 2.0)
14450         {
14451           *pos = GTK_TREE_VIEW_DROP_INTO_OR_AFTER;
14452         }
14453       else
14454         {
14455           *pos = GTK_TREE_VIEW_DROP_AFTER;
14456         }
14457     }
14458
14459   return TRUE;
14460 }
14461
14462
14463
14464 /* KEEP IN SYNC WITH GTK_TREE_VIEW_BIN_EXPOSE */
14465 /**
14466  * gtk_tree_view_create_row_drag_icon:
14467  * @tree_view: a #GtkTreeView
14468  * @path: a #GtkTreePath in @tree_view
14469  *
14470  * Creates a #cairo_surface_t representation of the row at @path.  
14471  * This image is used for a drag icon.
14472  *
14473  * Return value: (transfer full): a newly-allocated surface of the drag icon.
14474  **/
14475 cairo_surface_t *
14476 gtk_tree_view_create_row_drag_icon (GtkTreeView  *tree_view,
14477                                     GtkTreePath  *path)
14478 {
14479   GtkTreeIter   iter;
14480   GtkRBTree    *tree;
14481   GtkRBNode    *node;
14482   GtkStyleContext *context;
14483   GtkStateFlags state;
14484   gint cell_offset;
14485   GList *list;
14486   GdkRectangle background_area;
14487   GtkWidget *widget;
14488   gint depth;
14489   /* start drawing inside the black outline */
14490   gint x = 1, y = 1;
14491   cairo_surface_t *surface;
14492   gint bin_window_width;
14493   gboolean is_separator = FALSE;
14494   gboolean rtl, allow_rules;
14495   cairo_t *cr;
14496
14497   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14498   g_return_val_if_fail (path != NULL, NULL);
14499
14500   widget = GTK_WIDGET (tree_view);
14501
14502   if (!gtk_widget_get_realized (widget))
14503     return NULL;
14504
14505   depth = gtk_tree_path_get_depth (path);
14506
14507   _gtk_tree_view_find_node (tree_view,
14508                             path,
14509                             &tree,
14510                             &node);
14511
14512   if (tree == NULL)
14513     return NULL;
14514
14515   if (!gtk_tree_model_get_iter (tree_view->priv->model,
14516                                 &iter,
14517                                 path))
14518     return NULL;
14519
14520   context = gtk_widget_get_style_context (widget);
14521
14522   gtk_style_context_save (context);
14523
14524   state = gtk_widget_get_state_flags (widget);
14525   gtk_style_context_set_state (context, state);
14526
14527   gtk_style_context_add_class (context, GTK_STYLE_CLASS_VIEW);
14528   gtk_style_context_add_region (context, GTK_STYLE_REGION_COLUMN, 0);
14529
14530   gtk_widget_style_get (widget,
14531                         "allow-rules", &allow_rules,
14532                         NULL);
14533
14534   if (allow_rules && tree_view->priv->has_rules)
14535     {
14536       GtkRegionFlags row_flags;
14537
14538       if (_gtk_rbtree_node_find_parity (tree, node))
14539         row_flags = GTK_REGION_ODD;
14540       else
14541         row_flags = GTK_REGION_EVEN;
14542
14543       gtk_style_context_add_region (context, GTK_STYLE_REGION_ROW, row_flags);
14544     }
14545
14546   is_separator = row_is_separator (tree_view, &iter, NULL);
14547
14548   cell_offset = x;
14549
14550   background_area.y = y;
14551   background_area.height = gtk_tree_view_get_row_height (tree_view, node);
14552
14553   bin_window_width = gdk_window_get_width (tree_view->priv->bin_window);
14554
14555   surface = gdk_window_create_similar_surface (tree_view->priv->bin_window,
14556                                                CAIRO_CONTENT_COLOR,
14557                                                bin_window_width + 2,
14558                                                background_area.height + 2);
14559
14560   cr = cairo_create (surface);
14561
14562   gtk_render_background (context, cr, 0, 0,
14563                          bin_window_width + 2,
14564                          background_area.height + 2);
14565
14566   rtl = gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL;
14567
14568   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
14569       list;
14570       list = (rtl ? list->prev : list->next))
14571     {
14572       GtkTreeViewColumn *column = list->data;
14573       GdkRectangle cell_area;
14574       gint vertical_separator;
14575
14576       if (!gtk_tree_view_column_get_visible (column))
14577         continue;
14578
14579       gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, &iter,
14580                                                GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
14581                                                node->children?TRUE:FALSE);
14582
14583       background_area.x = cell_offset;
14584       background_area.width = gtk_tree_view_column_get_width (column);
14585
14586       gtk_widget_style_get (widget,
14587                             "vertical-separator", &vertical_separator,
14588                             NULL);
14589
14590       cell_area = background_area;
14591
14592       cell_area.y += vertical_separator / 2;
14593       cell_area.height -= vertical_separator;
14594
14595       if (gtk_tree_view_is_expander_column (tree_view, column))
14596         {
14597           if (!rtl)
14598             cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
14599           cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
14600
14601           if (gtk_tree_view_draw_expanders (tree_view))
14602             {
14603               if (!rtl)
14604                 cell_area.x += depth * tree_view->priv->expander_size;
14605               cell_area.width -= depth * tree_view->priv->expander_size;
14606             }
14607         }
14608
14609       if (gtk_tree_view_column_cell_is_visible (column))
14610         {
14611           if (is_separator)
14612             gtk_render_line (context, cr,
14613                              cell_area.x,
14614                              cell_area.y + cell_area.height / 2,
14615                              cell_area.x + cell_area.width,
14616                              cell_area.y + cell_area.height / 2);
14617           else
14618             _gtk_tree_view_column_cell_render (column,
14619                                                cr,
14620                                                &background_area,
14621                                                &cell_area,
14622                                                0, FALSE);
14623         }
14624       cell_offset += gtk_tree_view_column_get_width (column);
14625     }
14626
14627   cairo_set_source_rgb (cr, 0, 0, 0);
14628   cairo_rectangle (cr, 
14629                    0.5, 0.5, 
14630                    bin_window_width + 1,
14631                    background_area.height + 1);
14632   cairo_set_line_width (cr, 1.0);
14633   cairo_stroke (cr);
14634
14635   cairo_destroy (cr);
14636
14637   cairo_surface_set_device_offset (surface, 2, 2);
14638
14639   gtk_style_context_restore (context);
14640
14641   return surface;
14642 }
14643
14644
14645 /**
14646  * gtk_tree_view_set_destroy_count_func:
14647  * @tree_view: A #GtkTreeView
14648  * @func: (allow-none): Function to be called when a view row is destroyed, or %NULL
14649  * @data: (allow-none): User data to be passed to @func, or %NULL
14650  * @destroy: (allow-none): Destroy notifier for @data, or %NULL
14651  *
14652  * This function should almost never be used.  It is meant for private use by
14653  * ATK for determining the number of visible children that are removed when the
14654  * user collapses a row, or a row is deleted.
14655  **/
14656 void
14657 gtk_tree_view_set_destroy_count_func (GtkTreeView             *tree_view,
14658                                       GtkTreeDestroyCountFunc  func,
14659                                       gpointer                 data,
14660                                       GDestroyNotify           destroy)
14661 {
14662   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14663
14664   if (tree_view->priv->destroy_count_destroy)
14665     tree_view->priv->destroy_count_destroy (tree_view->priv->destroy_count_data);
14666
14667   tree_view->priv->destroy_count_func = func;
14668   tree_view->priv->destroy_count_data = data;
14669   tree_view->priv->destroy_count_destroy = destroy;
14670 }
14671
14672
14673 /*
14674  * Interactive search
14675  */
14676
14677 /**
14678  * gtk_tree_view_set_enable_search:
14679  * @tree_view: A #GtkTreeView
14680  * @enable_search: %TRUE, if the user can search interactively
14681  *
14682  * If @enable_search is set, then the user can type in text to search through
14683  * the tree interactively (this is sometimes called "typeahead find").
14684  * 
14685  * Note that even if this is %FALSE, the user can still initiate a search 
14686  * using the "start-interactive-search" key binding.
14687  */
14688 void
14689 gtk_tree_view_set_enable_search (GtkTreeView *tree_view,
14690                                  gboolean     enable_search)
14691 {
14692   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14693
14694   enable_search = !!enable_search;
14695   
14696   if (tree_view->priv->enable_search != enable_search)
14697     {
14698        tree_view->priv->enable_search = enable_search;
14699        g_object_notify (G_OBJECT (tree_view), "enable-search");
14700     }
14701 }
14702
14703 /**
14704  * gtk_tree_view_get_enable_search:
14705  * @tree_view: A #GtkTreeView
14706  *
14707  * Returns whether or not the tree allows to start interactive searching 
14708  * by typing in text.
14709  *
14710  * Return value: whether or not to let the user search interactively
14711  */
14712 gboolean
14713 gtk_tree_view_get_enable_search (GtkTreeView *tree_view)
14714 {
14715   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
14716
14717   return tree_view->priv->enable_search;
14718 }
14719
14720
14721 /**
14722  * gtk_tree_view_get_search_column:
14723  * @tree_view: A #GtkTreeView
14724  *
14725  * Gets the column searched on by the interactive search code.
14726  *
14727  * Return value: the column the interactive search code searches in.
14728  */
14729 gint
14730 gtk_tree_view_get_search_column (GtkTreeView *tree_view)
14731 {
14732   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
14733
14734   return (tree_view->priv->search_column);
14735 }
14736
14737 /**
14738  * gtk_tree_view_set_search_column:
14739  * @tree_view: A #GtkTreeView
14740  * @column: the column of the model to search in, or -1 to disable searching
14741  *
14742  * Sets @column as the column where the interactive search code should
14743  * search in for the current model. 
14744  * 
14745  * If the search column is set, users can use the "start-interactive-search"
14746  * key binding to bring up search popup. The enable-search property controls
14747  * whether simply typing text will also start an interactive search.
14748  *
14749  * Note that @column refers to a column of the current model. The search 
14750  * column is reset to -1 when the model is changed.
14751  */
14752 void
14753 gtk_tree_view_set_search_column (GtkTreeView *tree_view,
14754                                  gint         column)
14755 {
14756   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14757   g_return_if_fail (column >= -1);
14758
14759   if (tree_view->priv->search_column == column)
14760     return;
14761
14762   tree_view->priv->search_column = column;
14763   g_object_notify (G_OBJECT (tree_view), "search-column");
14764 }
14765
14766 /**
14767  * gtk_tree_view_get_search_equal_func: (skip)
14768  * @tree_view: A #GtkTreeView
14769  *
14770  * Returns the compare function currently in use.
14771  *
14772  * Return value: the currently used compare function for the search code.
14773  */
14774
14775 GtkTreeViewSearchEqualFunc
14776 gtk_tree_view_get_search_equal_func (GtkTreeView *tree_view)
14777 {
14778   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14779
14780   return tree_view->priv->search_equal_func;
14781 }
14782
14783 /**
14784  * gtk_tree_view_set_search_equal_func:
14785  * @tree_view: A #GtkTreeView
14786  * @search_equal_func: the compare function to use during the search
14787  * @search_user_data: (allow-none): user data to pass to @search_equal_func, or %NULL
14788  * @search_destroy: (allow-none): Destroy notifier for @search_user_data, or %NULL
14789  *
14790  * Sets the compare function for the interactive search capabilities; note
14791  * that somewhat like strcmp() returning 0 for equality
14792  * #GtkTreeViewSearchEqualFunc returns %FALSE on matches.
14793  **/
14794 void
14795 gtk_tree_view_set_search_equal_func (GtkTreeView                *tree_view,
14796                                      GtkTreeViewSearchEqualFunc  search_equal_func,
14797                                      gpointer                    search_user_data,
14798                                      GDestroyNotify              search_destroy)
14799 {
14800   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14801   g_return_if_fail (search_equal_func != NULL);
14802
14803   if (tree_view->priv->search_destroy)
14804     tree_view->priv->search_destroy (tree_view->priv->search_user_data);
14805
14806   tree_view->priv->search_equal_func = search_equal_func;
14807   tree_view->priv->search_user_data = search_user_data;
14808   tree_view->priv->search_destroy = search_destroy;
14809   if (tree_view->priv->search_equal_func == NULL)
14810     tree_view->priv->search_equal_func = gtk_tree_view_search_equal_func;
14811 }
14812
14813 /**
14814  * gtk_tree_view_get_search_entry:
14815  * @tree_view: A #GtkTreeView
14816  *
14817  * Returns the #GtkEntry which is currently in use as interactive search
14818  * entry for @tree_view.  In case the built-in entry is being used, %NULL
14819  * will be returned.
14820  *
14821  * Return value: (transfer none): the entry currently in use as search entry.
14822  *
14823  * Since: 2.10
14824  */
14825 GtkEntry *
14826 gtk_tree_view_get_search_entry (GtkTreeView *tree_view)
14827 {
14828   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14829
14830   if (tree_view->priv->search_custom_entry_set)
14831     return GTK_ENTRY (tree_view->priv->search_entry);
14832
14833   return NULL;
14834 }
14835
14836 /**
14837  * gtk_tree_view_set_search_entry:
14838  * @tree_view: A #GtkTreeView
14839  * @entry: (allow-none): the entry the interactive search code of @tree_view should use or %NULL
14840  *
14841  * Sets the entry which the interactive search code will use for this
14842  * @tree_view.  This is useful when you want to provide a search entry
14843  * in our interface at all time at a fixed position.  Passing %NULL for
14844  * @entry will make the interactive search code use the built-in popup
14845  * entry again.
14846  *
14847  * Since: 2.10
14848  */
14849 void
14850 gtk_tree_view_set_search_entry (GtkTreeView *tree_view,
14851                                 GtkEntry    *entry)
14852 {
14853   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14854   g_return_if_fail (entry == NULL || GTK_IS_ENTRY (entry));
14855
14856   if (tree_view->priv->search_custom_entry_set)
14857     {
14858       if (tree_view->priv->search_entry_changed_id)
14859         {
14860           g_signal_handler_disconnect (tree_view->priv->search_entry,
14861                                        tree_view->priv->search_entry_changed_id);
14862           tree_view->priv->search_entry_changed_id = 0;
14863         }
14864       g_signal_handlers_disconnect_by_func (tree_view->priv->search_entry,
14865                                             G_CALLBACK (gtk_tree_view_search_key_press_event),
14866                                             tree_view);
14867
14868       g_object_unref (tree_view->priv->search_entry);
14869     }
14870   else if (tree_view->priv->search_window)
14871     {
14872       gtk_widget_destroy (tree_view->priv->search_window);
14873
14874       tree_view->priv->search_window = NULL;
14875     }
14876
14877   if (entry)
14878     {
14879       tree_view->priv->search_entry = g_object_ref (entry);
14880       tree_view->priv->search_custom_entry_set = TRUE;
14881
14882       if (tree_view->priv->search_entry_changed_id == 0)
14883         {
14884           tree_view->priv->search_entry_changed_id =
14885             g_signal_connect (tree_view->priv->search_entry, "changed",
14886                               G_CALLBACK (gtk_tree_view_search_init),
14887                               tree_view);
14888         }
14889       
14890         g_signal_connect (tree_view->priv->search_entry, "key-press-event",
14891                           G_CALLBACK (gtk_tree_view_search_key_press_event),
14892                           tree_view);
14893
14894         gtk_tree_view_search_init (tree_view->priv->search_entry, tree_view);
14895     }
14896   else
14897     {
14898       tree_view->priv->search_entry = NULL;
14899       tree_view->priv->search_custom_entry_set = FALSE;
14900     }
14901 }
14902
14903 /**
14904  * gtk_tree_view_set_search_position_func:
14905  * @tree_view: A #GtkTreeView
14906  * @func: (allow-none): the function to use to position the search dialog, or %NULL
14907  *    to use the default search position function
14908  * @data: (allow-none): user data to pass to @func, or %NULL
14909  * @destroy: (allow-none): Destroy notifier for @data, or %NULL
14910  *
14911  * Sets the function to use when positioning the search dialog.
14912  *
14913  * Since: 2.10
14914  **/
14915 void
14916 gtk_tree_view_set_search_position_func (GtkTreeView                   *tree_view,
14917                                         GtkTreeViewSearchPositionFunc  func,
14918                                         gpointer                       user_data,
14919                                         GDestroyNotify                 destroy)
14920 {
14921   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14922
14923   if (tree_view->priv->search_position_destroy)
14924     tree_view->priv->search_position_destroy (tree_view->priv->search_position_user_data);
14925
14926   tree_view->priv->search_position_func = func;
14927   tree_view->priv->search_position_user_data = user_data;
14928   tree_view->priv->search_position_destroy = destroy;
14929   if (tree_view->priv->search_position_func == NULL)
14930     tree_view->priv->search_position_func = gtk_tree_view_search_position_func;
14931 }
14932
14933 /**
14934  * gtk_tree_view_get_search_position_func: (skip)
14935  * @tree_view: A #GtkTreeView
14936  *
14937  * Returns the positioning function currently in use.
14938  *
14939  * Return value: the currently used function for positioning the search dialog.
14940  *
14941  * Since: 2.10
14942  */
14943 GtkTreeViewSearchPositionFunc
14944 gtk_tree_view_get_search_position_func (GtkTreeView *tree_view)
14945 {
14946   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14947
14948   return tree_view->priv->search_position_func;
14949 }
14950
14951
14952 static void
14953 gtk_tree_view_search_dialog_hide (GtkWidget   *search_dialog,
14954                                   GtkTreeView *tree_view,
14955                                   GdkDevice   *device)
14956 {
14957   if (tree_view->priv->disable_popdown)
14958     return;
14959
14960   if (tree_view->priv->search_entry_changed_id)
14961     {
14962       g_signal_handler_disconnect (tree_view->priv->search_entry,
14963                                    tree_view->priv->search_entry_changed_id);
14964       tree_view->priv->search_entry_changed_id = 0;
14965     }
14966   if (tree_view->priv->typeselect_flush_timeout)
14967     {
14968       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14969       tree_view->priv->typeselect_flush_timeout = 0;
14970     }
14971         
14972   if (gtk_widget_get_visible (search_dialog))
14973     {
14974       /* send focus-in event */
14975       send_focus_change (GTK_WIDGET (tree_view->priv->search_entry), device, FALSE);
14976       gtk_widget_hide (search_dialog);
14977       gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
14978       send_focus_change (GTK_WIDGET (tree_view), device, TRUE);
14979     }
14980 }
14981
14982 static void
14983 gtk_tree_view_search_position_func (GtkTreeView *tree_view,
14984                                     GtkWidget   *search_dialog,
14985                                     gpointer     user_data)
14986 {
14987   gint x, y;
14988   gint tree_x, tree_y;
14989   gint tree_width, tree_height;
14990   GdkWindow *tree_window = gtk_widget_get_window (GTK_WIDGET (tree_view));
14991   GdkScreen *screen = gdk_window_get_screen (tree_window);
14992   GtkRequisition requisition;
14993   gint monitor_num;
14994   GdkRectangle monitor;
14995
14996   monitor_num = gdk_screen_get_monitor_at_window (screen, tree_window);
14997   gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
14998
14999   gtk_widget_realize (search_dialog);
15000
15001   gdk_window_get_origin (tree_window, &tree_x, &tree_y);
15002   tree_width = gdk_window_get_width (tree_window);
15003   tree_height = gdk_window_get_height (tree_window);
15004   gtk_widget_get_preferred_size (search_dialog, &requisition, NULL);
15005
15006   if (tree_x + tree_width > gdk_screen_get_width (screen))
15007     x = gdk_screen_get_width (screen) - requisition.width;
15008   else if (tree_x + tree_width - requisition.width < 0)
15009     x = 0;
15010   else
15011     x = tree_x + tree_width - requisition.width;
15012
15013   if (tree_y + tree_height + requisition.height > gdk_screen_get_height (screen))
15014     y = gdk_screen_get_height (screen) - requisition.height;
15015   else if (tree_y + tree_height < 0) /* isn't really possible ... */
15016     y = 0;
15017   else
15018     y = tree_y + tree_height;
15019
15020   gtk_window_move (GTK_WINDOW (search_dialog), x, y);
15021 }
15022
15023 static void
15024 gtk_tree_view_search_disable_popdown (GtkEntry *entry,
15025                                       GtkMenu  *menu,
15026                                       gpointer  data)
15027 {
15028   GtkTreeView *tree_view = (GtkTreeView *)data;
15029
15030   tree_view->priv->disable_popdown = 1;
15031   g_signal_connect (menu, "hide",
15032                     G_CALLBACK (gtk_tree_view_search_enable_popdown), data);
15033 }
15034
15035 /* Because we're visible but offscreen, we just set a flag in the preedit
15036  * callback.
15037  */
15038 static void
15039 gtk_tree_view_search_preedit_changed (GtkIMContext *im_context,
15040                                       GtkTreeView  *tree_view)
15041 {
15042   tree_view->priv->imcontext_changed = 1;
15043   if (tree_view->priv->typeselect_flush_timeout)
15044     {
15045       g_source_remove (tree_view->priv->typeselect_flush_timeout);
15046       tree_view->priv->typeselect_flush_timeout =
15047         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
15048                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
15049                        tree_view);
15050     }
15051
15052 }
15053
15054 static void
15055 gtk_tree_view_search_activate (GtkEntry    *entry,
15056                                GtkTreeView *tree_view)
15057 {
15058   GtkTreePath *path;
15059   GtkRBNode *node;
15060   GtkRBTree *tree;
15061
15062   gtk_tree_view_search_dialog_hide (tree_view->priv->search_window,
15063                                     tree_view,
15064                                     gtk_get_current_event_device ());
15065
15066   /* If we have a row selected and it's the cursor row, we activate
15067    * the row XXX */
15068   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
15069     {
15070       path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
15071       
15072       _gtk_tree_view_find_node (tree_view, path, &tree, &node);
15073       
15074       if (node && GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
15075         gtk_tree_view_row_activated (tree_view, path, tree_view->priv->focus_column);
15076       
15077       gtk_tree_path_free (path);
15078     }
15079 }
15080
15081 static gboolean
15082 gtk_tree_view_real_search_enable_popdown (gpointer data)
15083 {
15084   GtkTreeView *tree_view = (GtkTreeView *)data;
15085
15086   tree_view->priv->disable_popdown = 0;
15087
15088   return FALSE;
15089 }
15090
15091 static void
15092 gtk_tree_view_search_enable_popdown (GtkWidget *widget,
15093                                      gpointer   data)
15094 {
15095   gdk_threads_add_timeout_full (G_PRIORITY_HIGH, 200, gtk_tree_view_real_search_enable_popdown, g_object_ref (data), g_object_unref);
15096 }
15097
15098 static gboolean
15099 gtk_tree_view_search_delete_event (GtkWidget *widget,
15100                                    GdkEventAny *event,
15101                                    GtkTreeView *tree_view)
15102 {
15103   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
15104
15105   gtk_tree_view_search_dialog_hide (widget, tree_view, NULL);
15106
15107   return TRUE;
15108 }
15109
15110 static gboolean
15111 gtk_tree_view_search_button_press_event (GtkWidget *widget,
15112                                          GdkEventButton *event,
15113                                          GtkTreeView *tree_view)
15114 {
15115   GdkDevice *keyb_device;
15116
15117   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
15118
15119   keyb_device = gdk_device_get_associated_device (event->device);
15120   gtk_tree_view_search_dialog_hide (widget, tree_view, keyb_device);
15121
15122   if (event->window == tree_view->priv->bin_window)
15123     gtk_tree_view_button_press (GTK_WIDGET (tree_view), event);
15124
15125   return TRUE;
15126 }
15127
15128 static gboolean
15129 gtk_tree_view_search_scroll_event (GtkWidget *widget,
15130                                    GdkEventScroll *event,
15131                                    GtkTreeView *tree_view)
15132 {
15133   gboolean retval = FALSE;
15134
15135   if (event->direction == GDK_SCROLL_UP)
15136     {
15137       gtk_tree_view_search_move (widget, tree_view, TRUE);
15138       retval = TRUE;
15139     }
15140   else if (event->direction == GDK_SCROLL_DOWN)
15141     {
15142       gtk_tree_view_search_move (widget, tree_view, FALSE);
15143       retval = TRUE;
15144     }
15145
15146   /* renew the flush timeout */
15147   if (retval && tree_view->priv->typeselect_flush_timeout
15148       && !tree_view->priv->search_custom_entry_set)
15149     {
15150       g_source_remove (tree_view->priv->typeselect_flush_timeout);
15151       tree_view->priv->typeselect_flush_timeout =
15152         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
15153                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
15154                        tree_view);
15155     }
15156
15157   return retval;
15158 }
15159
15160 static gboolean
15161 gtk_tree_view_search_key_press_event (GtkWidget *widget,
15162                                       GdkEventKey *event,
15163                                       GtkTreeView *tree_view)
15164 {
15165   gboolean retval = FALSE;
15166
15167   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
15168   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15169
15170   /* close window and cancel the search */
15171   if (!tree_view->priv->search_custom_entry_set
15172       && (event->keyval == GDK_KEY_Escape ||
15173           event->keyval == GDK_KEY_Tab ||
15174             event->keyval == GDK_KEY_KP_Tab ||
15175             event->keyval == GDK_KEY_ISO_Left_Tab))
15176     {
15177       gtk_tree_view_search_dialog_hide (widget, tree_view,
15178                                         gdk_event_get_device ((GdkEvent *) event));
15179       return TRUE;
15180     }
15181
15182   /* select previous matching iter */
15183   if (event->keyval == GDK_KEY_Up || event->keyval == GDK_KEY_KP_Up)
15184     {
15185       if (!gtk_tree_view_search_move (widget, tree_view, TRUE))
15186         gtk_widget_error_bell (widget);
15187
15188       retval = TRUE;
15189     }
15190
15191   if (((event->state & (GTK_DEFAULT_ACCEL_MOD_MASK | GDK_SHIFT_MASK)) == (GTK_DEFAULT_ACCEL_MOD_MASK | GDK_SHIFT_MASK))
15192       && (event->keyval == GDK_KEY_g || event->keyval == GDK_KEY_G))
15193     {
15194       if (!gtk_tree_view_search_move (widget, tree_view, TRUE))
15195         gtk_widget_error_bell (widget);
15196
15197       retval = TRUE;
15198     }
15199
15200   /* select next matching iter */
15201   if (event->keyval == GDK_KEY_Down || event->keyval == GDK_KEY_KP_Down)
15202     {
15203       if (!gtk_tree_view_search_move (widget, tree_view, FALSE))
15204         gtk_widget_error_bell (widget);
15205
15206       retval = TRUE;
15207     }
15208
15209   if (((event->state & (GTK_DEFAULT_ACCEL_MOD_MASK | GDK_SHIFT_MASK)) == GTK_DEFAULT_ACCEL_MOD_MASK)
15210       && (event->keyval == GDK_KEY_g || event->keyval == GDK_KEY_G))
15211     {
15212       if (!gtk_tree_view_search_move (widget, tree_view, FALSE))
15213         gtk_widget_error_bell (widget);
15214
15215       retval = TRUE;
15216     }
15217
15218   /* renew the flush timeout */
15219   if (retval && tree_view->priv->typeselect_flush_timeout
15220       && !tree_view->priv->search_custom_entry_set)
15221     {
15222       g_source_remove (tree_view->priv->typeselect_flush_timeout);
15223       tree_view->priv->typeselect_flush_timeout =
15224         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
15225                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
15226                        tree_view);
15227     }
15228
15229   return retval;
15230 }
15231
15232 /*  this function returns FALSE if there is a search string but
15233  *  nothing was found, and TRUE otherwise.
15234  */
15235 static gboolean
15236 gtk_tree_view_search_move (GtkWidget   *window,
15237                            GtkTreeView *tree_view,
15238                            gboolean     up)
15239 {
15240   gboolean ret;
15241   gint len;
15242   gint count = 0;
15243   const gchar *text;
15244   GtkTreeIter iter;
15245   GtkTreeModel *model;
15246   GtkTreeSelection *selection;
15247
15248   text = gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry));
15249
15250   g_return_val_if_fail (text != NULL, FALSE);
15251
15252   len = strlen (text);
15253
15254   if (up && tree_view->priv->selected_iter == 1)
15255     return strlen (text) < 1;
15256
15257   len = strlen (text);
15258
15259   if (len < 1)
15260     return TRUE;
15261
15262   model = gtk_tree_view_get_model (tree_view);
15263   selection = gtk_tree_view_get_selection (tree_view);
15264
15265   /* search */
15266   gtk_tree_selection_unselect_all (selection);
15267   if (!gtk_tree_model_get_iter_first (model, &iter))
15268     return TRUE;
15269
15270   ret = gtk_tree_view_search_iter (model, selection, &iter, text,
15271                                    &count, up?((tree_view->priv->selected_iter) - 1):((tree_view->priv->selected_iter + 1)));
15272
15273   if (ret)
15274     {
15275       /* found */
15276       tree_view->priv->selected_iter += up?(-1):(1);
15277       return TRUE;
15278     }
15279   else
15280     {
15281       /* return to old iter */
15282       count = 0;
15283       gtk_tree_model_get_iter_first (model, &iter);
15284       gtk_tree_view_search_iter (model, selection,
15285                                  &iter, text,
15286                                  &count, tree_view->priv->selected_iter);
15287       return FALSE;
15288     }
15289 }
15290
15291 static gboolean
15292 gtk_tree_view_search_equal_func (GtkTreeModel *model,
15293                                  gint          column,
15294                                  const gchar  *key,
15295                                  GtkTreeIter  *iter,
15296                                  gpointer      search_data)
15297 {
15298   gboolean retval = TRUE;
15299   const gchar *str;
15300   gchar *normalized_string;
15301   gchar *normalized_key;
15302   gchar *case_normalized_string = NULL;
15303   gchar *case_normalized_key = NULL;
15304   GValue value = {0,};
15305   GValue transformed = {0,};
15306
15307   gtk_tree_model_get_value (model, iter, column, &value);
15308
15309   g_value_init (&transformed, G_TYPE_STRING);
15310
15311   if (!g_value_transform (&value, &transformed))
15312     {
15313       g_value_unset (&value);
15314       return TRUE;
15315     }
15316
15317   g_value_unset (&value);
15318
15319   str = g_value_get_string (&transformed);
15320   if (!str)
15321     {
15322       g_value_unset (&transformed);
15323       return TRUE;
15324     }
15325
15326   normalized_string = g_utf8_normalize (str, -1, G_NORMALIZE_ALL);
15327   normalized_key = g_utf8_normalize (key, -1, G_NORMALIZE_ALL);
15328
15329   if (normalized_string && normalized_key)
15330     {
15331       case_normalized_string = g_utf8_casefold (normalized_string, -1);
15332       case_normalized_key = g_utf8_casefold (normalized_key, -1);
15333
15334       if (strncmp (case_normalized_key, case_normalized_string, strlen (case_normalized_key)) == 0)
15335         retval = FALSE;
15336     }
15337
15338   g_value_unset (&transformed);
15339   g_free (normalized_key);
15340   g_free (normalized_string);
15341   g_free (case_normalized_key);
15342   g_free (case_normalized_string);
15343
15344   return retval;
15345 }
15346
15347 static gboolean
15348 gtk_tree_view_search_iter (GtkTreeModel     *model,
15349                            GtkTreeSelection *selection,
15350                            GtkTreeIter      *iter,
15351                            const gchar      *text,
15352                            gint             *count,
15353                            gint              n)
15354 {
15355   GtkRBTree *tree = NULL;
15356   GtkRBNode *node = NULL;
15357   GtkTreePath *path;
15358
15359   GtkTreeView *tree_view = gtk_tree_selection_get_tree_view (selection);
15360
15361   path = gtk_tree_model_get_path (model, iter);
15362   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
15363
15364   do
15365     {
15366       if (! tree_view->priv->search_equal_func (model, tree_view->priv->search_column, text, iter, tree_view->priv->search_user_data))
15367         {
15368           (*count)++;
15369           if (*count == n)
15370             {
15371               gtk_tree_view_scroll_to_cell (tree_view, path, NULL,
15372                                             TRUE, 0.5, 0.0);
15373               gtk_tree_selection_select_iter (selection, iter);
15374               gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
15375
15376               if (path)
15377                 gtk_tree_path_free (path);
15378
15379               return TRUE;
15380             }
15381         }
15382
15383       if (node->children)
15384         {
15385           gboolean has_child;
15386           GtkTreeIter tmp;
15387
15388           tree = node->children;
15389           node = tree->root;
15390
15391           while (node->left != tree->nil)
15392             node = node->left;
15393
15394           tmp = *iter;
15395           has_child = gtk_tree_model_iter_children (model, iter, &tmp);
15396           gtk_tree_path_down (path);
15397
15398           /* sanity check */
15399           TREE_VIEW_INTERNAL_ASSERT (has_child, FALSE);
15400         }
15401       else
15402         {
15403           gboolean done = FALSE;
15404
15405           do
15406             {
15407               node = _gtk_rbtree_next (tree, node);
15408
15409               if (node)
15410                 {
15411                   gboolean has_next;
15412
15413                   has_next = gtk_tree_model_iter_next (model, iter);
15414
15415                   done = TRUE;
15416                   gtk_tree_path_next (path);
15417
15418                   /* sanity check */
15419                   TREE_VIEW_INTERNAL_ASSERT (has_next, FALSE);
15420                 }
15421               else
15422                 {
15423                   gboolean has_parent;
15424                   GtkTreeIter tmp_iter = *iter;
15425
15426                   node = tree->parent_node;
15427                   tree = tree->parent_tree;
15428
15429                   if (!tree)
15430                     {
15431                       if (path)
15432                         gtk_tree_path_free (path);
15433
15434                       /* we've run out of tree, done with this func */
15435                       return FALSE;
15436                     }
15437
15438                   has_parent = gtk_tree_model_iter_parent (model,
15439                                                            iter,
15440                                                            &tmp_iter);
15441                   gtk_tree_path_up (path);
15442
15443                   /* sanity check */
15444                   TREE_VIEW_INTERNAL_ASSERT (has_parent, FALSE);
15445                 }
15446             }
15447           while (!done);
15448         }
15449     }
15450   while (1);
15451
15452   return FALSE;
15453 }
15454
15455 static void
15456 gtk_tree_view_search_init (GtkWidget   *entry,
15457                            GtkTreeView *tree_view)
15458 {
15459   gint ret;
15460   gint count = 0;
15461   const gchar *text;
15462   GtkTreeIter iter;
15463   GtkTreeModel *model;
15464   GtkTreeSelection *selection;
15465
15466   g_return_if_fail (GTK_IS_ENTRY (entry));
15467   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15468
15469   text = gtk_entry_get_text (GTK_ENTRY (entry));
15470
15471   model = gtk_tree_view_get_model (tree_view);
15472   selection = gtk_tree_view_get_selection (tree_view);
15473
15474   /* search */
15475   gtk_tree_selection_unselect_all (selection);
15476   if (tree_view->priv->typeselect_flush_timeout
15477       && !tree_view->priv->search_custom_entry_set)
15478     {
15479       g_source_remove (tree_view->priv->typeselect_flush_timeout);
15480       tree_view->priv->typeselect_flush_timeout =
15481         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
15482                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
15483                        tree_view);
15484     }
15485
15486   if (*text == '\0')
15487     return;
15488
15489   if (!gtk_tree_model_get_iter_first (model, &iter))
15490     return;
15491
15492   ret = gtk_tree_view_search_iter (model, selection,
15493                                    &iter, text,
15494                                    &count, 1);
15495
15496   if (ret)
15497     tree_view->priv->selected_iter = 1;
15498 }
15499
15500 void
15501 _gtk_tree_view_remove_editable (GtkTreeView       *tree_view,
15502                                 GtkTreeViewColumn *column,
15503                                 GtkCellEditable   *cell_editable)
15504 {
15505   if (tree_view->priv->edited_column == NULL)
15506     return;
15507
15508   g_return_if_fail (column == tree_view->priv->edited_column);
15509
15510   tree_view->priv->edited_column = NULL;
15511
15512   if (gtk_widget_has_focus (GTK_WIDGET (cell_editable)))
15513     gtk_widget_grab_focus (GTK_WIDGET (tree_view));
15514
15515   gtk_container_remove (GTK_CONTAINER (tree_view),
15516                         GTK_WIDGET (cell_editable));
15517
15518   /* FIXME should only redraw a single node */
15519   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15520 }
15521
15522 static gboolean
15523 gtk_tree_view_start_editing (GtkTreeView *tree_view,
15524                              GtkTreePath *cursor_path,
15525                              gboolean     edit_only)
15526 {
15527   GtkTreeIter iter;
15528   GdkRectangle cell_area;
15529   GtkTreeViewColumn *focus_column;
15530   guint flags = 0; /* can be 0, as the flags are primarily for rendering */
15531   gint retval = FALSE;
15532   GtkRBTree *cursor_tree;
15533   GtkRBNode *cursor_node;
15534
15535   g_assert (tree_view->priv->focus_column);
15536   focus_column = tree_view->priv->focus_column;
15537
15538   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
15539     return FALSE;
15540
15541   if (_gtk_tree_view_find_node (tree_view, cursor_path, &cursor_tree, &cursor_node) ||
15542       cursor_node == NULL)
15543     return FALSE;
15544
15545   gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path);
15546
15547   validate_row (tree_view, cursor_tree, cursor_node, &iter, cursor_path);
15548
15549   gtk_tree_view_column_cell_set_cell_data (focus_column,
15550                                            tree_view->priv->model,
15551                                            &iter,
15552                                            GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_PARENT),
15553                                            cursor_node->children ? TRUE : FALSE);
15554   gtk_tree_view_get_cell_area (tree_view,
15555                                cursor_path,
15556                                focus_column,
15557                                &cell_area);
15558
15559   if (gtk_cell_area_activate (gtk_cell_layout_get_area (GTK_CELL_LAYOUT (focus_column)),
15560                               _gtk_tree_view_column_get_context (focus_column),
15561                               GTK_WIDGET (tree_view),
15562                               &cell_area,
15563                               flags, edit_only))
15564     retval = TRUE;
15565
15566   return retval;
15567 }
15568
15569 void
15570 _gtk_tree_view_add_editable (GtkTreeView       *tree_view,
15571                              GtkTreeViewColumn *column,
15572                              GtkTreePath       *path,
15573                              GtkCellEditable   *cell_editable,
15574                              GdkRectangle      *cell_area)
15575 {
15576   gint pre_val = gtk_adjustment_get_value (tree_view->priv->vadjustment);
15577   GtkRequisition requisition;
15578
15579   tree_view->priv->edited_column = column;
15580
15581   gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
15582   cell_area->y += pre_val - (int)gtk_adjustment_get_value (tree_view->priv->vadjustment);
15583
15584   gtk_widget_get_preferred_size (GTK_WIDGET (cell_editable),
15585                                  &requisition, NULL);
15586
15587   tree_view->priv->draw_keyfocus = TRUE;
15588
15589   if (requisition.height < cell_area->height)
15590     {
15591       gint diff = cell_area->height - requisition.height;
15592       gtk_tree_view_put (tree_view,
15593                          GTK_WIDGET (cell_editable),
15594                          cell_area->x, cell_area->y + diff/2,
15595                          cell_area->width, requisition.height);
15596     }
15597   else
15598     {
15599       gtk_tree_view_put (tree_view,
15600                          GTK_WIDGET (cell_editable),
15601                          cell_area->x, cell_area->y,
15602                          cell_area->width, cell_area->height);
15603     }
15604 }
15605
15606 static void
15607 gtk_tree_view_stop_editing (GtkTreeView *tree_view,
15608                             gboolean     cancel_editing)
15609 {
15610   GtkTreeViewColumn *column;
15611
15612   if (tree_view->priv->edited_column == NULL)
15613     return;
15614
15615   /*
15616    * This is very evil. We need to do this, because
15617    * gtk_cell_editable_editing_done may trigger gtk_tree_view_row_changed
15618    * later on. If gtk_tree_view_row_changed notices
15619    * tree_view->priv->edited_column != NULL, it'll call
15620    * gtk_tree_view_stop_editing again. Bad things will happen then.
15621    *
15622    * Please read that again if you intend to modify anything here.
15623    */
15624
15625   column = tree_view->priv->edited_column;
15626   gtk_cell_area_stop_editing (gtk_cell_layout_get_area (GTK_CELL_LAYOUT (column)), cancel_editing);
15627   tree_view->priv->edited_column = NULL;
15628 }
15629
15630
15631 /**
15632  * gtk_tree_view_set_hover_selection:
15633  * @tree_view: a #GtkTreeView
15634  * @hover: %TRUE to enable hover selection mode
15635  *
15636  * Enables of disables the hover selection mode of @tree_view.
15637  * Hover selection makes the selected row follow the pointer.
15638  * Currently, this works only for the selection modes 
15639  * %GTK_SELECTION_SINGLE and %GTK_SELECTION_BROWSE.
15640  * 
15641  * Since: 2.6
15642  **/
15643 void     
15644 gtk_tree_view_set_hover_selection (GtkTreeView *tree_view,
15645                                    gboolean     hover)
15646 {
15647   hover = hover != FALSE;
15648
15649   if (hover != tree_view->priv->hover_selection)
15650     {
15651       tree_view->priv->hover_selection = hover;
15652
15653       g_object_notify (G_OBJECT (tree_view), "hover-selection");
15654     }
15655 }
15656
15657 /**
15658  * gtk_tree_view_get_hover_selection:
15659  * @tree_view: a #GtkTreeView
15660  * 
15661  * Returns whether hover selection mode is turned on for @tree_view.
15662  * 
15663  * Return value: %TRUE if @tree_view is in hover selection mode
15664  *
15665  * Since: 2.6 
15666  **/
15667 gboolean 
15668 gtk_tree_view_get_hover_selection (GtkTreeView *tree_view)
15669 {
15670   return tree_view->priv->hover_selection;
15671 }
15672
15673 /**
15674  * gtk_tree_view_set_hover_expand:
15675  * @tree_view: a #GtkTreeView
15676  * @expand: %TRUE to enable hover selection mode
15677  *
15678  * Enables of disables the hover expansion mode of @tree_view.
15679  * Hover expansion makes rows expand or collapse if the pointer 
15680  * moves over them.
15681  * 
15682  * Since: 2.6
15683  **/
15684 void     
15685 gtk_tree_view_set_hover_expand (GtkTreeView *tree_view,
15686                                 gboolean     expand)
15687 {
15688   expand = expand != FALSE;
15689
15690   if (expand != tree_view->priv->hover_expand)
15691     {
15692       tree_view->priv->hover_expand = expand;
15693
15694       g_object_notify (G_OBJECT (tree_view), "hover-expand");
15695     }
15696 }
15697
15698 /**
15699  * gtk_tree_view_get_hover_expand:
15700  * @tree_view: a #GtkTreeView
15701  * 
15702  * Returns whether hover expansion mode is turned on for @tree_view.
15703  * 
15704  * Return value: %TRUE if @tree_view is in hover expansion mode
15705  *
15706  * Since: 2.6 
15707  **/
15708 gboolean 
15709 gtk_tree_view_get_hover_expand (GtkTreeView *tree_view)
15710 {
15711   return tree_view->priv->hover_expand;
15712 }
15713
15714 /**
15715  * gtk_tree_view_set_rubber_banding:
15716  * @tree_view: a #GtkTreeView
15717  * @enable: %TRUE to enable rubber banding
15718  *
15719  * Enables or disables rubber banding in @tree_view.  If the selection mode
15720  * is #GTK_SELECTION_MULTIPLE, rubber banding will allow the user to select
15721  * multiple rows by dragging the mouse.
15722  * 
15723  * Since: 2.10
15724  **/
15725 void
15726 gtk_tree_view_set_rubber_banding (GtkTreeView *tree_view,
15727                                   gboolean     enable)
15728 {
15729   enable = enable != FALSE;
15730
15731   if (enable != tree_view->priv->rubber_banding_enable)
15732     {
15733       tree_view->priv->rubber_banding_enable = enable;
15734
15735       g_object_notify (G_OBJECT (tree_view), "rubber-banding");
15736     }
15737 }
15738
15739 /**
15740  * gtk_tree_view_get_rubber_banding:
15741  * @tree_view: a #GtkTreeView
15742  * 
15743  * Returns whether rubber banding is turned on for @tree_view.  If the
15744  * selection mode is #GTK_SELECTION_MULTIPLE, rubber banding will allow the
15745  * user to select multiple rows by dragging the mouse.
15746  * 
15747  * Return value: %TRUE if rubber banding in @tree_view is enabled.
15748  *
15749  * Since: 2.10
15750  **/
15751 gboolean
15752 gtk_tree_view_get_rubber_banding (GtkTreeView *tree_view)
15753 {
15754   return tree_view->priv->rubber_banding_enable;
15755 }
15756
15757 /**
15758  * gtk_tree_view_is_rubber_banding_active:
15759  * @tree_view: a #GtkTreeView
15760  * 
15761  * Returns whether a rubber banding operation is currently being done
15762  * in @tree_view.
15763  *
15764  * Return value: %TRUE if a rubber banding operation is currently being
15765  * done in @tree_view.
15766  *
15767  * Since: 2.12
15768  **/
15769 gboolean
15770 gtk_tree_view_is_rubber_banding_active (GtkTreeView *tree_view)
15771 {
15772   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15773
15774   if (tree_view->priv->rubber_banding_enable
15775       && tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
15776     return TRUE;
15777
15778   return FALSE;
15779 }
15780
15781 /**
15782  * gtk_tree_view_get_row_separator_func: (skip)
15783  * @tree_view: a #GtkTreeView
15784  * 
15785  * Returns the current row separator function.
15786  * 
15787  * Return value: the current row separator function.
15788  *
15789  * Since: 2.6
15790  **/
15791 GtkTreeViewRowSeparatorFunc 
15792 gtk_tree_view_get_row_separator_func (GtkTreeView *tree_view)
15793 {
15794   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
15795
15796   return tree_view->priv->row_separator_func;
15797 }
15798
15799 /**
15800  * gtk_tree_view_set_row_separator_func:
15801  * @tree_view: a #GtkTreeView
15802  * @func: (allow-none): a #GtkTreeViewRowSeparatorFunc
15803  * @data: (allow-none): user data to pass to @func, or %NULL
15804  * @destroy: (allow-none): destroy notifier for @data, or %NULL
15805  * 
15806  * Sets the row separator function, which is used to determine
15807  * whether a row should be drawn as a separator. If the row separator
15808  * function is %NULL, no separators are drawn. This is the default value.
15809  *
15810  * Since: 2.6
15811  **/
15812 void
15813 gtk_tree_view_set_row_separator_func (GtkTreeView                 *tree_view,
15814                                       GtkTreeViewRowSeparatorFunc  func,
15815                                       gpointer                     data,
15816                                       GDestroyNotify               destroy)
15817 {
15818   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15819
15820   if (tree_view->priv->row_separator_destroy)
15821     tree_view->priv->row_separator_destroy (tree_view->priv->row_separator_data);
15822
15823   tree_view->priv->row_separator_func = func;
15824   tree_view->priv->row_separator_data = data;
15825   tree_view->priv->row_separator_destroy = destroy;
15826
15827   /* Have the tree recalculate heights */
15828   _gtk_rbtree_mark_invalid (tree_view->priv->tree);
15829   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
15830 }
15831
15832   
15833 static void
15834 gtk_tree_view_grab_notify (GtkWidget *widget,
15835                            gboolean   was_grabbed)
15836 {
15837   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
15838
15839   tree_view->priv->in_grab = !was_grabbed;
15840
15841   if (!was_grabbed)
15842     {
15843       tree_view->priv->pressed_button = -1;
15844
15845       if (tree_view->priv->rubber_band_status)
15846         gtk_tree_view_stop_rubber_band (tree_view);
15847     }
15848 }
15849
15850 static void
15851 gtk_tree_view_state_flags_changed (GtkWidget     *widget,
15852                                    GtkStateFlags  previous_state)
15853 {
15854   if (gtk_widget_get_realized (widget))
15855     {
15856       GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
15857       GtkStyleContext *context;
15858
15859       context = gtk_widget_get_style_context (widget);
15860       gtk_style_context_set_background (context, tree_view->priv->bin_window);
15861     }
15862
15863   gtk_widget_queue_draw (widget);
15864 }
15865
15866 /**
15867  * gtk_tree_view_get_grid_lines:
15868  * @tree_view: a #GtkTreeView
15869  *
15870  * Returns which grid lines are enabled in @tree_view.
15871  *
15872  * Return value: a #GtkTreeViewGridLines value indicating which grid lines
15873  * are enabled.
15874  *
15875  * Since: 2.10
15876  */
15877 GtkTreeViewGridLines
15878 gtk_tree_view_get_grid_lines (GtkTreeView *tree_view)
15879 {
15880   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
15881
15882   return tree_view->priv->grid_lines;
15883 }
15884
15885 /**
15886  * gtk_tree_view_set_grid_lines:
15887  * @tree_view: a #GtkTreeView
15888  * @grid_lines: a #GtkTreeViewGridLines value indicating which grid lines to
15889  * enable.
15890  *
15891  * Sets which grid lines to draw in @tree_view.
15892  *
15893  * Since: 2.10
15894  */
15895 void
15896 gtk_tree_view_set_grid_lines (GtkTreeView           *tree_view,
15897                               GtkTreeViewGridLines   grid_lines)
15898 {
15899   GtkTreeViewPrivate *priv;
15900   GtkWidget *widget;
15901   GtkTreeViewGridLines old_grid_lines;
15902
15903   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15904
15905   priv = tree_view->priv;
15906   widget = GTK_WIDGET (tree_view);
15907
15908   old_grid_lines = priv->grid_lines;
15909   priv->grid_lines = grid_lines;
15910   
15911   if (gtk_widget_get_realized (widget))
15912     {
15913       if (grid_lines == GTK_TREE_VIEW_GRID_LINES_NONE &&
15914           priv->grid_line_width)
15915         {
15916           priv->grid_line_width = 0;
15917         }
15918       
15919       if (grid_lines != GTK_TREE_VIEW_GRID_LINES_NONE && 
15920           !priv->grid_line_width)
15921         {
15922           gint8 *dash_list;
15923
15924           gtk_widget_style_get (widget,
15925                                 "grid-line-width", &priv->grid_line_width,
15926                                 "grid-line-pattern", (gchar *)&dash_list,
15927                                 NULL);
15928       
15929           if (dash_list)
15930             {
15931               priv->grid_line_dashes[0] = dash_list[0];
15932               if (dash_list[0])
15933                 priv->grid_line_dashes[1] = dash_list[1];
15934               
15935               g_free (dash_list);
15936             }
15937           else
15938             {
15939               priv->grid_line_dashes[0] = 1;
15940               priv->grid_line_dashes[1] = 1;
15941             }
15942         }      
15943     }
15944
15945   if (old_grid_lines != grid_lines)
15946     {
15947       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15948       
15949       g_object_notify (G_OBJECT (tree_view), "enable-grid-lines");
15950     }
15951 }
15952
15953 /**
15954  * gtk_tree_view_get_enable_tree_lines:
15955  * @tree_view: a #GtkTreeView.
15956  *
15957  * Returns whether or not tree lines are drawn in @tree_view.
15958  *
15959  * Return value: %TRUE if tree lines are drawn in @tree_view, %FALSE
15960  * otherwise.
15961  *
15962  * Since: 2.10
15963  */
15964 gboolean
15965 gtk_tree_view_get_enable_tree_lines (GtkTreeView *tree_view)
15966 {
15967   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15968
15969   return tree_view->priv->tree_lines_enabled;
15970 }
15971
15972 /**
15973  * gtk_tree_view_set_enable_tree_lines:
15974  * @tree_view: a #GtkTreeView
15975  * @enabled: %TRUE to enable tree line drawing, %FALSE otherwise.
15976  *
15977  * Sets whether to draw lines interconnecting the expanders in @tree_view.
15978  * This does not have any visible effects for lists.
15979  *
15980  * Since: 2.10
15981  */
15982 void
15983 gtk_tree_view_set_enable_tree_lines (GtkTreeView *tree_view,
15984                                      gboolean     enabled)
15985 {
15986   GtkTreeViewPrivate *priv;
15987   GtkWidget *widget;
15988   gboolean was_enabled;
15989
15990   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15991
15992   enabled = enabled != FALSE;
15993
15994   priv = tree_view->priv;
15995   widget = GTK_WIDGET (tree_view);
15996
15997   was_enabled = priv->tree_lines_enabled;
15998
15999   priv->tree_lines_enabled = enabled;
16000
16001   if (gtk_widget_get_realized (widget))
16002     {
16003       if (!enabled && priv->tree_line_width)
16004         {
16005           priv->tree_line_width = 0;
16006         }
16007       
16008       if (enabled && !priv->tree_line_width)
16009         {
16010           gint8 *dash_list;
16011           gtk_widget_style_get (widget,
16012                                 "tree-line-width", &priv->tree_line_width,
16013                                 "tree-line-pattern", (gchar *)&dash_list,
16014                                 NULL);
16015           
16016           if (dash_list)
16017             {
16018               priv->tree_line_dashes[0] = dash_list[0];
16019               if (dash_list[0])
16020                 priv->tree_line_dashes[1] = dash_list[1];
16021               
16022               g_free (dash_list);
16023             }
16024           else
16025             {
16026               priv->tree_line_dashes[0] = 1;
16027               priv->tree_line_dashes[1] = 1;
16028             }
16029         }
16030     }
16031
16032   if (was_enabled != enabled)
16033     {
16034       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
16035
16036       g_object_notify (G_OBJECT (tree_view), "enable-tree-lines");
16037     }
16038 }
16039
16040
16041 /**
16042  * gtk_tree_view_set_show_expanders:
16043  * @tree_view: a #GtkTreeView
16044  * @enabled: %TRUE to enable expander drawing, %FALSE otherwise.
16045  *
16046  * Sets whether to draw and enable expanders and indent child rows in
16047  * @tree_view.  When disabled there will be no expanders visible in trees
16048  * and there will be no way to expand and collapse rows by default.  Also
16049  * note that hiding the expanders will disable the default indentation.  You
16050  * can set a custom indentation in this case using
16051  * gtk_tree_view_set_level_indentation().
16052  * This does not have any visible effects for lists.
16053  *
16054  * Since: 2.12
16055  */
16056 void
16057 gtk_tree_view_set_show_expanders (GtkTreeView *tree_view,
16058                                   gboolean     enabled)
16059 {
16060   gboolean was_enabled;
16061
16062   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
16063
16064   enabled = enabled != FALSE;
16065   was_enabled = tree_view->priv->show_expanders;
16066
16067   tree_view->priv->show_expanders = enabled == TRUE;
16068
16069   if (enabled != was_enabled)
16070     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
16071 }
16072
16073 /**
16074  * gtk_tree_view_get_show_expanders:
16075  * @tree_view: a #GtkTreeView.
16076  *
16077  * Returns whether or not expanders are drawn in @tree_view.
16078  *
16079  * Return value: %TRUE if expanders are drawn in @tree_view, %FALSE
16080  * otherwise.
16081  *
16082  * Since: 2.12
16083  */
16084 gboolean
16085 gtk_tree_view_get_show_expanders (GtkTreeView *tree_view)
16086 {
16087   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
16088
16089   return tree_view->priv->show_expanders;
16090 }
16091
16092 /**
16093  * gtk_tree_view_set_level_indentation:
16094  * @tree_view: a #GtkTreeView
16095  * @indentation: the amount, in pixels, of extra indentation in @tree_view.
16096  *
16097  * Sets the amount of extra indentation for child levels to use in @tree_view
16098  * in addition to the default indentation.  The value should be specified in
16099  * pixels, a value of 0 disables this feature and in this case only the default
16100  * indentation will be used.
16101  * This does not have any visible effects for lists.
16102  *
16103  * Since: 2.12
16104  */
16105 void
16106 gtk_tree_view_set_level_indentation (GtkTreeView *tree_view,
16107                                      gint         indentation)
16108 {
16109   tree_view->priv->level_indentation = indentation;
16110
16111   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
16112 }
16113
16114 /**
16115  * gtk_tree_view_get_level_indentation:
16116  * @tree_view: a #GtkTreeView.
16117  *
16118  * Returns the amount, in pixels, of extra indentation for child levels
16119  * in @tree_view.
16120  *
16121  * Return value: the amount of extra indentation for child levels in
16122  * @tree_view.  A return value of 0 means that this feature is disabled.
16123  *
16124  * Since: 2.12
16125  */
16126 gint
16127 gtk_tree_view_get_level_indentation (GtkTreeView *tree_view)
16128 {
16129   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
16130
16131   return tree_view->priv->level_indentation;
16132 }
16133
16134 /**
16135  * gtk_tree_view_set_tooltip_row:
16136  * @tree_view: a #GtkTreeView
16137  * @tooltip: a #GtkTooltip
16138  * @path: a #GtkTreePath
16139  *
16140  * Sets the tip area of @tooltip to be the area covered by the row at @path.
16141  * See also gtk_tree_view_set_tooltip_column() for a simpler alternative.
16142  * See also gtk_tooltip_set_tip_area().
16143  *
16144  * Since: 2.12
16145  */
16146 void
16147 gtk_tree_view_set_tooltip_row (GtkTreeView *tree_view,
16148                                GtkTooltip  *tooltip,
16149                                GtkTreePath *path)
16150 {
16151   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
16152   g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
16153
16154   gtk_tree_view_set_tooltip_cell (tree_view, tooltip, path, NULL, NULL);
16155 }
16156
16157 /**
16158  * gtk_tree_view_set_tooltip_cell:
16159  * @tree_view: a #GtkTreeView
16160  * @tooltip: a #GtkTooltip
16161  * @path: (allow-none): a #GtkTreePath or %NULL
16162  * @column: (allow-none): a #GtkTreeViewColumn or %NULL
16163  * @cell: (allow-none): a #GtkCellRenderer or %NULL
16164  *
16165  * Sets the tip area of @tooltip to the area @path, @column and @cell have
16166  * in common.  For example if @path is %NULL and @column is set, the tip
16167  * area will be set to the full area covered by @column.  See also
16168  * gtk_tooltip_set_tip_area().
16169  *
16170  * Note that if @path is not specified and @cell is set and part of a column
16171  * containing the expander, the tooltip might not show and hide at the correct
16172  * position.  In such cases @path must be set to the current node under the
16173  * mouse cursor for this function to operate correctly.
16174  *
16175  * See also gtk_tree_view_set_tooltip_column() for a simpler alternative.
16176  *
16177  * Since: 2.12
16178  */
16179 void
16180 gtk_tree_view_set_tooltip_cell (GtkTreeView       *tree_view,
16181                                 GtkTooltip        *tooltip,
16182                                 GtkTreePath       *path,
16183                                 GtkTreeViewColumn *column,
16184                                 GtkCellRenderer   *cell)
16185 {
16186   GtkAllocation allocation;
16187   GdkRectangle rect;
16188
16189   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
16190   g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
16191   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
16192   g_return_if_fail (cell == NULL || GTK_IS_CELL_RENDERER (cell));
16193
16194   /* Determine x values. */
16195   if (column && cell)
16196     {
16197       GdkRectangle tmp;
16198       gint start, width;
16199
16200       /* We always pass in path here, whether it is NULL or not.
16201        * For cells in expander columns path must be specified so that
16202        * we can correctly account for the indentation.  This also means
16203        * that the tooltip is constrained vertically by the "Determine y
16204        * values" code below; this is not a real problem since cells actually
16205        * don't stretch vertically in constrast to columns.
16206        */
16207       gtk_tree_view_get_cell_area (tree_view, path, column, &tmp);
16208       gtk_tree_view_column_cell_get_position (column, cell, &start, &width);
16209
16210       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
16211                                                          tmp.x + start, 0,
16212                                                          &rect.x, NULL);
16213       rect.width = width;
16214     }
16215   else if (column)
16216     {
16217       GdkRectangle tmp;
16218
16219       gtk_tree_view_get_background_area (tree_view, NULL, column, &tmp);
16220       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
16221                                                          tmp.x, 0,
16222                                                          &rect.x, NULL);
16223       rect.width = tmp.width;
16224     }
16225   else
16226     {
16227       gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
16228       rect.x = 0;
16229       rect.width = allocation.width;
16230     }
16231
16232   /* Determine y values. */
16233   if (path)
16234     {
16235       GdkRectangle tmp;
16236
16237       gtk_tree_view_get_background_area (tree_view, path, NULL, &tmp);
16238       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
16239                                                          0, tmp.y,
16240                                                          NULL, &rect.y);
16241       rect.height = tmp.height;
16242     }
16243   else
16244     {
16245       rect.y = 0;
16246       rect.height = gtk_adjustment_get_page_size (tree_view->priv->vadjustment);
16247     }
16248
16249   gtk_tooltip_set_tip_area (tooltip, &rect);
16250 }
16251
16252 /**
16253  * gtk_tree_view_get_tooltip_context:
16254  * @tree_view: a #GtkTreeView
16255  * @x: (inout): the x coordinate (relative to widget coordinates)
16256  * @y: (inout): the y coordinate (relative to widget coordinates)
16257  * @keyboard_tip: whether this is a keyboard tooltip or not
16258  * @model: (out) (allow-none): a pointer to receive a #GtkTreeModel or %NULL
16259  * @path: (out) (allow-none): a pointer to receive a #GtkTreePath or %NULL
16260  * @iter: (out) (allow-none): a pointer to receive a #GtkTreeIter or %NULL
16261  *
16262  * This function is supposed to be used in a #GtkWidget::query-tooltip
16263  * signal handler for #GtkTreeView.  The @x, @y and @keyboard_tip values
16264  * which are received in the signal handler, should be passed to this
16265  * function without modification.
16266  *
16267  * The return value indicates whether there is a tree view row at the given
16268  * coordinates (%TRUE) or not (%FALSE) for mouse tooltips.  For keyboard
16269  * tooltips the row returned will be the cursor row.  When %TRUE, then any of
16270  * @model, @path and @iter which have been provided will be set to point to
16271  * that row and the corresponding model.  @x and @y will always be converted
16272  * to be relative to @tree_view's bin_window if @keyboard_tooltip is %FALSE.
16273  *
16274  * Return value: whether or not the given tooltip context points to a row.
16275  *
16276  * Since: 2.12
16277  */
16278 gboolean
16279 gtk_tree_view_get_tooltip_context (GtkTreeView   *tree_view,
16280                                    gint          *x,
16281                                    gint          *y,
16282                                    gboolean       keyboard_tip,
16283                                    GtkTreeModel **model,
16284                                    GtkTreePath  **path,
16285                                    GtkTreeIter   *iter)
16286 {
16287   GtkTreePath *tmppath = NULL;
16288
16289   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
16290   g_return_val_if_fail (x != NULL, FALSE);
16291   g_return_val_if_fail (y != NULL, FALSE);
16292
16293   if (keyboard_tip)
16294     {
16295       gtk_tree_view_get_cursor (tree_view, &tmppath, NULL);
16296
16297       if (!tmppath)
16298         return FALSE;
16299     }
16300   else
16301     {
16302       gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, *x, *y,
16303                                                          x, y);
16304
16305       if (!gtk_tree_view_get_path_at_pos (tree_view, *x, *y,
16306                                           &tmppath, NULL, NULL, NULL))
16307         return FALSE;
16308     }
16309
16310   if (model)
16311     *model = gtk_tree_view_get_model (tree_view);
16312
16313   if (iter)
16314     gtk_tree_model_get_iter (gtk_tree_view_get_model (tree_view),
16315                              iter, tmppath);
16316
16317   if (path)
16318     *path = tmppath;
16319   else
16320     gtk_tree_path_free (tmppath);
16321
16322   return TRUE;
16323 }
16324
16325 static gboolean
16326 gtk_tree_view_set_tooltip_query_cb (GtkWidget  *widget,
16327                                     gint        x,
16328                                     gint        y,
16329                                     gboolean    keyboard_tip,
16330                                     GtkTooltip *tooltip,
16331                                     gpointer    data)
16332 {
16333   GValue value = { 0, };
16334   GValue transformed = { 0, };
16335   GtkTreeIter iter;
16336   GtkTreePath *path;
16337   GtkTreeModel *model;
16338   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
16339
16340   if (!gtk_tree_view_get_tooltip_context (GTK_TREE_VIEW (widget),
16341                                           &x, &y,
16342                                           keyboard_tip,
16343                                           &model, &path, &iter))
16344     return FALSE;
16345
16346   gtk_tree_model_get_value (model, &iter,
16347                             tree_view->priv->tooltip_column, &value);
16348
16349   g_value_init (&transformed, G_TYPE_STRING);
16350
16351   if (!g_value_transform (&value, &transformed))
16352     {
16353       g_value_unset (&value);
16354       gtk_tree_path_free (path);
16355
16356       return FALSE;
16357     }
16358
16359   g_value_unset (&value);
16360
16361   if (!g_value_get_string (&transformed))
16362     {
16363       g_value_unset (&transformed);
16364       gtk_tree_path_free (path);
16365
16366       return FALSE;
16367     }
16368
16369   gtk_tooltip_set_markup (tooltip, g_value_get_string (&transformed));
16370   gtk_tree_view_set_tooltip_row (tree_view, tooltip, path);
16371
16372   gtk_tree_path_free (path);
16373   g_value_unset (&transformed);
16374
16375   return TRUE;
16376 }
16377
16378 /**
16379  * gtk_tree_view_set_tooltip_column:
16380  * @tree_view: a #GtkTreeView
16381  * @column: an integer, which is a valid column number for @tree_view's model
16382  *
16383  * If you only plan to have simple (text-only) tooltips on full rows, you
16384  * can use this function to have #GtkTreeView handle these automatically
16385  * for you. @column should be set to the column in @tree_view's model
16386  * containing the tooltip texts, or -1 to disable this feature.
16387  *
16388  * When enabled, #GtkWidget::has-tooltip will be set to %TRUE and
16389  * @tree_view will connect a #GtkWidget::query-tooltip signal handler.
16390  *
16391  * Note that the signal handler sets the text with gtk_tooltip_set_markup(),
16392  * so &amp;, &lt;, etc have to be escaped in the text.
16393  *
16394  * Since: 2.12
16395  */
16396 void
16397 gtk_tree_view_set_tooltip_column (GtkTreeView *tree_view,
16398                                   gint         column)
16399 {
16400   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
16401
16402   if (column == tree_view->priv->tooltip_column)
16403     return;
16404
16405   if (column == -1)
16406     {
16407       g_signal_handlers_disconnect_by_func (tree_view,
16408                                             gtk_tree_view_set_tooltip_query_cb,
16409                                             NULL);
16410       gtk_widget_set_has_tooltip (GTK_WIDGET (tree_view), FALSE);
16411     }
16412   else
16413     {
16414       if (tree_view->priv->tooltip_column == -1)
16415         {
16416           g_signal_connect (tree_view, "query-tooltip",
16417                             G_CALLBACK (gtk_tree_view_set_tooltip_query_cb), NULL);
16418           gtk_widget_set_has_tooltip (GTK_WIDGET (tree_view), TRUE);
16419         }
16420     }
16421
16422   tree_view->priv->tooltip_column = column;
16423   g_object_notify (G_OBJECT (tree_view), "tooltip-column");
16424 }
16425
16426 /**
16427  * gtk_tree_view_get_tooltip_column:
16428  * @tree_view: a #GtkTreeView
16429  *
16430  * Returns the column of @tree_view's model which is being used for
16431  * displaying tooltips on @tree_view's rows.
16432  *
16433  * Return value: the index of the tooltip column that is currently being
16434  * used, or -1 if this is disabled.
16435  *
16436  * Since: 2.12
16437  */
16438 gint
16439 gtk_tree_view_get_tooltip_column (GtkTreeView *tree_view)
16440 {
16441   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
16442
16443   return tree_view->priv->tooltip_column;
16444 }