]> Pileus Git - ~andy/gtk/blob - gtk/gtktreeview.c
Documentation fixes
[~andy/gtk] / gtk / gtktreeview.c
1 /* gtktreeview.c
2  * Copyright (C) 2000  Red Hat, Inc.,  Jonathan Blandford <jrb@redhat.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20
21 #include "config.h"
22
23 #include <math.h>
24 #include <string.h>
25
26 #include "gtktreeview.h"
27 #include "gtkrbtree.h"
28 #include "gtktreednd.h"
29 #include "gtktreeprivate.h"
30 #include "gtkcellrenderer.h"
31 #include "gtkmainprivate.h"
32 #include "gtkmarshalers.h"
33 #include "gtkbuildable.h"
34 #include "gtkbutton.h"
35 #include "gtklabel.h"
36 #include "gtkbox.h"
37 #include "gtkarrow.h"
38 #include "gtkintl.h"
39 #include "gtkbindings.h"
40 #include "gtkcontainer.h"
41 #include "gtkentry.h"
42 #include "gtkframe.h"
43 #include "gtktreemodelsort.h"
44 #include "gtktooltip.h"
45 #include "gtkscrollable.h"
46 #include "gtkcelllayout.h"
47 #include "gtkprivate.h"
48 #include "gtkwidgetprivate.h"
49 #include "gtkentryprivate.h"
50 #include "gtkstylecontextprivate.h"
51 #include "gtktypebuiltins.h"
52 #include "a11y/gtktreeviewaccessible.h"
53
54
55 /**
56  * SECTION:gtktreeview
57  * @Short_description: A widget for displaying both trees and lists
58  * @Title: GtkTreeView
59  * @See_also: #GtkTreeViewColumn, #GtkTreeSelection, #GtkTreeDnd, #GtkTreeMode,
60  *   #GtkTreeSortable, #GtkTreeModelSort, #GtkListStore, #GtkTreeStore,
61  *   #GtkCellRenderer, #GtkCellEditable, #GtkCellRendererPixbuf,
62  *   #GtkCellRendererText, #GtkCellRendererToggle
63  *
64  * Widget that displays any object that implements the #GtkTreeModel interface.
65  *
66  * Please refer to the <link linkend="TreeWidget">tree widget conceptual
67  * overview</link> for an overview of all the objects and data types related
68  * to the tree widget and how they work together.
69  *
70  * Several different coordinate systems are exposed in the GtkTreeView API.
71  * These are:
72  *
73  * <inlinegraphic fileref="tree-view-coordinates.png" format="PNG"></inlinegraphic>
74  * <variablelist><title>Coordinate systems in GtkTreeView API</title>
75  * <varlistentry><term>Widget coordinates</term>
76  * <listitem>
77  * <para>
78  * Coordinates relative to the widget (usually <literal>widget->window</literal>).
79  * </para>
80  * </listitem>
81  * </varlistentry>
82  * <varlistentry><term>Bin window coordinates</term>
83  * <listitem>
84  * <para>
85  * Coordinates relative to the window that GtkTreeView renders to.
86  * </para>
87  * </listitem>
88  * </varlistentry>
89  * <varlistentry><term>Tree coordinates</term>
90  * <listitem>
91  * <para>
92  * Coordinates relative to the entire scrollable area of GtkTreeView. These
93  * coordinates start at (0, 0) for row 0 of the tree.
94  * </para>
95  * </listitem>
96  * </varlistentry>
97  * </variablelist>
98  *
99  * Several functions are available for converting between the different
100  * coordinate systems.  The most common translations are between widget and bin
101  * window coordinates and between bin window and tree coordinates. For the
102  * former you can use gtk_tree_view_convert_widget_to_bin_window_coords()
103  * (and vice versa), for the latter gtk_tree_view_convert_bin_window_to_tree_coords()
104  * (and vice versa).
105  *
106  * <refsect2 id="GtkTreeView-BUILDER-UI">
107  * <title>GtkTreeView as GtkBuildable</title>
108  * The GtkTreeView implementation of the GtkBuildable interface accepts
109  * #GtkTreeViewColumn objects as &lt;child&gt; elements and exposes the
110  * internal #GtkTreeSelection in UI definitions.
111  * <example>
112  * <title>A UI definition fragment with GtkTreeView</title>
113  * <programlisting><![CDATA[
114  * <object class="GtkTreeView" id="treeview">
115  *   <property name="model">liststore1</property>
116  *   <child>
117  *     <object class="GtkTreeViewColumn" id="test-column">
118  *       <property name="title">Test</property>
119  *       <child>
120  *         <object class="GtkCellRendererText" id="test-renderer"/>
121  *         <attributes>
122  *           <attribute name="text">1</attribute>
123  *         </attributes>
124  *       </child>
125  *     </object>
126  *   </child>
127  *   <child internal-child="selection">
128  *     <object class="GtkTreeSelection" id="selection">
129  *       <signal name="changed" handler="on_treeview_selection_changed"/>
130  *     </object>
131  *   </child>
132  * </object>
133  * ]]></programlisting>
134  * </example>
135  * </refsect2>
136  */
137
138 enum
139 {
140   DRAG_COLUMN_WINDOW_STATE_UNSET = 0,
141   DRAG_COLUMN_WINDOW_STATE_ORIGINAL = 1,
142   DRAG_COLUMN_WINDOW_STATE_ARROW = 2,
143   DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT = 3,
144   DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT = 4
145 };
146
147 enum
148 {
149   RUBBER_BAND_OFF = 0,
150   RUBBER_BAND_MAYBE_START = 1,
151   RUBBER_BAND_ACTIVE = 2
152 };
153
154  /* This lovely little value is used to determine how far away from the title bar
155   * you can move the mouse and still have a column drag work.
156   */
157 #define TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER(tree_view) (10*gtk_tree_view_get_effective_header_height(tree_view))
158
159 #ifdef __GNUC__
160
161 #define TREE_VIEW_INTERNAL_ASSERT(expr, ret)     G_STMT_START{          \
162      if (!(expr))                                                       \
163        {                                                                \
164          g_log (G_LOG_DOMAIN,                                           \
165                 G_LOG_LEVEL_CRITICAL,                                   \
166                 "%s (%s): assertion `%s' failed.\n"                     \
167                 "There is a disparity between the internal view of the GtkTreeView,\n"    \
168                 "and the GtkTreeModel.  This generally means that the model has changed\n"\
169                 "without letting the view know.  Any display from now on is likely to\n"  \
170                 "be incorrect.\n",                                                        \
171                 G_STRLOC,                                               \
172                 G_STRFUNC,                                              \
173                 #expr);                                                 \
174          return ret;                                                    \
175        };                               }G_STMT_END
176
177 #define TREE_VIEW_INTERNAL_ASSERT_VOID(expr)     G_STMT_START{          \
178      if (!(expr))                                                       \
179        {                                                                \
180          g_log (G_LOG_DOMAIN,                                           \
181                 G_LOG_LEVEL_CRITICAL,                                   \
182                 "%s (%s): assertion `%s' failed.\n"                     \
183                 "There is a disparity between the internal view of the GtkTreeView,\n"    \
184                 "and the GtkTreeModel.  This generally means that the model has changed\n"\
185                 "without letting the view know.  Any display from now on is likely to\n"  \
186                 "be incorrect.\n",                                                        \
187                 G_STRLOC,                                               \
188                 G_STRFUNC,                                              \
189                 #expr);                                                 \
190          return;                                                        \
191        };                               }G_STMT_END
192
193 #else
194
195 #define TREE_VIEW_INTERNAL_ASSERT(expr, ret)     G_STMT_START{          \
196      if (!(expr))                                                       \
197        {                                                                \
198          g_log (G_LOG_DOMAIN,                                           \
199                 G_LOG_LEVEL_CRITICAL,                                   \
200                 "file %s: line %d: assertion `%s' failed.\n"       \
201                 "There is a disparity between the internal view of the GtkTreeView,\n"    \
202                 "and the GtkTreeModel.  This generally means that the model has changed\n"\
203                 "without letting the view know.  Any display from now on is likely to\n"  \
204                 "be incorrect.\n",                                                        \
205                 __FILE__,                                               \
206                 __LINE__,                                               \
207                 #expr);                                                 \
208          return ret;                                                    \
209        };                               }G_STMT_END
210
211 #define TREE_VIEW_INTERNAL_ASSERT_VOID(expr)     G_STMT_START{          \
212      if (!(expr))                                                       \
213        {                                                                \
214          g_log (G_LOG_DOMAIN,                                           \
215                 G_LOG_LEVEL_CRITICAL,                                   \
216                 "file %s: line %d: assertion '%s' failed.\n"            \
217                 "There is a disparity between the internal view of the GtkTreeView,\n"    \
218                 "and the GtkTreeModel.  This generally means that the model has changed\n"\
219                 "without letting the view know.  Any display from now on is likely to\n"  \
220                 "be incorrect.\n",                                                        \
221                 __FILE__,                                               \
222                 __LINE__,                                               \
223                 #expr);                                                 \
224          return;                                                        \
225        };                               }G_STMT_END
226 #endif
227
228 #define GTK_TREE_VIEW_PRIORITY_VALIDATE (GDK_PRIORITY_REDRAW + 5)
229 #define GTK_TREE_VIEW_PRIORITY_SCROLL_SYNC (GTK_TREE_VIEW_PRIORITY_VALIDATE + 2)
230 #define GTK_TREE_VIEW_TIME_MS_PER_IDLE 30
231 #define SCROLL_EDGE_SIZE 15
232 #define EXPANDER_EXTRA_PADDING 4
233 #define GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT 5000
234 #define AUTO_EXPAND_TIMEOUT 500
235
236 /* Translate from bin_window coordinates to rbtree (tree coordinates) and
237  * vice versa.
238  */
239 #define TREE_WINDOW_Y_TO_RBTREE_Y(tree_view,y) ((y) + tree_view->priv->dy)
240 #define RBTREE_Y_TO_TREE_WINDOW_Y(tree_view,y) ((y) - tree_view->priv->dy)
241
242 typedef struct _GtkTreeViewColumnReorder GtkTreeViewColumnReorder;
243 struct _GtkTreeViewColumnReorder
244 {
245   gint left_align;
246   gint right_align;
247   GtkTreeViewColumn *left_column;
248   GtkTreeViewColumn *right_column;
249 };
250
251 typedef struct _GtkTreeViewChild GtkTreeViewChild;
252 struct _GtkTreeViewChild
253 {
254   GtkWidget *widget;
255   gint x;
256   gint y;
257   gint width;
258   gint height;
259 };
260
261
262 typedef struct _TreeViewDragInfo TreeViewDragInfo;
263 struct _TreeViewDragInfo
264 {
265   GdkModifierType start_button_mask;
266   GtkTargetList *_unused_source_target_list;
267   GdkDragAction source_actions;
268
269   GtkTargetList *_unused_dest_target_list;
270
271   guint source_set : 1;
272   guint dest_set : 1;
273 };
274
275
276 struct _GtkTreeViewPrivate
277 {
278   GtkTreeModel *model;
279
280   /* tree information */
281   GtkRBTree *tree;
282
283   /* Container info */
284   GList *children;
285   gint width;
286   gint height;
287
288   /* Adjustments */
289   GtkAdjustment *hadjustment;
290   GtkAdjustment *vadjustment;
291   gint           min_display_width;
292   gint           min_display_height;
293
294   /* Sub windows */
295   GdkWindow *bin_window;
296   GdkWindow *header_window;
297
298   /* Scroll position state keeping */
299   GtkTreeRowReference *top_row;
300   gint top_row_dy;
301   /* dy == y pos of top_row + top_row_dy */
302   /* we cache it for simplicity of the code */
303   gint dy;
304
305   guint presize_handler_timer;
306   guint validate_rows_timer;
307   guint scroll_sync_timer;
308
309   /* Indentation and expander layout */
310   gint expander_size;
311   GtkTreeViewColumn *expander_column;
312
313   gint level_indentation;
314
315   /* Key navigation (focus), selection */
316   gint cursor_offset;
317
318   GtkTreeRowReference *anchor;
319   GtkTreeRowReference *cursor;
320
321   GtkTreeViewColumn *focus_column;
322
323   /* Current pressed node, previously pressed, prelight */
324   GtkRBNode *button_pressed_node;
325   GtkRBTree *button_pressed_tree;
326
327   gint pressed_button;
328   gint press_start_x;
329   gint press_start_y;
330
331   gint event_last_x;
332   gint event_last_y;
333
334   guint last_button_time;
335   gint last_button_x;
336   gint last_button_y;
337
338   GtkRBNode *prelight_node;
339   GtkRBTree *prelight_tree;
340
341   /* Cell Editing */
342   GtkTreeViewColumn *edited_column;
343
344   /* The node that's currently being collapsed or expanded */
345   GtkRBNode *expanded_collapsed_node;
346   GtkRBTree *expanded_collapsed_tree;
347   guint expand_collapse_timeout;
348
349   /* Auto expand/collapse timeout in hover mode */
350   guint auto_expand_timeout;
351
352   /* Selection information */
353   GtkTreeSelection *selection;
354
355   /* Header information */
356   gint n_columns;
357   GList *columns;
358   gint header_height;
359
360   GtkTreeViewColumnDropFunc column_drop_func;
361   gpointer column_drop_func_data;
362   GDestroyNotify column_drop_func_data_destroy;
363   GList *column_drag_info;
364   GtkTreeViewColumnReorder *cur_reorder;
365
366   gint prev_width_before_expander;
367
368   /* Interactive Header reordering */
369   GdkWindow *drag_window;
370   GdkWindow *drag_highlight_window;
371   GtkTreeViewColumn *drag_column;
372   gint drag_column_x;
373
374   /* Interactive Header Resizing */
375   gint drag_pos;
376   gint x_drag;
377
378   /* Non-interactive Header Resizing, expand flag support */
379   gint prev_width;
380
381   gint last_extra_space;
382   gint last_extra_space_per_column;
383   gint last_number_of_expand_columns;
384
385   /* ATK Hack */
386   GtkTreeDestroyCountFunc destroy_count_func;
387   gpointer destroy_count_data;
388   GDestroyNotify destroy_count_destroy;
389
390   /* Scroll timeout (e.g. during dnd, rubber banding) */
391   guint scroll_timeout;
392
393   /* Row drag-and-drop */
394   GtkTreeRowReference *drag_dest_row;
395   GtkTreeViewDropPosition drag_dest_pos;
396   guint open_dest_timeout;
397
398   /* Rubber banding */
399   gint rubber_band_status;
400   gint rubber_band_x;
401   gint rubber_band_y;
402   gint rubber_band_shift;
403   gint rubber_band_ctrl;
404
405   GtkRBNode *rubber_band_start_node;
406   GtkRBTree *rubber_band_start_tree;
407
408   GtkRBNode *rubber_band_end_node;
409   GtkRBTree *rubber_band_end_tree;
410
411   /* fixed height */
412   gint fixed_height;
413
414   /* Scroll-to functionality when unrealized */
415   GtkTreeRowReference *scroll_to_path;
416   GtkTreeViewColumn *scroll_to_column;
417   gfloat scroll_to_row_align;
418   gfloat scroll_to_col_align;
419
420   /* Interactive search */
421   gint selected_iter;
422   gint search_column;
423   GtkTreeViewSearchPositionFunc search_position_func;
424   GtkTreeViewSearchEqualFunc search_equal_func;
425   gpointer search_user_data;
426   GDestroyNotify search_destroy;
427   gpointer search_position_user_data;
428   GDestroyNotify search_position_destroy;
429   GtkWidget *search_window;
430   GtkWidget *search_entry;
431   gulong search_entry_changed_id;
432   guint typeselect_flush_timeout;
433
434   /* Grid and tree lines */
435   GtkTreeViewGridLines grid_lines;
436   double grid_line_dashes[2];
437   int grid_line_width;
438
439   gboolean tree_lines_enabled;
440   double tree_line_dashes[2];
441   int tree_line_width;
442
443   /* Row separators */
444   GtkTreeViewRowSeparatorFunc row_separator_func;
445   gpointer row_separator_data;
446   GDestroyNotify row_separator_destroy;
447
448   /* Tooltip support */
449   gint tooltip_column;
450
451   /* Here comes the bitfield */
452   guint scroll_to_use_align : 1;
453
454   guint fixed_height_mode : 1;
455   guint fixed_height_check : 1;
456
457   guint reorderable : 1;
458   guint header_has_focus : 1;
459   guint drag_column_window_state : 3;
460   /* hint to display rows in alternating colors */
461   guint has_rules : 1;
462   guint mark_rows_col_dirty : 1;
463
464   /* for DnD */
465   guint empty_view_drop : 1;
466
467   guint ctrl_pressed : 1;
468   guint shift_pressed : 1;
469
470   guint init_hadjust_value : 1;
471
472   guint in_top_row_to_dy : 1;
473
474   /* interactive search */
475   guint enable_search : 1;
476   guint disable_popdown : 1;
477   guint search_custom_entry_set : 1;
478   
479   guint hover_selection : 1;
480   guint hover_expand : 1;
481   guint imcontext_changed : 1;
482
483   guint rubber_banding_enable : 1;
484
485   guint in_grab : 1;
486
487   guint post_validation_flag : 1;
488
489   /* Whether our key press handler is to avoid sending an unhandled binding to the search entry */
490   guint search_entry_avoid_unhandled_binding : 1;
491
492   /* GtkScrollablePolicy needs to be checked when
493    * driving the scrollable adjustment values */
494   guint hscroll_policy : 1;
495   guint vscroll_policy : 1;
496
497   /* GtkTreeView flags */
498   guint is_list : 1;
499   guint show_expanders : 1;
500   guint in_column_resize : 1;
501   guint arrow_prelit : 1;
502   guint headers_visible : 1;
503   guint draw_keyfocus : 1;
504   guint model_setup : 1;
505   guint in_column_drag : 1;
506 };
507
508
509 /* Signals */
510 enum
511 {
512   ROW_ACTIVATED,
513   TEST_EXPAND_ROW,
514   TEST_COLLAPSE_ROW,
515   ROW_EXPANDED,
516   ROW_COLLAPSED,
517   COLUMNS_CHANGED,
518   CURSOR_CHANGED,
519   MOVE_CURSOR,
520   SELECT_ALL,
521   UNSELECT_ALL,
522   SELECT_CURSOR_ROW,
523   TOGGLE_CURSOR_ROW,
524   EXPAND_COLLAPSE_CURSOR_ROW,
525   SELECT_CURSOR_PARENT,
526   START_INTERACTIVE_SEARCH,
527   LAST_SIGNAL
528 };
529
530 /* Properties */
531 enum {
532   PROP_0,
533   PROP_MODEL,
534   PROP_HADJUSTMENT,
535   PROP_VADJUSTMENT,
536   PROP_HSCROLL_POLICY,
537   PROP_VSCROLL_POLICY,
538   PROP_HEADERS_VISIBLE,
539   PROP_HEADERS_CLICKABLE,
540   PROP_EXPANDER_COLUMN,
541   PROP_REORDERABLE,
542   PROP_RULES_HINT,
543   PROP_ENABLE_SEARCH,
544   PROP_SEARCH_COLUMN,
545   PROP_FIXED_HEIGHT_MODE,
546   PROP_HOVER_SELECTION,
547   PROP_HOVER_EXPAND,
548   PROP_SHOW_EXPANDERS,
549   PROP_LEVEL_INDENTATION,
550   PROP_RUBBER_BANDING,
551   PROP_ENABLE_GRID_LINES,
552   PROP_ENABLE_TREE_LINES,
553   PROP_TOOLTIP_COLUMN
554 };
555
556 /* object signals */
557 static void     gtk_tree_view_finalize             (GObject          *object);
558 static void     gtk_tree_view_set_property         (GObject         *object,
559                                                     guint            prop_id,
560                                                     const GValue    *value,
561                                                     GParamSpec      *pspec);
562 static void     gtk_tree_view_get_property         (GObject         *object,
563                                                     guint            prop_id,
564                                                     GValue          *value,
565                                                     GParamSpec      *pspec);
566
567 /* gtkwidget signals */
568 static void     gtk_tree_view_destroy              (GtkWidget        *widget);
569 static void     gtk_tree_view_realize              (GtkWidget        *widget);
570 static void     gtk_tree_view_unrealize            (GtkWidget        *widget);
571 static void     gtk_tree_view_map                  (GtkWidget        *widget);
572 static void     gtk_tree_view_get_preferred_width  (GtkWidget        *widget,
573                                                     gint             *minimum,
574                                                     gint             *natural);
575 static void     gtk_tree_view_get_preferred_height (GtkWidget        *widget,
576                                                     gint             *minimum,
577                                                     gint             *natural);
578 static void     gtk_tree_view_size_request         (GtkWidget        *widget,
579                                                     GtkRequisition   *requisition,
580                                                     gboolean          may_validate);
581 static void     gtk_tree_view_size_allocate        (GtkWidget        *widget,
582                                                     GtkAllocation    *allocation);
583 static gboolean gtk_tree_view_draw                 (GtkWidget        *widget,
584                                                     cairo_t          *cr);
585 static gboolean gtk_tree_view_key_press            (GtkWidget        *widget,
586                                                     GdkEventKey      *event);
587 static gboolean gtk_tree_view_key_release          (GtkWidget        *widget,
588                                                     GdkEventKey      *event);
589 static gboolean gtk_tree_view_motion               (GtkWidget        *widget,
590                                                     GdkEventMotion   *event);
591 static gboolean gtk_tree_view_enter_notify         (GtkWidget        *widget,
592                                                     GdkEventCrossing *event);
593 static gboolean gtk_tree_view_leave_notify         (GtkWidget        *widget,
594                                                     GdkEventCrossing *event);
595 static gboolean gtk_tree_view_button_press         (GtkWidget        *widget,
596                                                     GdkEventButton   *event);
597 static gboolean gtk_tree_view_button_release       (GtkWidget        *widget,
598                                                     GdkEventButton   *event);
599 static gboolean gtk_tree_view_grab_broken          (GtkWidget          *widget,
600                                                     GdkEventGrabBroken *event);
601 #if 0
602 static gboolean gtk_tree_view_configure            (GtkWidget         *widget,
603                                                     GdkEventConfigure *event);
604 #endif
605
606 static GtkWidgetPath * gtk_tree_view_get_path_for_child (GtkContainer *container,
607                                                          GtkWidget    *child);
608
609 static void     gtk_tree_view_set_focus_child      (GtkContainer     *container,
610                                                     GtkWidget        *child);
611 static gint     gtk_tree_view_focus_out            (GtkWidget        *widget,
612                                                     GdkEventFocus    *event);
613 static gint     gtk_tree_view_focus                (GtkWidget        *widget,
614                                                     GtkDirectionType  direction);
615 static void     gtk_tree_view_grab_focus           (GtkWidget        *widget);
616 static void     gtk_tree_view_style_updated        (GtkWidget        *widget);
617 static void     gtk_tree_view_grab_notify          (GtkWidget        *widget,
618                                                     gboolean          was_grabbed);
619 static void     gtk_tree_view_state_flags_changed  (GtkWidget        *widget,
620                                                     GtkStateFlags     previous_state);
621
622 /* container signals */
623 static void     gtk_tree_view_remove               (GtkContainer     *container,
624                                                     GtkWidget        *widget);
625 static void     gtk_tree_view_forall               (GtkContainer     *container,
626                                                     gboolean          include_internals,
627                                                     GtkCallback       callback,
628                                                     gpointer          callback_data);
629
630 /* Source side drag signals */
631 static void gtk_tree_view_drag_begin       (GtkWidget        *widget,
632                                             GdkDragContext   *context);
633 static void gtk_tree_view_drag_end         (GtkWidget        *widget,
634                                             GdkDragContext   *context);
635 static void gtk_tree_view_drag_data_get    (GtkWidget        *widget,
636                                             GdkDragContext   *context,
637                                             GtkSelectionData *selection_data,
638                                             guint             info,
639                                             guint             time);
640 static void gtk_tree_view_drag_data_delete (GtkWidget        *widget,
641                                             GdkDragContext   *context);
642
643 /* Target side drag signals */
644 static void     gtk_tree_view_drag_leave         (GtkWidget        *widget,
645                                                   GdkDragContext   *context,
646                                                   guint             time);
647 static gboolean gtk_tree_view_drag_motion        (GtkWidget        *widget,
648                                                   GdkDragContext   *context,
649                                                   gint              x,
650                                                   gint              y,
651                                                   guint             time);
652 static gboolean gtk_tree_view_drag_drop          (GtkWidget        *widget,
653                                                   GdkDragContext   *context,
654                                                   gint              x,
655                                                   gint              y,
656                                                   guint             time);
657 static void     gtk_tree_view_drag_data_received (GtkWidget        *widget,
658                                                   GdkDragContext   *context,
659                                                   gint              x,
660                                                   gint              y,
661                                                   GtkSelectionData *selection_data,
662                                                   guint             info,
663                                                   guint             time);
664
665 /* tree_model signals */
666 static void     gtk_tree_view_set_hadjustment             (GtkTreeView     *tree_view,
667                                                            GtkAdjustment   *adjustment);
668 static void     gtk_tree_view_set_vadjustment             (GtkTreeView     *tree_view,
669                                                            GtkAdjustment   *adjustment);
670 static gboolean gtk_tree_view_real_move_cursor            (GtkTreeView     *tree_view,
671                                                            GtkMovementStep  step,
672                                                            gint             count);
673 static gboolean gtk_tree_view_real_select_all             (GtkTreeView     *tree_view);
674 static gboolean gtk_tree_view_real_unselect_all           (GtkTreeView     *tree_view);
675 static gboolean gtk_tree_view_real_select_cursor_row      (GtkTreeView     *tree_view,
676                                                            gboolean         start_editing);
677 static gboolean gtk_tree_view_real_toggle_cursor_row      (GtkTreeView     *tree_view);
678 static gboolean gtk_tree_view_real_expand_collapse_cursor_row (GtkTreeView     *tree_view,
679                                                                gboolean         logical,
680                                                                gboolean         expand,
681                                                                gboolean         open_all);
682 static gboolean gtk_tree_view_real_select_cursor_parent   (GtkTreeView     *tree_view);
683 static void gtk_tree_view_row_changed                     (GtkTreeModel    *model,
684                                                            GtkTreePath     *path,
685                                                            GtkTreeIter     *iter,
686                                                            gpointer         data);
687 static void gtk_tree_view_row_inserted                    (GtkTreeModel    *model,
688                                                            GtkTreePath     *path,
689                                                            GtkTreeIter     *iter,
690                                                            gpointer         data);
691 static void gtk_tree_view_row_has_child_toggled           (GtkTreeModel    *model,
692                                                            GtkTreePath     *path,
693                                                            GtkTreeIter     *iter,
694                                                            gpointer         data);
695 static void gtk_tree_view_row_deleted                     (GtkTreeModel    *model,
696                                                            GtkTreePath     *path,
697                                                            gpointer         data);
698 static void gtk_tree_view_rows_reordered                  (GtkTreeModel    *model,
699                                                            GtkTreePath     *parent,
700                                                            GtkTreeIter     *iter,
701                                                            gint            *new_order,
702                                                            gpointer         data);
703
704 /* Incremental reflow */
705 static gboolean validate_row             (GtkTreeView *tree_view,
706                                           GtkRBTree   *tree,
707                                           GtkRBNode   *node,
708                                           GtkTreeIter *iter,
709                                           GtkTreePath *path);
710 static void     validate_visible_area    (GtkTreeView *tree_view);
711 static gboolean validate_rows_handler    (GtkTreeView *tree_view);
712 static gboolean do_validate_rows         (GtkTreeView *tree_view,
713                                           gboolean     size_request);
714 static gboolean validate_rows            (GtkTreeView *tree_view);
715 static gboolean presize_handler_callback (gpointer     data);
716 static void     install_presize_handler  (GtkTreeView *tree_view);
717 static void     install_scroll_sync_handler (GtkTreeView *tree_view);
718 static void     gtk_tree_view_set_top_row   (GtkTreeView *tree_view,
719                                              GtkTreePath *path,
720                                              gint         offset);
721 static void     gtk_tree_view_dy_to_top_row (GtkTreeView *tree_view);
722 static void     gtk_tree_view_top_row_to_dy (GtkTreeView *tree_view);
723 static void     invalidate_empty_focus      (GtkTreeView *tree_view);
724
725 /* Internal functions */
726 static gboolean gtk_tree_view_is_expander_column             (GtkTreeView        *tree_view,
727                                                               GtkTreeViewColumn  *column);
728 static inline gboolean gtk_tree_view_draw_expanders          (GtkTreeView        *tree_view);
729 static void     gtk_tree_view_add_move_binding               (GtkBindingSet      *binding_set,
730                                                               guint               keyval,
731                                                               guint               modmask,
732                                                               gboolean            add_shifted_binding,
733                                                               GtkMovementStep     step,
734                                                               gint                count);
735 static gint     gtk_tree_view_unref_and_check_selection_tree (GtkTreeView        *tree_view,
736                                                               GtkRBTree          *tree);
737 static void     gtk_tree_view_queue_draw_path                (GtkTreeView        *tree_view,
738                                                               GtkTreePath        *path,
739                                                               const GdkRectangle *clip_rect);
740 static void     gtk_tree_view_queue_draw_arrow               (GtkTreeView        *tree_view,
741                                                               GtkRBTree          *tree,
742                                                               GtkRBNode          *node);
743 static void     gtk_tree_view_draw_arrow                     (GtkTreeView        *tree_view,
744                                                               cairo_t            *cr,
745                                                               GtkRBTree          *tree,
746                                                               GtkRBNode          *node,
747                                                               gint                x,
748                                                               gint                y);
749 static void     gtk_tree_view_get_arrow_xrange               (GtkTreeView        *tree_view,
750                                                               GtkRBTree          *tree,
751                                                               gint               *x1,
752                                                               gint               *x2);
753 static gint     gtk_tree_view_new_column_width               (GtkTreeView        *tree_view,
754                                                               gint                i,
755                                                               gint               *x);
756 static void     gtk_tree_view_adjustment_changed             (GtkAdjustment      *adjustment,
757                                                               GtkTreeView        *tree_view);
758 static void     gtk_tree_view_build_tree                     (GtkTreeView        *tree_view,
759                                                               GtkRBTree          *tree,
760                                                               GtkTreeIter        *iter,
761                                                               gint                depth,
762                                                               gboolean            recurse);
763 static void     gtk_tree_view_clamp_node_visible             (GtkTreeView        *tree_view,
764                                                               GtkRBTree          *tree,
765                                                               GtkRBNode          *node);
766 static void     gtk_tree_view_clamp_column_visible           (GtkTreeView        *tree_view,
767                                                               GtkTreeViewColumn  *column,
768                                                               gboolean            focus_to_cell);
769 static gboolean gtk_tree_view_maybe_begin_dragging_row       (GtkTreeView        *tree_view,
770                                                               GdkEventMotion     *event);
771 static void     gtk_tree_view_focus_to_cursor                (GtkTreeView        *tree_view);
772 static void     gtk_tree_view_move_cursor_up_down            (GtkTreeView        *tree_view,
773                                                               gint                count);
774 static void     gtk_tree_view_move_cursor_page_up_down       (GtkTreeView        *tree_view,
775                                                               gint                count);
776 static void     gtk_tree_view_move_cursor_left_right         (GtkTreeView        *tree_view,
777                                                               gint                count);
778 static void     gtk_tree_view_move_cursor_start_end          (GtkTreeView        *tree_view,
779                                                               gint                count);
780 static gboolean gtk_tree_view_real_collapse_row              (GtkTreeView        *tree_view,
781                                                               GtkTreePath        *path,
782                                                               GtkRBTree          *tree,
783                                                               GtkRBNode          *node,
784                                                               gboolean            animate);
785 static gboolean gtk_tree_view_real_expand_row                (GtkTreeView        *tree_view,
786                                                               GtkTreePath        *path,
787                                                               GtkRBTree          *tree,
788                                                               GtkRBNode          *node,
789                                                               gboolean            open_all,
790                                                               gboolean            animate);
791 static void     gtk_tree_view_real_set_cursor                (GtkTreeView        *tree_view,
792                                                               GtkTreePath        *path,
793                                                               gboolean            clear_and_select,
794                                                               gboolean            clamp_node);
795 static gboolean gtk_tree_view_has_can_focus_cell             (GtkTreeView        *tree_view);
796 static void     column_sizing_notify                         (GObject            *object,
797                                                               GParamSpec         *pspec,
798                                                               gpointer            data);
799 static void     gtk_tree_view_stop_rubber_band               (GtkTreeView        *tree_view);
800 static void     update_prelight                              (GtkTreeView        *tree_view,
801                                                               int                 x,
802                                                               int                 y);
803
804 static inline gint gtk_tree_view_get_effective_header_height (GtkTreeView *tree_view);
805
806 static inline gint gtk_tree_view_get_cell_area_y_offset      (GtkTreeView *tree_view,
807                                                               GtkRBTree   *tree,
808                                                               GtkRBNode   *node,
809                                                               gint         vertical_separator);
810 static inline gint gtk_tree_view_get_cell_area_height        (GtkTreeView *tree_view,
811                                                               GtkRBNode   *node,
812                                                               gint         vertical_separator);
813
814 static inline gint gtk_tree_view_get_row_y_offset            (GtkTreeView *tree_view,
815                                                               GtkRBTree   *tree,
816                                                               GtkRBNode   *node);
817 static inline gint gtk_tree_view_get_row_height              (GtkTreeView *tree_view,
818                                                               GtkRBNode   *node);
819
820 /* interactive search */
821 static void     gtk_tree_view_ensure_interactive_directory (GtkTreeView *tree_view);
822 static void     gtk_tree_view_search_dialog_hide        (GtkWidget        *search_dialog,
823                                                          GtkTreeView      *tree_view,
824                                                          GdkDevice        *device);
825 static void     gtk_tree_view_search_position_func      (GtkTreeView      *tree_view,
826                                                          GtkWidget        *search_dialog,
827                                                          gpointer          user_data);
828 static void     gtk_tree_view_search_disable_popdown    (GtkEntry         *entry,
829                                                          GtkMenu          *menu,
830                                                          gpointer          data);
831 static void     gtk_tree_view_search_preedit_changed    (GtkIMContext     *im_context,
832                                                          GtkTreeView      *tree_view);
833 static void     gtk_tree_view_search_activate           (GtkEntry         *entry,
834                                                          GtkTreeView      *tree_view);
835 static gboolean gtk_tree_view_real_search_enable_popdown(gpointer          data);
836 static void     gtk_tree_view_search_enable_popdown     (GtkWidget        *widget,
837                                                          gpointer          data);
838 static gboolean gtk_tree_view_search_delete_event       (GtkWidget        *widget,
839                                                          GdkEventAny      *event,
840                                                          GtkTreeView      *tree_view);
841 static gboolean gtk_tree_view_search_button_press_event (GtkWidget        *widget,
842                                                          GdkEventButton   *event,
843                                                          GtkTreeView      *tree_view);
844 static gboolean gtk_tree_view_search_scroll_event       (GtkWidget        *entry,
845                                                          GdkEventScroll   *event,
846                                                          GtkTreeView      *tree_view);
847 static gboolean gtk_tree_view_search_key_press_event    (GtkWidget        *entry,
848                                                          GdkEventKey      *event,
849                                                          GtkTreeView      *tree_view);
850 static gboolean gtk_tree_view_search_move               (GtkWidget        *window,
851                                                          GtkTreeView      *tree_view,
852                                                          gboolean          up);
853 static gboolean gtk_tree_view_search_equal_func         (GtkTreeModel     *model,
854                                                          gint              column,
855                                                          const gchar      *key,
856                                                          GtkTreeIter      *iter,
857                                                          gpointer          search_data);
858 static gboolean gtk_tree_view_search_iter               (GtkTreeModel     *model,
859                                                          GtkTreeSelection *selection,
860                                                          GtkTreeIter      *iter,
861                                                          const gchar      *text,
862                                                          gint             *count,
863                                                          gint              n);
864 static void     gtk_tree_view_search_init               (GtkWidget        *entry,
865                                                          GtkTreeView      *tree_view);
866 static void     gtk_tree_view_put                       (GtkTreeView      *tree_view,
867                                                          GtkWidget        *child_widget,
868                                                          gint              x,
869                                                          gint              y,
870                                                          gint              width,
871                                                          gint              height);
872 static gboolean gtk_tree_view_start_editing             (GtkTreeView      *tree_view,
873                                                          GtkTreePath      *cursor_path,
874                                                          gboolean          edit_only);
875 static void gtk_tree_view_stop_editing                  (GtkTreeView *tree_view,
876                                                          gboolean     cancel_editing);
877 static gboolean gtk_tree_view_real_start_interactive_search (GtkTreeView *tree_view,
878                                                              GdkDevice   *device,
879                                                              gboolean     keybinding);
880 static gboolean gtk_tree_view_start_interactive_search      (GtkTreeView *tree_view);
881 static GtkTreeViewColumn *gtk_tree_view_get_drop_column (GtkTreeView       *tree_view,
882                                                          GtkTreeViewColumn *column,
883                                                          gint               drop_position);
884
885 /* GtkBuildable */
886 static void     gtk_tree_view_buildable_add_child          (GtkBuildable      *tree_view,
887                                                             GtkBuilder        *builder,
888                                                             GObject           *child,
889                                                             const gchar       *type);
890 static GObject *gtk_tree_view_buildable_get_internal_child (GtkBuildable      *buildable,
891                                                             GtkBuilder        *builder,
892                                                             const gchar       *childname);
893 static void     gtk_tree_view_buildable_init               (GtkBuildableIface *iface);
894
895
896 static gboolean scroll_row_timeout                   (gpointer     data);
897 static void     add_scroll_timeout                   (GtkTreeView *tree_view);
898 static void     remove_scroll_timeout                (GtkTreeView *tree_view);
899
900 static guint tree_view_signals [LAST_SIGNAL] = { 0 };
901
902 \f
903
904 /* GType Methods
905  */
906
907 G_DEFINE_TYPE_WITH_CODE (GtkTreeView, gtk_tree_view, GTK_TYPE_CONTAINER,
908                          G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
909                                                 gtk_tree_view_buildable_init)
910                          G_IMPLEMENT_INTERFACE (GTK_TYPE_SCROLLABLE, NULL))
911
912 static void
913 gtk_tree_view_class_init (GtkTreeViewClass *class)
914 {
915   GObjectClass *o_class;
916   GtkWidgetClass *widget_class;
917   GtkContainerClass *container_class;
918   GtkBindingSet *binding_set;
919
920   binding_set = gtk_binding_set_by_class (class);
921
922   o_class = (GObjectClass *) class;
923   widget_class = (GtkWidgetClass *) class;
924   container_class = (GtkContainerClass *) class;
925
926   /* GObject signals */
927   o_class->set_property = gtk_tree_view_set_property;
928   o_class->get_property = gtk_tree_view_get_property;
929   o_class->finalize = gtk_tree_view_finalize;
930
931   /* GtkWidget signals */
932   widget_class->destroy = gtk_tree_view_destroy;
933   widget_class->map = gtk_tree_view_map;
934   widget_class->realize = gtk_tree_view_realize;
935   widget_class->unrealize = gtk_tree_view_unrealize;
936   widget_class->get_preferred_width = gtk_tree_view_get_preferred_width;
937   widget_class->get_preferred_height = gtk_tree_view_get_preferred_height;
938   widget_class->size_allocate = gtk_tree_view_size_allocate;
939   widget_class->button_press_event = gtk_tree_view_button_press;
940   widget_class->button_release_event = gtk_tree_view_button_release;
941   widget_class->grab_broken_event = gtk_tree_view_grab_broken;
942   /*widget_class->configure_event = gtk_tree_view_configure;*/
943   widget_class->motion_notify_event = gtk_tree_view_motion;
944   widget_class->draw = gtk_tree_view_draw;
945   widget_class->key_press_event = gtk_tree_view_key_press;
946   widget_class->key_release_event = gtk_tree_view_key_release;
947   widget_class->enter_notify_event = gtk_tree_view_enter_notify;
948   widget_class->leave_notify_event = gtk_tree_view_leave_notify;
949   widget_class->focus_out_event = gtk_tree_view_focus_out;
950   widget_class->drag_begin = gtk_tree_view_drag_begin;
951   widget_class->drag_end = gtk_tree_view_drag_end;
952   widget_class->drag_data_get = gtk_tree_view_drag_data_get;
953   widget_class->drag_data_delete = gtk_tree_view_drag_data_delete;
954   widget_class->drag_leave = gtk_tree_view_drag_leave;
955   widget_class->drag_motion = gtk_tree_view_drag_motion;
956   widget_class->drag_drop = gtk_tree_view_drag_drop;
957   widget_class->drag_data_received = gtk_tree_view_drag_data_received;
958   widget_class->focus = gtk_tree_view_focus;
959   widget_class->grab_focus = gtk_tree_view_grab_focus;
960   widget_class->style_updated = gtk_tree_view_style_updated;
961   widget_class->grab_notify = gtk_tree_view_grab_notify;
962   widget_class->state_flags_changed = gtk_tree_view_state_flags_changed;
963
964   /* GtkContainer signals */
965   container_class->remove = gtk_tree_view_remove;
966   container_class->forall = gtk_tree_view_forall;
967   container_class->set_focus_child = gtk_tree_view_set_focus_child;
968   container_class->get_path_for_child = gtk_tree_view_get_path_for_child;
969
970   class->move_cursor = gtk_tree_view_real_move_cursor;
971   class->select_all = gtk_tree_view_real_select_all;
972   class->unselect_all = gtk_tree_view_real_unselect_all;
973   class->select_cursor_row = gtk_tree_view_real_select_cursor_row;
974   class->toggle_cursor_row = gtk_tree_view_real_toggle_cursor_row;
975   class->expand_collapse_cursor_row = gtk_tree_view_real_expand_collapse_cursor_row;
976   class->select_cursor_parent = gtk_tree_view_real_select_cursor_parent;
977   class->start_interactive_search = gtk_tree_view_start_interactive_search;
978
979   /* Properties */
980
981   g_object_class_install_property (o_class,
982                                    PROP_MODEL,
983                                    g_param_spec_object ("model",
984                                                         P_("TreeView Model"),
985                                                         P_("The model for the tree view"),
986                                                         GTK_TYPE_TREE_MODEL,
987                                                         GTK_PARAM_READWRITE));
988
989   g_object_class_override_property (o_class, PROP_HADJUSTMENT,    "hadjustment");
990   g_object_class_override_property (o_class, PROP_VADJUSTMENT,    "vadjustment");
991   g_object_class_override_property (o_class, PROP_HSCROLL_POLICY, "hscroll-policy");
992   g_object_class_override_property (o_class, PROP_VSCROLL_POLICY, "vscroll-policy");
993
994   g_object_class_install_property (o_class,
995                                    PROP_HEADERS_VISIBLE,
996                                    g_param_spec_boolean ("headers-visible",
997                                                          P_("Headers Visible"),
998                                                          P_("Show the column header buttons"),
999                                                          TRUE,
1000                                                          GTK_PARAM_READWRITE));
1001
1002   g_object_class_install_property (o_class,
1003                                    PROP_HEADERS_CLICKABLE,
1004                                    g_param_spec_boolean ("headers-clickable",
1005                                                          P_("Headers Clickable"),
1006                                                          P_("Column headers respond to click events"),
1007                                                          TRUE,
1008                                                          GTK_PARAM_READWRITE));
1009
1010   g_object_class_install_property (o_class,
1011                                    PROP_EXPANDER_COLUMN,
1012                                    g_param_spec_object ("expander-column",
1013                                                         P_("Expander Column"),
1014                                                         P_("Set the column for the expander column"),
1015                                                         GTK_TYPE_TREE_VIEW_COLUMN,
1016                                                         GTK_PARAM_READWRITE));
1017
1018   g_object_class_install_property (o_class,
1019                                    PROP_REORDERABLE,
1020                                    g_param_spec_boolean ("reorderable",
1021                                                          P_("Reorderable"),
1022                                                          P_("View is reorderable"),
1023                                                          FALSE,
1024                                                          GTK_PARAM_READWRITE));
1025
1026   g_object_class_install_property (o_class,
1027                                    PROP_RULES_HINT,
1028                                    g_param_spec_boolean ("rules-hint",
1029                                                          P_("Rules Hint"),
1030                                                          P_("Set a hint to the theme engine to draw rows in alternating colors"),
1031                                                          FALSE,
1032                                                          GTK_PARAM_READWRITE));
1033
1034     g_object_class_install_property (o_class,
1035                                      PROP_ENABLE_SEARCH,
1036                                      g_param_spec_boolean ("enable-search",
1037                                                            P_("Enable Search"),
1038                                                            P_("View allows user to search through columns interactively"),
1039                                                            TRUE,
1040                                                            GTK_PARAM_READWRITE));
1041
1042     g_object_class_install_property (o_class,
1043                                      PROP_SEARCH_COLUMN,
1044                                      g_param_spec_int ("search-column",
1045                                                        P_("Search Column"),
1046                                                        P_("Model column to search through during interactive search"),
1047                                                        -1,
1048                                                        G_MAXINT,
1049                                                        -1,
1050                                                        GTK_PARAM_READWRITE));
1051
1052     /**
1053      * GtkTreeView:fixed-height-mode:
1054      *
1055      * Setting the ::fixed-height-mode property to %TRUE speeds up 
1056      * #GtkTreeView by assuming that all rows have the same height. 
1057      * Only enable this option if all rows are the same height.  
1058      * Please see gtk_tree_view_set_fixed_height_mode() for more 
1059      * information on this option.
1060      *
1061      * Since: 2.4
1062      **/
1063     g_object_class_install_property (o_class,
1064                                      PROP_FIXED_HEIGHT_MODE,
1065                                      g_param_spec_boolean ("fixed-height-mode",
1066                                                            P_("Fixed Height Mode"),
1067                                                            P_("Speeds up GtkTreeView by assuming that all rows have the same height"),
1068                                                            FALSE,
1069                                                            GTK_PARAM_READWRITE));
1070     
1071     /**
1072      * GtkTreeView:hover-selection:
1073      * 
1074      * Enables or disables the hover selection mode of @tree_view.
1075      * Hover selection makes the selected row follow the pointer.
1076      * Currently, this works only for the selection modes 
1077      * %GTK_SELECTION_SINGLE and %GTK_SELECTION_BROWSE.
1078      *
1079      * This mode is primarily intended for treeviews in popups, e.g.
1080      * in #GtkComboBox or #GtkEntryCompletion.
1081      *
1082      * Since: 2.6
1083      */
1084     g_object_class_install_property (o_class,
1085                                      PROP_HOVER_SELECTION,
1086                                      g_param_spec_boolean ("hover-selection",
1087                                                            P_("Hover Selection"),
1088                                                            P_("Whether the selection should follow the pointer"),
1089                                                            FALSE,
1090                                                            GTK_PARAM_READWRITE));
1091
1092     /**
1093      * GtkTreeView:hover-expand:
1094      * 
1095      * Enables or disables the hover expansion mode of @tree_view.
1096      * Hover expansion makes rows expand or collapse if the pointer moves 
1097      * over them.
1098      *
1099      * This mode is primarily intended for treeviews in popups, e.g.
1100      * in #GtkComboBox or #GtkEntryCompletion.
1101      *
1102      * Since: 2.6
1103      */
1104     g_object_class_install_property (o_class,
1105                                      PROP_HOVER_EXPAND,
1106                                      g_param_spec_boolean ("hover-expand",
1107                                                            P_("Hover Expand"),
1108                                                            P_("Whether rows should be expanded/collapsed when the pointer moves over them"),
1109                                                            FALSE,
1110                                                            GTK_PARAM_READWRITE));
1111
1112     /**
1113      * GtkTreeView:show-expanders:
1114      *
1115      * %TRUE if the view has expanders.
1116      *
1117      * Since: 2.12
1118      */
1119     g_object_class_install_property (o_class,
1120                                      PROP_SHOW_EXPANDERS,
1121                                      g_param_spec_boolean ("show-expanders",
1122                                                            P_("Show Expanders"),
1123                                                            P_("View has expanders"),
1124                                                            TRUE,
1125                                                            GTK_PARAM_READWRITE));
1126
1127     /**
1128      * GtkTreeView:level-indentation:
1129      *
1130      * Extra indentation for each level.
1131      *
1132      * Since: 2.12
1133      */
1134     g_object_class_install_property (o_class,
1135                                      PROP_LEVEL_INDENTATION,
1136                                      g_param_spec_int ("level-indentation",
1137                                                        P_("Level Indentation"),
1138                                                        P_("Extra indentation for each level"),
1139                                                        0,
1140                                                        G_MAXINT,
1141                                                        0,
1142                                                        GTK_PARAM_READWRITE));
1143
1144     g_object_class_install_property (o_class,
1145                                      PROP_RUBBER_BANDING,
1146                                      g_param_spec_boolean ("rubber-banding",
1147                                                            P_("Rubber Banding"),
1148                                                            P_("Whether to enable selection of multiple items by dragging the mouse pointer"),
1149                                                            FALSE,
1150                                                            GTK_PARAM_READWRITE));
1151
1152     g_object_class_install_property (o_class,
1153                                      PROP_ENABLE_GRID_LINES,
1154                                      g_param_spec_enum ("enable-grid-lines",
1155                                                         P_("Enable Grid Lines"),
1156                                                         P_("Whether grid lines should be drawn in the tree view"),
1157                                                         GTK_TYPE_TREE_VIEW_GRID_LINES,
1158                                                         GTK_TREE_VIEW_GRID_LINES_NONE,
1159                                                         GTK_PARAM_READWRITE));
1160
1161     g_object_class_install_property (o_class,
1162                                      PROP_ENABLE_TREE_LINES,
1163                                      g_param_spec_boolean ("enable-tree-lines",
1164                                                            P_("Enable Tree Lines"),
1165                                                            P_("Whether tree lines should be drawn in the tree view"),
1166                                                            FALSE,
1167                                                            GTK_PARAM_READWRITE));
1168
1169     g_object_class_install_property (o_class,
1170                                      PROP_TOOLTIP_COLUMN,
1171                                      g_param_spec_int ("tooltip-column",
1172                                                        P_("Tooltip Column"),
1173                                                        P_("The column in the model containing the tooltip texts for the rows"),
1174                                                        -1,
1175                                                        G_MAXINT,
1176                                                        -1,
1177                                                        GTK_PARAM_READWRITE));
1178
1179   /* Style properties */
1180 #define _TREE_VIEW_EXPANDER_SIZE 14
1181 #define _TREE_VIEW_VERTICAL_SEPARATOR 2
1182 #define _TREE_VIEW_HORIZONTAL_SEPARATOR 2
1183
1184   gtk_widget_class_install_style_property (widget_class,
1185                                            g_param_spec_int ("expander-size",
1186                                                              P_("Expander Size"),
1187                                                              P_("Size of the expander arrow"),
1188                                                              0,
1189                                                              G_MAXINT,
1190                                                              _TREE_VIEW_EXPANDER_SIZE,
1191                                                              GTK_PARAM_READABLE));
1192
1193   gtk_widget_class_install_style_property (widget_class,
1194                                            g_param_spec_int ("vertical-separator",
1195                                                              P_("Vertical Separator Width"),
1196                                                              P_("Vertical space between cells.  Must be an even number"),
1197                                                              0,
1198                                                              G_MAXINT,
1199                                                              _TREE_VIEW_VERTICAL_SEPARATOR,
1200                                                              GTK_PARAM_READABLE));
1201
1202   gtk_widget_class_install_style_property (widget_class,
1203                                            g_param_spec_int ("horizontal-separator",
1204                                                              P_("Horizontal Separator Width"),
1205                                                              P_("Horizontal space between cells.  Must be an even number"),
1206                                                              0,
1207                                                              G_MAXINT,
1208                                                              _TREE_VIEW_HORIZONTAL_SEPARATOR,
1209                                                              GTK_PARAM_READABLE));
1210
1211   gtk_widget_class_install_style_property (widget_class,
1212                                            g_param_spec_boolean ("allow-rules",
1213                                                                  P_("Allow Rules"),
1214                                                                  P_("Allow drawing of alternating color rows"),
1215                                                                  TRUE,
1216                                                                  GTK_PARAM_READABLE));
1217
1218   gtk_widget_class_install_style_property (widget_class,
1219                                            g_param_spec_boolean ("indent-expanders",
1220                                                                  P_("Indent Expanders"),
1221                                                                  P_("Make the expanders indented"),
1222                                                                  TRUE,
1223                                                                  GTK_PARAM_READABLE));
1224
1225   gtk_widget_class_install_style_property (widget_class,
1226                                            g_param_spec_boxed ("even-row-color",
1227                                                                P_("Even Row Color"),
1228                                                                P_("Color to use for even rows"),
1229                                                                GDK_TYPE_COLOR,
1230                                                                GTK_PARAM_READABLE));
1231
1232   gtk_widget_class_install_style_property (widget_class,
1233                                            g_param_spec_boxed ("odd-row-color",
1234                                                                P_("Odd Row Color"),
1235                                                                P_("Color to use for odd rows"),
1236                                                                GDK_TYPE_COLOR,
1237                                                                GTK_PARAM_READABLE));
1238
1239   gtk_widget_class_install_style_property (widget_class,
1240                                            g_param_spec_int ("grid-line-width",
1241                                                              P_("Grid line width"),
1242                                                              P_("Width, in pixels, of the tree view grid lines"),
1243                                                              0, G_MAXINT, 1,
1244                                                              GTK_PARAM_READABLE));
1245
1246   gtk_widget_class_install_style_property (widget_class,
1247                                            g_param_spec_int ("tree-line-width",
1248                                                              P_("Tree line width"),
1249                                                              P_("Width, in pixels, of the tree view lines"),
1250                                                              0, G_MAXINT, 1,
1251                                                              GTK_PARAM_READABLE));
1252
1253   gtk_widget_class_install_style_property (widget_class,
1254                                            g_param_spec_string ("grid-line-pattern",
1255                                                                 P_("Grid line pattern"),
1256                                                                 P_("Dash pattern used to draw the tree view grid lines"),
1257                                                                 "\1\1",
1258                                                                 GTK_PARAM_READABLE));
1259
1260   gtk_widget_class_install_style_property (widget_class,
1261                                            g_param_spec_string ("tree-line-pattern",
1262                                                                 P_("Tree line pattern"),
1263                                                                 P_("Dash pattern used to draw the tree view lines"),
1264                                                                 "\1\1",
1265                                                                 GTK_PARAM_READABLE));
1266
1267   /* Signals */
1268   /**
1269    * GtkTreeView::row-activated:
1270    * @tree_view: the object on which the signal is emitted
1271    * @path: the #GtkTreePath for the activated row
1272    * @column: the #GtkTreeViewColumn in which the activation occurred
1273    *
1274    * The "row-activated" signal is emitted when the method
1275    * gtk_tree_view_row_activated() is called or the user double clicks 
1276    * a treeview row. It is also emitted when a non-editable row is 
1277    * selected and one of the keys: Space, Shift+Space, Return or 
1278    * Enter is pressed.
1279    * 
1280    * For selection handling refer to the <link linkend="TreeWidget">tree 
1281    * widget conceptual overview</link> as well as #GtkTreeSelection.
1282    */
1283   tree_view_signals[ROW_ACTIVATED] =
1284     g_signal_new (I_("row-activated"),
1285                   G_TYPE_FROM_CLASS (o_class),
1286                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1287                   G_STRUCT_OFFSET (GtkTreeViewClass, row_activated),
1288                   NULL, NULL,
1289                   _gtk_marshal_VOID__BOXED_OBJECT,
1290                   G_TYPE_NONE, 2,
1291                   GTK_TYPE_TREE_PATH,
1292                   GTK_TYPE_TREE_VIEW_COLUMN);
1293
1294   /**
1295    * GtkTreeView::test-expand-row:
1296    * @tree_view: the object on which the signal is emitted
1297    * @iter: the tree iter of the row to expand
1298    * @path: a tree path that points to the row 
1299    * 
1300    * The given row is about to be expanded (show its children nodes). Use this
1301    * signal if you need to control the expandability of individual rows.
1302    *
1303    * Returns: %FALSE to allow expansion, %TRUE to reject
1304    */
1305   tree_view_signals[TEST_EXPAND_ROW] =
1306     g_signal_new (I_("test-expand-row"),
1307                   G_TYPE_FROM_CLASS (o_class),
1308                   G_SIGNAL_RUN_LAST,
1309                   G_STRUCT_OFFSET (GtkTreeViewClass, test_expand_row),
1310                   _gtk_boolean_handled_accumulator, NULL,
1311                   _gtk_marshal_BOOLEAN__BOXED_BOXED,
1312                   G_TYPE_BOOLEAN, 2,
1313                   GTK_TYPE_TREE_ITER,
1314                   GTK_TYPE_TREE_PATH);
1315
1316   /**
1317    * GtkTreeView::test-collapse-row:
1318    * @tree_view: the object on which the signal is emitted
1319    * @iter: the tree iter of the row to collapse
1320    * @path: a tree path that points to the row 
1321    * 
1322    * The given row is about to be collapsed (hide its children nodes). Use this
1323    * signal if you need to control the collapsibility of individual rows.
1324    *
1325    * Returns: %FALSE to allow collapsing, %TRUE to reject
1326    */
1327   tree_view_signals[TEST_COLLAPSE_ROW] =
1328     g_signal_new (I_("test-collapse-row"),
1329                   G_TYPE_FROM_CLASS (o_class),
1330                   G_SIGNAL_RUN_LAST,
1331                   G_STRUCT_OFFSET (GtkTreeViewClass, test_collapse_row),
1332                   _gtk_boolean_handled_accumulator, NULL,
1333                   _gtk_marshal_BOOLEAN__BOXED_BOXED,
1334                   G_TYPE_BOOLEAN, 2,
1335                   GTK_TYPE_TREE_ITER,
1336                   GTK_TYPE_TREE_PATH);
1337
1338   /**
1339    * GtkTreeView::row-expanded:
1340    * @tree_view: the object on which the signal is emitted
1341    * @iter: the tree iter of the expanded row
1342    * @path: a tree path that points to the row 
1343    * 
1344    * The given row has been expanded (child nodes are shown).
1345    */
1346   tree_view_signals[ROW_EXPANDED] =
1347     g_signal_new (I_("row-expanded"),
1348                   G_TYPE_FROM_CLASS (o_class),
1349                   G_SIGNAL_RUN_LAST,
1350                   G_STRUCT_OFFSET (GtkTreeViewClass, row_expanded),
1351                   NULL, NULL,
1352                   _gtk_marshal_VOID__BOXED_BOXED,
1353                   G_TYPE_NONE, 2,
1354                   GTK_TYPE_TREE_ITER,
1355                   GTK_TYPE_TREE_PATH);
1356
1357   /**
1358    * GtkTreeView::row-collapsed:
1359    * @tree_view: the object on which the signal is emitted
1360    * @iter: the tree iter of the collapsed row
1361    * @path: a tree path that points to the row 
1362    * 
1363    * The given row has been collapsed (child nodes are hidden).
1364    */
1365   tree_view_signals[ROW_COLLAPSED] =
1366     g_signal_new (I_("row-collapsed"),
1367                   G_TYPE_FROM_CLASS (o_class),
1368                   G_SIGNAL_RUN_LAST,
1369                   G_STRUCT_OFFSET (GtkTreeViewClass, row_collapsed),
1370                   NULL, NULL,
1371                   _gtk_marshal_VOID__BOXED_BOXED,
1372                   G_TYPE_NONE, 2,
1373                   GTK_TYPE_TREE_ITER,
1374                   GTK_TYPE_TREE_PATH);
1375
1376   /**
1377    * GtkTreeView::columns-changed:
1378    * @tree_view: the object on which the signal is emitted 
1379    * 
1380    * The number of columns of the treeview has changed.
1381    */
1382   tree_view_signals[COLUMNS_CHANGED] =
1383     g_signal_new (I_("columns-changed"),
1384                   G_TYPE_FROM_CLASS (o_class),
1385                   G_SIGNAL_RUN_LAST,
1386                   G_STRUCT_OFFSET (GtkTreeViewClass, columns_changed),
1387                   NULL, NULL,
1388                   _gtk_marshal_VOID__VOID,
1389                   G_TYPE_NONE, 0);
1390
1391   /**
1392    * GtkTreeView::cursor-changed:
1393    * @tree_view: the object on which the signal is emitted
1394    * 
1395    * The position of the cursor (focused cell) has changed.
1396    */
1397   tree_view_signals[CURSOR_CHANGED] =
1398     g_signal_new (I_("cursor-changed"),
1399                   G_TYPE_FROM_CLASS (o_class),
1400                   G_SIGNAL_RUN_LAST,
1401                   G_STRUCT_OFFSET (GtkTreeViewClass, cursor_changed),
1402                   NULL, NULL,
1403                   _gtk_marshal_VOID__VOID,
1404                   G_TYPE_NONE, 0);
1405
1406   tree_view_signals[MOVE_CURSOR] =
1407     g_signal_new (I_("move-cursor"),
1408                   G_TYPE_FROM_CLASS (o_class),
1409                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1410                   G_STRUCT_OFFSET (GtkTreeViewClass, move_cursor),
1411                   NULL, NULL,
1412                   _gtk_marshal_BOOLEAN__ENUM_INT,
1413                   G_TYPE_BOOLEAN, 2,
1414                   GTK_TYPE_MOVEMENT_STEP,
1415                   G_TYPE_INT);
1416
1417   tree_view_signals[SELECT_ALL] =
1418     g_signal_new (I_("select-all"),
1419                   G_TYPE_FROM_CLASS (o_class),
1420                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1421                   G_STRUCT_OFFSET (GtkTreeViewClass, select_all),
1422                   NULL, NULL,
1423                   _gtk_marshal_BOOLEAN__VOID,
1424                   G_TYPE_BOOLEAN, 0);
1425
1426   tree_view_signals[UNSELECT_ALL] =
1427     g_signal_new (I_("unselect-all"),
1428                   G_TYPE_FROM_CLASS (o_class),
1429                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1430                   G_STRUCT_OFFSET (GtkTreeViewClass, unselect_all),
1431                   NULL, NULL,
1432                   _gtk_marshal_BOOLEAN__VOID,
1433                   G_TYPE_BOOLEAN, 0);
1434
1435   tree_view_signals[SELECT_CURSOR_ROW] =
1436     g_signal_new (I_("select-cursor-row"),
1437                   G_TYPE_FROM_CLASS (o_class),
1438                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1439                   G_STRUCT_OFFSET (GtkTreeViewClass, select_cursor_row),
1440                   NULL, NULL,
1441                   _gtk_marshal_BOOLEAN__BOOLEAN,
1442                   G_TYPE_BOOLEAN, 1,
1443                   G_TYPE_BOOLEAN);
1444
1445   tree_view_signals[TOGGLE_CURSOR_ROW] =
1446     g_signal_new (I_("toggle-cursor-row"),
1447                   G_TYPE_FROM_CLASS (o_class),
1448                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1449                   G_STRUCT_OFFSET (GtkTreeViewClass, toggle_cursor_row),
1450                   NULL, NULL,
1451                   _gtk_marshal_BOOLEAN__VOID,
1452                   G_TYPE_BOOLEAN, 0);
1453
1454   tree_view_signals[EXPAND_COLLAPSE_CURSOR_ROW] =
1455     g_signal_new (I_("expand-collapse-cursor-row"),
1456                   G_TYPE_FROM_CLASS (o_class),
1457                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1458                   G_STRUCT_OFFSET (GtkTreeViewClass, expand_collapse_cursor_row),
1459                   NULL, NULL,
1460                   _gtk_marshal_BOOLEAN__BOOLEAN_BOOLEAN_BOOLEAN,
1461                   G_TYPE_BOOLEAN, 3,
1462                   G_TYPE_BOOLEAN,
1463                   G_TYPE_BOOLEAN,
1464                   G_TYPE_BOOLEAN);
1465
1466   tree_view_signals[SELECT_CURSOR_PARENT] =
1467     g_signal_new (I_("select-cursor-parent"),
1468                   G_TYPE_FROM_CLASS (o_class),
1469                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1470                   G_STRUCT_OFFSET (GtkTreeViewClass, select_cursor_parent),
1471                   NULL, NULL,
1472                   _gtk_marshal_BOOLEAN__VOID,
1473                   G_TYPE_BOOLEAN, 0);
1474
1475   tree_view_signals[START_INTERACTIVE_SEARCH] =
1476     g_signal_new (I_("start-interactive-search"),
1477                   G_TYPE_FROM_CLASS (o_class),
1478                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1479                   G_STRUCT_OFFSET (GtkTreeViewClass, start_interactive_search),
1480                   NULL, NULL,
1481                   _gtk_marshal_BOOLEAN__VOID,
1482                   G_TYPE_BOOLEAN, 0);
1483
1484   /* Key bindings */
1485   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Up, 0, TRUE,
1486                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
1487   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Up, 0, TRUE,
1488                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
1489
1490   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Down, 0, TRUE,
1491                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
1492   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Down, 0, TRUE,
1493                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
1494
1495   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_p, GDK_CONTROL_MASK, FALSE,
1496                                   GTK_MOVEMENT_DISPLAY_LINES, -1);
1497
1498   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_n, GDK_CONTROL_MASK, FALSE,
1499                                   GTK_MOVEMENT_DISPLAY_LINES, 1);
1500
1501   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Home, 0, TRUE,
1502                                   GTK_MOVEMENT_BUFFER_ENDS, -1);
1503   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Home, 0, TRUE,
1504                                   GTK_MOVEMENT_BUFFER_ENDS, -1);
1505
1506   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_End, 0, TRUE,
1507                                   GTK_MOVEMENT_BUFFER_ENDS, 1);
1508   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_End, 0, TRUE,
1509                                   GTK_MOVEMENT_BUFFER_ENDS, 1);
1510
1511   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Page_Up, 0, TRUE,
1512                                   GTK_MOVEMENT_PAGES, -1);
1513   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Page_Up, 0, TRUE,
1514                                   GTK_MOVEMENT_PAGES, -1);
1515
1516   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_Page_Down, 0, TRUE,
1517                                   GTK_MOVEMENT_PAGES, 1);
1518   gtk_tree_view_add_move_binding (binding_set, GDK_KEY_KP_Page_Down, 0, TRUE,
1519                                   GTK_MOVEMENT_PAGES, 1);
1520
1521
1522   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Right, 0, "move-cursor", 2,
1523                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1524                                 G_TYPE_INT, 1);
1525
1526   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Left, 0, "move-cursor", 2,
1527                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1528                                 G_TYPE_INT, -1);
1529
1530   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Right, 0, "move-cursor", 2,
1531                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1532                                 G_TYPE_INT, 1);
1533
1534   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Left, 0, "move-cursor", 2,
1535                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1536                                 G_TYPE_INT, -1);
1537
1538   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Right, GDK_CONTROL_MASK,
1539                                 "move-cursor", 2,
1540                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1541                                 G_TYPE_INT, 1);
1542
1543   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Left, GDK_CONTROL_MASK,
1544                                 "move-cursor", 2,
1545                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1546                                 G_TYPE_INT, -1);
1547
1548   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Right, GDK_CONTROL_MASK,
1549                                 "move-cursor", 2,
1550                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1551                                 G_TYPE_INT, 1);
1552
1553   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Left, GDK_CONTROL_MASK,
1554                                 "move-cursor", 2,
1555                                 G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
1556                                 G_TYPE_INT, -1);
1557
1558   gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, GDK_CONTROL_MASK, "toggle-cursor-row", 0);
1559   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Space, GDK_CONTROL_MASK, "toggle-cursor-row", 0);
1560
1561   gtk_binding_entry_add_signal (binding_set, GDK_KEY_a, GDK_CONTROL_MASK, "select-all", 0);
1562   gtk_binding_entry_add_signal (binding_set, GDK_KEY_slash, GDK_CONTROL_MASK, "select-all", 0);
1563
1564   gtk_binding_entry_add_signal (binding_set, GDK_KEY_A, GDK_CONTROL_MASK | GDK_SHIFT_MASK, "unselect-all", 0);
1565   gtk_binding_entry_add_signal (binding_set, GDK_KEY_backslash, GDK_CONTROL_MASK, "unselect-all", 0);
1566
1567   gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, GDK_SHIFT_MASK, "select-cursor-row", 1,
1568                                 G_TYPE_BOOLEAN, TRUE);
1569   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Space, GDK_SHIFT_MASK, "select-cursor-row", 1,
1570                                 G_TYPE_BOOLEAN, TRUE);
1571
1572   gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, 0, "select-cursor-row", 1,
1573                                 G_TYPE_BOOLEAN, TRUE);
1574   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Space, 0, "select-cursor-row", 1,
1575                                 G_TYPE_BOOLEAN, TRUE);
1576   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Return, 0, "select-cursor-row", 1,
1577                                 G_TYPE_BOOLEAN, TRUE);
1578   gtk_binding_entry_add_signal (binding_set, GDK_KEY_ISO_Enter, 0, "select-cursor-row", 1,
1579                                 G_TYPE_BOOLEAN, TRUE);
1580   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Enter, 0, "select-cursor-row", 1,
1581                                 G_TYPE_BOOLEAN, TRUE);
1582
1583   /* expand and collapse rows */
1584   gtk_binding_entry_add_signal (binding_set, GDK_KEY_plus, 0, "expand-collapse-cursor-row", 3,
1585                                 G_TYPE_BOOLEAN, TRUE,
1586                                 G_TYPE_BOOLEAN, TRUE,
1587                                 G_TYPE_BOOLEAN, FALSE);
1588
1589   gtk_binding_entry_add_signal (binding_set, GDK_KEY_asterisk, 0,
1590                                 "expand-collapse-cursor-row", 3,
1591                                 G_TYPE_BOOLEAN, TRUE,
1592                                 G_TYPE_BOOLEAN, TRUE,
1593                                 G_TYPE_BOOLEAN, TRUE);
1594   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Multiply, 0,
1595                                 "expand-collapse-cursor-row", 3,
1596                                 G_TYPE_BOOLEAN, TRUE,
1597                                 G_TYPE_BOOLEAN, TRUE,
1598                                 G_TYPE_BOOLEAN, TRUE);
1599
1600   gtk_binding_entry_add_signal (binding_set, GDK_KEY_slash, 0,
1601                                 "expand-collapse-cursor-row", 3,
1602                                 G_TYPE_BOOLEAN, TRUE,
1603                                 G_TYPE_BOOLEAN, FALSE,
1604                                 G_TYPE_BOOLEAN, FALSE);
1605   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Divide, 0,
1606                                 "expand-collapse-cursor-row", 3,
1607                                 G_TYPE_BOOLEAN, TRUE,
1608                                 G_TYPE_BOOLEAN, FALSE,
1609                                 G_TYPE_BOOLEAN, FALSE);
1610
1611   /* Not doable on US keyboards */
1612   gtk_binding_entry_add_signal (binding_set, GDK_KEY_plus, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1613                                 G_TYPE_BOOLEAN, TRUE,
1614                                 G_TYPE_BOOLEAN, TRUE,
1615                                 G_TYPE_BOOLEAN, TRUE);
1616   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Add, 0, "expand-collapse-cursor-row", 3,
1617                                 G_TYPE_BOOLEAN, TRUE,
1618                                 G_TYPE_BOOLEAN, TRUE,
1619                                 G_TYPE_BOOLEAN, FALSE);
1620   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Add, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1621                                 G_TYPE_BOOLEAN, TRUE,
1622                                 G_TYPE_BOOLEAN, TRUE,
1623                                 G_TYPE_BOOLEAN, TRUE);
1624   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Add, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1625                                 G_TYPE_BOOLEAN, TRUE,
1626                                 G_TYPE_BOOLEAN, TRUE,
1627                                 G_TYPE_BOOLEAN, TRUE);
1628   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Right, GDK_SHIFT_MASK,
1629                                 "expand-collapse-cursor-row", 3,
1630                                 G_TYPE_BOOLEAN, FALSE,
1631                                 G_TYPE_BOOLEAN, TRUE,
1632                                 G_TYPE_BOOLEAN, TRUE);
1633   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Right, GDK_SHIFT_MASK,
1634                                 "expand-collapse-cursor-row", 3,
1635                                 G_TYPE_BOOLEAN, FALSE,
1636                                 G_TYPE_BOOLEAN, TRUE,
1637                                 G_TYPE_BOOLEAN, TRUE);
1638   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Right,
1639                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1640                                 "expand-collapse-cursor-row", 3,
1641                                 G_TYPE_BOOLEAN, FALSE,
1642                                 G_TYPE_BOOLEAN, TRUE,
1643                                 G_TYPE_BOOLEAN, TRUE);
1644   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Right,
1645                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1646                                 "expand-collapse-cursor-row", 3,
1647                                 G_TYPE_BOOLEAN, FALSE,
1648                                 G_TYPE_BOOLEAN, TRUE,
1649                                 G_TYPE_BOOLEAN, TRUE);
1650
1651   gtk_binding_entry_add_signal (binding_set, GDK_KEY_minus, 0, "expand-collapse-cursor-row", 3,
1652                                 G_TYPE_BOOLEAN, TRUE,
1653                                 G_TYPE_BOOLEAN, FALSE,
1654                                 G_TYPE_BOOLEAN, FALSE);
1655   gtk_binding_entry_add_signal (binding_set, GDK_KEY_minus, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1656                                 G_TYPE_BOOLEAN, TRUE,
1657                                 G_TYPE_BOOLEAN, FALSE,
1658                                 G_TYPE_BOOLEAN, TRUE);
1659   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Subtract, 0, "expand-collapse-cursor-row", 3,
1660                                 G_TYPE_BOOLEAN, TRUE,
1661                                 G_TYPE_BOOLEAN, FALSE,
1662                                 G_TYPE_BOOLEAN, FALSE);
1663   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Subtract, GDK_SHIFT_MASK, "expand-collapse-cursor-row", 3,
1664                                 G_TYPE_BOOLEAN, TRUE,
1665                                 G_TYPE_BOOLEAN, FALSE,
1666                                 G_TYPE_BOOLEAN, TRUE);
1667   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Left, GDK_SHIFT_MASK,
1668                                 "expand-collapse-cursor-row", 3,
1669                                 G_TYPE_BOOLEAN, FALSE,
1670                                 G_TYPE_BOOLEAN, FALSE,
1671                                 G_TYPE_BOOLEAN, TRUE);
1672   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Left, GDK_SHIFT_MASK,
1673                                 "expand-collapse-cursor-row", 3,
1674                                 G_TYPE_BOOLEAN, FALSE,
1675                                 G_TYPE_BOOLEAN, FALSE,
1676                                 G_TYPE_BOOLEAN, TRUE);
1677   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Left,
1678                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1679                                 "expand-collapse-cursor-row", 3,
1680                                 G_TYPE_BOOLEAN, FALSE,
1681                                 G_TYPE_BOOLEAN, FALSE,
1682                                 G_TYPE_BOOLEAN, TRUE);
1683   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Left,
1684                                 GDK_CONTROL_MASK | GDK_SHIFT_MASK,
1685                                 "expand-collapse-cursor-row", 3,
1686                                 G_TYPE_BOOLEAN, FALSE,
1687                                 G_TYPE_BOOLEAN, FALSE,
1688                                 G_TYPE_BOOLEAN, TRUE);
1689
1690   gtk_binding_entry_add_signal (binding_set, GDK_KEY_BackSpace, 0, "select-cursor-parent", 0);
1691   gtk_binding_entry_add_signal (binding_set, GDK_KEY_BackSpace, GDK_CONTROL_MASK, "select-cursor-parent", 0);
1692
1693   gtk_binding_entry_add_signal (binding_set, GDK_KEY_f, GDK_CONTROL_MASK, "start-interactive-search", 0);
1694
1695   gtk_binding_entry_add_signal (binding_set, GDK_KEY_F, GDK_CONTROL_MASK, "start-interactive-search", 0);
1696
1697   g_type_class_add_private (o_class, sizeof (GtkTreeViewPrivate));
1698
1699   gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_TREE_VIEW_ACCESSIBLE);
1700 }
1701
1702 static void
1703 gtk_tree_view_init (GtkTreeView *tree_view)
1704 {
1705   tree_view->priv = G_TYPE_INSTANCE_GET_PRIVATE (tree_view, GTK_TYPE_TREE_VIEW, GtkTreeViewPrivate);
1706
1707   gtk_widget_set_can_focus (GTK_WIDGET (tree_view), TRUE);
1708   gtk_widget_set_redraw_on_allocate (GTK_WIDGET (tree_view), FALSE);
1709
1710   tree_view->priv->show_expanders = TRUE;
1711   tree_view->priv->draw_keyfocus = TRUE;
1712   tree_view->priv->headers_visible = TRUE;
1713
1714   /* We need some padding */
1715   tree_view->priv->dy = 0;
1716   tree_view->priv->cursor_offset = 0;
1717   tree_view->priv->n_columns = 0;
1718   tree_view->priv->header_height = 1;
1719   tree_view->priv->x_drag = 0;
1720   tree_view->priv->drag_pos = -1;
1721   tree_view->priv->header_has_focus = FALSE;
1722   tree_view->priv->pressed_button = -1;
1723   tree_view->priv->press_start_x = -1;
1724   tree_view->priv->press_start_y = -1;
1725   tree_view->priv->reorderable = FALSE;
1726   tree_view->priv->presize_handler_timer = 0;
1727   tree_view->priv->scroll_sync_timer = 0;
1728   tree_view->priv->fixed_height = -1;
1729   tree_view->priv->fixed_height_mode = FALSE;
1730   tree_view->priv->fixed_height_check = 0;
1731   tree_view->priv->selection = _gtk_tree_selection_new_with_tree_view (tree_view);
1732   tree_view->priv->enable_search = TRUE;
1733   tree_view->priv->search_column = -1;
1734   tree_view->priv->search_position_func = gtk_tree_view_search_position_func;
1735   tree_view->priv->search_equal_func = gtk_tree_view_search_equal_func;
1736   tree_view->priv->search_custom_entry_set = FALSE;
1737   tree_view->priv->typeselect_flush_timeout = 0;
1738   tree_view->priv->init_hadjust_value = TRUE;    
1739   tree_view->priv->width = 0;
1740           
1741   tree_view->priv->hover_selection = FALSE;
1742   tree_view->priv->hover_expand = FALSE;
1743
1744   tree_view->priv->level_indentation = 0;
1745
1746   tree_view->priv->rubber_banding_enable = FALSE;
1747
1748   tree_view->priv->grid_lines = GTK_TREE_VIEW_GRID_LINES_NONE;
1749   tree_view->priv->tree_lines_enabled = FALSE;
1750
1751   tree_view->priv->tooltip_column = -1;
1752
1753   tree_view->priv->post_validation_flag = FALSE;
1754
1755   tree_view->priv->last_button_x = -1;
1756   tree_view->priv->last_button_y = -1;
1757
1758   tree_view->priv->event_last_x = -10000;
1759   tree_view->priv->event_last_y = -10000;
1760
1761   gtk_tree_view_set_vadjustment (tree_view, NULL);
1762   gtk_tree_view_set_hadjustment (tree_view, NULL);
1763 }
1764
1765 \f
1766
1767 /* GObject Methods
1768  */
1769
1770 static void
1771 gtk_tree_view_set_property (GObject         *object,
1772                             guint            prop_id,
1773                             const GValue    *value,
1774                             GParamSpec      *pspec)
1775 {
1776   GtkTreeView *tree_view;
1777
1778   tree_view = GTK_TREE_VIEW (object);
1779
1780   switch (prop_id)
1781     {
1782     case PROP_MODEL:
1783       gtk_tree_view_set_model (tree_view, g_value_get_object (value));
1784       break;
1785     case PROP_HADJUSTMENT:
1786       gtk_tree_view_set_hadjustment (tree_view, g_value_get_object (value));
1787       break;
1788     case PROP_VADJUSTMENT:
1789       gtk_tree_view_set_vadjustment (tree_view, g_value_get_object (value));
1790       break;
1791     case PROP_HSCROLL_POLICY:
1792       tree_view->priv->hscroll_policy = g_value_get_enum (value);
1793       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
1794       break;
1795     case PROP_VSCROLL_POLICY:
1796       tree_view->priv->vscroll_policy = g_value_get_enum (value);
1797       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
1798       break;
1799     case PROP_HEADERS_VISIBLE:
1800       gtk_tree_view_set_headers_visible (tree_view, g_value_get_boolean (value));
1801       break;
1802     case PROP_HEADERS_CLICKABLE:
1803       gtk_tree_view_set_headers_clickable (tree_view, g_value_get_boolean (value));
1804       break;
1805     case PROP_EXPANDER_COLUMN:
1806       gtk_tree_view_set_expander_column (tree_view, g_value_get_object (value));
1807       break;
1808     case PROP_REORDERABLE:
1809       gtk_tree_view_set_reorderable (tree_view, g_value_get_boolean (value));
1810       break;
1811     case PROP_RULES_HINT:
1812       gtk_tree_view_set_rules_hint (tree_view, g_value_get_boolean (value));
1813       break;
1814     case PROP_ENABLE_SEARCH:
1815       gtk_tree_view_set_enable_search (tree_view, g_value_get_boolean (value));
1816       break;
1817     case PROP_SEARCH_COLUMN:
1818       gtk_tree_view_set_search_column (tree_view, g_value_get_int (value));
1819       break;
1820     case PROP_FIXED_HEIGHT_MODE:
1821       gtk_tree_view_set_fixed_height_mode (tree_view, g_value_get_boolean (value));
1822       break;
1823     case PROP_HOVER_SELECTION:
1824       tree_view->priv->hover_selection = g_value_get_boolean (value);
1825       break;
1826     case PROP_HOVER_EXPAND:
1827       tree_view->priv->hover_expand = g_value_get_boolean (value);
1828       break;
1829     case PROP_SHOW_EXPANDERS:
1830       gtk_tree_view_set_show_expanders (tree_view, g_value_get_boolean (value));
1831       break;
1832     case PROP_LEVEL_INDENTATION:
1833       tree_view->priv->level_indentation = g_value_get_int (value);
1834       break;
1835     case PROP_RUBBER_BANDING:
1836       tree_view->priv->rubber_banding_enable = g_value_get_boolean (value);
1837       break;
1838     case PROP_ENABLE_GRID_LINES:
1839       gtk_tree_view_set_grid_lines (tree_view, g_value_get_enum (value));
1840       break;
1841     case PROP_ENABLE_TREE_LINES:
1842       gtk_tree_view_set_enable_tree_lines (tree_view, g_value_get_boolean (value));
1843       break;
1844     case PROP_TOOLTIP_COLUMN:
1845       gtk_tree_view_set_tooltip_column (tree_view, g_value_get_int (value));
1846       break;
1847     default:
1848       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1849       break;
1850     }
1851 }
1852
1853 static void
1854 gtk_tree_view_get_property (GObject    *object,
1855                             guint       prop_id,
1856                             GValue     *value,
1857                             GParamSpec *pspec)
1858 {
1859   GtkTreeView *tree_view;
1860
1861   tree_view = GTK_TREE_VIEW (object);
1862
1863   switch (prop_id)
1864     {
1865     case PROP_MODEL:
1866       g_value_set_object (value, tree_view->priv->model);
1867       break;
1868     case PROP_HADJUSTMENT:
1869       g_value_set_object (value, tree_view->priv->hadjustment);
1870       break;
1871     case PROP_VADJUSTMENT:
1872       g_value_set_object (value, tree_view->priv->vadjustment);
1873       break;
1874     case PROP_HSCROLL_POLICY:
1875       g_value_set_enum (value, tree_view->priv->hscroll_policy);
1876       break;
1877     case PROP_VSCROLL_POLICY:
1878       g_value_set_enum (value, tree_view->priv->vscroll_policy);
1879       break;
1880     case PROP_HEADERS_VISIBLE:
1881       g_value_set_boolean (value, gtk_tree_view_get_headers_visible (tree_view));
1882       break;
1883     case PROP_HEADERS_CLICKABLE:
1884       g_value_set_boolean (value, gtk_tree_view_get_headers_clickable (tree_view));
1885       break;
1886     case PROP_EXPANDER_COLUMN:
1887       g_value_set_object (value, tree_view->priv->expander_column);
1888       break;
1889     case PROP_REORDERABLE:
1890       g_value_set_boolean (value, tree_view->priv->reorderable);
1891       break;
1892     case PROP_RULES_HINT:
1893       g_value_set_boolean (value, tree_view->priv->has_rules);
1894       break;
1895     case PROP_ENABLE_SEARCH:
1896       g_value_set_boolean (value, tree_view->priv->enable_search);
1897       break;
1898     case PROP_SEARCH_COLUMN:
1899       g_value_set_int (value, tree_view->priv->search_column);
1900       break;
1901     case PROP_FIXED_HEIGHT_MODE:
1902       g_value_set_boolean (value, tree_view->priv->fixed_height_mode);
1903       break;
1904     case PROP_HOVER_SELECTION:
1905       g_value_set_boolean (value, tree_view->priv->hover_selection);
1906       break;
1907     case PROP_HOVER_EXPAND:
1908       g_value_set_boolean (value, tree_view->priv->hover_expand);
1909       break;
1910     case PROP_SHOW_EXPANDERS:
1911       g_value_set_boolean (value, tree_view->priv->show_expanders);
1912       break;
1913     case PROP_LEVEL_INDENTATION:
1914       g_value_set_int (value, tree_view->priv->level_indentation);
1915       break;
1916     case PROP_RUBBER_BANDING:
1917       g_value_set_boolean (value, tree_view->priv->rubber_banding_enable);
1918       break;
1919     case PROP_ENABLE_GRID_LINES:
1920       g_value_set_enum (value, tree_view->priv->grid_lines);
1921       break;
1922     case PROP_ENABLE_TREE_LINES:
1923       g_value_set_boolean (value, tree_view->priv->tree_lines_enabled);
1924       break;
1925     case PROP_TOOLTIP_COLUMN:
1926       g_value_set_int (value, tree_view->priv->tooltip_column);
1927       break;
1928     default:
1929       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1930       break;
1931     }
1932 }
1933
1934 static void
1935 gtk_tree_view_finalize (GObject *object)
1936 {
1937   G_OBJECT_CLASS (gtk_tree_view_parent_class)->finalize (object);
1938 }
1939
1940
1941 static GtkBuildableIface *parent_buildable_iface;
1942
1943 static void
1944 gtk_tree_view_buildable_init (GtkBuildableIface *iface)
1945 {
1946   parent_buildable_iface = g_type_interface_peek_parent (iface);
1947   iface->add_child = gtk_tree_view_buildable_add_child;
1948   iface->get_internal_child = gtk_tree_view_buildable_get_internal_child;
1949 }
1950
1951 static void
1952 gtk_tree_view_buildable_add_child (GtkBuildable *tree_view,
1953                                    GtkBuilder  *builder,
1954                                    GObject     *child,
1955                                    const gchar *type)
1956 {
1957   gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), GTK_TREE_VIEW_COLUMN (child));
1958 }
1959
1960 static GObject *
1961 gtk_tree_view_buildable_get_internal_child (GtkBuildable      *buildable,
1962                                             GtkBuilder        *builder,
1963                                             const gchar       *childname)
1964 {
1965     if (strcmp (childname, "selection") == 0)
1966       return G_OBJECT (GTK_TREE_VIEW (buildable)->priv->selection);
1967     
1968     return parent_buildable_iface->get_internal_child (buildable,
1969                                                        builder,
1970                                                        childname);
1971 }
1972
1973 /* GtkWidget Methods
1974  */
1975
1976 static void
1977 gtk_tree_view_free_rbtree (GtkTreeView *tree_view)
1978 {
1979   _gtk_rbtree_free (tree_view->priv->tree);
1980   
1981   tree_view->priv->tree = NULL;
1982   tree_view->priv->button_pressed_node = NULL;
1983   tree_view->priv->button_pressed_tree = NULL;
1984   tree_view->priv->prelight_tree = NULL;
1985   tree_view->priv->prelight_node = NULL;
1986   tree_view->priv->expanded_collapsed_node = NULL;
1987   tree_view->priv->expanded_collapsed_tree = NULL;
1988 }
1989
1990 static void
1991 gtk_tree_view_destroy (GtkWidget *widget)
1992 {
1993   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
1994   GList *list;
1995
1996   gtk_tree_view_stop_editing (tree_view, TRUE);
1997
1998   if (tree_view->priv->columns != NULL)
1999     {
2000       list = tree_view->priv->columns;
2001       while (list)
2002         {
2003           GtkTreeViewColumn *column;
2004           column = GTK_TREE_VIEW_COLUMN (list->data);
2005           list = list->next;
2006           gtk_tree_view_remove_column (tree_view, column);
2007         }
2008       tree_view->priv->columns = NULL;
2009     }
2010
2011   if (tree_view->priv->tree != NULL)
2012     {
2013       gtk_tree_view_unref_and_check_selection_tree (tree_view, tree_view->priv->tree);
2014
2015       gtk_tree_view_free_rbtree (tree_view);
2016     }
2017
2018   if (tree_view->priv->selection != NULL)
2019     {
2020       _gtk_tree_selection_set_tree_view (tree_view->priv->selection, NULL);
2021       g_object_unref (tree_view->priv->selection);
2022       tree_view->priv->selection = NULL;
2023     }
2024
2025   if (tree_view->priv->scroll_to_path != NULL)
2026     {
2027       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
2028       tree_view->priv->scroll_to_path = NULL;
2029     }
2030
2031   if (tree_view->priv->drag_dest_row != NULL)
2032     {
2033       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
2034       tree_view->priv->drag_dest_row = NULL;
2035     }
2036
2037   if (tree_view->priv->top_row != NULL)
2038     {
2039       gtk_tree_row_reference_free (tree_view->priv->top_row);
2040       tree_view->priv->top_row = NULL;
2041     }
2042
2043   if (tree_view->priv->column_drop_func_data &&
2044       tree_view->priv->column_drop_func_data_destroy)
2045     {
2046       tree_view->priv->column_drop_func_data_destroy (tree_view->priv->column_drop_func_data);
2047       tree_view->priv->column_drop_func_data = NULL;
2048     }
2049
2050   if (tree_view->priv->destroy_count_destroy &&
2051       tree_view->priv->destroy_count_data)
2052     {
2053       tree_view->priv->destroy_count_destroy (tree_view->priv->destroy_count_data);
2054       tree_view->priv->destroy_count_data = NULL;
2055     }
2056
2057   gtk_tree_row_reference_free (tree_view->priv->cursor);
2058   tree_view->priv->cursor = NULL;
2059
2060   gtk_tree_row_reference_free (tree_view->priv->anchor);
2061   tree_view->priv->anchor = NULL;
2062
2063   /* destroy interactive search dialog */
2064   if (tree_view->priv->search_window)
2065     {
2066       gtk_widget_destroy (tree_view->priv->search_window);
2067       tree_view->priv->search_window = NULL;
2068       tree_view->priv->search_entry = NULL;
2069       if (tree_view->priv->typeselect_flush_timeout)
2070         {
2071           g_source_remove (tree_view->priv->typeselect_flush_timeout);
2072           tree_view->priv->typeselect_flush_timeout = 0;
2073         }
2074     }
2075
2076   if (tree_view->priv->search_destroy && tree_view->priv->search_user_data)
2077     {
2078       tree_view->priv->search_destroy (tree_view->priv->search_user_data);
2079       tree_view->priv->search_user_data = NULL;
2080     }
2081
2082   if (tree_view->priv->search_position_destroy && tree_view->priv->search_position_user_data)
2083     {
2084       tree_view->priv->search_position_destroy (tree_view->priv->search_position_user_data);
2085       tree_view->priv->search_position_user_data = NULL;
2086     }
2087
2088   if (tree_view->priv->row_separator_destroy && tree_view->priv->row_separator_data)
2089     {
2090       tree_view->priv->row_separator_destroy (tree_view->priv->row_separator_data);
2091       tree_view->priv->row_separator_data = NULL;
2092     }
2093   
2094   gtk_tree_view_set_model (tree_view, NULL);
2095
2096   if (tree_view->priv->hadjustment)
2097     {
2098       g_object_unref (tree_view->priv->hadjustment);
2099       tree_view->priv->hadjustment = NULL;
2100     }
2101   if (tree_view->priv->vadjustment)
2102     {
2103       g_object_unref (tree_view->priv->vadjustment);
2104       tree_view->priv->vadjustment = NULL;
2105     }
2106
2107   GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->destroy (widget);
2108 }
2109
2110 /* GtkWidget::map helper */
2111 static void
2112 gtk_tree_view_map_buttons (GtkTreeView *tree_view)
2113 {
2114   GList *list;
2115
2116   g_return_if_fail (gtk_widget_get_mapped (GTK_WIDGET (tree_view)));
2117
2118   if (tree_view->priv->headers_visible)
2119     {
2120       GtkTreeViewColumn *column;
2121       GtkWidget         *button;
2122       GdkWindow         *window;
2123
2124       for (list = tree_view->priv->columns; list; list = list->next)
2125         {
2126           column = list->data;
2127           button = gtk_tree_view_column_get_button (column);
2128
2129           if (gtk_tree_view_column_get_visible (column) && button)
2130             gtk_widget_show_now (button);
2131
2132           if (gtk_widget_get_visible (button) &&
2133               !gtk_widget_get_mapped (button))
2134             gtk_widget_map (button);
2135         }
2136       for (list = tree_view->priv->columns; list; list = list->next)
2137         {
2138           column = list->data;
2139           if (gtk_tree_view_column_get_visible (column) == FALSE)
2140             continue;
2141
2142           window = _gtk_tree_view_column_get_window (column);
2143           if (gtk_tree_view_column_get_resizable (column))
2144             {
2145               gdk_window_raise (window);
2146               gdk_window_show (window);
2147             }
2148           else
2149             gdk_window_hide (window);
2150         }
2151       gdk_window_show (tree_view->priv->header_window);
2152     }
2153 }
2154
2155 static void
2156 gtk_tree_view_map (GtkWidget *widget)
2157 {
2158   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2159   GList *tmp_list;
2160
2161   gtk_widget_set_mapped (widget, TRUE);
2162
2163   tmp_list = tree_view->priv->children;
2164   while (tmp_list)
2165     {
2166       GtkTreeViewChild *child = tmp_list->data;
2167       tmp_list = tmp_list->next;
2168
2169       if (gtk_widget_get_visible (child->widget))
2170         {
2171           if (!gtk_widget_get_mapped (child->widget))
2172             gtk_widget_map (child->widget);
2173         }
2174     }
2175   gdk_window_show (tree_view->priv->bin_window);
2176
2177   gtk_tree_view_map_buttons (tree_view);
2178
2179   gdk_window_show (gtk_widget_get_window (widget));
2180 }
2181
2182 static void
2183 gtk_tree_view_realize (GtkWidget *widget)
2184 {
2185   GtkAllocation allocation;
2186   GtkStyleContext *context;
2187   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2188   GdkWindow *window;
2189   GdkWindowAttr attributes;
2190   GList *tmp_list;
2191   gint attributes_mask;
2192
2193   gtk_widget_set_realized (widget, TRUE);
2194
2195   gtk_widget_get_allocation (widget, &allocation);
2196
2197   /* Make the main, clipping window */
2198   attributes.window_type = GDK_WINDOW_CHILD;
2199   attributes.x = allocation.x;
2200   attributes.y = allocation.y;
2201   attributes.width = allocation.width;
2202   attributes.height = allocation.height;
2203   attributes.wclass = GDK_INPUT_OUTPUT;
2204   attributes.visual = gtk_widget_get_visual (widget);
2205   attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK;
2206
2207   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
2208
2209   window = gdk_window_new (gtk_widget_get_parent_window (widget),
2210                            &attributes, attributes_mask);
2211   gtk_widget_set_window (widget, window);
2212   gdk_window_set_user_data (window, widget);
2213
2214   gtk_widget_get_allocation (widget, &allocation);
2215
2216   /* Make the window for the tree */
2217   attributes.x = 0;
2218   attributes.y = gtk_tree_view_get_effective_header_height (tree_view);
2219   attributes.width = MAX (tree_view->priv->width, allocation.width);
2220   attributes.height = allocation.height;
2221   attributes.event_mask = (GDK_EXPOSURE_MASK |
2222                            GDK_SCROLL_MASK |
2223                            GDK_POINTER_MOTION_MASK |
2224                            GDK_ENTER_NOTIFY_MASK |
2225                            GDK_LEAVE_NOTIFY_MASK |
2226                            GDK_BUTTON_PRESS_MASK |
2227                            GDK_BUTTON_RELEASE_MASK |
2228                            gtk_widget_get_events (widget));
2229
2230   tree_view->priv->bin_window = gdk_window_new (window,
2231                                                 &attributes, attributes_mask);
2232   gdk_window_set_user_data (tree_view->priv->bin_window, widget);
2233
2234   gtk_widget_get_allocation (widget, &allocation);
2235
2236   /* Make the column header window */
2237   attributes.x = 0;
2238   attributes.y = 0;
2239   attributes.width = MAX (tree_view->priv->width, allocation.width);
2240   attributes.height = tree_view->priv->header_height;
2241   attributes.event_mask = (GDK_EXPOSURE_MASK |
2242                            GDK_SCROLL_MASK |
2243                            GDK_ENTER_NOTIFY_MASK |
2244                            GDK_LEAVE_NOTIFY_MASK |
2245                            GDK_BUTTON_PRESS_MASK |
2246                            GDK_BUTTON_RELEASE_MASK |
2247                            GDK_KEY_PRESS_MASK |
2248                            GDK_KEY_RELEASE_MASK |
2249                            gtk_widget_get_events (widget));
2250
2251   tree_view->priv->header_window = gdk_window_new (window,
2252                                                    &attributes, attributes_mask);
2253   gdk_window_set_user_data (tree_view->priv->header_window, widget);
2254
2255   context = gtk_widget_get_style_context (widget);
2256
2257   gtk_style_context_save (context);
2258   gtk_style_context_add_class (context, GTK_STYLE_CLASS_VIEW);
2259   gtk_style_context_set_background (context, tree_view->priv->bin_window);
2260   gtk_style_context_restore (context);
2261
2262   gtk_style_context_set_background (context, tree_view->priv->header_window);
2263
2264   tmp_list = tree_view->priv->children;
2265   while (tmp_list)
2266     {
2267       GtkTreeViewChild *child = tmp_list->data;
2268       tmp_list = tmp_list->next;
2269
2270       gtk_widget_set_parent_window (child->widget, tree_view->priv->bin_window);
2271     }
2272
2273   for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
2274     _gtk_tree_view_column_realize_button (GTK_TREE_VIEW_COLUMN (tmp_list->data));
2275
2276   /* Need to call those here, since they create GCs */
2277   gtk_tree_view_set_grid_lines (tree_view, tree_view->priv->grid_lines);
2278   gtk_tree_view_set_enable_tree_lines (tree_view, tree_view->priv->tree_lines_enabled);
2279
2280   install_presize_handler (tree_view); 
2281 }
2282
2283 static void
2284 gtk_tree_view_unrealize (GtkWidget *widget)
2285 {
2286   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2287   GtkTreeViewPrivate *priv = tree_view->priv;
2288   GtkStyleContext *context;
2289   GList *list;
2290
2291   if (priv->scroll_timeout != 0)
2292     {
2293       g_source_remove (priv->scroll_timeout);
2294       priv->scroll_timeout = 0;
2295     }
2296
2297   if (priv->auto_expand_timeout != 0)
2298     {
2299       g_source_remove (priv->auto_expand_timeout);
2300       priv->auto_expand_timeout = 0;
2301     }
2302
2303   if (priv->open_dest_timeout != 0)
2304     {
2305       g_source_remove (priv->open_dest_timeout);
2306       priv->open_dest_timeout = 0;
2307     }
2308
2309   context = gtk_widget_get_style_context (widget);
2310   gtk_style_context_cancel_animations (context, NULL);
2311
2312   if (priv->presize_handler_timer != 0)
2313     {
2314       g_source_remove (priv->presize_handler_timer);
2315       priv->presize_handler_timer = 0;
2316     }
2317
2318   if (priv->validate_rows_timer != 0)
2319     {
2320       g_source_remove (priv->validate_rows_timer);
2321       priv->validate_rows_timer = 0;
2322     }
2323
2324   if (priv->scroll_sync_timer != 0)
2325     {
2326       g_source_remove (priv->scroll_sync_timer);
2327       priv->scroll_sync_timer = 0;
2328     }
2329
2330   if (priv->typeselect_flush_timeout)
2331     {
2332       g_source_remove (priv->typeselect_flush_timeout);
2333       priv->typeselect_flush_timeout = 0;
2334     }
2335   
2336   for (list = priv->columns; list; list = list->next)
2337     _gtk_tree_view_column_unrealize_button (GTK_TREE_VIEW_COLUMN (list->data));
2338
2339   gdk_window_set_user_data (priv->bin_window, NULL);
2340   gdk_window_destroy (priv->bin_window);
2341   priv->bin_window = NULL;
2342
2343   gdk_window_set_user_data (priv->header_window, NULL);
2344   gdk_window_destroy (priv->header_window);
2345   priv->header_window = NULL;
2346
2347   if (priv->drag_window)
2348     {
2349       gdk_window_set_user_data (priv->drag_window, NULL);
2350       gdk_window_destroy (priv->drag_window);
2351       priv->drag_window = NULL;
2352     }
2353
2354   if (priv->drag_highlight_window)
2355     {
2356       gdk_window_set_user_data (priv->drag_highlight_window, NULL);
2357       gdk_window_destroy (priv->drag_highlight_window);
2358       priv->drag_highlight_window = NULL;
2359     }
2360
2361   GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->unrealize (widget);
2362 }
2363
2364 /* GtkWidget::size_request helper */
2365 static void
2366 gtk_tree_view_size_request_columns (GtkTreeView *tree_view)
2367 {
2368   GList *list;
2369
2370   tree_view->priv->header_height = 0;
2371
2372   for (list = tree_view->priv->columns; list; list = list->next)
2373     {
2374       GtkRequisition     requisition;
2375       GtkTreeViewColumn *column = list->data;
2376       GtkWidget         *button = gtk_tree_view_column_get_button (column);
2377
2378       if (button == NULL)
2379         continue;
2380
2381       gtk_widget_get_preferred_size (button, &requisition, NULL);
2382       tree_view->priv->header_height = MAX (tree_view->priv->header_height, requisition.height);
2383     }
2384 }
2385
2386
2387 /* Called only by ::size_request */
2388 static void
2389 gtk_tree_view_update_size (GtkTreeView *tree_view)
2390 {
2391   GList *list;
2392   GtkTreeViewColumn *column;
2393   gint i;
2394
2395   if (tree_view->priv->model == NULL)
2396     {
2397       tree_view->priv->width = 0;
2398       tree_view->priv->prev_width = 0;                   
2399       tree_view->priv->height = 0;
2400       return;
2401     }
2402
2403   tree_view->priv->prev_width = tree_view->priv->width;  
2404   tree_view->priv->width = 0;
2405
2406   /* keep this in sync with size_allocate below */
2407   for (list = tree_view->priv->columns, i = 0; list; list = list->next, i++)
2408     {
2409       column = list->data;
2410       if (!gtk_tree_view_column_get_visible (column))
2411         continue;
2412
2413       tree_view->priv->width += _gtk_tree_view_column_request_width (column);
2414     }
2415
2416   if (tree_view->priv->tree == NULL)
2417     tree_view->priv->height = 0;
2418   else
2419     tree_view->priv->height = tree_view->priv->tree->root->offset;
2420 }
2421
2422 static void
2423 gtk_tree_view_size_request (GtkWidget      *widget,
2424                             GtkRequisition *requisition,
2425                             gboolean        may_validate)
2426 {
2427   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2428
2429   if (may_validate)
2430     {
2431       /* we validate some rows initially just to make sure we have some size.
2432        * In practice, with a lot of static lists, this should get a good width.
2433        */
2434       do_validate_rows (tree_view, FALSE);
2435     }
2436
2437   gtk_tree_view_size_request_columns (tree_view);
2438   gtk_tree_view_update_size (GTK_TREE_VIEW (widget));
2439
2440   requisition->width = tree_view->priv->width;
2441   requisition->height = tree_view->priv->height + gtk_tree_view_get_effective_header_height (tree_view);
2442 }
2443
2444 static void
2445 gtk_tree_view_get_preferred_width (GtkWidget *widget,
2446                                    gint      *minimum,
2447                                    gint      *natural)
2448 {
2449   GtkRequisition requisition;
2450
2451   gtk_tree_view_size_request (widget, &requisition, TRUE);
2452
2453   *minimum = *natural = requisition.width;
2454 }
2455
2456 static void
2457 gtk_tree_view_get_preferred_height (GtkWidget *widget,
2458                                     gint      *minimum,
2459                                     gint      *natural)
2460 {
2461   GtkRequisition requisition;
2462
2463   gtk_tree_view_size_request (widget, &requisition, TRUE);
2464
2465   *minimum = *natural = requisition.height;
2466 }
2467
2468 static int
2469 gtk_tree_view_calculate_width_before_expander (GtkTreeView *tree_view)
2470 {
2471   int width = 0;
2472   GList *list;
2473   gboolean rtl;
2474
2475   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2476   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
2477        list->data != tree_view->priv->expander_column;
2478        list = (rtl ? list->prev : list->next))
2479     {
2480       GtkTreeViewColumn *column = list->data;
2481
2482       width += gtk_tree_view_column_get_width (column);
2483     }
2484
2485   return width;
2486 }
2487
2488 /* GtkWidget::size_allocate helper */
2489 static void
2490 gtk_tree_view_size_allocate_columns (GtkWidget *widget,
2491                                      gboolean  *width_changed)
2492 {
2493   GtkTreeView *tree_view;
2494   GList *list, *first_column, *last_column;
2495   GtkTreeViewColumn *column;
2496   GtkAllocation widget_allocation;
2497   gint width = 0;
2498   gint extra, extra_per_column, extra_for_last;
2499   gint full_requested_width = 0;
2500   gint number_of_expand_columns = 0;
2501   gboolean rtl;
2502   gboolean update_expand;
2503   
2504   tree_view = GTK_TREE_VIEW (widget);
2505
2506   for (last_column = g_list_last (tree_view->priv->columns);
2507        last_column &&
2508        !(gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (last_column->data)));
2509        last_column = last_column->prev)
2510     ;
2511   if (last_column == NULL)
2512     return;
2513
2514   for (first_column = g_list_first (tree_view->priv->columns);
2515        first_column &&
2516        !(gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (first_column->data)));
2517        first_column = first_column->next)
2518     ;
2519
2520   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
2521
2522   /* find out how many extra space and expandable columns we have */
2523   for (list = tree_view->priv->columns; list != last_column->next; list = list->next)
2524     {
2525       column = (GtkTreeViewColumn *)list->data;
2526
2527       if (!gtk_tree_view_column_get_visible (column))
2528         continue;
2529
2530       full_requested_width += _gtk_tree_view_column_request_width (column);
2531
2532       if (gtk_tree_view_column_get_expand (column))
2533         number_of_expand_columns++;
2534     }
2535
2536   /* Only update the expand value if the width of the widget has changed,
2537    * or the number of expand columns has changed, or if there are no expand
2538    * columns, or if we didn't have an size-allocation yet after the
2539    * last validated node.
2540    */
2541   update_expand = (width_changed && *width_changed == TRUE)
2542       || number_of_expand_columns != tree_view->priv->last_number_of_expand_columns
2543       || number_of_expand_columns == 0
2544       || tree_view->priv->post_validation_flag == TRUE;
2545
2546   tree_view->priv->post_validation_flag = FALSE;
2547
2548   gtk_widget_get_allocation (widget, &widget_allocation);
2549   if (!update_expand)
2550     {
2551       extra = tree_view->priv->last_extra_space;
2552       extra_for_last = MAX (widget_allocation.width - full_requested_width - extra, 0);
2553     }
2554   else
2555     {
2556       extra = MAX (widget_allocation.width - full_requested_width, 0);
2557       extra_for_last = 0;
2558
2559       tree_view->priv->last_extra_space = extra;
2560     }
2561
2562   if (number_of_expand_columns > 0)
2563     extra_per_column = extra/number_of_expand_columns;
2564   else
2565     extra_per_column = 0;
2566
2567   if (update_expand)
2568     {
2569       tree_view->priv->last_extra_space_per_column = extra_per_column;
2570       tree_view->priv->last_number_of_expand_columns = number_of_expand_columns;
2571     }
2572
2573   for (list = (rtl ? last_column : first_column); 
2574        list != (rtl ? first_column->prev : last_column->next);
2575        list = (rtl ? list->prev : list->next)) 
2576     {
2577       gint column_width;
2578
2579       column = list->data;
2580
2581       if (!gtk_tree_view_column_get_visible (column))
2582         continue;
2583
2584       /* We need to handle the dragged button specially.
2585        */
2586       if (column == tree_view->priv->drag_column)
2587         {
2588           GtkAllocation drag_allocation;
2589           GtkWidget    *button;
2590
2591           button = gtk_tree_view_column_get_button (tree_view->priv->drag_column);
2592
2593           drag_allocation.x = 0;
2594           drag_allocation.y = 0;
2595           drag_allocation.width = gdk_window_get_width (tree_view->priv->drag_window);
2596           drag_allocation.height = gdk_window_get_height (tree_view->priv->drag_window);
2597           gtk_widget_size_allocate (button, &drag_allocation);
2598           width += drag_allocation.width;
2599           continue;
2600         }
2601
2602       column_width = _gtk_tree_view_column_request_width (column);
2603
2604       if (gtk_tree_view_column_get_expand (column))
2605         {
2606           if (number_of_expand_columns == 1)
2607             {
2608               /* We add the remander to the last column as
2609                * */
2610               column_width += extra;
2611             }
2612           else
2613             {
2614               column_width += extra_per_column;
2615               extra -= extra_per_column;
2616               number_of_expand_columns --;
2617             }
2618         }
2619       else if (number_of_expand_columns == 0 &&
2620                list == last_column)
2621         {
2622           column_width += extra;
2623         }
2624
2625       /* In addition to expand, the last column can get even more
2626        * extra space so all available space is filled up.
2627        */
2628       if (extra_for_last > 0 && list == last_column)
2629         column_width += extra_for_last;
2630
2631       _gtk_tree_view_column_allocate (column, width, column_width);
2632
2633       width += column_width;
2634     }
2635
2636   /* We change the width here.  The user might have been resizing columns,
2637    * which changes the total width of the tree view.  This is of
2638    * importance for getting the horizontal scroll bar right.
2639    */
2640   if (tree_view->priv->width != width)
2641     {
2642       tree_view->priv->width = width;
2643       if (width_changed)
2644         *width_changed = TRUE;
2645     }
2646 }
2647
2648
2649 static void
2650 gtk_tree_view_size_allocate (GtkWidget     *widget,
2651                              GtkAllocation *allocation)
2652 {
2653   GtkAllocation widget_allocation;
2654   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2655   GList *tmp_list;
2656   gboolean width_changed = FALSE;
2657   gint old_width;
2658
2659   gtk_widget_get_allocation (widget, &widget_allocation);
2660   old_width = widget_allocation.width;
2661   if (allocation->width != widget_allocation.width)
2662     width_changed = TRUE;
2663
2664   gtk_widget_set_allocation (widget, allocation);
2665
2666   tmp_list = tree_view->priv->children;
2667
2668   while (tmp_list)
2669     {
2670       GtkAllocation allocation;
2671
2672       GtkTreeViewChild *child = tmp_list->data;
2673       tmp_list = tmp_list->next;
2674
2675       /* totally ignore our child's requisition */
2676       allocation.x = child->x;
2677       allocation.y = child->y;
2678       allocation.width = child->width;
2679       allocation.height = child->height;
2680       gtk_widget_size_allocate (child->widget, &allocation);
2681     }
2682
2683   /* We size-allocate the columns first because the width of the
2684    * tree view (used in updating the adjustments below) might change.
2685    */
2686   gtk_tree_view_size_allocate_columns (widget, &width_changed);
2687
2688   g_object_freeze_notify (G_OBJECT (tree_view->priv->hadjustment));
2689   gtk_adjustment_set_page_size (tree_view->priv->hadjustment,
2690                                 allocation->width);
2691   gtk_adjustment_set_page_increment (tree_view->priv->hadjustment,
2692                                      allocation->width * 0.9);
2693   gtk_adjustment_set_step_increment (tree_view->priv->hadjustment,
2694                                      allocation->width * 0.1);
2695   gtk_adjustment_set_lower (tree_view->priv->hadjustment, 0);
2696   gtk_adjustment_set_upper (tree_view->priv->hadjustment,
2697                             MAX (gtk_adjustment_get_page_size (tree_view->priv->hadjustment),
2698                                  tree_view->priv->width));
2699   g_object_thaw_notify (G_OBJECT (tree_view->priv->hadjustment));
2700
2701   if (gtk_widget_get_direction(widget) == GTK_TEXT_DIR_RTL)   
2702     {
2703       if (allocation->width < tree_view->priv->width)
2704         {
2705           if (tree_view->priv->init_hadjust_value)
2706             {
2707               gtk_adjustment_set_value (tree_view->priv->hadjustment,
2708                                         MAX (tree_view->priv->width -
2709                                              allocation->width, 0));
2710               tree_view->priv->init_hadjust_value = FALSE;
2711             }
2712           else if (allocation->width != old_width)
2713             {
2714               gtk_adjustment_set_value (tree_view->priv->hadjustment,
2715                                         CLAMP (gtk_adjustment_get_value (tree_view->priv->hadjustment) - allocation->width + old_width,
2716                                                0,
2717                                                tree_view->priv->width - allocation->width));
2718             }
2719           else
2720             gtk_adjustment_set_value (tree_view->priv->hadjustment,
2721                                       CLAMP (tree_view->priv->width - (tree_view->priv->prev_width - gtk_adjustment_get_value (tree_view->priv->hadjustment)),
2722                                              0,
2723                                              tree_view->priv->width - allocation->width));
2724         }
2725       else
2726         {
2727           gtk_adjustment_set_value (tree_view->priv->hadjustment, 0);
2728           tree_view->priv->init_hadjust_value = TRUE;
2729         }
2730     }
2731   else
2732     if (gtk_adjustment_get_value (tree_view->priv->hadjustment) + allocation->width > tree_view->priv->width)
2733       gtk_adjustment_set_value (tree_view->priv->hadjustment,
2734                                 MAX (tree_view->priv->width -
2735                                      allocation->width, 0));
2736
2737   g_object_freeze_notify (G_OBJECT (tree_view->priv->vadjustment));
2738   gtk_adjustment_set_page_size (tree_view->priv->vadjustment,
2739                                 allocation->height -
2740                                 gtk_tree_view_get_effective_header_height (tree_view));
2741   gtk_adjustment_set_step_increment (tree_view->priv->vadjustment,
2742                                      gtk_adjustment_get_page_size (tree_view->priv->vadjustment) * 0.1);
2743   gtk_adjustment_set_page_increment (tree_view->priv->vadjustment,
2744                                      gtk_adjustment_get_page_size (tree_view->priv->vadjustment) * 0.9);
2745   gtk_adjustment_set_lower (tree_view->priv->vadjustment, 0);
2746   gtk_adjustment_set_upper (tree_view->priv->vadjustment,
2747                             MAX (gtk_adjustment_get_page_size (tree_view->priv->vadjustment),
2748                                  tree_view->priv->height));
2749   g_object_thaw_notify (G_OBJECT (tree_view->priv->vadjustment));
2750
2751   /* now the adjustments and window sizes are in sync, we can sync toprow/dy again */
2752   if (tree_view->priv->height <= gtk_adjustment_get_page_size (tree_view->priv->vadjustment))
2753     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
2754   else if (gtk_adjustment_get_value (tree_view->priv->vadjustment) + gtk_adjustment_get_page_size (tree_view->priv->vadjustment) > tree_view->priv->height)
2755     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment),
2756                               tree_view->priv->height - gtk_adjustment_get_page_size (tree_view->priv->vadjustment));
2757   else if (gtk_tree_row_reference_valid (tree_view->priv->top_row))
2758     gtk_tree_view_top_row_to_dy (tree_view);
2759   else
2760     gtk_tree_view_dy_to_top_row (tree_view);
2761   
2762   if (gtk_widget_get_realized (widget))
2763     {
2764       gdk_window_move_resize (gtk_widget_get_window (widget),
2765                               allocation->x, allocation->y,
2766                               allocation->width, allocation->height);
2767       gdk_window_move_resize (tree_view->priv->header_window,
2768                               - (gint) gtk_adjustment_get_value (tree_view->priv->hadjustment),
2769                               0,
2770                               MAX (tree_view->priv->width, allocation->width),
2771                               tree_view->priv->header_height);
2772       gdk_window_move_resize (tree_view->priv->bin_window,
2773                               - (gint) gtk_adjustment_get_value (tree_view->priv->hadjustment),
2774                               gtk_tree_view_get_effective_header_height (tree_view),
2775                               MAX (tree_view->priv->width, allocation->width),
2776                               allocation->height - gtk_tree_view_get_effective_header_height (tree_view));
2777
2778       if (tree_view->priv->tree == NULL)
2779         invalidate_empty_focus (tree_view);
2780
2781       if (width_changed && tree_view->priv->expander_column)
2782         {
2783           /* Might seem awkward, but is the best heuristic I could come up
2784            * with.  Only if the width of the columns before the expander
2785            * changes, we will update the prelight status.  It is this
2786            * width that makes the expander move vertically.  Always updating
2787            * prelight status causes trouble with hover selections.
2788            */
2789           gint width_before_expander;
2790
2791           width_before_expander = gtk_tree_view_calculate_width_before_expander (tree_view);
2792
2793           if (tree_view->priv->prev_width_before_expander
2794               != width_before_expander)
2795               update_prelight (tree_view,
2796                                tree_view->priv->event_last_x,
2797                                tree_view->priv->event_last_y);
2798
2799           tree_view->priv->prev_width_before_expander = width_before_expander;
2800         }
2801     }
2802 }
2803
2804 /* Grabs the focus and unsets the GTK_TREE_VIEW_DRAW_KEYFOCUS flag */
2805 static void
2806 grab_focus_and_unset_draw_keyfocus (GtkTreeView *tree_view)
2807 {
2808   GtkWidget *widget = GTK_WIDGET (tree_view);
2809
2810   if (gtk_widget_get_can_focus (widget) && !gtk_widget_has_focus (widget))
2811     gtk_widget_grab_focus (widget);
2812   tree_view->priv->draw_keyfocus = 0;
2813 }
2814
2815 static inline gboolean
2816 row_is_separator (GtkTreeView *tree_view,
2817                   GtkTreeIter *iter,
2818                   GtkTreePath *path)
2819 {
2820   gboolean is_separator = FALSE;
2821
2822   if (tree_view->priv->row_separator_func)
2823     {
2824       GtkTreeIter tmpiter;
2825
2826       if (iter)
2827         tmpiter = *iter;
2828       else
2829         {
2830           if (!gtk_tree_model_get_iter (tree_view->priv->model, &tmpiter, path))
2831             return FALSE;
2832         }
2833
2834       is_separator = tree_view->priv->row_separator_func (tree_view->priv->model,
2835                                                           &tmpiter,
2836                                                           tree_view->priv->row_separator_data);
2837     }
2838
2839   return is_separator;
2840 }
2841
2842 static gboolean
2843 gtk_tree_view_button_press (GtkWidget      *widget,
2844                             GdkEventButton *event)
2845 {
2846   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
2847   GList *list;
2848   GtkTreeViewColumn *column = NULL;
2849   gint i;
2850   GdkRectangle background_area;
2851   GdkRectangle cell_area;
2852   gint vertical_separator;
2853   gint horizontal_separator;
2854   gboolean path_is_selectable;
2855   gboolean rtl;
2856
2857   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
2858   gtk_tree_view_stop_editing (tree_view, FALSE);
2859   gtk_widget_style_get (widget,
2860                         "vertical-separator", &vertical_separator,
2861                         "horizontal-separator", &horizontal_separator,
2862                         NULL);
2863
2864   /* Because grab_focus can cause reentrancy, we delay grab_focus until after
2865    * we're done handling the button press.
2866    */
2867
2868   if (event->window == tree_view->priv->bin_window)
2869     {
2870       GtkRBNode *node;
2871       GtkRBTree *tree;
2872       GtkTreePath *path;
2873       gint depth;
2874       gint new_y;
2875       gint y_offset;
2876       gint dval;
2877       gint pre_val, aft_val;
2878       GtkTreeViewColumn *column = NULL;
2879       gint column_handled_click = FALSE;
2880       gboolean row_double_click = FALSE;
2881       gboolean rtl;
2882       gboolean node_selected;
2883
2884       /* Empty tree? */
2885       if (tree_view->priv->tree == NULL)
2886         {
2887           grab_focus_and_unset_draw_keyfocus (tree_view);
2888           return TRUE;
2889         }
2890
2891       /* are we in an arrow? */
2892       if (tree_view->priv->prelight_node &&
2893           tree_view->priv->arrow_prelit &&
2894           gtk_tree_view_draw_expanders (tree_view))
2895         {
2896           if (event->button == 1)
2897             {
2898               gtk_grab_add (widget);
2899               tree_view->priv->button_pressed_node = tree_view->priv->prelight_node;
2900               tree_view->priv->button_pressed_tree = tree_view->priv->prelight_tree;
2901               gtk_tree_view_queue_draw_arrow (GTK_TREE_VIEW (widget),
2902                                               tree_view->priv->prelight_tree,
2903                                               tree_view->priv->prelight_node);
2904             }
2905
2906           grab_focus_and_unset_draw_keyfocus (tree_view);
2907           return TRUE;
2908         }
2909
2910       /* find the node that was clicked */
2911       new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
2912       if (new_y < 0)
2913         new_y = 0;
2914       y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
2915
2916       if (node == NULL)
2917         {
2918           /* We clicked in dead space */
2919           grab_focus_and_unset_draw_keyfocus (tree_view);
2920           return TRUE;
2921         }
2922
2923       /* Get the path and the node */
2924       path = _gtk_tree_view_find_path (tree_view, tree, node);
2925       path_is_selectable = !row_is_separator (tree_view, NULL, path);
2926
2927       if (!path_is_selectable)
2928         {
2929           gtk_tree_path_free (path);
2930           grab_focus_and_unset_draw_keyfocus (tree_view);
2931           return TRUE;
2932         }
2933
2934       depth = gtk_tree_path_get_depth (path);
2935       background_area.y = y_offset + event->y;
2936       background_area.height = gtk_tree_view_get_row_height (tree_view, node);
2937       background_area.x = 0;
2938
2939
2940       /* Let the column have a chance at selecting it. */
2941       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
2942       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
2943            list; list = (rtl ? list->prev : list->next))
2944         {
2945           GtkTreeViewColumn *candidate = list->data;
2946
2947           if (!gtk_tree_view_column_get_visible (candidate))
2948             continue;
2949
2950           background_area.width = gtk_tree_view_column_get_width (candidate);
2951           if ((background_area.x > (gint) event->x) ||
2952               (background_area.x + background_area.width <= (gint) event->x))
2953             {
2954               background_area.x += background_area.width;
2955               continue;
2956             }
2957
2958           /* we found the focus column */
2959           column = candidate;
2960           cell_area = background_area;
2961           cell_area.width -= horizontal_separator;
2962           cell_area.height -= vertical_separator;
2963           cell_area.x += horizontal_separator/2;
2964           cell_area.y += vertical_separator/2;
2965           if (gtk_tree_view_is_expander_column (tree_view, column))
2966             {
2967               if (!rtl)
2968                 cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
2969               cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
2970
2971               if (gtk_tree_view_draw_expanders (tree_view))
2972                 {
2973                   if (!rtl)
2974                     cell_area.x += depth * tree_view->priv->expander_size;
2975                   cell_area.width -= depth * tree_view->priv->expander_size;
2976                 }
2977             }
2978           break;
2979         }
2980
2981       if (column == NULL)
2982         {
2983           gtk_tree_path_free (path);
2984           grab_focus_and_unset_draw_keyfocus (tree_view);
2985           return FALSE;
2986         }
2987
2988       tree_view->priv->focus_column = column;
2989
2990       /* decide if we edit */
2991       if (event->type == GDK_BUTTON_PRESS && event->button == 1 &&
2992           !(event->state & gtk_accelerator_get_default_mod_mask ()))
2993         {
2994           GtkTreePath *anchor;
2995           GtkTreeIter iter;
2996
2997           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
2998           gtk_tree_view_column_cell_set_cell_data (column,
2999                                                    tree_view->priv->model,
3000                                                    &iter,
3001                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
3002                                                    node->children?TRUE:FALSE);
3003
3004           if (tree_view->priv->anchor)
3005             anchor = gtk_tree_row_reference_get_path (tree_view->priv->anchor);
3006           else
3007             anchor = NULL;
3008
3009           if ((anchor && !gtk_tree_path_compare (anchor, path))
3010               || !_gtk_tree_view_column_has_editable_cell (column))
3011             {
3012               GtkCellEditable *cell_editable = NULL;
3013
3014               /* FIXME: get the right flags */
3015               guint flags = 0;
3016
3017               if (_gtk_tree_view_column_cell_event (column,
3018                                                     (GdkEvent *)event,
3019                                                     &cell_area, flags))
3020                 {
3021                   GtkCellArea *area = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (column));
3022                   cell_editable = gtk_cell_area_get_edit_widget (area);
3023
3024                   if (cell_editable != NULL)
3025                     {
3026                       gtk_tree_path_free (path);
3027                       gtk_tree_path_free (anchor);
3028                       return TRUE;
3029                     }
3030                   column_handled_click = TRUE;
3031                 }
3032             }
3033           if (anchor)
3034             gtk_tree_path_free (anchor);
3035         }
3036
3037       /* select */
3038       node_selected = GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED);
3039       pre_val = gtk_adjustment_get_value (tree_view->priv->vadjustment);
3040
3041       /* we only handle selection modifications on the first button press
3042        */
3043       if (event->type == GDK_BUTTON_PRESS)
3044         {
3045           GtkCellRenderer *focus_cell;
3046
3047           if ((event->state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
3048             tree_view->priv->ctrl_pressed = TRUE;
3049           if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
3050             tree_view->priv->shift_pressed = TRUE;
3051
3052           /* We update the focus cell here, this is also needed if the
3053            * column does not contain an editable cell.  In this case,
3054            * GtkCellArea did not receive the event for processing (and
3055            * could not update the focus cell).
3056            */
3057           focus_cell = _gtk_tree_view_column_get_cell_at_pos (column,
3058                                                               &cell_area,
3059                                                               &background_area,
3060                                                               event->x,
3061                                                               event->y);
3062
3063           if (focus_cell)
3064             gtk_tree_view_column_focus_cell (column, focus_cell);
3065
3066           if (event->state & GDK_CONTROL_MASK)
3067             {
3068               gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
3069               gtk_tree_view_real_toggle_cursor_row (tree_view);
3070             }
3071           else if (event->state & GDK_SHIFT_MASK)
3072             {
3073               gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
3074               gtk_tree_view_real_select_cursor_row (tree_view, FALSE);
3075             }
3076           else
3077             {
3078               gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
3079             }
3080
3081           tree_view->priv->ctrl_pressed = FALSE;
3082           tree_view->priv->shift_pressed = FALSE;
3083         }
3084
3085       /* the treeview may have been scrolled because of _set_cursor,
3086        * correct here
3087        */
3088
3089       aft_val = gtk_adjustment_get_value (tree_view->priv->vadjustment);
3090       dval = pre_val - aft_val;
3091
3092       cell_area.y += dval;
3093       background_area.y += dval;
3094
3095       /* Save press to possibly begin a drag
3096        */
3097       if (!column_handled_click &&
3098           !tree_view->priv->in_grab &&
3099           tree_view->priv->pressed_button < 0)
3100         {
3101           tree_view->priv->pressed_button = event->button;
3102           tree_view->priv->press_start_x = event->x;
3103           tree_view->priv->press_start_y = event->y;
3104
3105           if (tree_view->priv->rubber_banding_enable
3106               && !node_selected
3107               && gtk_tree_selection_get_mode (tree_view->priv->selection) == GTK_SELECTION_MULTIPLE)
3108             {
3109               tree_view->priv->press_start_y += tree_view->priv->dy;
3110               tree_view->priv->rubber_band_x = event->x;
3111               tree_view->priv->rubber_band_y = event->y + tree_view->priv->dy;
3112               tree_view->priv->rubber_band_status = RUBBER_BAND_MAYBE_START;
3113
3114               if ((event->state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
3115                 tree_view->priv->rubber_band_ctrl = TRUE;
3116               if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
3117                 tree_view->priv->rubber_band_shift = TRUE;
3118             }
3119         }
3120
3121       /* Test if a double click happened on the same row. */
3122       if (event->button == 1 && event->type == GDK_BUTTON_PRESS)
3123         {
3124           int double_click_time, double_click_distance;
3125
3126           g_object_get (gtk_settings_get_default (),
3127                         "gtk-double-click-time", &double_click_time,
3128                         "gtk-double-click-distance", &double_click_distance,
3129                         NULL);
3130
3131           /* Same conditions as _gdk_event_button_generate */
3132           if (tree_view->priv->last_button_x != -1 &&
3133               (event->time < tree_view->priv->last_button_time + double_click_time) &&
3134               (ABS (event->x - tree_view->priv->last_button_x) <= double_click_distance) &&
3135               (ABS (event->y - tree_view->priv->last_button_y) <= double_click_distance))
3136             {
3137               /* We do no longer compare paths of this row and the
3138                * row clicked previously.  We use the double click
3139                * distance to decide whether this is a valid click,
3140                * allowing the mouse to slightly move over another row.
3141                */
3142               row_double_click = TRUE;
3143
3144               tree_view->priv->last_button_time = 0;
3145               tree_view->priv->last_button_x = -1;
3146               tree_view->priv->last_button_y = -1;
3147             }
3148           else
3149             {
3150               tree_view->priv->last_button_time = event->time;
3151               tree_view->priv->last_button_x = event->x;
3152               tree_view->priv->last_button_y = event->y;
3153             }
3154         }
3155
3156       if (row_double_click)
3157         {
3158           gtk_grab_remove (widget);
3159           gtk_tree_view_row_activated (tree_view, path, column);
3160
3161           if (tree_view->priv->pressed_button == event->button)
3162             tree_view->priv->pressed_button = -1;
3163         }
3164
3165       gtk_tree_path_free (path);
3166
3167       /* If we activated the row through a double click we don't want to grab
3168        * focus back, as moving focus to another widget is pretty common.
3169        */
3170       if (!row_double_click)
3171         grab_focus_and_unset_draw_keyfocus (tree_view);
3172
3173       return TRUE;
3174     }
3175
3176   /* We didn't click in the window.  Let's check to see if we clicked on a column resize window.
3177    */
3178   for (i = 0, list = tree_view->priv->columns; list; list = list->next, i++)
3179     {
3180       column = list->data;
3181       if (event->window == _gtk_tree_view_column_get_window (column) &&
3182           gtk_tree_view_column_get_resizable (column) &&
3183           _gtk_tree_view_column_get_window (column))
3184         {
3185           gpointer drag_data;
3186
3187           if (event->type == GDK_2BUTTON_PRESS &&
3188               gtk_tree_view_column_get_sizing (column) != GTK_TREE_VIEW_COLUMN_AUTOSIZE)
3189             {
3190               _gtk_tree_view_column_set_use_resized_width (column, FALSE);
3191               _gtk_tree_view_column_autosize (tree_view, column);
3192               return TRUE;
3193             }
3194
3195           if (gdk_device_grab (gdk_event_get_device ((GdkEvent*)event),
3196                                _gtk_tree_view_column_get_window (column),
3197                                GDK_OWNERSHIP_NONE,
3198                                FALSE,
3199                                GDK_POINTER_MOTION_HINT_MASK
3200                                 | GDK_BUTTON1_MOTION_MASK
3201                                 | GDK_BUTTON_RELEASE_MASK,
3202                                NULL,
3203                                event->time) != GDK_GRAB_SUCCESS)
3204             return FALSE;
3205
3206           gtk_grab_add (widget);
3207           tree_view->priv->in_column_resize = TRUE;
3208
3209           _gtk_tree_view_column_set_resized_width (column, gtk_tree_view_column_get_width (column) -
3210                                                    tree_view->priv->last_extra_space_per_column);
3211
3212           /* block attached dnd signal handler */
3213           drag_data = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
3214           if (drag_data)
3215             g_signal_handlers_block_matched (widget,
3216                                              G_SIGNAL_MATCH_DATA,
3217                                              0, 0, NULL, NULL,
3218                                              drag_data);
3219
3220           tree_view->priv->drag_pos = i;
3221           tree_view->priv->x_drag = gtk_tree_view_column_get_x_offset (column) + (rtl ? 0 : gtk_tree_view_column_get_width (column));
3222
3223           if (!gtk_widget_has_focus (widget))
3224             gtk_widget_grab_focus (widget);
3225
3226           return TRUE;
3227         }
3228     }
3229   return FALSE;
3230 }
3231
3232 /* GtkWidget::button_release_event helper */
3233 static gboolean
3234 gtk_tree_view_button_release_drag_column (GtkWidget      *widget,
3235                                           GdkEventButton *event)
3236 {
3237   GtkTreeView *tree_view;
3238   GtkWidget *button;
3239   GList *l;
3240   gboolean rtl;
3241   GdkDevice *device, *other;
3242
3243   tree_view = GTK_TREE_VIEW (widget);
3244
3245   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
3246   device = gdk_event_get_device ((GdkEvent*)event);
3247   other = gdk_device_get_associated_device (device);
3248   gdk_device_ungrab (device, event->time);
3249   gdk_device_ungrab (other, event->time);
3250
3251   /* Move the button back */
3252   button = gtk_tree_view_column_get_button (tree_view->priv->drag_column);
3253   g_object_ref (button);
3254   gtk_container_remove (GTK_CONTAINER (tree_view), button);
3255   gtk_widget_set_parent_window (button, tree_view->priv->header_window);
3256   gtk_widget_set_parent (button, GTK_WIDGET (tree_view));
3257   g_object_unref (button);
3258   gtk_widget_queue_resize (widget);
3259   if (gtk_tree_view_column_get_resizable (tree_view->priv->drag_column))
3260     {
3261       gdk_window_raise (_gtk_tree_view_column_get_window (tree_view->priv->drag_column));
3262       gdk_window_show (_gtk_tree_view_column_get_window (tree_view->priv->drag_column));
3263     }
3264   else
3265     gdk_window_hide (_gtk_tree_view_column_get_window (tree_view->priv->drag_column));
3266
3267   gtk_widget_grab_focus (button);
3268
3269   if (rtl)
3270     {
3271       if (tree_view->priv->cur_reorder &&
3272           tree_view->priv->cur_reorder->right_column != tree_view->priv->drag_column)
3273         gtk_tree_view_move_column_after (tree_view, tree_view->priv->drag_column,
3274                                          tree_view->priv->cur_reorder->right_column);
3275     }
3276   else
3277     {
3278       if (tree_view->priv->cur_reorder &&
3279           tree_view->priv->cur_reorder->left_column != tree_view->priv->drag_column)
3280         gtk_tree_view_move_column_after (tree_view, tree_view->priv->drag_column,
3281                                          tree_view->priv->cur_reorder->left_column);
3282     }
3283   tree_view->priv->drag_column = NULL;
3284   gdk_window_hide (tree_view->priv->drag_window);
3285
3286   for (l = tree_view->priv->column_drag_info; l != NULL; l = l->next)
3287     g_slice_free (GtkTreeViewColumnReorder, l->data);
3288   g_list_free (tree_view->priv->column_drag_info);
3289   tree_view->priv->column_drag_info = NULL;
3290   tree_view->priv->cur_reorder = NULL;
3291
3292   if (tree_view->priv->drag_highlight_window)
3293     gdk_window_hide (tree_view->priv->drag_highlight_window);
3294
3295   /* Reset our flags */
3296   tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_UNSET;
3297   tree_view->priv->in_column_drag = FALSE;
3298
3299   return TRUE;
3300 }
3301
3302 /* GtkWidget::button_release_event helper */
3303 static gboolean
3304 gtk_tree_view_button_release_column_resize (GtkWidget      *widget,
3305                                             GdkEventButton *event)
3306 {
3307   GtkTreeView *tree_view;
3308   gpointer drag_data;
3309
3310   tree_view = GTK_TREE_VIEW (widget);
3311
3312   tree_view->priv->drag_pos = -1;
3313
3314   /* unblock attached dnd signal handler */
3315   drag_data = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
3316   if (drag_data)
3317     g_signal_handlers_unblock_matched (widget,
3318                                        G_SIGNAL_MATCH_DATA,
3319                                        0, 0, NULL, NULL,
3320                                        drag_data);
3321
3322   tree_view->priv->in_column_resize = FALSE;
3323   gtk_grab_remove (widget);
3324   gdk_device_ungrab (gdk_event_get_device ((GdkEvent*)event), event->time);
3325   return TRUE;
3326 }
3327
3328 static gboolean
3329 gtk_tree_view_button_release (GtkWidget      *widget,
3330                               GdkEventButton *event)
3331 {
3332   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
3333
3334   if (tree_view->priv->in_column_drag)
3335     return gtk_tree_view_button_release_drag_column (widget, event);
3336
3337   if (tree_view->priv->rubber_band_status)
3338     gtk_tree_view_stop_rubber_band (tree_view);
3339
3340   if (tree_view->priv->pressed_button == event->button)
3341     tree_view->priv->pressed_button = -1;
3342
3343   if (tree_view->priv->in_column_resize)
3344     return gtk_tree_view_button_release_column_resize (widget, event);
3345
3346   if (tree_view->priv->button_pressed_node == NULL)
3347     return FALSE;
3348
3349   if (event->button == 1)
3350     {
3351       if (tree_view->priv->button_pressed_node == tree_view->priv->prelight_node &&
3352           tree_view->priv->arrow_prelit)
3353         {
3354           GtkTreePath *path = NULL;
3355
3356           path = _gtk_tree_view_find_path (tree_view,
3357                                            tree_view->priv->button_pressed_tree,
3358                                            tree_view->priv->button_pressed_node);
3359           /* Actually activate the node */
3360           if (tree_view->priv->button_pressed_node->children == NULL)
3361             gtk_tree_view_real_expand_row (tree_view, path,
3362                                            tree_view->priv->button_pressed_tree,
3363                                            tree_view->priv->button_pressed_node,
3364                                            FALSE, TRUE);
3365           else
3366             gtk_tree_view_real_collapse_row (GTK_TREE_VIEW (widget), path,
3367                                              tree_view->priv->button_pressed_tree,
3368                                              tree_view->priv->button_pressed_node, TRUE);
3369           gtk_tree_path_free (path);
3370         }
3371
3372       gtk_grab_remove (widget);
3373       tree_view->priv->button_pressed_tree = NULL;
3374       tree_view->priv->button_pressed_node = NULL;
3375     }
3376
3377   return TRUE;
3378 }
3379
3380 static gboolean
3381 gtk_tree_view_grab_broken (GtkWidget          *widget,
3382                            GdkEventGrabBroken *event)
3383 {
3384   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
3385
3386   if (tree_view->priv->in_column_drag)
3387     gtk_tree_view_button_release_drag_column (widget, (GdkEventButton *)event);
3388
3389   if (tree_view->priv->in_column_resize)
3390     gtk_tree_view_button_release_column_resize (widget, (GdkEventButton *)event);
3391
3392   return TRUE;
3393 }
3394
3395 #if 0
3396 static gboolean
3397 gtk_tree_view_configure (GtkWidget *widget,
3398                          GdkEventConfigure *event)
3399 {
3400   GtkTreeView *tree_view;
3401
3402   tree_view = GTK_TREE_VIEW (widget);
3403   tree_view->priv->search_position_func (tree_view, tree_view->priv->search_window);
3404
3405   return FALSE;
3406 }
3407 #endif
3408
3409 /* GtkWidget::motion_event function set.
3410  */
3411
3412 static gboolean
3413 coords_are_over_arrow (GtkTreeView *tree_view,
3414                        GtkRBTree   *tree,
3415                        GtkRBNode   *node,
3416                        /* these are in bin window coords */
3417                        gint         x,
3418                        gint         y)
3419 {
3420   GdkRectangle arrow;
3421   gint x2;
3422
3423   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
3424     return FALSE;
3425
3426   if ((node->flags & GTK_RBNODE_IS_PARENT) == 0)
3427     return FALSE;
3428
3429   arrow.y = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
3430   arrow.height = gtk_tree_view_get_row_height (tree_view, node);
3431
3432   gtk_tree_view_get_arrow_xrange (tree_view, tree, &arrow.x, &x2);
3433
3434   arrow.width = x2 - arrow.x;
3435
3436   return (x >= arrow.x &&
3437           x < (arrow.x + arrow.width) &&
3438           y >= arrow.y &&
3439           y < (arrow.y + arrow.height));
3440 }
3441
3442 static gboolean
3443 auto_expand_timeout (gpointer data)
3444 {
3445   GtkTreeView *tree_view = GTK_TREE_VIEW (data);
3446   GtkTreePath *path;
3447
3448   if (tree_view->priv->prelight_node)
3449     {
3450       path = _gtk_tree_view_find_path (tree_view,
3451                                        tree_view->priv->prelight_tree,
3452                                        tree_view->priv->prelight_node);   
3453
3454       if (tree_view->priv->prelight_node->children)
3455         gtk_tree_view_collapse_row (tree_view, path);
3456       else
3457         gtk_tree_view_expand_row (tree_view, path, FALSE);
3458
3459       gtk_tree_path_free (path);
3460     }
3461
3462   tree_view->priv->auto_expand_timeout = 0;
3463
3464   return FALSE;
3465 }
3466
3467 static void
3468 remove_auto_expand_timeout (GtkTreeView *tree_view)
3469 {
3470   if (tree_view->priv->auto_expand_timeout != 0)
3471     {
3472       g_source_remove (tree_view->priv->auto_expand_timeout);
3473       tree_view->priv->auto_expand_timeout = 0;
3474     }
3475 }
3476
3477 static void
3478 do_prelight (GtkTreeView *tree_view,
3479              GtkRBTree   *tree,
3480              GtkRBNode   *node,
3481              /* these are in bin_window coords */
3482              gint         x,
3483              gint         y)
3484 {
3485   if (tree_view->priv->prelight_tree == tree &&
3486       tree_view->priv->prelight_node == node)
3487     {
3488       /*  We are still on the same node,
3489           but we might need to take care of the arrow  */
3490
3491       if (tree && node && gtk_tree_view_draw_expanders (tree_view))
3492         {
3493           gboolean over_arrow;
3494
3495           over_arrow = coords_are_over_arrow (tree_view, tree, node, x, y);
3496
3497           if (over_arrow != tree_view->priv->arrow_prelit)
3498             {
3499               if (over_arrow)
3500                 tree_view->priv->arrow_prelit = TRUE;
3501               else
3502                 tree_view->priv->arrow_prelit = FALSE;
3503
3504               gtk_tree_view_queue_draw_arrow (tree_view, tree, node);
3505             }
3506         }
3507
3508       return;
3509     }
3510
3511   if (tree_view->priv->prelight_tree && tree_view->priv->prelight_node)
3512     {
3513       /*  Unprelight the old node and arrow  */
3514
3515       GTK_RBNODE_UNSET_FLAG (tree_view->priv->prelight_node,
3516                              GTK_RBNODE_IS_PRELIT);
3517
3518       if (tree_view->priv->arrow_prelit
3519           && gtk_tree_view_draw_expanders (tree_view))
3520         {
3521           tree_view->priv->arrow_prelit = FALSE;
3522           
3523           gtk_tree_view_queue_draw_arrow (tree_view,
3524                                           tree_view->priv->prelight_tree,
3525                                           tree_view->priv->prelight_node);
3526         }
3527
3528       _gtk_tree_view_queue_draw_node (tree_view,
3529                                       tree_view->priv->prelight_tree,
3530                                       tree_view->priv->prelight_node,
3531                                       NULL);
3532     }
3533
3534
3535   if (tree_view->priv->hover_expand)
3536     remove_auto_expand_timeout (tree_view);
3537
3538   /*  Set the new prelight values  */
3539   tree_view->priv->prelight_node = node;
3540   tree_view->priv->prelight_tree = tree;
3541
3542   if (!node || !tree)
3543     return;
3544
3545   /*  Prelight the new node and arrow  */
3546
3547   if (gtk_tree_view_draw_expanders (tree_view)
3548       && coords_are_over_arrow (tree_view, tree, node, x, y))
3549     {
3550       tree_view->priv->arrow_prelit = TRUE;
3551
3552       gtk_tree_view_queue_draw_arrow (tree_view, tree, node);
3553     }
3554
3555   GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_PRELIT);
3556
3557   _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
3558
3559   if (tree_view->priv->hover_expand)
3560     {
3561       tree_view->priv->auto_expand_timeout = 
3562         gdk_threads_add_timeout (AUTO_EXPAND_TIMEOUT, auto_expand_timeout, tree_view);
3563     }
3564 }
3565
3566 static void
3567 prelight_or_select (GtkTreeView *tree_view,
3568                     GtkRBTree   *tree,
3569                     GtkRBNode   *node,
3570                     /* these are in bin_window coords */
3571                     gint         x,
3572                     gint         y)
3573 {
3574   GtkSelectionMode mode = gtk_tree_selection_get_mode (tree_view->priv->selection);
3575   
3576   if (tree_view->priv->hover_selection &&
3577       (mode == GTK_SELECTION_SINGLE || mode == GTK_SELECTION_BROWSE) &&
3578       !(tree_view->priv->edited_column &&
3579         gtk_cell_area_get_edit_widget 
3580         (gtk_cell_layout_get_area (GTK_CELL_LAYOUT (tree_view->priv->edited_column)))))
3581     {
3582       if (node)
3583         {
3584           if (!GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
3585             {
3586               GtkTreePath *path;
3587               
3588               path = _gtk_tree_view_find_path (tree_view, tree, node);
3589               gtk_tree_selection_select_path (tree_view->priv->selection, path);
3590               if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
3591                 {
3592                   tree_view->priv->draw_keyfocus = FALSE;
3593                   gtk_tree_view_real_set_cursor (tree_view, path, FALSE, FALSE);
3594                 }
3595               gtk_tree_path_free (path);
3596             }
3597         }
3598
3599       else if (mode == GTK_SELECTION_SINGLE)
3600         gtk_tree_selection_unselect_all (tree_view->priv->selection);
3601     }
3602
3603     do_prelight (tree_view, tree, node, x, y);
3604 }
3605
3606 static void
3607 ensure_unprelighted (GtkTreeView *tree_view)
3608 {
3609   do_prelight (tree_view,
3610                NULL, NULL,
3611                -1000, -1000); /* coords not possibly over an arrow */
3612
3613   g_assert (tree_view->priv->prelight_node == NULL);
3614 }
3615
3616 static void
3617 update_prelight (GtkTreeView *tree_view,
3618                  gint         x,
3619                  gint         y)
3620 {
3621   int new_y;
3622   GtkRBTree *tree;
3623   GtkRBNode *node;
3624
3625   if (tree_view->priv->tree == NULL)
3626     return;
3627
3628   if (x == -10000)
3629     {
3630       ensure_unprelighted (tree_view);
3631       return;
3632     }
3633
3634   new_y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, y);
3635   if (new_y < 0)
3636     new_y = 0;
3637
3638   _gtk_rbtree_find_offset (tree_view->priv->tree,
3639                            new_y, &tree, &node);
3640
3641   if (node)
3642     prelight_or_select (tree_view, tree, node, x, y);
3643 }
3644
3645
3646
3647
3648 /* Our motion arrow is either a box (in the case of the original spot)
3649  * or an arrow.  It is expander_size wide.
3650  */
3651 /*
3652  * 11111111111111
3653  * 01111111111110
3654  * 00111111111100
3655  * 00011111111000
3656  * 00001111110000
3657  * 00000111100000
3658  * 00000111100000
3659  * 00000111100000
3660  * ~ ~ ~ ~ ~ ~ ~
3661  * 00000111100000
3662  * 00000111100000
3663  * 00000111100000
3664  * 00001111110000
3665  * 00011111111000
3666  * 00111111111100
3667  * 01111111111110
3668  * 11111111111111
3669  */
3670
3671 static void
3672 gtk_tree_view_motion_draw_column_motion_arrow (GtkTreeView *tree_view)
3673 {
3674   GtkTreeViewColumnReorder *reorder = tree_view->priv->cur_reorder;
3675   GtkWidget *widget = GTK_WIDGET (tree_view);
3676   cairo_surface_t *mask_image;
3677   cairo_region_t *mask_region;
3678   gint x;
3679   gint y;
3680   gint width;
3681   gint height;
3682   gint arrow_type = DRAG_COLUMN_WINDOW_STATE_UNSET;
3683   GdkWindowAttr attributes;
3684   guint attributes_mask;
3685   cairo_t *cr;
3686
3687   if (!reorder ||
3688       reorder->left_column == tree_view->priv->drag_column ||
3689       reorder->right_column == tree_view->priv->drag_column)
3690     arrow_type = DRAG_COLUMN_WINDOW_STATE_ORIGINAL;
3691   else if (reorder->left_column || reorder->right_column)
3692     {
3693       GtkAllocation left_allocation, right_allocation;
3694       GdkRectangle visible_rect;
3695       GtkWidget *button;
3696
3697       gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
3698       if (reorder->left_column)
3699         {
3700           button = gtk_tree_view_column_get_button (reorder->left_column);
3701           gtk_widget_get_allocation (button, &left_allocation);
3702           x = left_allocation.x + left_allocation.width;
3703         }
3704       else
3705         {
3706           button = gtk_tree_view_column_get_button (reorder->right_column);
3707           gtk_widget_get_allocation (button, &right_allocation);
3708           x = right_allocation.x;
3709         }
3710
3711       if (x < visible_rect.x)
3712         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT;
3713       else if (x > visible_rect.x + visible_rect.width)
3714         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT;
3715       else
3716         arrow_type = DRAG_COLUMN_WINDOW_STATE_ARROW;
3717     }
3718
3719   /* We want to draw the rectangle over the initial location. */
3720   if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ORIGINAL)
3721     {
3722       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ORIGINAL)
3723         {
3724           GtkAllocation drag_allocation;
3725           GtkWidget    *button;
3726
3727           if (tree_view->priv->drag_highlight_window)
3728             {
3729               gdk_window_set_user_data (tree_view->priv->drag_highlight_window,
3730                                         NULL);
3731               gdk_window_destroy (tree_view->priv->drag_highlight_window);
3732             }
3733
3734           button = gtk_tree_view_column_get_button (tree_view->priv->drag_column);
3735           attributes.window_type = GDK_WINDOW_CHILD;
3736           attributes.wclass = GDK_INPUT_OUTPUT;
3737           attributes.x = tree_view->priv->drag_column_x;
3738           attributes.y = 0;
3739           gtk_widget_get_allocation (button, &drag_allocation);
3740           width = attributes.width = drag_allocation.width;
3741           height = attributes.height = drag_allocation.height;
3742           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
3743           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3744           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
3745           tree_view->priv->drag_highlight_window = gdk_window_new (tree_view->priv->header_window, &attributes, attributes_mask);
3746           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
3747
3748           mask_image = cairo_image_surface_create (CAIRO_FORMAT_A1, width, height);
3749           cr = cairo_create (mask_image);
3750
3751           cairo_rectangle (cr, 1, 1, width - 2, height - 2);
3752           cairo_stroke (cr);
3753           cairo_destroy (cr);
3754
3755           mask_region = gdk_cairo_region_create_from_surface (mask_image);
3756           gdk_window_shape_combine_region (tree_view->priv->drag_highlight_window,
3757                                            mask_region, 0, 0);
3758
3759           cairo_region_destroy (mask_region);
3760           cairo_surface_destroy (mask_image);
3761
3762           tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_ORIGINAL;
3763         }
3764     }
3765   else if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW)
3766     {
3767       GtkAllocation button_allocation;
3768       GtkWidget    *button;
3769
3770       width = tree_view->priv->expander_size;
3771
3772       /* Get x, y, width, height of arrow */
3773       gdk_window_get_origin (tree_view->priv->header_window, &x, &y);
3774       if (reorder->left_column)
3775         {
3776           button = gtk_tree_view_column_get_button (reorder->left_column);
3777           gtk_widget_get_allocation (button, &button_allocation);
3778           x += button_allocation.x + button_allocation.width - width/2;
3779           height = button_allocation.height;
3780         }
3781       else
3782         {
3783           button = gtk_tree_view_column_get_button (reorder->right_column);
3784           gtk_widget_get_allocation (button, &button_allocation);
3785           x += button_allocation.x - width/2;
3786           height = button_allocation.height;
3787         }
3788       y -= tree_view->priv->expander_size/2; /* The arrow takes up only half the space */
3789       height += tree_view->priv->expander_size;
3790
3791       /* Create the new window */
3792       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW)
3793         {
3794           if (tree_view->priv->drag_highlight_window)
3795             {
3796               gdk_window_set_user_data (tree_view->priv->drag_highlight_window,
3797                                         NULL);
3798               gdk_window_destroy (tree_view->priv->drag_highlight_window);
3799             }
3800
3801           attributes.window_type = GDK_WINDOW_TEMP;
3802           attributes.wclass = GDK_INPUT_OUTPUT;
3803           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
3804           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3805           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
3806           attributes.x = x;
3807           attributes.y = y;
3808           attributes.width = width;
3809           attributes.height = height;
3810           tree_view->priv->drag_highlight_window = gdk_window_new (gtk_widget_get_root_window (widget),
3811                                                                    &attributes, attributes_mask);
3812           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
3813
3814           mask_image = cairo_image_surface_create (CAIRO_FORMAT_A1, width, height);
3815
3816           cr = cairo_create (mask_image);
3817           cairo_move_to (cr, 0, 0);
3818           cairo_line_to (cr, width, 0);
3819           cairo_line_to (cr, width / 2., width / 2);
3820           cairo_move_to (cr, 0, height);
3821           cairo_line_to (cr, width, height);
3822           cairo_line_to (cr, width / 2., height - width / 2.);
3823           cairo_fill (cr);
3824           cairo_destroy (cr);
3825
3826           mask_region = gdk_cairo_region_create_from_surface (mask_image);
3827           gdk_window_shape_combine_region (tree_view->priv->drag_highlight_window,
3828                                            mask_region, 0, 0);
3829
3830           cairo_region_destroy (mask_region);
3831           cairo_surface_destroy (mask_image);
3832         }
3833
3834       tree_view->priv->drag_column_window_state = DRAG_COLUMN_WINDOW_STATE_ARROW;
3835       gdk_window_move (tree_view->priv->drag_highlight_window, x, y);
3836     }
3837   else if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT ||
3838            arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
3839     {
3840       GtkAllocation allocation;
3841       GtkWidget    *button;
3842
3843       width = tree_view->priv->expander_size;
3844
3845       /* Get x, y, width, height of arrow */
3846       width = width/2; /* remember, the arrow only takes half the available width */
3847       gdk_window_get_origin (gtk_widget_get_window (widget),
3848                              &x, &y);
3849       if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
3850         {
3851           gtk_widget_get_allocation (widget, &allocation);
3852           x += allocation.width - width;
3853         }
3854
3855       if (reorder->left_column)
3856         {
3857           button = gtk_tree_view_column_get_button (reorder->left_column);
3858           gtk_widget_get_allocation (button, &allocation);
3859           height = allocation.height;
3860         }
3861       else
3862         {
3863           button = gtk_tree_view_column_get_button (reorder->right_column);
3864           gtk_widget_get_allocation (button, &allocation);
3865           height = allocation.height;
3866         }
3867
3868       y -= tree_view->priv->expander_size;
3869       height += 2*tree_view->priv->expander_size;
3870
3871       /* Create the new window */
3872       if (tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT &&
3873           tree_view->priv->drag_column_window_state != DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT)
3874         {
3875           if (tree_view->priv->drag_highlight_window)
3876             {
3877               gdk_window_set_user_data (tree_view->priv->drag_highlight_window,
3878                                         NULL);
3879               gdk_window_destroy (tree_view->priv->drag_highlight_window);
3880             }
3881
3882           attributes.window_type = GDK_WINDOW_TEMP;
3883           attributes.wclass = GDK_INPUT_OUTPUT;
3884           attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
3885           attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
3886           attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
3887           attributes.x = x;
3888           attributes.y = y;
3889           attributes.width = width;
3890           attributes.height = height;
3891           tree_view->priv->drag_highlight_window = gdk_window_new (NULL, &attributes, attributes_mask);
3892           gdk_window_set_user_data (tree_view->priv->drag_highlight_window, GTK_WIDGET (tree_view));
3893
3894           mask_image = cairo_image_surface_create (CAIRO_FORMAT_A1, width, height);
3895
3896           cr = cairo_create (mask_image);
3897           /* mirror if we're on the left */
3898           if (arrow_type == DRAG_COLUMN_WINDOW_STATE_ARROW_LEFT)
3899             {
3900               cairo_translate (cr, width, 0);
3901               cairo_scale (cr, -1, 1);
3902             }
3903           cairo_move_to (cr, 0, 0);
3904           cairo_line_to (cr, width, width);
3905           cairo_line_to (cr, 0, tree_view->priv->expander_size);
3906           cairo_move_to (cr, 0, height);
3907           cairo_line_to (cr, width, height - width);
3908           cairo_line_to (cr, 0, height - tree_view->priv->expander_size);
3909           cairo_fill (cr);
3910           cairo_destroy (cr);
3911
3912           mask_region = gdk_cairo_region_create_from_surface (mask_image);
3913           gdk_window_shape_combine_region (tree_view->priv->drag_highlight_window,
3914                                            mask_region, 0, 0);
3915
3916           cairo_region_destroy (mask_region);
3917           cairo_surface_destroy (mask_image);
3918         }
3919
3920       tree_view->priv->drag_column_window_state = arrow_type;
3921       gdk_window_move (tree_view->priv->drag_highlight_window, x, y);
3922    }
3923   else
3924     {
3925       g_warning (G_STRLOC"Invalid GtkTreeViewColumnReorder struct");
3926       gdk_window_hide (tree_view->priv->drag_highlight_window);
3927       return;
3928     }
3929
3930   gdk_window_show (tree_view->priv->drag_highlight_window);
3931   gdk_window_raise (tree_view->priv->drag_highlight_window);
3932 }
3933
3934 static gboolean
3935 gtk_tree_view_motion_resize_column (GtkWidget      *widget,
3936                                     GdkEventMotion *event)
3937 {
3938   gint x;
3939   gint new_width;
3940   GtkTreeViewColumn *column;
3941   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
3942
3943   column = gtk_tree_view_get_column (tree_view, tree_view->priv->drag_pos);
3944
3945   if (event->is_hint || event->window != gtk_widget_get_window (widget))
3946     gtk_widget_get_pointer (widget, &x, NULL);
3947   else
3948     x = event->x;
3949
3950   if (tree_view->priv->hadjustment)
3951     x += gtk_adjustment_get_value (tree_view->priv->hadjustment);
3952
3953   new_width = gtk_tree_view_new_column_width (tree_view,
3954                                               tree_view->priv->drag_pos, &x);
3955   if (x != tree_view->priv->x_drag &&
3956       (new_width != gtk_tree_view_column_get_fixed_width (column)))
3957     {
3958       _gtk_tree_view_column_set_use_resized_width (column, TRUE);
3959
3960       if (gtk_tree_view_column_get_expand (column))
3961         new_width -= tree_view->priv->last_extra_space_per_column;
3962
3963       _gtk_tree_view_column_set_resized_width (column, new_width);
3964
3965
3966       gtk_widget_queue_resize (widget);
3967     }
3968
3969   return FALSE;
3970 }
3971
3972
3973 static void
3974 gtk_tree_view_update_current_reorder (GtkTreeView *tree_view)
3975 {
3976   GtkTreeViewColumnReorder *reorder = NULL;
3977   GList *list;
3978   gint mouse_x;
3979
3980   gdk_window_get_pointer (tree_view->priv->header_window, &mouse_x, NULL, NULL);
3981   for (list = tree_view->priv->column_drag_info; list; list = list->next)
3982     {
3983       reorder = (GtkTreeViewColumnReorder *) list->data;
3984       if (mouse_x >= reorder->left_align && mouse_x < reorder->right_align)
3985         break;
3986       reorder = NULL;
3987     }
3988
3989   /*  if (reorder && reorder == tree_view->priv->cur_reorder)
3990       return;*/
3991
3992   tree_view->priv->cur_reorder = reorder;
3993   gtk_tree_view_motion_draw_column_motion_arrow (tree_view);
3994 }
3995
3996 static void
3997 gtk_tree_view_vertical_autoscroll (GtkTreeView *tree_view)
3998 {
3999   GdkRectangle visible_rect;
4000   gint y;
4001   gint offset;
4002
4003   gdk_window_get_pointer (tree_view->priv->bin_window, NULL, &y, NULL);
4004   y += tree_view->priv->dy;
4005
4006   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
4007
4008   /* see if we are near the edge. */
4009   offset = y - (visible_rect.y + 2 * SCROLL_EDGE_SIZE);
4010   if (offset > 0)
4011     {
4012       offset = y - (visible_rect.y + visible_rect.height - 2 * SCROLL_EDGE_SIZE);
4013       if (offset < 0)
4014         return;
4015     }
4016
4017   gtk_adjustment_set_value (tree_view->priv->vadjustment,
4018                             MAX (gtk_adjustment_get_value (tree_view->priv->vadjustment) + offset, 0.0));
4019 }
4020
4021 static gboolean
4022 gtk_tree_view_horizontal_autoscroll (GtkTreeView *tree_view)
4023 {
4024   GdkRectangle visible_rect;
4025   gint x;
4026   gint offset;
4027
4028   gdk_window_get_pointer (tree_view->priv->bin_window, &x, NULL, NULL);
4029
4030   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
4031
4032   /* See if we are near the edge. */
4033   offset = x - (visible_rect.x + SCROLL_EDGE_SIZE);
4034   if (offset > 0)
4035     {
4036       offset = x - (visible_rect.x + visible_rect.width - SCROLL_EDGE_SIZE);
4037       if (offset < 0)
4038         return TRUE;
4039     }
4040   offset = offset/3;
4041
4042   gtk_adjustment_set_value (tree_view->priv->hadjustment,
4043                             MAX (gtk_adjustment_get_value (tree_view->priv->hadjustment) + offset, 0.0));
4044
4045   return TRUE;
4046
4047 }
4048
4049 static gboolean
4050 gtk_tree_view_motion_drag_column (GtkWidget      *widget,
4051                                   GdkEventMotion *event)
4052 {
4053   GtkAllocation allocation, button_allocation;
4054   GtkTreeView *tree_view = (GtkTreeView *) widget;
4055   GtkTreeViewColumn *column = tree_view->priv->drag_column;
4056   GtkWidget *button;
4057   gint x, y;
4058
4059   /* Sanity Check */
4060   if ((column == NULL) ||
4061       (event->window != tree_view->priv->drag_window))
4062     return FALSE;
4063
4064   button = gtk_tree_view_column_get_button (column);
4065
4066   /* Handle moving the header */
4067   gdk_window_get_position (tree_view->priv->drag_window, &x, &y);
4068   gtk_widget_get_allocation (widget, &allocation);
4069   gtk_widget_get_allocation (button, &button_allocation);
4070   x = CLAMP (x + (gint)event->x - _gtk_tree_view_column_get_drag_x (column), 0,
4071              MAX (tree_view->priv->width, allocation.width) - button_allocation.width);
4072   gdk_window_move (tree_view->priv->drag_window, x, y);
4073   
4074   /* autoscroll, if needed */
4075   gtk_tree_view_horizontal_autoscroll (tree_view);
4076   /* Update the current reorder position and arrow; */
4077   gtk_tree_view_update_current_reorder (tree_view);
4078
4079   return TRUE;
4080 }
4081
4082 static void
4083 gtk_tree_view_stop_rubber_band (GtkTreeView *tree_view)
4084 {
4085   remove_scroll_timeout (tree_view);
4086   gtk_grab_remove (GTK_WIDGET (tree_view));
4087
4088   if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
4089     {
4090       GtkTreePath *tmp_path;
4091
4092       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
4093
4094       /* The anchor path should be set to the start path */
4095       tmp_path = _gtk_tree_view_find_path (tree_view,
4096                                            tree_view->priv->rubber_band_start_tree,
4097                                            tree_view->priv->rubber_band_start_node);
4098
4099       if (tree_view->priv->anchor)
4100         gtk_tree_row_reference_free (tree_view->priv->anchor);
4101
4102       tree_view->priv->anchor =
4103         gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
4104                                           tree_view->priv->model,
4105                                           tmp_path);
4106
4107       gtk_tree_path_free (tmp_path);
4108
4109       /* ... and the cursor to the end path */
4110       tmp_path = _gtk_tree_view_find_path (tree_view,
4111                                            tree_view->priv->rubber_band_end_tree,
4112                                            tree_view->priv->rubber_band_end_node);
4113       gtk_tree_view_real_set_cursor (GTK_TREE_VIEW (tree_view), tmp_path, FALSE, FALSE);
4114       gtk_tree_path_free (tmp_path);
4115
4116       _gtk_tree_selection_emit_changed (tree_view->priv->selection);
4117     }
4118
4119   /* Clear status variables */
4120   tree_view->priv->rubber_band_status = RUBBER_BAND_OFF;
4121   tree_view->priv->rubber_band_shift = 0;
4122   tree_view->priv->rubber_band_ctrl = 0;
4123
4124   tree_view->priv->rubber_band_start_node = NULL;
4125   tree_view->priv->rubber_band_start_tree = NULL;
4126   tree_view->priv->rubber_band_end_node = NULL;
4127   tree_view->priv->rubber_band_end_tree = NULL;
4128 }
4129
4130 static void
4131 gtk_tree_view_update_rubber_band_selection_range (GtkTreeView *tree_view,
4132                                                  GtkRBTree   *start_tree,
4133                                                  GtkRBNode   *start_node,
4134                                                  GtkRBTree   *end_tree,
4135                                                  GtkRBNode   *end_node,
4136                                                  gboolean     select,
4137                                                  gboolean     skip_start,
4138                                                  gboolean     skip_end)
4139 {
4140   if (start_node == end_node)
4141     return;
4142
4143   /* We skip the first node and jump inside the loop */
4144   if (skip_start)
4145     goto skip_first;
4146
4147   do
4148     {
4149       /* Small optimization by assuming insensitive nodes are never
4150        * selected.
4151        */
4152       if (!GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
4153         {
4154           GtkTreePath *path;
4155           gboolean selectable;
4156
4157           path = _gtk_tree_view_find_path (tree_view, start_tree, start_node);
4158           selectable = _gtk_tree_selection_row_is_selectable (tree_view->priv->selection, start_node, path);
4159           gtk_tree_path_free (path);
4160
4161           if (!selectable)
4162             goto node_not_selectable;
4163         }
4164
4165       if (select)
4166         {
4167           if (tree_view->priv->rubber_band_shift)
4168             GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4169           else if (tree_view->priv->rubber_band_ctrl)
4170             {
4171               /* Toggle the selection state */
4172               if (GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
4173                 GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4174               else
4175                 GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4176             }
4177           else
4178             GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4179         }
4180       else
4181         {
4182           /* Mirror the above */
4183           if (tree_view->priv->rubber_band_shift)
4184             GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4185           else if (tree_view->priv->rubber_band_ctrl)
4186             {
4187               /* Toggle the selection state */
4188               if (GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
4189                 GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4190               else
4191                 GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4192             }
4193           else
4194             GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
4195         }
4196
4197       _gtk_tree_view_queue_draw_node (tree_view, start_tree, start_node, NULL);
4198
4199 node_not_selectable:
4200       if (start_node == end_node)
4201         break;
4202
4203 skip_first:
4204
4205       if (start_node->children)
4206         {
4207           start_tree = start_node->children;
4208           start_node = start_tree->root;
4209           while (start_node->left != start_tree->nil)
4210             start_node = start_node->left;
4211         }
4212       else
4213         {
4214           _gtk_rbtree_next_full (start_tree, start_node, &start_tree, &start_node);
4215
4216           if (!start_tree)
4217             /* Ran out of tree */
4218             break;
4219         }
4220
4221       if (skip_end && start_node == end_node)
4222         break;
4223     }
4224   while (TRUE);
4225 }
4226
4227 static void
4228 gtk_tree_view_update_rubber_band_selection (GtkTreeView *tree_view)
4229 {
4230   GtkRBTree *start_tree, *end_tree;
4231   GtkRBNode *start_node, *end_node;
4232
4233   _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);
4234   _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);
4235
4236   /* Handle the start area first */
4237   if (!tree_view->priv->rubber_band_start_node)
4238     {
4239       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4240                                                        start_tree,
4241                                                        start_node,
4242                                                        end_tree,
4243                                                        end_node,
4244                                                        TRUE,
4245                                                        FALSE,
4246                                                        FALSE);
4247     }
4248   else if (_gtk_rbtree_node_find_offset (start_tree, start_node) <
4249            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_start_tree, tree_view->priv->rubber_band_start_node))
4250     {
4251       /* New node is above the old one; selection became bigger */
4252       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4253                                                        start_tree,
4254                                                        start_node,
4255                                                        tree_view->priv->rubber_band_start_tree,
4256                                                        tree_view->priv->rubber_band_start_node,
4257                                                        TRUE,
4258                                                        FALSE,
4259                                                        TRUE);
4260     }
4261   else if (_gtk_rbtree_node_find_offset (start_tree, start_node) >
4262            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_start_tree, tree_view->priv->rubber_band_start_node))
4263     {
4264       /* New node is below the old one; selection became smaller */
4265       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4266                                                        tree_view->priv->rubber_band_start_tree,
4267                                                        tree_view->priv->rubber_band_start_node,
4268                                                        start_tree,
4269                                                        start_node,
4270                                                        FALSE,
4271                                                        FALSE,
4272                                                        TRUE);
4273     }
4274
4275   tree_view->priv->rubber_band_start_tree = start_tree;
4276   tree_view->priv->rubber_band_start_node = start_node;
4277
4278   /* Next, handle the end area */
4279   if (!tree_view->priv->rubber_band_end_node)
4280     {
4281       /* In the event this happens, start_node was also NULL; this case is
4282        * handled above.
4283        */
4284     }
4285   else if (!end_node)
4286     {
4287       /* Find the last node in the tree */
4288       _gtk_rbtree_find_offset (tree_view->priv->tree, tree_view->priv->height - 1,
4289                                &end_tree, &end_node);
4290
4291       /* Selection reached end of the tree */
4292       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4293                                                        tree_view->priv->rubber_band_end_tree,
4294                                                        tree_view->priv->rubber_band_end_node,
4295                                                        end_tree,
4296                                                        end_node,
4297                                                        TRUE,
4298                                                        TRUE,
4299                                                        FALSE);
4300     }
4301   else if (_gtk_rbtree_node_find_offset (end_tree, end_node) >
4302            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_end_tree, tree_view->priv->rubber_band_end_node))
4303     {
4304       /* New node is below the old one; selection became bigger */
4305       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4306                                                        tree_view->priv->rubber_band_end_tree,
4307                                                        tree_view->priv->rubber_band_end_node,
4308                                                        end_tree,
4309                                                        end_node,
4310                                                        TRUE,
4311                                                        TRUE,
4312                                                        FALSE);
4313     }
4314   else if (_gtk_rbtree_node_find_offset (end_tree, end_node) <
4315            _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_end_tree, tree_view->priv->rubber_band_end_node))
4316     {
4317       /* New node is above the old one; selection became smaller */
4318       gtk_tree_view_update_rubber_band_selection_range (tree_view,
4319                                                        end_tree,
4320                                                        end_node,
4321                                                        tree_view->priv->rubber_band_end_tree,
4322                                                        tree_view->priv->rubber_band_end_node,
4323                                                        FALSE,
4324                                                        TRUE,
4325                                                        FALSE);
4326     }
4327
4328   tree_view->priv->rubber_band_end_tree = end_tree;
4329   tree_view->priv->rubber_band_end_node = end_node;
4330 }
4331
4332 static void
4333 gtk_tree_view_update_rubber_band (GtkTreeView *tree_view)
4334 {
4335   gint x, y;
4336   GdkRectangle old_area;
4337   GdkRectangle new_area;
4338   GdkRectangle common;
4339   cairo_region_t *invalid_region;
4340
4341   old_area.x = MIN (tree_view->priv->press_start_x, tree_view->priv->rubber_band_x);
4342   old_area.y = MIN (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y) - tree_view->priv->dy;
4343   old_area.width = ABS (tree_view->priv->rubber_band_x - tree_view->priv->press_start_x) + 1;
4344   old_area.height = ABS (tree_view->priv->rubber_band_y - tree_view->priv->press_start_y) + 1;
4345
4346   gdk_window_get_pointer (tree_view->priv->bin_window, &x, &y, NULL);
4347
4348   x = MAX (x, 0);
4349   y = MAX (y, 0) + tree_view->priv->dy;
4350
4351   new_area.x = MIN (tree_view->priv->press_start_x, x);
4352   new_area.y = MIN (tree_view->priv->press_start_y, y) - tree_view->priv->dy;
4353   new_area.width = ABS (x - tree_view->priv->press_start_x) + 1;
4354   new_area.height = ABS (y - tree_view->priv->press_start_y) + 1;
4355
4356   invalid_region = cairo_region_create_rectangle (&old_area);
4357   cairo_region_union_rectangle (invalid_region, &new_area);
4358
4359   gdk_rectangle_intersect (&old_area, &new_area, &common);
4360   if (common.width > 2 && common.height > 2)
4361     {
4362       cairo_region_t *common_region;
4363
4364       /* make sure the border is invalidated */
4365       common.x += 1;
4366       common.y += 1;
4367       common.width -= 2;
4368       common.height -= 2;
4369
4370       common_region = cairo_region_create_rectangle (&common);
4371
4372       cairo_region_subtract (invalid_region, common_region);
4373       cairo_region_destroy (common_region);
4374     }
4375
4376   gdk_window_invalidate_region (tree_view->priv->bin_window, invalid_region, TRUE);
4377
4378   cairo_region_destroy (invalid_region);
4379
4380   tree_view->priv->rubber_band_x = x;
4381   tree_view->priv->rubber_band_y = y;
4382
4383   gtk_tree_view_update_rubber_band_selection (tree_view);
4384 }
4385
4386 static void
4387 gtk_tree_view_paint_rubber_band (GtkTreeView  *tree_view,
4388                                  cairo_t      *cr)
4389 {
4390   GdkRectangle rect;
4391   GtkStyleContext *context;
4392
4393   cairo_save (cr);
4394
4395   context = gtk_widget_get_style_context (GTK_WIDGET (tree_view));
4396
4397   gtk_style_context_save (context);
4398   gtk_style_context_add_class (context, GTK_STYLE_CLASS_RUBBERBAND);
4399
4400   rect.x = MIN (tree_view->priv->press_start_x, tree_view->priv->rubber_band_x);
4401   rect.y = MIN (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y) - tree_view->priv->dy;
4402   rect.width = ABS (tree_view->priv->press_start_x - tree_view->priv->rubber_band_x) + 1;
4403   rect.height = ABS (tree_view->priv->press_start_y - tree_view->priv->rubber_band_y) + 1;
4404
4405   gdk_cairo_rectangle (cr, &rect);
4406   cairo_clip (cr);
4407
4408   gtk_render_background (context, cr,
4409                          rect.x, rect.y,
4410                          rect.width, rect.height);
4411   gtk_render_frame (context, cr,
4412                     rect.x, rect.y,
4413                     rect.width, rect.height);
4414
4415   gtk_style_context_restore (context);
4416   cairo_restore (cr);
4417 }
4418
4419 static gboolean
4420 gtk_tree_view_motion_bin_window (GtkWidget      *widget,
4421                                  GdkEventMotion *event)
4422 {
4423   GtkTreeView *tree_view;
4424   GtkRBTree *tree;
4425   GtkRBNode *node;
4426   gint new_y;
4427
4428   tree_view = (GtkTreeView *) widget;
4429
4430   if (tree_view->priv->tree == NULL)
4431     return FALSE;
4432
4433   if (tree_view->priv->rubber_band_status == RUBBER_BAND_MAYBE_START)
4434     {
4435       gtk_grab_add (GTK_WIDGET (tree_view));
4436       gtk_tree_view_update_rubber_band (tree_view);
4437
4438       tree_view->priv->rubber_band_status = RUBBER_BAND_ACTIVE;
4439     }
4440   else if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
4441     {
4442       gtk_tree_view_update_rubber_band (tree_view);
4443
4444       add_scroll_timeout (tree_view);
4445     }
4446
4447   /* only check for an initiated drag when a button is pressed */
4448   if (tree_view->priv->pressed_button >= 0
4449       && !tree_view->priv->rubber_band_status)
4450     gtk_tree_view_maybe_begin_dragging_row (tree_view, event);
4451
4452   new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
4453   if (new_y < 0)
4454     new_y = 0;
4455
4456   _gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
4457
4458   /* If we are currently pressing down a button, we don't want to prelight anything else. */
4459   if ((tree_view->priv->button_pressed_node != NULL) &&
4460       (tree_view->priv->button_pressed_node != node))
4461     node = NULL;
4462
4463   tree_view->priv->event_last_x = event->x;
4464   tree_view->priv->event_last_y = event->y;
4465
4466   prelight_or_select (tree_view, tree, node, event->x, event->y);
4467
4468   return TRUE;
4469 }
4470
4471 static gboolean
4472 gtk_tree_view_motion (GtkWidget      *widget,
4473                       GdkEventMotion *event)
4474 {
4475   GtkTreeView *tree_view;
4476
4477   tree_view = (GtkTreeView *) widget;
4478
4479   /* Resizing a column */
4480   if (tree_view->priv->in_column_resize)
4481     return gtk_tree_view_motion_resize_column (widget, event);
4482
4483   /* Drag column */
4484   if (tree_view->priv->in_column_drag)
4485     return gtk_tree_view_motion_drag_column (widget, event);
4486
4487   /* Sanity check it */
4488   if (event->window == tree_view->priv->bin_window)
4489     return gtk_tree_view_motion_bin_window (widget, event);
4490
4491   return FALSE;
4492 }
4493
4494 /* Invalidate the focus rectangle near the edge of the bin_window; used when
4495  * the tree is empty.
4496  */
4497 static void
4498 invalidate_empty_focus (GtkTreeView *tree_view)
4499 {
4500   GdkRectangle area;
4501
4502   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
4503     return;
4504
4505   area.x = 0;
4506   area.y = 0;
4507   area.width = gdk_window_get_width (tree_view->priv->bin_window);
4508   area.height = gdk_window_get_height (tree_view->priv->bin_window);
4509   gdk_window_invalidate_rect (tree_view->priv->bin_window, &area, FALSE);
4510 }
4511
4512 /* Draws a focus rectangle near the edge of the bin_window; used when the tree
4513  * is empty.
4514  */
4515 static void
4516 draw_empty_focus (GtkTreeView *tree_view, cairo_t *cr)
4517 {
4518   GtkWidget *widget = GTK_WIDGET (tree_view);
4519   gint w, h;
4520
4521   if (!gtk_widget_has_visible_focus (widget))
4522     return;
4523
4524   w = gdk_window_get_width (tree_view->priv->bin_window) - 2;
4525   h = gdk_window_get_height (tree_view->priv->bin_window) - 2;
4526
4527   if (w > 0 && h > 0)
4528     {
4529       GtkStyleContext *context;
4530       GtkStateFlags state;
4531
4532       context = gtk_widget_get_style_context (widget);
4533       state = gtk_widget_get_state_flags (widget);
4534
4535       gtk_style_context_save (context);
4536       gtk_style_context_set_state (context, state);
4537
4538       gtk_render_focus (context, cr, 1, 1, w, h);
4539
4540       gtk_style_context_restore (context);
4541     }
4542 }
4543
4544 typedef enum {
4545   GTK_TREE_VIEW_GRID_LINE,
4546   GTK_TREE_VIEW_TREE_LINE,
4547   GTK_TREE_VIEW_FOREGROUND_LINE
4548 } GtkTreeViewLineType;
4549
4550 static void
4551 gtk_tree_view_draw_line (GtkTreeView         *tree_view,
4552                          cairo_t             *cr,
4553                          GtkTreeViewLineType  type,
4554                          int                  x1,
4555                          int                  y1,
4556                          int                  x2,
4557                          int                  y2)
4558 {
4559   cairo_save (cr);
4560
4561   switch (type)
4562     {
4563     case GTK_TREE_VIEW_TREE_LINE:
4564       cairo_set_source_rgb (cr, 0, 0, 0);
4565       cairo_set_line_width (cr, tree_view->priv->tree_line_width);
4566       if (tree_view->priv->tree_line_dashes[0])
4567         cairo_set_dash (cr, 
4568                         tree_view->priv->tree_line_dashes,
4569                         2, 0.5);
4570       break;
4571     case GTK_TREE_VIEW_GRID_LINE:
4572       cairo_set_source_rgb (cr, 0, 0, 0);
4573       cairo_set_line_width (cr, tree_view->priv->grid_line_width);
4574       if (tree_view->priv->grid_line_dashes[0])
4575         cairo_set_dash (cr, 
4576                         tree_view->priv->grid_line_dashes,
4577                         2, 0.5);
4578       break;
4579     default:
4580       g_assert_not_reached ();
4581       /* fall through */
4582     case GTK_TREE_VIEW_FOREGROUND_LINE:
4583       {
4584         GtkStyleContext *context;
4585         GtkStateFlags state;
4586         GdkRGBA color;
4587
4588         context = gtk_widget_get_style_context (GTK_WIDGET (tree_view));
4589         state = gtk_widget_get_state_flags (GTK_WIDGET (tree_view));
4590
4591         cairo_set_line_width (cr, 1.0);
4592         gtk_style_context_get_color (context, state, &color);
4593         gdk_cairo_set_source_rgba (cr, &color);
4594       }
4595
4596       break;
4597     }
4598
4599   cairo_move_to (cr, x1 + 0.5, y1 + 0.5);
4600   cairo_line_to (cr, x2 + 0.5, y2 + 0.5);
4601   cairo_stroke (cr);
4602
4603   cairo_restore (cr);
4604 }
4605                          
4606 static void
4607 gtk_tree_view_draw_grid_lines (GtkTreeView    *tree_view,
4608                                cairo_t        *cr,
4609                                gint            n_visible_columns)
4610 {
4611   GList *list = tree_view->priv->columns;
4612   gint i = 0;
4613   gint current_x = 0;
4614
4615   if (tree_view->priv->grid_lines != GTK_TREE_VIEW_GRID_LINES_VERTICAL
4616       && tree_view->priv->grid_lines != GTK_TREE_VIEW_GRID_LINES_BOTH)
4617     return;
4618
4619   /* Only draw the lines for visible rows and columns */
4620   for (list = tree_view->priv->columns; list; list = list->next, i++)
4621     {
4622       GtkTreeViewColumn *column = list->data;
4623
4624       /* We don't want a line for the last column */
4625       if (i == n_visible_columns - 1)
4626         break;
4627
4628       if (!gtk_tree_view_column_get_visible (column))
4629         continue;
4630
4631       current_x += gtk_tree_view_column_get_width (column);
4632
4633       gtk_tree_view_draw_line (tree_view, cr,
4634                                GTK_TREE_VIEW_GRID_LINE,
4635                                current_x - 1, 0,
4636                                current_x - 1, tree_view->priv->height);
4637     }
4638 }
4639
4640 /* Warning: Very scary function.
4641  * Modify at your own risk
4642  *
4643  * KEEP IN SYNC WITH gtk_tree_view_create_row_drag_icon()!
4644  * FIXME: It's not...
4645  */
4646 static gboolean
4647 gtk_tree_view_bin_draw (GtkWidget      *widget,
4648                         cairo_t        *cr)
4649 {
4650   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
4651   GtkTreePath *path;
4652   GtkRBTree *tree;
4653   GList *list;
4654   GtkRBNode *node;
4655   GtkRBNode *cursor = NULL;
4656   GtkRBTree *cursor_tree = NULL;
4657   GtkRBNode *drag_highlight = NULL;
4658   GtkRBTree *drag_highlight_tree = NULL;
4659   GtkTreeIter iter;
4660   gint new_y;
4661   gint y_offset, cell_offset;
4662   gint max_height;
4663   gint depth;
4664   GdkRectangle background_area;
4665   GdkRectangle cell_area;
4666   GdkRectangle clip;
4667   guint flags;
4668   gint highlight_x;
4669   gint expander_cell_width;
4670   gint bin_window_width;
4671   gint bin_window_height;
4672   GtkTreePath *cursor_path;
4673   GtkTreePath *drag_dest_path;
4674   GList *first_column, *last_column;
4675   gint vertical_separator;
4676   gint horizontal_separator;
4677   gint focus_line_width;
4678   gboolean allow_rules;
4679   gboolean has_can_focus_cell;
4680   gboolean rtl;
4681   gint n_visible_columns;
4682   gint pointer_x, pointer_y;
4683   gint grid_line_width;
4684   gboolean got_pointer = FALSE;
4685   gboolean draw_vgrid_lines, draw_hgrid_lines;
4686   GtkStyleContext *context;
4687   GtkStateFlags state;
4688
4689   rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
4690   context = gtk_widget_get_style_context (widget);
4691   state = gtk_widget_get_state_flags (widget);
4692
4693   gtk_widget_style_get (widget,
4694                         "horizontal-separator", &horizontal_separator,
4695                         "vertical-separator", &vertical_separator,
4696                         "allow-rules", &allow_rules,
4697                         "focus-line-width", &focus_line_width,
4698                         NULL);
4699
4700   if (tree_view->priv->tree == NULL)
4701     {
4702       draw_empty_focus (tree_view, cr);
4703       return TRUE;
4704     }
4705
4706   bin_window_width = gdk_window_get_width (tree_view->priv->bin_window);
4707   bin_window_height = gdk_window_get_height (tree_view->priv->bin_window);
4708   cairo_rectangle (cr, 0, 0, bin_window_width, bin_window_height);
4709   cairo_clip (cr);
4710   if (!gdk_cairo_get_clip_rectangle (cr, &clip))
4711     return TRUE;
4712
4713   new_y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, clip.y);
4714
4715   if (new_y < 0)
4716     new_y = 0;
4717   y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
4718
4719   if (tree_view->priv->height < bin_window_height)
4720     {
4721       gtk_style_context_save (context);
4722       gtk_style_context_set_state (context, state);
4723       gtk_style_context_add_class (context, GTK_STYLE_CLASS_CELL);
4724
4725       gtk_render_background (context, cr,
4726                              0, tree_view->priv->height,
4727                              bin_window_width,
4728                              bin_window_height - tree_view->priv->height);
4729
4730       gtk_style_context_restore (context);
4731     }
4732
4733   if (node == NULL)
4734     return TRUE;
4735
4736   /* find the path for the node */
4737   path = _gtk_tree_view_find_path ((GtkTreeView *)widget,
4738                                    tree,
4739                                    node);
4740   gtk_tree_model_get_iter (tree_view->priv->model,
4741                            &iter,
4742                            path);
4743   depth = gtk_tree_path_get_depth (path);
4744   gtk_tree_path_free (path);
4745   
4746   cursor_path = NULL;
4747   drag_dest_path = NULL;
4748
4749   if (tree_view->priv->cursor)
4750     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
4751
4752   if (cursor_path)
4753     _gtk_tree_view_find_node (tree_view, cursor_path,
4754                               &cursor_tree, &cursor);
4755
4756   if (tree_view->priv->drag_dest_row)
4757     drag_dest_path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
4758
4759   if (drag_dest_path)
4760     _gtk_tree_view_find_node (tree_view, drag_dest_path,
4761                               &drag_highlight_tree, &drag_highlight);
4762
4763   draw_vgrid_lines =
4764     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_VERTICAL
4765     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
4766   draw_hgrid_lines =
4767     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_HORIZONTAL
4768     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
4769
4770   if (draw_vgrid_lines || draw_hgrid_lines)
4771     gtk_widget_style_get (widget, "grid-line-width", &grid_line_width, NULL);
4772   
4773   n_visible_columns = 0;
4774   for (list = tree_view->priv->columns; list; list = list->next)
4775     {
4776       if (!gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (list->data)))
4777         continue;
4778       n_visible_columns ++;
4779     }
4780
4781   /* Find the last column */
4782   for (last_column = g_list_last (tree_view->priv->columns);
4783        last_column &&
4784        !(gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (last_column->data)));
4785        last_column = last_column->prev)
4786     ;
4787
4788   /* and the first */
4789   for (first_column = g_list_first (tree_view->priv->columns);
4790        first_column &&
4791        !(gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (first_column->data)));
4792        first_column = first_column->next)
4793     ;
4794
4795   /* Actually process the expose event.  To do this, we want to
4796    * start at the first node of the event, and walk the tree in
4797    * order, drawing each successive node.
4798    */
4799
4800   do
4801     {
4802       gboolean parity;
4803       gboolean is_separator = FALSE;
4804       gboolean is_first = FALSE;
4805       gboolean is_last = FALSE;
4806       gint n_col = 0;
4807
4808       is_separator = row_is_separator (tree_view, &iter, NULL);
4809
4810       max_height = gtk_tree_view_get_row_height (tree_view, node);
4811
4812       cell_offset = 0;
4813       highlight_x = 0; /* should match x coord of first cell */
4814       expander_cell_width = 0;
4815
4816       background_area.y = y_offset + clip.y;
4817       background_area.height = max_height;
4818
4819       flags = 0;
4820
4821       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PRELIT))
4822         flags |= GTK_CELL_RENDERER_PRELIT;
4823
4824       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
4825         flags |= GTK_CELL_RENDERER_SELECTED;
4826
4827       parity = _gtk_rbtree_node_find_parity (tree, node);
4828
4829       /* we *need* to set cell data on all cells before the call
4830        * to _has_can_focus_cell, else _has_can_focus_cell() does not
4831        * return a correct value.
4832        */
4833       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
4834            list;
4835            list = (rtl ? list->prev : list->next))
4836         {
4837           GtkTreeViewColumn *column = list->data;
4838           gtk_tree_view_column_cell_set_cell_data (column,
4839                                                    tree_view->priv->model,
4840                                                    &iter,
4841                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
4842                                                    node->children?TRUE:FALSE);
4843         }
4844
4845       has_can_focus_cell = gtk_tree_view_has_can_focus_cell (tree_view);
4846
4847       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
4848            list;
4849            list = (rtl ? list->prev : list->next))
4850         {
4851           GtkTreeViewColumn *column = list->data;
4852           GtkRegionFlags row_flags = 0, column_flags = 0;
4853           GtkStateFlags state = 0;
4854           gint width;
4855           gboolean draw_focus;
4856
4857           if (!gtk_tree_view_column_get_visible (column))
4858             continue;
4859
4860           n_col++;
4861           width = gtk_tree_view_column_get_width (column);
4862
4863           if (cell_offset > clip.x + clip.width ||
4864               cell_offset + width < clip.x)
4865             {
4866               cell_offset += width;
4867               continue;
4868             }
4869
4870           if (gtk_tree_view_column_get_sort_indicator (column))
4871             flags |= GTK_CELL_RENDERER_SORTED;
4872           else
4873             flags &= ~GTK_CELL_RENDERER_SORTED;
4874
4875           if (cursor == node)
4876             flags |= GTK_CELL_RENDERER_FOCUSED;
4877           else
4878             flags &= ~GTK_CELL_RENDERER_FOCUSED;
4879
4880           background_area.x = cell_offset;
4881           background_area.width = width;
4882
4883           cell_area = background_area;
4884           cell_area.y += vertical_separator / 2;
4885           cell_area.x += horizontal_separator / 2;
4886           cell_area.height -= vertical_separator;
4887           cell_area.width -= horizontal_separator;
4888
4889           if (draw_vgrid_lines)
4890             {
4891               if (list == first_column)
4892                 {
4893                   cell_area.width -= grid_line_width / 2;
4894                 }
4895               else if (list == last_column)
4896                 {
4897                   cell_area.x += grid_line_width / 2;
4898                   cell_area.width -= grid_line_width / 2;
4899                 }
4900               else
4901                 {
4902                   cell_area.x += grid_line_width / 2;
4903                   cell_area.width -= grid_line_width;
4904                 }
4905             }
4906
4907           if (draw_hgrid_lines)
4908             {
4909               cell_area.y += grid_line_width / 2;
4910               cell_area.height -= grid_line_width;
4911             }
4912
4913           if (!gdk_rectangle_intersect (&clip, &background_area, NULL))
4914             {
4915               cell_offset += gtk_tree_view_column_get_width (column);
4916               continue;
4917             }
4918
4919           gtk_tree_view_column_cell_set_cell_data (column,
4920                                                    tree_view->priv->model,
4921                                                    &iter,
4922                                                    GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
4923                                                    node->children?TRUE:FALSE);
4924
4925           /* Select the detail for drawing the cell.  relevant
4926            * factors are parity, sortedness, and whether to
4927            * display rules.
4928            */
4929           if (allow_rules && tree_view->priv->has_rules)
4930             {
4931               if (parity)
4932                 row_flags |= GTK_REGION_ODD;
4933               else
4934                 row_flags |= GTK_REGION_EVEN;
4935             }
4936
4937           if ((flags & GTK_CELL_RENDERER_SORTED) &&
4938               n_visible_columns >= 3)
4939             column_flags |= GTK_REGION_SORTED;
4940
4941           is_first = (rtl ? !list->next : !list->prev);
4942           is_last = (rtl ? !list->prev : !list->next);
4943
4944           if (is_first)
4945             column_flags |= GTK_REGION_FIRST;
4946
4947           if (is_last)
4948             column_flags |= GTK_REGION_LAST;
4949
4950           if ((n_col % 2) == 0)
4951             column_flags |= GTK_REGION_EVEN;
4952           else
4953             column_flags |= GTK_REGION_ODD;
4954
4955           gtk_style_context_save (context);
4956
4957           state = gtk_cell_renderer_get_state (NULL, widget, flags);
4958           gtk_style_context_set_state (context, state);
4959
4960           gtk_style_context_add_class (context, GTK_STYLE_CLASS_CELL);
4961           gtk_style_context_add_region (context, GTK_STYLE_REGION_ROW, row_flags);
4962           gtk_style_context_add_region (context, GTK_STYLE_REGION_COLUMN, column_flags);
4963
4964           if (node == cursor && has_can_focus_cell
4965               && ((column == tree_view->priv->focus_column
4966                    && tree_view->priv->draw_keyfocus &&
4967                    gtk_widget_has_visible_focus (widget))
4968                   || (column == tree_view->priv->edited_column)))
4969             draw_focus = TRUE;
4970           else
4971             draw_focus = FALSE;
4972
4973           /* Draw background */
4974           gtk_render_background (context, cr,
4975                                  background_area.x,
4976                                  background_area.y,
4977                                  background_area.width,
4978                                  background_area.height);
4979
4980           /* Draw frame */
4981           gtk_render_frame (context, cr,
4982                             background_area.x,
4983                             background_area.y,
4984                             background_area.width,
4985                             background_area.height);
4986
4987           if (gtk_tree_view_is_expander_column (tree_view, column))
4988             {
4989               if (!rtl)
4990                 cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
4991               cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
4992
4993               if (gtk_tree_view_draw_expanders (tree_view))
4994                 {
4995                   if (!rtl)
4996                     cell_area.x += depth * tree_view->priv->expander_size;
4997                   cell_area.width -= depth * tree_view->priv->expander_size;
4998                 }
4999
5000               /* If we have an expander column, the highlight underline
5001                * starts with that column, so that it indicates which
5002                * level of the tree we're dropping at.
5003                */
5004               highlight_x = cell_area.x;
5005               expander_cell_width = cell_area.width;
5006
5007               if (is_separator)
5008                 {
5009                   gtk_style_context_save (context);
5010                   gtk_style_context_add_class (context, GTK_STYLE_CLASS_SEPARATOR);
5011
5012                   gtk_render_line (context, cr,
5013                                    cell_area.x,
5014                                    cell_area.y + cell_area.height / 2,
5015                                    cell_area.x + cell_area.width,
5016                                    cell_area.y + cell_area.height / 2);
5017
5018                   gtk_style_context_restore (context);
5019                 }
5020               else
5021                 {
5022                   _gtk_tree_view_column_cell_render (column,
5023                                                      cr,
5024                                                      &background_area,
5025                                                      &cell_area,
5026                                                      flags,
5027                                                      draw_focus);
5028                 }
5029
5030               if (gtk_tree_view_draw_expanders (tree_view)
5031                   && (node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT)
5032                 {
5033                   if (!got_pointer)
5034                     {
5035                       gdk_window_get_pointer (tree_view->priv->bin_window, 
5036                                               &pointer_x, &pointer_y, NULL);
5037                       got_pointer = TRUE;
5038                     }
5039
5040                   gtk_tree_view_draw_arrow (GTK_TREE_VIEW (widget),
5041                                             cr,
5042                                             tree,
5043                                             node,
5044                                             pointer_x, pointer_y);
5045                 }
5046             }
5047           else
5048             {
5049               if (is_separator)
5050                 {
5051                   gtk_style_context_save (context);
5052                   gtk_style_context_add_class (context, GTK_STYLE_CLASS_SEPARATOR);
5053
5054                   gtk_render_line (context, cr,
5055                                    cell_area.x,
5056                                    cell_area.y + cell_area.height / 2,
5057                                    cell_area.x + cell_area.width,
5058                                    cell_area.y + cell_area.height / 2);
5059
5060                   gtk_style_context_restore (context);
5061                 }
5062               else
5063                 _gtk_tree_view_column_cell_render (column,
5064                                                    cr,
5065                                                    &background_area,
5066                                                    &cell_area,
5067                                                    flags,
5068                                                    draw_focus);
5069             }
5070
5071           if (draw_hgrid_lines)
5072             {
5073               if (background_area.y > 0)
5074                 gtk_tree_view_draw_line (tree_view, cr,
5075                                          GTK_TREE_VIEW_GRID_LINE,
5076                                          background_area.x, background_area.y,
5077                                          background_area.x + background_area.width,
5078                                          background_area.y);
5079
5080               if (y_offset + max_height >= clip.height)
5081                 gtk_tree_view_draw_line (tree_view, cr,
5082                                          GTK_TREE_VIEW_GRID_LINE,
5083                                          background_area.x, background_area.y + max_height,
5084                                          background_area.x + background_area.width,
5085                                          background_area.y + max_height);
5086             }
5087
5088           if (gtk_tree_view_is_expander_column (tree_view, column) &&
5089               tree_view->priv->tree_lines_enabled)
5090             {
5091               gint x = background_area.x;
5092               gint mult = rtl ? -1 : 1;
5093               gint y0 = background_area.y;
5094               gint y1 = background_area.y + background_area.height/2;
5095               gint y2 = background_area.y + background_area.height;
5096
5097               if (rtl)
5098                 x += background_area.width - 1;
5099
5100               if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT
5101                   && depth > 1)
5102                 {
5103                   gtk_tree_view_draw_line (tree_view, cr,
5104                                            GTK_TREE_VIEW_TREE_LINE,
5105                                            x + tree_view->priv->expander_size * (depth - 1.5) * mult,
5106                                            y1,
5107                                            x + tree_view->priv->expander_size * (depth - 1.1) * mult,
5108                                            y1);
5109                 }
5110               else if (depth > 1)
5111                 {
5112                   gtk_tree_view_draw_line (tree_view, cr,
5113                                            GTK_TREE_VIEW_TREE_LINE,
5114                                            x + tree_view->priv->expander_size * (depth - 1.5) * mult,
5115                                            y1,
5116                                            x + tree_view->priv->expander_size * (depth - 0.5) * mult,
5117                                            y1);
5118                 }
5119
5120               if (depth > 1)
5121                 {
5122                   gint i;
5123                   GtkRBNode *tmp_node;
5124                   GtkRBTree *tmp_tree;
5125
5126                   if (!_gtk_rbtree_next (tree, node))
5127                     gtk_tree_view_draw_line (tree_view, cr,
5128                                              GTK_TREE_VIEW_TREE_LINE,
5129                                              x + tree_view->priv->expander_size * (depth - 1.5) * mult,
5130                                              y0,
5131                                              x + tree_view->priv->expander_size * (depth - 1.5) * mult,
5132                                              y1);
5133                   else
5134                     gtk_tree_view_draw_line (tree_view, cr,
5135                                              GTK_TREE_VIEW_TREE_LINE,
5136                                              x + tree_view->priv->expander_size * (depth - 1.5) * mult,
5137                                              y0,
5138                                              x + tree_view->priv->expander_size * (depth - 1.5) * mult,
5139                                              y2);
5140
5141                   tmp_node = tree->parent_node;
5142                   tmp_tree = tree->parent_tree;
5143
5144                   for (i = depth - 2; i > 0; i--)
5145                     {
5146                       if (_gtk_rbtree_next (tmp_tree, tmp_node))
5147                         gtk_tree_view_draw_line (tree_view, cr,
5148                                                  GTK_TREE_VIEW_TREE_LINE,
5149                                                  x + tree_view->priv->expander_size * (i - 0.5) * mult,
5150                                                  y0,
5151                                                  x + tree_view->priv->expander_size * (i - 0.5) * mult,
5152                                                  y2);
5153
5154                       tmp_node = tmp_tree->parent_node;
5155                       tmp_tree = tmp_tree->parent_tree;
5156                     }
5157                 }
5158             }
5159
5160           gtk_style_context_restore (context);
5161           cell_offset += gtk_tree_view_column_get_width (column);
5162         }
5163
5164       if (node == drag_highlight)
5165         {
5166           /* Draw indicator for the drop
5167            */
5168           gint highlight_y = -1;
5169           GtkRBTree *tree = NULL;
5170           GtkRBNode *node = NULL;
5171
5172           switch (tree_view->priv->drag_dest_pos)
5173             {
5174             case GTK_TREE_VIEW_DROP_BEFORE:
5175               highlight_y = background_area.y - 1;
5176               if (highlight_y < 0)
5177                       highlight_y = 0;
5178               break;
5179
5180             case GTK_TREE_VIEW_DROP_AFTER:
5181               highlight_y = background_area.y + background_area.height - 1;
5182               break;
5183
5184             case GTK_TREE_VIEW_DROP_INTO_OR_BEFORE:
5185             case GTK_TREE_VIEW_DROP_INTO_OR_AFTER:
5186               _gtk_tree_view_find_node (tree_view, drag_dest_path, &tree, &node);
5187
5188               if (tree == NULL)
5189                 break;
5190
5191               gtk_render_focus (context, cr,
5192                                 0, gtk_tree_view_get_row_y_offset (tree_view, tree, node)
5193                                    - focus_line_width / 2,
5194                                 gdk_window_get_width (tree_view->priv->bin_window),
5195                                 gtk_tree_view_get_row_height (tree_view, node)
5196                                    - focus_line_width + 1);
5197               break;
5198             }
5199
5200           if (highlight_y >= 0)
5201             {
5202               gtk_tree_view_draw_line (tree_view, cr,
5203                                        GTK_TREE_VIEW_FOREGROUND_LINE,
5204                                        rtl ? highlight_x + expander_cell_width : highlight_x,
5205                                        highlight_y,
5206                                        rtl ? 0 : bin_window_width,
5207                                        highlight_y);
5208             }
5209         }
5210
5211       /* draw the big row-spanning focus rectangle, if needed */
5212       if (!has_can_focus_cell && node == cursor &&
5213           tree_view->priv->draw_keyfocus &&
5214           gtk_widget_has_visible_focus (widget))
5215         {
5216           gint tmp_y, tmp_height;
5217           GtkStateFlags focus_rect_state = 0;
5218
5219           gtk_style_context_save (context);
5220
5221           focus_rect_state = gtk_cell_renderer_get_state (NULL, widget, flags);
5222           gtk_style_context_set_state (context, focus_rect_state);
5223
5224           if (draw_hgrid_lines)
5225             {
5226               tmp_y = gtk_tree_view_get_row_y_offset (tree_view, tree, node) + grid_line_width / 2;
5227               tmp_height = gtk_tree_view_get_row_height (tree_view, node) - grid_line_width;
5228             }
5229           else
5230             {
5231               tmp_y = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
5232               tmp_height = gtk_tree_view_get_row_height (tree_view, node);
5233             }
5234
5235           gtk_render_focus (context, cr,
5236                             0, tmp_y,
5237                             gdk_window_get_width (tree_view->priv->bin_window),
5238                             tmp_height);
5239
5240           gtk_style_context_restore (context);
5241         }
5242
5243       y_offset += max_height;
5244       if (node->children)
5245         {
5246           GtkTreeIter parent = iter;
5247           gboolean has_child;
5248
5249           tree = node->children;
5250           node = tree->root;
5251
5252           g_assert (node != tree->nil);
5253
5254           while (node->left != tree->nil)
5255             node = node->left;
5256           has_child = gtk_tree_model_iter_children (tree_view->priv->model,
5257                                                     &iter,
5258                                                     &parent);
5259           depth++;
5260
5261           /* Sanity Check! */
5262           TREE_VIEW_INTERNAL_ASSERT (has_child, FALSE);
5263         }
5264       else
5265         {
5266           gboolean done = FALSE;
5267
5268           do
5269             {
5270               node = _gtk_rbtree_next (tree, node);
5271               if (node != NULL)
5272                 {
5273                   gboolean has_next = gtk_tree_model_iter_next (tree_view->priv->model, &iter);
5274                   done = TRUE;
5275
5276                   /* Sanity Check! */
5277                   TREE_VIEW_INTERNAL_ASSERT (has_next, FALSE);
5278                 }
5279               else
5280                 {
5281                   GtkTreeIter parent_iter = iter;
5282                   gboolean has_parent;
5283
5284                   node = tree->parent_node;
5285                   tree = tree->parent_tree;
5286                   if (tree == NULL)
5287                     /* we should go to done to free some memory */
5288                     goto done;
5289                   has_parent = gtk_tree_model_iter_parent (tree_view->priv->model,
5290                                                            &iter,
5291                                                            &parent_iter);
5292                   depth--;
5293
5294                   /* Sanity check */
5295                   TREE_VIEW_INTERNAL_ASSERT (has_parent, FALSE);
5296                 }
5297             }
5298           while (!done);
5299         }
5300     }
5301   while (y_offset < clip.height);
5302
5303 done:
5304   gtk_tree_view_draw_grid_lines (tree_view, cr, n_visible_columns);
5305
5306   if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
5307     gtk_tree_view_paint_rubber_band (tree_view, cr);
5308
5309   if (cursor_path)
5310     gtk_tree_path_free (cursor_path);
5311
5312   if (drag_dest_path)
5313     gtk_tree_path_free (drag_dest_path);
5314
5315   return FALSE;
5316 }
5317
5318 static gboolean
5319 gtk_tree_view_draw (GtkWidget *widget,
5320                     cairo_t   *cr)
5321 {
5322   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
5323   GtkWidget   *button;
5324
5325   if (gtk_cairo_should_draw_window (cr, tree_view->priv->bin_window))
5326     {
5327       GtkStyleContext *context;
5328       GList *tmp_list;
5329
5330       context = gtk_widget_get_style_context (widget);
5331
5332       cairo_save (cr);
5333
5334       gtk_style_context_save (context);
5335       gtk_style_context_add_class (context, GTK_STYLE_CLASS_VIEW);
5336
5337       gtk_cairo_transform_to_window (cr, widget, tree_view->priv->bin_window);
5338
5339       gtk_tree_view_bin_draw (widget, cr);
5340
5341       gtk_style_context_restore (context);
5342       cairo_restore (cr);
5343
5344       /* We can't just chain up to Container::draw as it will try to send the
5345        * event to the headers, so we handle propagating it to our children
5346        * (eg. widgets being edited) ourselves.
5347        */
5348       tmp_list = tree_view->priv->children;
5349       while (tmp_list)
5350         {
5351           GtkTreeViewChild *child = tmp_list->data;
5352           tmp_list = tmp_list->next;
5353
5354           gtk_container_propagate_draw (GTK_CONTAINER (tree_view), child->widget, cr);
5355         }
5356     }
5357
5358   if (gtk_cairo_should_draw_window (cr, tree_view->priv->header_window))
5359     {
5360       GList *list;
5361       
5362       for (list = tree_view->priv->columns; list != NULL; list = list->next)
5363         {
5364           GtkTreeViewColumn *column = list->data;
5365
5366           if (column == tree_view->priv->drag_column)
5367             continue;
5368
5369           if (gtk_tree_view_column_get_visible (column))
5370             {
5371               button = gtk_tree_view_column_get_button (column);
5372               gtk_container_propagate_draw (GTK_CONTAINER (tree_view),
5373                                             button, cr);
5374             }
5375         }
5376     }
5377   
5378   if (tree_view->priv->drag_window &&
5379       gtk_cairo_should_draw_window (cr, tree_view->priv->drag_window))
5380     {
5381       button = gtk_tree_view_column_get_button (tree_view->priv->drag_column);
5382       gtk_container_propagate_draw (GTK_CONTAINER (tree_view),
5383                                     button, cr);
5384     }
5385
5386   return FALSE;
5387 }
5388
5389 enum
5390 {
5391   DROP_HOME,
5392   DROP_RIGHT,
5393   DROP_LEFT,
5394   DROP_END
5395 };
5396
5397 /* returns 0x1 when no column has been found -- yes it's hackish */
5398 static GtkTreeViewColumn *
5399 gtk_tree_view_get_drop_column (GtkTreeView       *tree_view,
5400                                GtkTreeViewColumn *column,
5401                                gint               drop_position)
5402 {
5403   GtkTreeViewColumn *left_column = NULL;
5404   GtkTreeViewColumn *cur_column = NULL;
5405   GList *tmp_list;
5406
5407   if (!gtk_tree_view_column_get_reorderable (column))
5408     return (GtkTreeViewColumn *)0x1;
5409
5410   switch (drop_position)
5411     {
5412       case DROP_HOME:
5413         /* find first column where we can drop */
5414         tmp_list = tree_view->priv->columns;
5415         if (column == GTK_TREE_VIEW_COLUMN (tmp_list->data))
5416           return (GtkTreeViewColumn *)0x1;
5417
5418         while (tmp_list)
5419           {
5420             g_assert (tmp_list);
5421
5422             cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5423             tmp_list = tmp_list->next;
5424
5425             if (left_column &&
5426                 gtk_tree_view_column_get_visible (left_column) == FALSE)
5427               continue;
5428
5429             if (!tree_view->priv->column_drop_func)
5430               return left_column;
5431
5432             if (!tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5433               {
5434                 left_column = cur_column;
5435                 continue;
5436               }
5437
5438             return left_column;
5439           }
5440
5441         if (!tree_view->priv->column_drop_func)
5442           return left_column;
5443
5444         if (tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data))
5445           return left_column;
5446         else
5447           return (GtkTreeViewColumn *)0x1;
5448         break;
5449
5450       case DROP_RIGHT:
5451         /* find first column after column where we can drop */
5452         tmp_list = tree_view->priv->columns;
5453
5454         for (; tmp_list; tmp_list = tmp_list->next)
5455           if (GTK_TREE_VIEW_COLUMN (tmp_list->data) == column)
5456             break;
5457
5458         if (!tmp_list || !tmp_list->next)
5459           return (GtkTreeViewColumn *)0x1;
5460
5461         tmp_list = tmp_list->next;
5462         left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5463         tmp_list = tmp_list->next;
5464
5465         while (tmp_list)
5466           {
5467             g_assert (tmp_list);
5468
5469             cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5470             tmp_list = tmp_list->next;
5471
5472             if (left_column &&
5473                 gtk_tree_view_column_get_visible (left_column) == FALSE)
5474               {
5475                 left_column = cur_column;
5476                 if (tmp_list)
5477                   tmp_list = tmp_list->next;
5478                 continue;
5479               }
5480
5481             if (!tree_view->priv->column_drop_func)
5482               return left_column;
5483
5484             if (!tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5485               {
5486                 left_column = cur_column;
5487                 continue;
5488               }
5489
5490             return left_column;
5491           }
5492
5493         if (!tree_view->priv->column_drop_func)
5494           return left_column;
5495
5496         if (tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data))
5497           return left_column;
5498         else
5499           return (GtkTreeViewColumn *)0x1;
5500         break;
5501
5502       case DROP_LEFT:
5503         /* find first column before column where we can drop */
5504         tmp_list = tree_view->priv->columns;
5505
5506         for (; tmp_list; tmp_list = tmp_list->next)
5507           if (GTK_TREE_VIEW_COLUMN (tmp_list->data) == column)
5508             break;
5509
5510         if (!tmp_list || !tmp_list->prev)
5511           return (GtkTreeViewColumn *)0x1;
5512
5513         tmp_list = tmp_list->prev;
5514         cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5515         tmp_list = tmp_list->prev;
5516
5517         while (tmp_list)
5518           {
5519             g_assert (tmp_list);
5520
5521             left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5522
5523             if (left_column &&
5524                 gtk_tree_view_column_get_visible (left_column) == FALSE)
5525               {
5526                 /*if (!tmp_list->prev)
5527                   return (GtkTreeViewColumn *)0x1;
5528                   */
5529 /*
5530                 cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->prev->data);
5531                 tmp_list = tmp_list->prev->prev;
5532                 continue;*/
5533
5534                 cur_column = left_column;
5535                 if (tmp_list)
5536                   tmp_list = tmp_list->prev;
5537                 continue;
5538               }
5539
5540             if (!tree_view->priv->column_drop_func)
5541               return left_column;
5542
5543             if (tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5544               return left_column;
5545
5546             cur_column = left_column;
5547             tmp_list = tmp_list->prev;
5548           }
5549
5550         if (!tree_view->priv->column_drop_func)
5551           return NULL;
5552
5553         if (tree_view->priv->column_drop_func (tree_view, column, NULL, cur_column, tree_view->priv->column_drop_func_data))
5554           return NULL;
5555         else
5556           return (GtkTreeViewColumn *)0x1;
5557         break;
5558
5559       case DROP_END:
5560         /* same as DROP_HOME case, but doing it backwards */
5561         tmp_list = g_list_last (tree_view->priv->columns);
5562         cur_column = NULL;
5563
5564         if (column == GTK_TREE_VIEW_COLUMN (tmp_list->data))
5565           return (GtkTreeViewColumn *)0x1;
5566
5567         while (tmp_list)
5568           {
5569             g_assert (tmp_list);
5570
5571             left_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
5572
5573             if (left_column &&
5574                 gtk_tree_view_column_get_visible (left_column) == FALSE)
5575               {
5576                 cur_column = left_column;
5577                 tmp_list = tmp_list->prev;
5578               }
5579
5580             if (!tree_view->priv->column_drop_func)
5581               return left_column;
5582
5583             if (tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
5584               return left_column;
5585
5586             cur_column = left_column;
5587             tmp_list = tmp_list->prev;
5588           }
5589
5590         if (!tree_view->priv->column_drop_func)
5591           return NULL;
5592
5593         if (tree_view->priv->column_drop_func (tree_view, column, NULL, cur_column, tree_view->priv->column_drop_func_data))
5594           return NULL;
5595         else
5596           return (GtkTreeViewColumn *)0x1;
5597         break;
5598     }
5599
5600   return (GtkTreeViewColumn *)0x1;
5601 }
5602
5603 static gboolean
5604 gtk_tree_view_key_press (GtkWidget   *widget,
5605                          GdkEventKey *event)
5606 {
5607   GtkTreeView *tree_view = (GtkTreeView *) widget;
5608   GtkWidget   *button;
5609
5610   if (tree_view->priv->rubber_band_status)
5611     {
5612       if (event->keyval == GDK_KEY_Escape)
5613         gtk_tree_view_stop_rubber_band (tree_view);
5614
5615       return TRUE;
5616     }
5617
5618   if (tree_view->priv->in_column_drag)
5619     {
5620       if (event->keyval == GDK_KEY_Escape)
5621         {
5622           tree_view->priv->cur_reorder = NULL;
5623           gtk_tree_view_button_release_drag_column (widget, NULL);
5624         }
5625       return TRUE;
5626     }
5627
5628   if (tree_view->priv->headers_visible)
5629     {
5630       GList *focus_column;
5631       gboolean rtl;
5632
5633       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
5634
5635       for (focus_column = tree_view->priv->columns;
5636            focus_column;
5637            focus_column = focus_column->next)
5638         {
5639           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
5640           
5641           button = gtk_tree_view_column_get_button (column);
5642           if (gtk_widget_has_focus (button))
5643             break;
5644         }
5645
5646       if (focus_column &&
5647           (event->state & GDK_SHIFT_MASK) && (event->state & GDK_MOD1_MASK) &&
5648           (event->keyval == GDK_KEY_Left || event->keyval == GDK_KEY_KP_Left
5649            || event->keyval == GDK_KEY_Right || event->keyval == GDK_KEY_KP_Right))
5650         {
5651           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
5652           gint max_width, min_width;
5653
5654           if (!gtk_tree_view_column_get_resizable (column))
5655             {
5656               gtk_widget_error_bell (widget);
5657               return TRUE;
5658             }
5659
5660           if (event->keyval == (rtl ? GDK_KEY_Right : GDK_KEY_Left)
5661               || event->keyval == (rtl ? GDK_KEY_KP_Right : GDK_KEY_KP_Left))
5662             {
5663               GtkRequisition button_req;
5664               gint old_width = _gtk_tree_view_column_get_resized_width (column);
5665               gint new_width;
5666
5667               button = gtk_tree_view_column_get_button (column);
5668
5669               gtk_widget_get_preferred_size (button, &button_req, NULL);
5670
5671               new_width = MAX (old_width, gtk_tree_view_column_get_width (column));
5672               new_width -= 2;
5673               if (new_width < 0)
5674                 new_width = 0;
5675
5676               _gtk_tree_view_column_set_resized_width (column, new_width);
5677
5678               min_width = gtk_tree_view_column_get_min_width (column);
5679               if (min_width == -1)
5680                 new_width = MAX (button_req.width, new_width);
5681               else
5682                 {
5683                   new_width = MAX (min_width, new_width);
5684                 }
5685
5686               max_width = gtk_tree_view_column_get_max_width (column);
5687               if (max_width != -1)
5688                 new_width = MIN (new_width, max_width);
5689
5690               _gtk_tree_view_column_set_use_resized_width (column, TRUE);
5691
5692               if (new_width != old_width)
5693                 {
5694                   _gtk_tree_view_column_set_resized_width (column, new_width);
5695                   gtk_widget_queue_resize (widget);
5696                 }
5697               else
5698                 gtk_widget_error_bell (widget);
5699             }
5700           else if (event->keyval == (rtl ? GDK_KEY_Left : GDK_KEY_Right)
5701                    || event->keyval == (rtl ? GDK_KEY_KP_Left : GDK_KEY_KP_Right))
5702             {
5703               gint old_width = _gtk_tree_view_column_get_resized_width (column);
5704               gint new_width;
5705
5706               new_width = MAX (old_width, gtk_tree_view_column_get_width (column));
5707               new_width += 2;
5708
5709               max_width = gtk_tree_view_column_get_max_width (column);
5710               if (max_width != -1)
5711                 new_width = MIN (new_width, max_width);
5712
5713               _gtk_tree_view_column_set_use_resized_width (column, TRUE);
5714
5715               if (new_width != old_width)
5716                 {
5717                   _gtk_tree_view_column_set_resized_width (column, new_width);
5718                   gtk_widget_queue_resize (widget);
5719                 }
5720               else
5721                 gtk_widget_error_bell (widget);
5722             }
5723
5724           return TRUE;
5725         }
5726
5727       if (focus_column &&
5728           (event->state & GDK_MOD1_MASK) &&
5729           (event->keyval == GDK_KEY_Left || event->keyval == GDK_KEY_KP_Left
5730            || event->keyval == GDK_KEY_Right || event->keyval == GDK_KEY_KP_Right
5731            || event->keyval == GDK_KEY_Home || event->keyval == GDK_KEY_KP_Home
5732            || event->keyval == GDK_KEY_End || event->keyval == GDK_KEY_KP_End))
5733         {
5734           GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
5735
5736           if (event->keyval == (rtl ? GDK_KEY_Right : GDK_KEY_Left)
5737               || event->keyval == (rtl ? GDK_KEY_KP_Right : GDK_KEY_KP_Left))
5738             {
5739               GtkTreeViewColumn *col;
5740               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_LEFT);
5741               if (col != (GtkTreeViewColumn *)0x1)
5742                 gtk_tree_view_move_column_after (tree_view, column, col);
5743               else
5744                 gtk_widget_error_bell (widget);
5745             }
5746           else if (event->keyval == (rtl ? GDK_KEY_Left : GDK_KEY_Right)
5747                    || event->keyval == (rtl ? GDK_KEY_KP_Left : GDK_KEY_KP_Right))
5748             {
5749               GtkTreeViewColumn *col;
5750               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_RIGHT);
5751               if (col != (GtkTreeViewColumn *)0x1)
5752                 gtk_tree_view_move_column_after (tree_view, column, col);
5753               else
5754                 gtk_widget_error_bell (widget);
5755             }
5756           else if (event->keyval == GDK_KEY_Home || event->keyval == GDK_KEY_KP_Home)
5757             {
5758               GtkTreeViewColumn *col;
5759               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_HOME);
5760               if (col != (GtkTreeViewColumn *)0x1)
5761                 gtk_tree_view_move_column_after (tree_view, column, col);
5762               else
5763                 gtk_widget_error_bell (widget);
5764             }
5765           else if (event->keyval == GDK_KEY_End || event->keyval == GDK_KEY_KP_End)
5766             {
5767               GtkTreeViewColumn *col;
5768               col = gtk_tree_view_get_drop_column (tree_view, column, DROP_END);
5769               if (col != (GtkTreeViewColumn *)0x1)
5770                 gtk_tree_view_move_column_after (tree_view, column, col);
5771               else
5772                 gtk_widget_error_bell (widget);
5773             }
5774
5775           return TRUE;
5776         }
5777     }
5778
5779   /* Chain up to the parent class.  It handles the keybindings. */
5780   if (GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->key_press_event (widget, event))
5781     return TRUE;
5782
5783   if (tree_view->priv->search_entry_avoid_unhandled_binding)
5784     {
5785       tree_view->priv->search_entry_avoid_unhandled_binding = FALSE;
5786       return FALSE;
5787     }
5788
5789   /* We pass the event to the search_entry.  If its text changes, then we start
5790    * the typeahead find capabilities. */
5791   if (gtk_widget_has_focus (GTK_WIDGET (tree_view))
5792       && tree_view->priv->enable_search
5793       && !tree_view->priv->search_custom_entry_set)
5794     {
5795       GdkEvent *new_event;
5796       char *old_text;
5797       const char *new_text;
5798       gboolean retval;
5799       GdkScreen *screen;
5800       gboolean text_modified;
5801       gulong popup_menu_id;
5802
5803       gtk_tree_view_ensure_interactive_directory (tree_view);
5804
5805       /* Make a copy of the current text */
5806       old_text = g_strdup (gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry)));
5807       new_event = gdk_event_copy ((GdkEvent *) event);
5808       g_object_unref (((GdkEventKey *) new_event)->window);
5809       ((GdkEventKey *) new_event)->window = g_object_ref (gtk_widget_get_window (tree_view->priv->search_window));
5810       gtk_widget_realize (tree_view->priv->search_window);
5811
5812       popup_menu_id = g_signal_connect (tree_view->priv->search_entry, 
5813                                         "popup-menu", G_CALLBACK (gtk_true),
5814                                         NULL);
5815
5816       /* Move the entry off screen */
5817       screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
5818       gtk_window_move (GTK_WINDOW (tree_view->priv->search_window),
5819                        gdk_screen_get_width (screen) + 1,
5820                        gdk_screen_get_height (screen) + 1);
5821       gtk_widget_show (tree_view->priv->search_window);
5822
5823       /* Send the event to the window.  If the preedit_changed signal is emitted
5824        * during this event, we will set priv->imcontext_changed  */
5825       tree_view->priv->imcontext_changed = FALSE;
5826       retval = gtk_widget_event (tree_view->priv->search_window, new_event);
5827       gdk_event_free (new_event);
5828       gtk_widget_hide (tree_view->priv->search_window);
5829
5830       g_signal_handler_disconnect (tree_view->priv->search_entry, 
5831                                    popup_menu_id);
5832
5833       /* We check to make sure that the entry tried to handle the text, and that
5834        * the text has changed.
5835        */
5836       new_text = gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry));
5837       text_modified = strcmp (old_text, new_text) != 0;
5838       g_free (old_text);
5839       if (tree_view->priv->imcontext_changed ||    /* we're in a preedit */
5840           (retval && text_modified))               /* ...or the text was modified */
5841         {
5842           if (gtk_tree_view_real_start_interactive_search (tree_view,
5843                                                            gdk_event_get_device ((GdkEvent *) event),
5844                                                            FALSE))
5845             {
5846               gtk_widget_grab_focus (GTK_WIDGET (tree_view));
5847               return TRUE;
5848             }
5849           else
5850             {
5851               gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
5852               return FALSE;
5853             }
5854         }
5855     }
5856
5857   return FALSE;
5858 }
5859
5860 static gboolean
5861 gtk_tree_view_key_release (GtkWidget   *widget,
5862                            GdkEventKey *event)
5863 {
5864   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
5865
5866   if (tree_view->priv->rubber_band_status)
5867     return TRUE;
5868
5869   return GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->key_release_event (widget, event);
5870 }
5871
5872 /* FIXME Is this function necessary? Can I get an enter_notify event
5873  * w/o either an expose event or a mouse motion event?
5874  */
5875 static gboolean
5876 gtk_tree_view_enter_notify (GtkWidget        *widget,
5877                             GdkEventCrossing *event)
5878 {
5879   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
5880   GtkRBTree *tree;
5881   GtkRBNode *node;
5882   gint new_y;
5883
5884   /* Sanity check it */
5885   if (event->window != tree_view->priv->bin_window)
5886     return FALSE;
5887
5888   if (tree_view->priv->tree == NULL)
5889     return FALSE;
5890
5891   if (event->mode == GDK_CROSSING_GRAB ||
5892       event->mode == GDK_CROSSING_GTK_GRAB ||
5893       event->mode == GDK_CROSSING_GTK_UNGRAB ||
5894       event->mode == GDK_CROSSING_STATE_CHANGED)
5895     return TRUE;
5896
5897   /* find the node internally */
5898   new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
5899   if (new_y < 0)
5900     new_y = 0;
5901   _gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
5902
5903   tree_view->priv->event_last_x = event->x;
5904   tree_view->priv->event_last_y = event->y;
5905
5906   if ((tree_view->priv->button_pressed_node == NULL) ||
5907       (tree_view->priv->button_pressed_node == node))
5908     prelight_or_select (tree_view, tree, node, event->x, event->y);
5909
5910   return TRUE;
5911 }
5912
5913 static gboolean
5914 gtk_tree_view_leave_notify (GtkWidget        *widget,
5915                             GdkEventCrossing *event)
5916 {
5917   GtkTreeView *tree_view;
5918
5919   if (event->mode == GDK_CROSSING_GRAB)
5920     return TRUE;
5921
5922   tree_view = GTK_TREE_VIEW (widget);
5923
5924   if (tree_view->priv->prelight_node)
5925     _gtk_tree_view_queue_draw_node (tree_view,
5926                                    tree_view->priv->prelight_tree,
5927                                    tree_view->priv->prelight_node,
5928                                    NULL);
5929
5930   tree_view->priv->event_last_x = -10000;
5931   tree_view->priv->event_last_y = -10000;
5932
5933   prelight_or_select (tree_view,
5934                       NULL, NULL,
5935                       -1000, -1000); /* coords not possibly over an arrow */
5936
5937   return TRUE;
5938 }
5939
5940
5941 static gint
5942 gtk_tree_view_focus_out (GtkWidget     *widget,
5943                          GdkEventFocus *event)
5944 {
5945   GtkTreeView *tree_view;
5946
5947   tree_view = GTK_TREE_VIEW (widget);
5948
5949   gtk_widget_queue_draw (widget);
5950
5951   /* destroy interactive search dialog */
5952   if (tree_view->priv->search_window)
5953     gtk_tree_view_search_dialog_hide (tree_view->priv->search_window, tree_view,
5954                                       gdk_event_get_device ((GdkEvent *) event));
5955
5956   return FALSE;
5957 }
5958
5959
5960 /* Incremental Reflow
5961  */
5962
5963 static void
5964 gtk_tree_view_node_queue_redraw (GtkTreeView *tree_view,
5965                                  GtkRBTree   *tree,
5966                                  GtkRBNode   *node)
5967 {
5968   GtkAllocation allocation;
5969   gint y;
5970
5971   y = _gtk_rbtree_node_find_offset (tree, node)
5972     - gtk_adjustment_get_value (tree_view->priv->vadjustment)
5973     + gtk_tree_view_get_effective_header_height (tree_view);
5974
5975   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
5976   gtk_widget_queue_draw_area (GTK_WIDGET (tree_view),
5977                               0, y,
5978                               allocation.width,
5979                               GTK_RBNODE_GET_HEIGHT (node));
5980 }
5981
5982 static gboolean
5983 node_is_visible (GtkTreeView *tree_view,
5984                  GtkRBTree   *tree,
5985                  GtkRBNode   *node)
5986 {
5987   int y;
5988   int height;
5989
5990   y = _gtk_rbtree_node_find_offset (tree, node);
5991   height = gtk_tree_view_get_row_height (tree_view, node);
5992
5993   if (y >= gtk_adjustment_get_value (tree_view->priv->vadjustment) &&
5994       y + height <= (gtk_adjustment_get_value (tree_view->priv->vadjustment)
5995                      + gtk_adjustment_get_page_size (tree_view->priv->vadjustment)))
5996     return TRUE;
5997
5998   return FALSE;
5999 }
6000
6001 /* Returns TRUE if it updated the size
6002  */
6003 static gboolean
6004 validate_row (GtkTreeView *tree_view,
6005               GtkRBTree   *tree,
6006               GtkRBNode   *node,
6007               GtkTreeIter *iter,
6008               GtkTreePath *path)
6009 {
6010   GtkTreeViewColumn *column;
6011   GList *list, *first_column, *last_column;
6012   gint height = 0;
6013   gint horizontal_separator;
6014   gint vertical_separator;
6015   gint depth = gtk_tree_path_get_depth (path);
6016   gboolean retval = FALSE;
6017   gboolean is_separator = FALSE;
6018   gboolean draw_vgrid_lines, draw_hgrid_lines;
6019   gint focus_pad;
6020   gint grid_line_width;
6021   gboolean wide_separators;
6022   gint separator_height;
6023
6024   /* double check the row needs validating */
6025   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) &&
6026       ! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6027     return FALSE;
6028
6029   is_separator = row_is_separator (tree_view, iter, NULL);
6030
6031   gtk_widget_style_get (GTK_WIDGET (tree_view),
6032                         "focus-padding", &focus_pad,
6033                         "horizontal-separator", &horizontal_separator,
6034                         "vertical-separator", &vertical_separator,
6035                         "grid-line-width", &grid_line_width,
6036                         "wide-separators",  &wide_separators,
6037                         "separator-height", &separator_height,
6038                         NULL);
6039   
6040   draw_vgrid_lines =
6041     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_VERTICAL
6042     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
6043   draw_hgrid_lines =
6044     tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_HORIZONTAL
6045     || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH;
6046
6047   for (last_column = g_list_last (tree_view->priv->columns);
6048        last_column &&
6049        !(gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (last_column->data)));
6050        last_column = last_column->prev)
6051     ;
6052
6053   for (first_column = g_list_first (tree_view->priv->columns);
6054        first_column &&
6055        !(gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (first_column->data)));
6056        first_column = first_column->next)
6057     ;
6058
6059   for (list = tree_view->priv->columns; list; list = list->next)
6060     {
6061       gint padding = 0;
6062       gint original_width;
6063       gint new_width;
6064       gint row_height;
6065
6066       column = list->data;
6067
6068       if (!gtk_tree_view_column_get_visible (column))
6069         continue;
6070
6071       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID) && 
6072           !_gtk_tree_view_column_cell_get_dirty (column))
6073         continue;
6074
6075       original_width = _gtk_tree_view_column_get_requested_width (column);
6076
6077       gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, iter,
6078                                                GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
6079                                                node->children?TRUE:FALSE);
6080       gtk_tree_view_column_cell_get_size (column,
6081                                           NULL, NULL, NULL,
6082                                           NULL, &row_height);
6083
6084       if (!is_separator)
6085         {
6086           row_height += vertical_separator;
6087           height = MAX (height, row_height);
6088           height = MAX (height, tree_view->priv->expander_size);
6089         }
6090       else
6091         {
6092           if (wide_separators)
6093             height = separator_height + 2 * focus_pad;
6094           else
6095             height = 2 + 2 * focus_pad;
6096         }
6097
6098       if (gtk_tree_view_is_expander_column (tree_view, column))
6099         {
6100           padding += horizontal_separator + (depth - 1) * tree_view->priv->level_indentation;
6101
6102           if (gtk_tree_view_draw_expanders (tree_view))
6103             padding += depth * tree_view->priv->expander_size;
6104         }
6105       else
6106         padding += horizontal_separator;
6107
6108       if (draw_vgrid_lines)
6109         {
6110           if (list->data == first_column || list->data == last_column)
6111             padding += grid_line_width / 2.0;
6112           else
6113             padding += grid_line_width;
6114         }
6115
6116       /* Update the padding for the column */
6117       _gtk_tree_view_column_push_padding (column, padding);
6118       new_width = _gtk_tree_view_column_get_requested_width (column);
6119
6120       if (new_width > original_width)
6121         retval = TRUE;
6122     }
6123
6124   if (draw_hgrid_lines)
6125     height += grid_line_width;
6126
6127   if (height != GTK_RBNODE_GET_HEIGHT (node))
6128     {
6129       retval = TRUE;
6130       _gtk_rbtree_node_set_height (tree, node, height);
6131     }
6132   _gtk_rbtree_node_mark_valid (tree, node);
6133   tree_view->priv->post_validation_flag = TRUE;
6134
6135   return retval;
6136 }
6137
6138
6139 static void
6140 validate_visible_area (GtkTreeView *tree_view)
6141 {
6142   GtkAllocation allocation;
6143   GtkTreePath *path = NULL;
6144   GtkTreePath *above_path = NULL;
6145   GtkTreeIter iter;
6146   GtkRBTree *tree = NULL;
6147   GtkRBNode *node = NULL;
6148   gboolean need_redraw = FALSE;
6149   gboolean size_changed = FALSE;
6150   gint total_height;
6151   gint area_above = 0;
6152   gint area_below = 0;
6153
6154   if (tree_view->priv->tree == NULL)
6155     return;
6156
6157   if (! GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID) &&
6158       tree_view->priv->scroll_to_path == NULL)
6159     return;
6160
6161   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
6162   total_height = allocation.height - gtk_tree_view_get_effective_header_height (tree_view);
6163
6164   if (total_height == 0)
6165     return;
6166
6167   /* First, we check to see if we need to scroll anywhere
6168    */
6169   if (tree_view->priv->scroll_to_path)
6170     {
6171       path = gtk_tree_row_reference_get_path (tree_view->priv->scroll_to_path);
6172       if (path && !_gtk_tree_view_find_node (tree_view, path, &tree, &node))
6173         {
6174           /* we are going to scroll, and will update dy */
6175           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6176           if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6177               GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6178             {
6179               _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
6180               if (validate_row (tree_view, tree, node, &iter, path))
6181                 size_changed = TRUE;
6182             }
6183
6184           if (tree_view->priv->scroll_to_use_align)
6185             {
6186               gint height = gtk_tree_view_get_row_height (tree_view, node);
6187               area_above = (total_height - height) *
6188                 tree_view->priv->scroll_to_row_align;
6189               area_below = total_height - area_above - height;
6190               area_above = MAX (area_above, 0);
6191               area_below = MAX (area_below, 0);
6192             }
6193           else
6194             {
6195               /* two cases:
6196                * 1) row not visible
6197                * 2) row visible
6198                */
6199               gint dy;
6200               gint height = gtk_tree_view_get_row_height (tree_view, node);
6201
6202               dy = _gtk_rbtree_node_find_offset (tree, node);
6203
6204               if (dy >= gtk_adjustment_get_value (tree_view->priv->vadjustment) &&
6205                   dy + height <= (gtk_adjustment_get_value (tree_view->priv->vadjustment)
6206                                   + gtk_adjustment_get_page_size (tree_view->priv->vadjustment)))
6207                 {
6208                   /* row visible: keep the row at the same position */
6209                   area_above = dy - gtk_adjustment_get_value (tree_view->priv->vadjustment);
6210                   area_below = (gtk_adjustment_get_value (tree_view->priv->vadjustment) +
6211                                 gtk_adjustment_get_page_size (tree_view->priv->vadjustment))
6212                                - dy - height;
6213                 }
6214               else
6215                 {
6216                   /* row not visible */
6217                   if (dy >= 0
6218                       && dy + height <= gtk_adjustment_get_page_size (tree_view->priv->vadjustment))
6219                     {
6220                       /* row at the beginning -- fixed */
6221                       area_above = dy;
6222                       area_below = gtk_adjustment_get_page_size (tree_view->priv->vadjustment)
6223                                    - area_above - height;
6224                     }
6225                   else if (dy >= (gtk_adjustment_get_upper (tree_view->priv->vadjustment) -
6226                                   gtk_adjustment_get_page_size (tree_view->priv->vadjustment)))
6227                     {
6228                       /* row at the end -- fixed */
6229                       area_above = dy - (gtk_adjustment_get_upper (tree_view->priv->vadjustment) -
6230                                    gtk_adjustment_get_page_size (tree_view->priv->vadjustment));
6231                       area_below = gtk_adjustment_get_page_size (tree_view->priv->vadjustment) -
6232                                    area_above - height;
6233
6234                       if (area_below < 0)
6235                         {
6236                           area_above = gtk_adjustment_get_page_size (tree_view->priv->vadjustment) - height;
6237                           area_below = 0;
6238                         }
6239                     }
6240                   else
6241                     {
6242                       /* row somewhere in the middle, bring it to the top
6243                        * of the view
6244                        */
6245                       area_above = 0;
6246                       area_below = total_height - height;
6247                     }
6248                 }
6249             }
6250         }
6251       else
6252         /* the scroll to isn't valid; ignore it.
6253          */
6254         {
6255           if (tree_view->priv->scroll_to_path && !path)
6256             {
6257               gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
6258               tree_view->priv->scroll_to_path = NULL;
6259             }
6260           if (path)
6261             gtk_tree_path_free (path);
6262           path = NULL;
6263         }      
6264     }
6265
6266   /* We didn't have a scroll_to set, so we just handle things normally
6267    */
6268   if (path == NULL)
6269     {
6270       gint offset;
6271
6272       offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
6273                                         TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, 0),
6274                                         &tree, &node);
6275       if (node == NULL)
6276         {
6277           /* In this case, nothing has been validated */
6278           path = gtk_tree_path_new_first ();
6279           _gtk_tree_view_find_node (tree_view, path, &tree, &node);
6280         }
6281       else
6282         {
6283           path = _gtk_tree_view_find_path (tree_view, tree, node);
6284           total_height += offset;
6285         }
6286
6287       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6288
6289       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6290           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6291         {
6292           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
6293           if (validate_row (tree_view, tree, node, &iter, path))
6294             size_changed = TRUE;
6295         }
6296       area_above = 0;
6297       area_below = total_height - gtk_tree_view_get_row_height (tree_view, node);
6298     }
6299
6300   above_path = gtk_tree_path_copy (path);
6301
6302   /* if we do not validate any row above the new top_row, we will make sure
6303    * that the row immediately above top_row has been validated. (if we do not
6304    * do this, _gtk_rbtree_find_offset will find the row above top_row, because
6305    * when invalidated that row's height will be zero. and this will mess up
6306    * scrolling).
6307    */
6308   if (area_above == 0)
6309     {
6310       GtkRBTree *tmptree;
6311       GtkRBNode *tmpnode;
6312
6313       _gtk_tree_view_find_node (tree_view, above_path, &tmptree, &tmpnode);
6314       _gtk_rbtree_prev_full (tmptree, tmpnode, &tmptree, &tmpnode);
6315
6316       if (tmpnode)
6317         {
6318           GtkTreePath *tmppath;
6319           GtkTreeIter tmpiter;
6320
6321           tmppath = _gtk_tree_view_find_path (tree_view, tmptree, tmpnode);
6322           gtk_tree_model_get_iter (tree_view->priv->model, &tmpiter, tmppath);
6323
6324           if (GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_INVALID) ||
6325               GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_COLUMN_INVALID))
6326             {
6327               _gtk_tree_view_queue_draw_node (tree_view, tmptree, tmpnode, NULL);
6328               if (validate_row (tree_view, tmptree, tmpnode, &tmpiter, tmppath))
6329                 size_changed = TRUE;
6330             }
6331
6332           gtk_tree_path_free (tmppath);
6333         }
6334     }
6335
6336   /* Now, we walk forwards and backwards, measuring rows. Unfortunately,
6337    * backwards is much slower then forward, as there is no iter_prev function.
6338    * We go forwards first in case we run out of tree.  Then we go backwards to
6339    * fill out the top.
6340    */
6341   while (node && area_below > 0)
6342     {
6343       if (node->children)
6344         {
6345           GtkTreeIter parent = iter;
6346           gboolean has_child;
6347
6348           tree = node->children;
6349           node = tree->root;
6350
6351           g_assert (node != tree->nil);
6352
6353           while (node->left != tree->nil)
6354             node = node->left;
6355           has_child = gtk_tree_model_iter_children (tree_view->priv->model,
6356                                                     &iter,
6357                                                     &parent);
6358           TREE_VIEW_INTERNAL_ASSERT_VOID (has_child);
6359           gtk_tree_path_down (path);
6360         }
6361       else
6362         {
6363           gboolean done = FALSE;
6364           do
6365             {
6366               node = _gtk_rbtree_next (tree, node);
6367               if (node != NULL)
6368                 {
6369                   gboolean has_next = gtk_tree_model_iter_next (tree_view->priv->model, &iter);
6370                   done = TRUE;
6371                   gtk_tree_path_next (path);
6372
6373                   /* Sanity Check! */
6374                   TREE_VIEW_INTERNAL_ASSERT_VOID (has_next);
6375                 }
6376               else
6377                 {
6378                   GtkTreeIter parent_iter = iter;
6379                   gboolean has_parent;
6380
6381                   node = tree->parent_node;
6382                   tree = tree->parent_tree;
6383                   if (tree == NULL)
6384                     break;
6385                   has_parent = gtk_tree_model_iter_parent (tree_view->priv->model,
6386                                                            &iter,
6387                                                            &parent_iter);
6388                   gtk_tree_path_up (path);
6389
6390                   /* Sanity check */
6391                   TREE_VIEW_INTERNAL_ASSERT_VOID (has_parent);
6392                 }
6393             }
6394           while (!done);
6395         }
6396
6397       if (!node)
6398         break;
6399
6400       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6401           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6402         {
6403           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
6404           if (validate_row (tree_view, tree, node, &iter, path))
6405               size_changed = TRUE;
6406         }
6407
6408       area_below -= gtk_tree_view_get_row_height (tree_view, node);
6409     }
6410   gtk_tree_path_free (path);
6411
6412   /* If we ran out of tree, and have extra area_below left, we need to add it
6413    * to area_above */
6414   if (area_below > 0)
6415     area_above += area_below;
6416
6417   _gtk_tree_view_find_node (tree_view, above_path, &tree, &node);
6418
6419   /* We walk backwards */
6420   while (area_above > 0)
6421     {
6422       _gtk_rbtree_prev_full (tree, node, &tree, &node);
6423
6424       /* Always find the new path in the tree.  We cannot just assume
6425        * a gtk_tree_path_prev() is enough here, as there might be children
6426        * in between this node and the previous sibling node.  If this
6427        * appears to be a performance hotspot in profiles, we can look into
6428        * intrigate logic for keeping path, node and iter in sync like
6429        * we do for forward walks.  (Which will be hard because of the lacking
6430        * iter_prev).
6431        */
6432
6433       if (node == NULL)
6434         break;
6435
6436       gtk_tree_path_free (above_path);
6437       above_path = _gtk_tree_view_find_path (tree_view, tree, node);
6438
6439       gtk_tree_model_get_iter (tree_view->priv->model, &iter, above_path);
6440
6441       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6442           GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6443         {
6444           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
6445           if (validate_row (tree_view, tree, node, &iter, above_path))
6446             size_changed = TRUE;
6447         }
6448       area_above -= gtk_tree_view_get_row_height (tree_view, node);
6449     }
6450
6451   /* if we scrolled to a path, we need to set the dy here,
6452    * and sync the top row accordingly
6453    */
6454   if (tree_view->priv->scroll_to_path)
6455     {
6456       gtk_tree_view_set_top_row (tree_view, above_path, -area_above);
6457       gtk_tree_view_top_row_to_dy (tree_view);
6458
6459       need_redraw = TRUE;
6460     }
6461   else if (tree_view->priv->height <= gtk_adjustment_get_page_size (tree_view->priv->vadjustment))
6462     {
6463       /* when we are not scrolling, we should never set dy to something
6464        * else than zero. we update top_row to be in sync with dy = 0.
6465        */
6466       gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
6467       gtk_tree_view_dy_to_top_row (tree_view);
6468     }
6469   else if (gtk_adjustment_get_value (tree_view->priv->vadjustment) + gtk_adjustment_get_page_size (tree_view->priv->vadjustment) > tree_view->priv->height)
6470     {
6471       gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), tree_view->priv->height - gtk_adjustment_get_page_size (tree_view->priv->vadjustment));
6472       gtk_tree_view_dy_to_top_row (tree_view);
6473     }
6474   else
6475     gtk_tree_view_top_row_to_dy (tree_view);
6476
6477   /* update width/height and queue a resize */
6478   if (size_changed)
6479     {
6480       GtkRequisition requisition;
6481
6482       /* We temporarily guess a size, under the assumption that it will be the
6483        * same when we get our next size_allocate.  If we don't do this, we'll be
6484        * in an inconsistent state if we call top_row_to_dy. */
6485
6486       gtk_widget_get_preferred_size (GTK_WIDGET (tree_view),
6487                                      &requisition, NULL);
6488       gtk_adjustment_set_upper (tree_view->priv->hadjustment,
6489                                 MAX (gtk_adjustment_get_upper (tree_view->priv->hadjustment), requisition.width));
6490       gtk_adjustment_set_upper (tree_view->priv->vadjustment,
6491                                 MAX (gtk_adjustment_get_upper (tree_view->priv->vadjustment), requisition.height));
6492       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6493     }
6494
6495   if (tree_view->priv->scroll_to_path)
6496     {
6497       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
6498       tree_view->priv->scroll_to_path = NULL;
6499     }
6500
6501   if (above_path)
6502     gtk_tree_path_free (above_path);
6503
6504   if (tree_view->priv->scroll_to_column)
6505     {
6506       tree_view->priv->scroll_to_column = NULL;
6507     }
6508   if (need_redraw)
6509     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
6510 }
6511
6512 static void
6513 initialize_fixed_height_mode (GtkTreeView *tree_view)
6514 {
6515   if (!tree_view->priv->tree)
6516     return;
6517
6518   if (tree_view->priv->fixed_height < 0)
6519     {
6520       GtkTreeIter iter;
6521       GtkTreePath *path;
6522
6523       GtkRBTree *tree = NULL;
6524       GtkRBNode *node = NULL;
6525
6526       tree = tree_view->priv->tree;
6527       node = tree->root;
6528
6529       path = _gtk_tree_view_find_path (tree_view, tree, node);
6530       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6531
6532       validate_row (tree_view, tree, node, &iter, path);
6533
6534       gtk_tree_path_free (path);
6535
6536       tree_view->priv->fixed_height = gtk_tree_view_get_row_height (tree_view, node);
6537     }
6538
6539    _gtk_rbtree_set_fixed_height (tree_view->priv->tree,
6540                                  tree_view->priv->fixed_height, TRUE);
6541 }
6542
6543 /* Our strategy for finding nodes to validate is a little convoluted.  We find
6544  * the left-most uninvalidated node.  We then try walking right, validating
6545  * nodes.  Once we find a valid node, we repeat the previous process of finding
6546  * the first invalid node.
6547  */
6548
6549 static gboolean
6550 do_validate_rows (GtkTreeView *tree_view, gboolean queue_resize)
6551 {
6552   GtkRBTree *tree = NULL;
6553   GtkRBNode *node = NULL;
6554   gboolean validated_area = FALSE;
6555   gint retval = TRUE;
6556   GtkTreePath *path = NULL;
6557   GtkTreeIter iter;
6558   GTimer *timer;
6559   gint i = 0;
6560
6561   gint y = -1;
6562   gint prev_height = -1;
6563   gboolean fixed_height = TRUE;
6564
6565   g_assert (tree_view);
6566
6567   if (tree_view->priv->tree == NULL)
6568       return FALSE;
6569
6570   if (tree_view->priv->fixed_height_mode)
6571     {
6572       if (tree_view->priv->fixed_height < 0)
6573         initialize_fixed_height_mode (tree_view);
6574
6575       return FALSE;
6576     }
6577
6578   timer = g_timer_new ();
6579   g_timer_start (timer);
6580
6581   do
6582     {
6583       gboolean changed = FALSE;
6584
6585       if (! GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID))
6586         {
6587           retval = FALSE;
6588           goto done;
6589         }
6590
6591       if (path != NULL)
6592         {
6593           node = _gtk_rbtree_next (tree, node);
6594           if (node != NULL)
6595             {
6596               TREE_VIEW_INTERNAL_ASSERT (gtk_tree_model_iter_next (tree_view->priv->model, &iter), FALSE);
6597               gtk_tree_path_next (path);
6598             }
6599           else
6600             {
6601               gtk_tree_path_free (path);
6602               path = NULL;
6603             }
6604         }
6605
6606       if (path == NULL)
6607         {
6608           tree = tree_view->priv->tree;
6609           node = tree_view->priv->tree->root;
6610
6611           g_assert (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_DESCENDANTS_INVALID));
6612
6613           do
6614             {
6615               if (node->left != tree->nil &&
6616                   GTK_RBNODE_FLAG_SET (node->left, GTK_RBNODE_DESCENDANTS_INVALID))
6617                 {
6618                   node = node->left;
6619                 }
6620               else if (node->right != tree->nil &&
6621                        GTK_RBNODE_FLAG_SET (node->right, GTK_RBNODE_DESCENDANTS_INVALID))
6622                 {
6623                   node = node->right;
6624                 }
6625               else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
6626                        GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
6627                 {
6628                   break;
6629                 }
6630               else if (node->children != NULL)
6631                 {
6632                   tree = node->children;
6633                   node = tree->root;
6634                 }
6635               else
6636                 /* RBTree corruption!  All bad */
6637                 g_assert_not_reached ();
6638             }
6639           while (TRUE);
6640           path = _gtk_tree_view_find_path (tree_view, tree, node);
6641           gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
6642         }
6643
6644       changed = validate_row (tree_view, tree, node, &iter, path);
6645       validated_area = changed || validated_area;
6646
6647       if (changed)
6648         {
6649           gint offset = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
6650
6651           if (y == -1 || y > offset)
6652             y = offset;
6653         }
6654
6655       if (!tree_view->priv->fixed_height_check)
6656         {
6657           gint height;
6658
6659           height = gtk_tree_view_get_row_height (tree_view, node);
6660           if (prev_height < 0)
6661             prev_height = height;
6662           else if (prev_height != height)
6663             fixed_height = FALSE;
6664         }
6665
6666       i++;
6667     }
6668   while (g_timer_elapsed (timer, NULL) < GTK_TREE_VIEW_TIME_MS_PER_IDLE / 1000.);
6669
6670   if (!tree_view->priv->fixed_height_check)
6671    {
6672      if (fixed_height)
6673        _gtk_rbtree_set_fixed_height (tree_view->priv->tree, prev_height, FALSE);
6674
6675      tree_view->priv->fixed_height_check = 1;
6676    }
6677   
6678  done:
6679   if (validated_area)
6680     {
6681       GtkRequisition requisition;
6682
6683       /* We temporarily guess a size, under the assumption that it will be the
6684        * same when we get our next size_allocate.  If we don't do this, we'll be
6685        * in an inconsistent state when we call top_row_to_dy. */
6686
6687       /* FIXME: This is called from size_request, for some reason it is not infinitely
6688        * recursing, we cannot call gtk_widget_get_preferred_size() here because that's
6689        * not allowed (from inside ->get_preferred_width/height() implementations, one
6690        * should call the vfuncs directly). However what is desired here is the full
6691        * size including any margins and limited by any alignment (i.e. after 
6692        * GtkWidget:adjust_size_request() is called).
6693        *
6694        * Currently bypassing this but the real solution is to not update the scroll adjustments
6695        * untill we've recieved an allocation (never update scroll adjustments from size-requests).
6696        */
6697       gtk_tree_view_size_request (GTK_WIDGET (tree_view), &requisition, FALSE);
6698
6699       /* If rows above the current position have changed height, this has
6700        * affected the current view and thus needs a redraw.
6701        */
6702       if (y != -1 && y < gtk_adjustment_get_value (tree_view->priv->vadjustment))
6703         gtk_widget_queue_draw (GTK_WIDGET (tree_view));
6704
6705       gtk_adjustment_set_upper (tree_view->priv->hadjustment,
6706                                 MAX (gtk_adjustment_get_upper (tree_view->priv->hadjustment), requisition.width));
6707       gtk_adjustment_set_upper (tree_view->priv->vadjustment,
6708                                 MAX (gtk_adjustment_get_upper (tree_view->priv->vadjustment), requisition.height));
6709
6710       if (queue_resize)
6711         gtk_widget_queue_resize_no_redraw (GTK_WIDGET (tree_view));
6712     }
6713
6714   if (path) gtk_tree_path_free (path);
6715   g_timer_destroy (timer);
6716
6717   return retval;
6718 }
6719
6720 static gboolean
6721 validate_rows (GtkTreeView *tree_view)
6722 {
6723   gboolean retval;
6724   
6725   retval = do_validate_rows (tree_view, TRUE);
6726   
6727   if (! retval && tree_view->priv->validate_rows_timer)
6728     {
6729       g_source_remove (tree_view->priv->validate_rows_timer);
6730       tree_view->priv->validate_rows_timer = 0;
6731     }
6732
6733   return retval;
6734 }
6735
6736 static gboolean
6737 validate_rows_handler (GtkTreeView *tree_view)
6738 {
6739   gboolean retval;
6740
6741   retval = do_validate_rows (tree_view, TRUE);
6742   if (! retval && tree_view->priv->validate_rows_timer)
6743     {
6744       g_source_remove (tree_view->priv->validate_rows_timer);
6745       tree_view->priv->validate_rows_timer = 0;
6746     }
6747
6748   return retval;
6749 }
6750
6751 static gboolean
6752 do_presize_handler (GtkTreeView *tree_view)
6753 {
6754   if (tree_view->priv->mark_rows_col_dirty)
6755     {
6756       if (tree_view->priv->tree)
6757         _gtk_rbtree_column_invalid (tree_view->priv->tree);
6758       tree_view->priv->mark_rows_col_dirty = FALSE;
6759     }
6760   validate_visible_area (tree_view);
6761   tree_view->priv->presize_handler_timer = 0;
6762
6763   if (tree_view->priv->fixed_height_mode)
6764     {
6765       GtkRequisition requisition;
6766
6767       gtk_widget_get_preferred_size (GTK_WIDGET (tree_view),
6768                                      &requisition, NULL);
6769
6770       gtk_adjustment_set_upper (tree_view->priv->hadjustment,
6771                                 MAX (gtk_adjustment_get_upper (tree_view->priv->hadjustment), requisition.width));
6772       gtk_adjustment_set_upper (tree_view->priv->vadjustment,
6773                                 MAX (gtk_adjustment_get_upper (tree_view->priv->vadjustment), requisition.height));
6774       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6775     }
6776                    
6777   return FALSE;
6778 }
6779
6780 static gboolean
6781 presize_handler_callback (gpointer data)
6782 {
6783   do_presize_handler (GTK_TREE_VIEW (data));
6784                    
6785   return FALSE;
6786 }
6787
6788 static void
6789 install_presize_handler (GtkTreeView *tree_view)
6790 {
6791   if (! gtk_widget_get_realized (GTK_WIDGET (tree_view)))
6792     return;
6793
6794   if (! tree_view->priv->presize_handler_timer)
6795     {
6796       tree_view->priv->presize_handler_timer =
6797         gdk_threads_add_idle_full (GTK_PRIORITY_RESIZE - 2, presize_handler_callback, tree_view, NULL);
6798     }
6799   if (! tree_view->priv->validate_rows_timer)
6800     {
6801       tree_view->priv->validate_rows_timer =
6802         gdk_threads_add_idle_full (GTK_TREE_VIEW_PRIORITY_VALIDATE, (GSourceFunc) validate_rows_handler, tree_view, NULL);
6803     }
6804 }
6805
6806 static void
6807 gtk_tree_view_bin_process_updates (GtkTreeView *tree_view)
6808 {
6809   /* Prior to drawing, we make sure the visible area is validated. */
6810   if (tree_view->priv->presize_handler_timer)
6811     {
6812       g_source_remove (tree_view->priv->presize_handler_timer);
6813       tree_view->priv->presize_handler_timer = 0;
6814
6815       do_presize_handler (tree_view);
6816     }
6817
6818   gdk_window_process_updates (tree_view->priv->bin_window, TRUE);
6819 }
6820
6821 static gboolean
6822 scroll_sync_handler (GtkTreeView *tree_view)
6823 {
6824   if (tree_view->priv->height <= gtk_adjustment_get_page_size (tree_view->priv->vadjustment))
6825     gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
6826   else if (gtk_tree_row_reference_valid (tree_view->priv->top_row))
6827     gtk_tree_view_top_row_to_dy (tree_view);
6828   else
6829     gtk_tree_view_dy_to_top_row (tree_view);
6830
6831   tree_view->priv->scroll_sync_timer = 0;
6832
6833   return FALSE;
6834 }
6835
6836 static void
6837 install_scroll_sync_handler (GtkTreeView *tree_view)
6838 {
6839   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
6840     return;
6841
6842   if (!tree_view->priv->scroll_sync_timer)
6843     {
6844       tree_view->priv->scroll_sync_timer =
6845         gdk_threads_add_idle_full (GTK_TREE_VIEW_PRIORITY_SCROLL_SYNC, (GSourceFunc) scroll_sync_handler, tree_view, NULL);
6846     }
6847 }
6848
6849 static void
6850 gtk_tree_view_set_top_row (GtkTreeView *tree_view,
6851                            GtkTreePath *path,
6852                            gint         offset)
6853 {
6854   gtk_tree_row_reference_free (tree_view->priv->top_row);
6855
6856   if (!path)
6857     {
6858       tree_view->priv->top_row = NULL;
6859       tree_view->priv->top_row_dy = 0;
6860     }
6861   else
6862     {
6863       tree_view->priv->top_row = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
6864       tree_view->priv->top_row_dy = offset;
6865     }
6866 }
6867
6868 /* Always call this iff dy is in the visible range.  If the tree is empty, then
6869  * it's set to be NULL, and top_row_dy is 0;
6870  */
6871 static void
6872 gtk_tree_view_dy_to_top_row (GtkTreeView *tree_view)
6873 {
6874   gint offset;
6875   GtkTreePath *path;
6876   GtkRBTree *tree;
6877   GtkRBNode *node;
6878
6879   if (tree_view->priv->tree == NULL)
6880     {
6881       gtk_tree_view_set_top_row (tree_view, NULL, 0);
6882     }
6883   else
6884     {
6885       offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
6886                                         tree_view->priv->dy,
6887                                         &tree, &node);
6888
6889       if (tree == NULL)
6890         {
6891           gtk_tree_view_set_top_row (tree_view, NULL, 0);
6892         }
6893       else
6894         {
6895           path = _gtk_tree_view_find_path (tree_view, tree, node);
6896           gtk_tree_view_set_top_row (tree_view, path, offset);
6897           gtk_tree_path_free (path);
6898         }
6899     }
6900 }
6901
6902 static void
6903 gtk_tree_view_top_row_to_dy (GtkTreeView *tree_view)
6904 {
6905   GtkTreePath *path;
6906   GtkRBTree *tree;
6907   GtkRBNode *node;
6908   int new_dy;
6909
6910   /* Avoid recursive calls */
6911   if (tree_view->priv->in_top_row_to_dy)
6912     return;
6913
6914   if (tree_view->priv->top_row)
6915     path = gtk_tree_row_reference_get_path (tree_view->priv->top_row);
6916   else
6917     path = NULL;
6918
6919   if (!path)
6920     tree = NULL;
6921   else
6922     _gtk_tree_view_find_node (tree_view, path, &tree, &node);
6923
6924   if (path)
6925     gtk_tree_path_free (path);
6926
6927   if (tree == NULL)
6928     {
6929       /* keep dy and set new toprow */
6930       gtk_tree_row_reference_free (tree_view->priv->top_row);
6931       tree_view->priv->top_row = NULL;
6932       tree_view->priv->top_row_dy = 0;
6933       /* DO NOT install the idle handler */
6934       gtk_tree_view_dy_to_top_row (tree_view);
6935       return;
6936     }
6937
6938   if (gtk_tree_view_get_row_height (tree_view, node)
6939       < tree_view->priv->top_row_dy)
6940     {
6941       /* new top row -- do NOT install the idle handler */
6942       gtk_tree_view_dy_to_top_row (tree_view);
6943       return;
6944     }
6945
6946   new_dy = _gtk_rbtree_node_find_offset (tree, node);
6947   new_dy += tree_view->priv->top_row_dy;
6948
6949   if (new_dy + gtk_adjustment_get_page_size (tree_view->priv->vadjustment) > tree_view->priv->height)
6950     new_dy = tree_view->priv->height - gtk_adjustment_get_page_size (tree_view->priv->vadjustment);
6951
6952   new_dy = MAX (0, new_dy);
6953
6954   tree_view->priv->in_top_row_to_dy = TRUE;
6955   gtk_adjustment_set_value (tree_view->priv->vadjustment, (gdouble)new_dy);
6956   tree_view->priv->in_top_row_to_dy = FALSE;
6957 }
6958
6959
6960 void
6961 _gtk_tree_view_install_mark_rows_col_dirty (GtkTreeView *tree_view,
6962                                             gboolean     install_handler)
6963 {
6964   tree_view->priv->mark_rows_col_dirty = TRUE;
6965
6966   if (install_handler)
6967     install_presize_handler (tree_view);
6968 }
6969
6970 /*
6971  * This function works synchronously (due to the while (validate_rows...)
6972  * loop).
6973  *
6974  * There was a check for column_type != GTK_TREE_VIEW_COLUMN_AUTOSIZE
6975  * here. You now need to check that yourself.
6976  */
6977 void
6978 _gtk_tree_view_column_autosize (GtkTreeView *tree_view,
6979                                 GtkTreeViewColumn *column)
6980 {
6981   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
6982   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (column));
6983
6984   _gtk_tree_view_column_cell_set_dirty (column, FALSE);
6985
6986   do_presize_handler (tree_view);
6987   while (validate_rows (tree_view));
6988
6989   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
6990 }
6991
6992 /* Drag-and-drop */
6993
6994 static void
6995 set_source_row (GdkDragContext *context,
6996                 GtkTreeModel   *model,
6997                 GtkTreePath    *source_row)
6998 {
6999   g_object_set_data_full (G_OBJECT (context),
7000                           I_("gtk-tree-view-source-row"),
7001                           source_row ? gtk_tree_row_reference_new (model, source_row) : NULL,
7002                           (GDestroyNotify) (source_row ? gtk_tree_row_reference_free : NULL));
7003 }
7004
7005 static GtkTreePath*
7006 get_source_row (GdkDragContext *context)
7007 {
7008   GtkTreeRowReference *ref =
7009     g_object_get_data (G_OBJECT (context), "gtk-tree-view-source-row");
7010
7011   if (ref)
7012     return gtk_tree_row_reference_get_path (ref);
7013   else
7014     return NULL;
7015 }
7016
7017 typedef struct
7018 {
7019   GtkTreeRowReference *dest_row;
7020   guint                path_down_mode   : 1;
7021   guint                empty_view_drop  : 1;
7022   guint                drop_append_mode : 1;
7023 }
7024 DestRow;
7025
7026 static void
7027 dest_row_free (gpointer data)
7028 {
7029   DestRow *dr = (DestRow *)data;
7030
7031   gtk_tree_row_reference_free (dr->dest_row);
7032   g_slice_free (DestRow, dr);
7033 }
7034
7035 static void
7036 set_dest_row (GdkDragContext *context,
7037               GtkTreeModel   *model,
7038               GtkTreePath    *dest_row,
7039               gboolean        path_down_mode,
7040               gboolean        empty_view_drop,
7041               gboolean        drop_append_mode)
7042 {
7043   DestRow *dr;
7044
7045   if (!dest_row)
7046     {
7047       g_object_set_data_full (G_OBJECT (context), I_("gtk-tree-view-dest-row"),
7048                               NULL, NULL);
7049       return;
7050     }
7051
7052   dr = g_slice_new (DestRow);
7053
7054   dr->dest_row = gtk_tree_row_reference_new (model, dest_row);
7055   dr->path_down_mode = path_down_mode != FALSE;
7056   dr->empty_view_drop = empty_view_drop != FALSE;
7057   dr->drop_append_mode = drop_append_mode != FALSE;
7058
7059   g_object_set_data_full (G_OBJECT (context), I_("gtk-tree-view-dest-row"),
7060                           dr, (GDestroyNotify) dest_row_free);
7061 }
7062
7063 static GtkTreePath*
7064 get_dest_row (GdkDragContext *context,
7065               gboolean       *path_down_mode)
7066 {
7067   DestRow *dr =
7068     g_object_get_data (G_OBJECT (context), "gtk-tree-view-dest-row");
7069
7070   if (dr)
7071     {
7072       GtkTreePath *path = NULL;
7073
7074       if (path_down_mode)
7075         *path_down_mode = dr->path_down_mode;
7076
7077       if (dr->dest_row)
7078         path = gtk_tree_row_reference_get_path (dr->dest_row);
7079       else if (dr->empty_view_drop)
7080         path = gtk_tree_path_new_from_indices (0, -1);
7081       else
7082         path = NULL;
7083
7084       if (path && dr->drop_append_mode)
7085         gtk_tree_path_next (path);
7086
7087       return path;
7088     }
7089   else
7090     return NULL;
7091 }
7092
7093 /* Get/set whether drag_motion requested the drag data and
7094  * drag_data_received should thus not actually insert the data,
7095  * since the data doesn't result from a drop.
7096  */
7097 static void
7098 set_status_pending (GdkDragContext *context,
7099                     GdkDragAction   suggested_action)
7100 {
7101   g_object_set_data (G_OBJECT (context),
7102                      I_("gtk-tree-view-status-pending"),
7103                      GINT_TO_POINTER (suggested_action));
7104 }
7105
7106 static GdkDragAction
7107 get_status_pending (GdkDragContext *context)
7108 {
7109   return GPOINTER_TO_INT (g_object_get_data (G_OBJECT (context),
7110                                              "gtk-tree-view-status-pending"));
7111 }
7112
7113 static TreeViewDragInfo*
7114 get_info (GtkTreeView *tree_view)
7115 {
7116   return g_object_get_data (G_OBJECT (tree_view), "gtk-tree-view-drag-info");
7117 }
7118
7119 static void
7120 destroy_info (TreeViewDragInfo *di)
7121 {
7122   g_slice_free (TreeViewDragInfo, di);
7123 }
7124
7125 static TreeViewDragInfo*
7126 ensure_info (GtkTreeView *tree_view)
7127 {
7128   TreeViewDragInfo *di;
7129
7130   di = get_info (tree_view);
7131
7132   if (di == NULL)
7133     {
7134       di = g_slice_new0 (TreeViewDragInfo);
7135
7136       g_object_set_data_full (G_OBJECT (tree_view),
7137                               I_("gtk-tree-view-drag-info"),
7138                               di,
7139                               (GDestroyNotify) destroy_info);
7140     }
7141
7142   return di;
7143 }
7144
7145 static void
7146 remove_info (GtkTreeView *tree_view)
7147 {
7148   g_object_set_data (G_OBJECT (tree_view), I_("gtk-tree-view-drag-info"), NULL);
7149 }
7150
7151 #if 0
7152 static gint
7153 drag_scan_timeout (gpointer data)
7154 {
7155   GtkTreeView *tree_view;
7156   gint x, y;
7157   GdkModifierType state;
7158   GtkTreePath *path = NULL;
7159   GtkTreeViewColumn *column = NULL;
7160   GdkRectangle visible_rect;
7161
7162   GDK_THREADS_ENTER ();
7163
7164   tree_view = GTK_TREE_VIEW (data);
7165
7166   gdk_window_get_pointer (tree_view->priv->bin_window,
7167                           &x, &y, &state);
7168
7169   gtk_tree_view_get_visible_rect (tree_view, &visible_rect);
7170
7171   /* See if we are near the edge. */
7172   if ((x - visible_rect.x) < SCROLL_EDGE_SIZE ||
7173       (visible_rect.x + visible_rect.width - x) < SCROLL_EDGE_SIZE ||
7174       (y - visible_rect.y) < SCROLL_EDGE_SIZE ||
7175       (visible_rect.y + visible_rect.height - y) < SCROLL_EDGE_SIZE)
7176     {
7177       gtk_tree_view_get_path_at_pos (tree_view,
7178                                      tree_view->priv->bin_window,
7179                                      x, y,
7180                                      &path,
7181                                      &column,
7182                                      NULL,
7183                                      NULL);
7184
7185       if (path != NULL)
7186         {
7187           gtk_tree_view_scroll_to_cell (tree_view,
7188                                         path,
7189                                         column,
7190                                         TRUE,
7191                                         0.5, 0.5);
7192
7193           gtk_tree_path_free (path);
7194         }
7195     }
7196
7197   GDK_THREADS_LEAVE ();
7198
7199   return TRUE;
7200 }
7201 #endif /* 0 */
7202
7203 static void
7204 add_scroll_timeout (GtkTreeView *tree_view)
7205 {
7206   if (tree_view->priv->scroll_timeout == 0)
7207     {
7208       tree_view->priv->scroll_timeout =
7209         gdk_threads_add_timeout (150, scroll_row_timeout, tree_view);
7210     }
7211 }
7212
7213 static void
7214 remove_scroll_timeout (GtkTreeView *tree_view)
7215 {
7216   if (tree_view->priv->scroll_timeout != 0)
7217     {
7218       g_source_remove (tree_view->priv->scroll_timeout);
7219       tree_view->priv->scroll_timeout = 0;
7220     }
7221 }
7222
7223 static gboolean
7224 check_model_dnd (GtkTreeModel *model,
7225                  GType         required_iface,
7226                  const gchar  *signal)
7227 {
7228   if (model == NULL || !G_TYPE_CHECK_INSTANCE_TYPE ((model), required_iface))
7229     {
7230       g_warning ("You must override the default '%s' handler "
7231                  "on GtkTreeView when using models that don't support "
7232                  "the %s interface and enabling drag-and-drop. The simplest way to do this "
7233                  "is to connect to '%s' and call "
7234                  "g_signal_stop_emission_by_name() in your signal handler to prevent "
7235                  "the default handler from running. Look at the source code "
7236                  "for the default handler in gtktreeview.c to get an idea what "
7237                  "your handler should do. (gtktreeview.c is in the GTK source "
7238                  "code.) If you're using GTK from a language other than C, "
7239                  "there may be a more natural way to override default handlers, e.g. via derivation.",
7240                  signal, g_type_name (required_iface), signal);
7241       return FALSE;
7242     }
7243   else
7244     return TRUE;
7245 }
7246
7247 static void
7248 remove_open_timeout (GtkTreeView *tree_view)
7249 {
7250   if (tree_view->priv->open_dest_timeout != 0)
7251     {
7252       g_source_remove (tree_view->priv->open_dest_timeout);
7253       tree_view->priv->open_dest_timeout = 0;
7254     }
7255 }
7256
7257
7258 static gint
7259 open_row_timeout (gpointer data)
7260 {
7261   GtkTreeView *tree_view = data;
7262   GtkTreePath *dest_path = NULL;
7263   GtkTreeViewDropPosition pos;
7264   gboolean result = FALSE;
7265
7266   gtk_tree_view_get_drag_dest_row (tree_view,
7267                                    &dest_path,
7268                                    &pos);
7269
7270   if (dest_path &&
7271       (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
7272        pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
7273     {
7274       gtk_tree_view_expand_row (tree_view, dest_path, FALSE);
7275       tree_view->priv->open_dest_timeout = 0;
7276
7277       gtk_tree_path_free (dest_path);
7278     }
7279   else
7280     {
7281       if (dest_path)
7282         gtk_tree_path_free (dest_path);
7283
7284       result = TRUE;
7285     }
7286
7287   return result;
7288 }
7289
7290 static gboolean
7291 scroll_row_timeout (gpointer data)
7292 {
7293   GtkTreeView *tree_view = data;
7294
7295   gtk_tree_view_vertical_autoscroll (tree_view);
7296
7297   if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
7298     gtk_tree_view_update_rubber_band (tree_view);
7299
7300   return TRUE;
7301 }
7302
7303 /* Returns TRUE if event should not be propagated to parent widgets */
7304 static gboolean
7305 set_destination_row (GtkTreeView    *tree_view,
7306                      GdkDragContext *context,
7307                      /* coordinates relative to the widget */
7308                      gint            x,
7309                      gint            y,
7310                      GdkDragAction  *suggested_action,
7311                      GdkAtom        *target)
7312 {
7313   GtkTreePath *path = NULL;
7314   GtkTreeViewDropPosition pos;
7315   GtkTreeViewDropPosition old_pos;
7316   TreeViewDragInfo *di;
7317   GtkWidget *widget;
7318   GtkTreePath *old_dest_path = NULL;
7319   gboolean can_drop = FALSE;
7320
7321   *suggested_action = 0;
7322   *target = GDK_NONE;
7323
7324   widget = GTK_WIDGET (tree_view);
7325
7326   di = get_info (tree_view);
7327
7328   if (di == NULL || y - gtk_tree_view_get_effective_header_height (tree_view) < 0)
7329     {
7330       /* someone unset us as a drag dest, note that if
7331        * we return FALSE drag_leave isn't called
7332        */
7333
7334       gtk_tree_view_set_drag_dest_row (tree_view,
7335                                        NULL,
7336                                        GTK_TREE_VIEW_DROP_BEFORE);
7337
7338       remove_scroll_timeout (GTK_TREE_VIEW (widget));
7339       remove_open_timeout (GTK_TREE_VIEW (widget));
7340
7341       return FALSE; /* no longer a drop site */
7342     }
7343
7344   *target = gtk_drag_dest_find_target (widget, context,
7345                                        gtk_drag_dest_get_target_list (widget));
7346   if (*target == GDK_NONE)
7347     {
7348       return FALSE;
7349     }
7350
7351   if (!gtk_tree_view_get_dest_row_at_pos (tree_view,
7352                                           x, y,
7353                                           &path,
7354                                           &pos))
7355     {
7356       gint n_children;
7357       GtkTreeModel *model;
7358
7359       remove_open_timeout (tree_view);
7360
7361       /* the row got dropped on empty space, let's setup a special case
7362        */
7363
7364       if (path)
7365         gtk_tree_path_free (path);
7366
7367       model = gtk_tree_view_get_model (tree_view);
7368
7369       n_children = gtk_tree_model_iter_n_children (model, NULL);
7370       if (n_children)
7371         {
7372           pos = GTK_TREE_VIEW_DROP_AFTER;
7373           path = gtk_tree_path_new_from_indices (n_children - 1, -1);
7374         }
7375       else
7376         {
7377           pos = GTK_TREE_VIEW_DROP_BEFORE;
7378           path = gtk_tree_path_new_from_indices (0, -1);
7379         }
7380
7381       can_drop = TRUE;
7382
7383       goto out;
7384     }
7385
7386   g_assert (path);
7387
7388   /* If we left the current row's "open" zone, unset the timeout for
7389    * opening the row
7390    */
7391   gtk_tree_view_get_drag_dest_row (tree_view,
7392                                    &old_dest_path,
7393                                    &old_pos);
7394
7395   if (old_dest_path &&
7396       (gtk_tree_path_compare (path, old_dest_path) != 0 ||
7397        !(pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
7398          pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE)))
7399     remove_open_timeout (tree_view);
7400
7401   if (old_dest_path)
7402     gtk_tree_path_free (old_dest_path);
7403
7404   if (TRUE /* FIXME if the location droppable predicate */)
7405     {
7406       can_drop = TRUE;
7407     }
7408
7409 out:
7410   if (can_drop)
7411     {
7412       GtkWidget *source_widget;
7413
7414       *suggested_action = gdk_drag_context_get_suggested_action (context);
7415       source_widget = gtk_drag_get_source_widget (context);
7416
7417       if (source_widget == widget)
7418         {
7419           /* Default to MOVE, unless the user has
7420            * pressed ctrl or shift to affect available actions
7421            */
7422           if ((gdk_drag_context_get_actions (context) & GDK_ACTION_MOVE) != 0)
7423             *suggested_action = GDK_ACTION_MOVE;
7424         }
7425
7426       gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7427                                        path, pos);
7428     }
7429   else
7430     {
7431       /* can't drop here */
7432       remove_open_timeout (tree_view);
7433
7434       gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7435                                        NULL,
7436                                        GTK_TREE_VIEW_DROP_BEFORE);
7437     }
7438
7439   if (path)
7440     gtk_tree_path_free (path);
7441
7442   return TRUE;
7443 }
7444
7445 static GtkTreePath*
7446 get_logical_dest_row (GtkTreeView *tree_view,
7447                       gboolean    *path_down_mode,
7448                       gboolean    *drop_append_mode)
7449 {
7450   /* adjust path to point to the row the drop goes in front of */
7451   GtkTreePath *path = NULL;
7452   GtkTreeViewDropPosition pos;
7453
7454   g_return_val_if_fail (path_down_mode != NULL, NULL);
7455   g_return_val_if_fail (drop_append_mode != NULL, NULL);
7456
7457   *path_down_mode = FALSE;
7458   *drop_append_mode = 0;
7459
7460   gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
7461
7462   if (path == NULL)
7463     return NULL;
7464
7465   if (pos == GTK_TREE_VIEW_DROP_BEFORE)
7466     ; /* do nothing */
7467   else if (pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE ||
7468            pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER)
7469     *path_down_mode = TRUE;
7470   else
7471     {
7472       GtkTreeIter iter;
7473       GtkTreeModel *model = gtk_tree_view_get_model (tree_view);
7474
7475       g_assert (pos == GTK_TREE_VIEW_DROP_AFTER);
7476
7477       if (!gtk_tree_model_get_iter (model, &iter, path) ||
7478           !gtk_tree_model_iter_next (model, &iter))
7479         *drop_append_mode = 1;
7480       else
7481         {
7482           *drop_append_mode = 0;
7483           gtk_tree_path_next (path);
7484         }
7485     }
7486
7487   return path;
7488 }
7489
7490 static gboolean
7491 gtk_tree_view_maybe_begin_dragging_row (GtkTreeView      *tree_view,
7492                                         GdkEventMotion   *event)
7493 {
7494   GtkWidget *widget = GTK_WIDGET (tree_view);
7495   GdkDragContext *context;
7496   TreeViewDragInfo *di;
7497   GtkTreePath *path = NULL;
7498   gint button;
7499   gint cell_x, cell_y;
7500   GtkTreeModel *model;
7501   gboolean retval = FALSE;
7502
7503   di = get_info (tree_view);
7504
7505   if (di == NULL || !di->source_set)
7506     goto out;
7507
7508   if (tree_view->priv->pressed_button < 0)
7509     goto out;
7510
7511   if (!gtk_drag_check_threshold (widget,
7512                                  tree_view->priv->press_start_x,
7513                                  tree_view->priv->press_start_y,
7514                                  event->x, event->y))
7515     goto out;
7516
7517   model = gtk_tree_view_get_model (tree_view);
7518
7519   if (model == NULL)
7520     goto out;
7521
7522   button = tree_view->priv->pressed_button;
7523   tree_view->priv->pressed_button = -1;
7524
7525   gtk_tree_view_get_path_at_pos (tree_view,
7526                                  tree_view->priv->press_start_x,
7527                                  tree_view->priv->press_start_y,
7528                                  &path,
7529                                  NULL,
7530                                  &cell_x,
7531                                  &cell_y);
7532
7533   if (path == NULL)
7534     goto out;
7535
7536   if (!GTK_IS_TREE_DRAG_SOURCE (model) ||
7537       !gtk_tree_drag_source_row_draggable (GTK_TREE_DRAG_SOURCE (model),
7538                                            path))
7539     goto out;
7540
7541   if (!(GDK_BUTTON1_MASK << (button - 1) & di->start_button_mask))
7542     goto out;
7543
7544   /* Now we can begin the drag */
7545
7546   retval = TRUE;
7547
7548   context = gtk_drag_begin (widget,
7549                             gtk_drag_source_get_target_list (widget),
7550                             di->source_actions,
7551                             button,
7552                             (GdkEvent*)event);
7553
7554   set_source_row (context, model, path);
7555
7556  out:
7557   if (path)
7558     gtk_tree_path_free (path);
7559
7560   return retval;
7561 }
7562
7563
7564 static void
7565 gtk_tree_view_drag_begin (GtkWidget      *widget,
7566                           GdkDragContext *context)
7567 {
7568   GtkTreeView *tree_view;
7569   GtkTreePath *path = NULL;
7570   gint cell_x, cell_y;
7571   cairo_surface_t *row_pix;
7572   TreeViewDragInfo *di;
7573
7574   tree_view = GTK_TREE_VIEW (widget);
7575
7576   /* if the user uses a custom DND source impl, we don't set the icon here */
7577   di = get_info (tree_view);
7578
7579   if (di == NULL || !di->source_set)
7580     return;
7581
7582   gtk_tree_view_get_path_at_pos (tree_view,
7583                                  tree_view->priv->press_start_x,
7584                                  tree_view->priv->press_start_y,
7585                                  &path,
7586                                  NULL,
7587                                  &cell_x,
7588                                  &cell_y);
7589
7590   g_return_if_fail (path != NULL);
7591
7592   row_pix = gtk_tree_view_create_row_drag_icon (tree_view,
7593                                                 path);
7594   cairo_surface_set_device_offset (row_pix,
7595                                    /* the + 1 is for the black border in the icon */
7596                                    - (tree_view->priv->press_start_x + 1),
7597                                    - (cell_y + 1));
7598
7599   gtk_drag_set_icon_surface (context, row_pix);
7600
7601   cairo_surface_destroy (row_pix);
7602   gtk_tree_path_free (path);
7603 }
7604
7605 static void
7606 gtk_tree_view_drag_end (GtkWidget      *widget,
7607                         GdkDragContext *context)
7608 {
7609   /* do nothing */
7610 }
7611
7612 /* Default signal implementations for the drag signals */
7613 static void
7614 gtk_tree_view_drag_data_get (GtkWidget        *widget,
7615                              GdkDragContext   *context,
7616                              GtkSelectionData *selection_data,
7617                              guint             info,
7618                              guint             time)
7619 {
7620   GtkTreeView *tree_view;
7621   GtkTreeModel *model;
7622   TreeViewDragInfo *di;
7623   GtkTreePath *source_row;
7624
7625   tree_view = GTK_TREE_VIEW (widget);
7626
7627   model = gtk_tree_view_get_model (tree_view);
7628
7629   if (model == NULL)
7630     return;
7631
7632   di = get_info (GTK_TREE_VIEW (widget));
7633
7634   if (di == NULL)
7635     return;
7636
7637   source_row = get_source_row (context);
7638
7639   if (source_row == NULL)
7640     return;
7641
7642   /* We can implement the GTK_TREE_MODEL_ROW target generically for
7643    * any model; for DragSource models there are some other targets
7644    * we also support.
7645    */
7646
7647   if (GTK_IS_TREE_DRAG_SOURCE (model) &&
7648       gtk_tree_drag_source_drag_data_get (GTK_TREE_DRAG_SOURCE (model),
7649                                           source_row,
7650                                           selection_data))
7651     goto done;
7652
7653   /* If drag_data_get does nothing, try providing row data. */
7654   if (gtk_selection_data_get_target (selection_data) == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
7655     {
7656       gtk_tree_set_row_drag_data (selection_data,
7657                                   model,
7658                                   source_row);
7659     }
7660
7661  done:
7662   gtk_tree_path_free (source_row);
7663 }
7664
7665
7666 static void
7667 gtk_tree_view_drag_data_delete (GtkWidget      *widget,
7668                                 GdkDragContext *context)
7669 {
7670   TreeViewDragInfo *di;
7671   GtkTreeModel *model;
7672   GtkTreeView *tree_view;
7673   GtkTreePath *source_row;
7674
7675   tree_view = GTK_TREE_VIEW (widget);
7676   model = gtk_tree_view_get_model (tree_view);
7677
7678   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_SOURCE, "drag_data_delete"))
7679     return;
7680
7681   di = get_info (tree_view);
7682
7683   if (di == NULL)
7684     return;
7685
7686   source_row = get_source_row (context);
7687
7688   if (source_row == NULL)
7689     return;
7690
7691   gtk_tree_drag_source_drag_data_delete (GTK_TREE_DRAG_SOURCE (model),
7692                                          source_row);
7693
7694   gtk_tree_path_free (source_row);
7695
7696   set_source_row (context, NULL, NULL);
7697 }
7698
7699 static void
7700 gtk_tree_view_drag_leave (GtkWidget      *widget,
7701                           GdkDragContext *context,
7702                           guint             time)
7703 {
7704   /* unset any highlight row */
7705   gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7706                                    NULL,
7707                                    GTK_TREE_VIEW_DROP_BEFORE);
7708
7709   remove_scroll_timeout (GTK_TREE_VIEW (widget));
7710   remove_open_timeout (GTK_TREE_VIEW (widget));
7711 }
7712
7713
7714 static gboolean
7715 gtk_tree_view_drag_motion (GtkWidget        *widget,
7716                            GdkDragContext   *context,
7717                            /* coordinates relative to the widget */
7718                            gint              x,
7719                            gint              y,
7720                            guint             time)
7721 {
7722   gboolean empty;
7723   GtkTreePath *path = NULL;
7724   GtkTreeViewDropPosition pos;
7725   GtkTreeView *tree_view;
7726   GdkDragAction suggested_action = 0;
7727   GdkAtom target;
7728
7729   tree_view = GTK_TREE_VIEW (widget);
7730
7731   if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
7732     return FALSE;
7733
7734   gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
7735
7736   /* we only know this *after* set_desination_row */
7737   empty = tree_view->priv->empty_view_drop;
7738
7739   if (path == NULL && !empty)
7740     {
7741       /* Can't drop here. */
7742       gdk_drag_status (context, 0, time);
7743     }
7744   else
7745     {
7746       if (tree_view->priv->open_dest_timeout == 0 &&
7747           (pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER ||
7748            pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
7749         {
7750           tree_view->priv->open_dest_timeout =
7751             gdk_threads_add_timeout (AUTO_EXPAND_TIMEOUT, open_row_timeout, tree_view);
7752         }
7753       else
7754         {
7755           add_scroll_timeout (tree_view);
7756         }
7757
7758       if (target == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
7759         {
7760           /* Request data so we can use the source row when
7761            * determining whether to accept the drop
7762            */
7763           set_status_pending (context, suggested_action);
7764           gtk_drag_get_data (widget, context, target, time);
7765         }
7766       else
7767         {
7768           set_status_pending (context, 0);
7769           gdk_drag_status (context, suggested_action, time);
7770         }
7771     }
7772
7773   if (path)
7774     gtk_tree_path_free (path);
7775
7776   return TRUE;
7777 }
7778
7779
7780 static gboolean
7781 gtk_tree_view_drag_drop (GtkWidget        *widget,
7782                          GdkDragContext   *context,
7783                          /* coordinates relative to the widget */
7784                          gint              x,
7785                          gint              y,
7786                          guint             time)
7787 {
7788   GtkTreeView *tree_view;
7789   GtkTreePath *path;
7790   GdkDragAction suggested_action = 0;
7791   GdkAtom target = GDK_NONE;
7792   TreeViewDragInfo *di;
7793   GtkTreeModel *model;
7794   gboolean path_down_mode;
7795   gboolean drop_append_mode;
7796
7797   tree_view = GTK_TREE_VIEW (widget);
7798
7799   model = gtk_tree_view_get_model (tree_view);
7800
7801   remove_scroll_timeout (GTK_TREE_VIEW (widget));
7802   remove_open_timeout (GTK_TREE_VIEW (widget));
7803
7804   di = get_info (tree_view);
7805
7806   if (di == NULL)
7807     return FALSE;
7808
7809   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_drop"))
7810     return FALSE;
7811
7812   if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
7813     return FALSE;
7814
7815   path = get_logical_dest_row (tree_view, &path_down_mode, &drop_append_mode);
7816
7817   if (target != GDK_NONE && path != NULL)
7818     {
7819       /* in case a motion had requested drag data, change things so we
7820        * treat drag data receives as a drop.
7821        */
7822       set_status_pending (context, 0);
7823       set_dest_row (context, model, path,
7824                     path_down_mode, tree_view->priv->empty_view_drop,
7825                     drop_append_mode);
7826     }
7827
7828   if (path)
7829     gtk_tree_path_free (path);
7830
7831   /* Unset this thing */
7832   gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7833                                    NULL,
7834                                    GTK_TREE_VIEW_DROP_BEFORE);
7835
7836   if (target != GDK_NONE)
7837     {
7838       gtk_drag_get_data (widget, context, target, time);
7839       return TRUE;
7840     }
7841   else
7842     return FALSE;
7843 }
7844
7845 static void
7846 gtk_tree_view_drag_data_received (GtkWidget        *widget,
7847                                   GdkDragContext   *context,
7848                                   /* coordinates relative to the widget */
7849                                   gint              x,
7850                                   gint              y,
7851                                   GtkSelectionData *selection_data,
7852                                   guint             info,
7853                                   guint             time)
7854 {
7855   GtkTreePath *path;
7856   TreeViewDragInfo *di;
7857   gboolean accepted = FALSE;
7858   GtkTreeModel *model;
7859   GtkTreeView *tree_view;
7860   GtkTreePath *dest_row;
7861   GdkDragAction suggested_action;
7862   gboolean path_down_mode;
7863   gboolean drop_append_mode;
7864
7865   tree_view = GTK_TREE_VIEW (widget);
7866
7867   model = gtk_tree_view_get_model (tree_view);
7868
7869   if (!check_model_dnd (model, GTK_TYPE_TREE_DRAG_DEST, "drag_data_received"))
7870     return;
7871
7872   di = get_info (tree_view);
7873
7874   if (di == NULL)
7875     return;
7876
7877   suggested_action = get_status_pending (context);
7878
7879   if (suggested_action)
7880     {
7881       /* We are getting this data due to a request in drag_motion,
7882        * rather than due to a request in drag_drop, so we are just
7883        * supposed to call drag_status, not actually paste in the
7884        * data.
7885        */
7886       path = get_logical_dest_row (tree_view, &path_down_mode,
7887                                    &drop_append_mode);
7888
7889       if (path == NULL)
7890         suggested_action = 0;
7891       else if (path_down_mode)
7892         gtk_tree_path_down (path);
7893
7894       if (suggested_action)
7895         {
7896           if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
7897                                                      path,
7898                                                      selection_data))
7899             {
7900               if (path_down_mode)
7901                 {
7902                   path_down_mode = FALSE;
7903                   gtk_tree_path_up (path);
7904
7905                   if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
7906                                                              path,
7907                                                              selection_data))
7908                     suggested_action = 0;
7909                 }
7910               else
7911                 suggested_action = 0;
7912             }
7913         }
7914
7915       gdk_drag_status (context, suggested_action, time);
7916
7917       if (path)
7918         gtk_tree_path_free (path);
7919
7920       /* If you can't drop, remove user drop indicator until the next motion */
7921       if (suggested_action == 0)
7922         gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
7923                                          NULL,
7924                                          GTK_TREE_VIEW_DROP_BEFORE);
7925
7926       return;
7927     }
7928
7929   dest_row = get_dest_row (context, &path_down_mode);
7930
7931   if (dest_row == NULL)
7932     return;
7933
7934   if (gtk_selection_data_get_length (selection_data) >= 0)
7935     {
7936       if (path_down_mode)
7937         {
7938           gtk_tree_path_down (dest_row);
7939           if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
7940                                                      dest_row, selection_data))
7941             gtk_tree_path_up (dest_row);
7942         }
7943     }
7944
7945   if (gtk_selection_data_get_length (selection_data) >= 0)
7946     {
7947       if (gtk_tree_drag_dest_drag_data_received (GTK_TREE_DRAG_DEST (model),
7948                                                  dest_row,
7949                                                  selection_data))
7950         accepted = TRUE;
7951     }
7952
7953   gtk_drag_finish (context,
7954                    accepted,
7955                    (gdk_drag_context_get_selected_action (context) == GDK_ACTION_MOVE),
7956                    time);
7957
7958   if (gtk_tree_path_get_depth (dest_row) == 1
7959       && gtk_tree_path_get_indices (dest_row)[0] == 0)
7960     {
7961       /* special special case drag to "0", scroll to first item */
7962       if (!tree_view->priv->scroll_to_path)
7963         gtk_tree_view_scroll_to_cell (tree_view, dest_row, NULL, FALSE, 0.0, 0.0);
7964     }
7965
7966   gtk_tree_path_free (dest_row);
7967
7968   /* drop dest_row */
7969   set_dest_row (context, NULL, NULL, FALSE, FALSE, FALSE);
7970 }
7971
7972
7973
7974 /* GtkContainer Methods
7975  */
7976
7977
7978 static void
7979 gtk_tree_view_remove (GtkContainer *container,
7980                       GtkWidget    *widget)
7981 {
7982   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
7983   GtkTreeViewChild *child = NULL;
7984   GList *tmp_list;
7985
7986   tmp_list = tree_view->priv->children;
7987   while (tmp_list)
7988     {
7989       child = tmp_list->data;
7990       if (child->widget == widget)
7991         {
7992           gtk_widget_unparent (widget);
7993
7994           tree_view->priv->children = g_list_remove_link (tree_view->priv->children, tmp_list);
7995           g_list_free_1 (tmp_list);
7996           g_slice_free (GtkTreeViewChild, child);
7997           return;
7998         }
7999
8000       tmp_list = tmp_list->next;
8001     }
8002
8003   tmp_list = tree_view->priv->columns;
8004
8005   while (tmp_list)
8006     {
8007       GtkTreeViewColumn *column;
8008       GtkWidget         *button;
8009
8010       column = tmp_list->data;
8011       button = gtk_tree_view_column_get_button (column);
8012
8013       if (button == widget)
8014         {
8015           gtk_widget_unparent (widget);
8016           return;
8017         }
8018       tmp_list = tmp_list->next;
8019     }
8020 }
8021
8022 static void
8023 gtk_tree_view_forall (GtkContainer *container,
8024                       gboolean      include_internals,
8025                       GtkCallback   callback,
8026                       gpointer      callback_data)
8027 {
8028   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
8029   GtkTreeViewChild *child = NULL;
8030   GtkTreeViewColumn *column;
8031   GtkWidget *button;
8032   GList *tmp_list;
8033
8034   tmp_list = tree_view->priv->children;
8035   while (tmp_list)
8036     {
8037       child = tmp_list->data;
8038       tmp_list = tmp_list->next;
8039
8040       (* callback) (child->widget, callback_data);
8041     }
8042   if (include_internals == FALSE)
8043     return;
8044
8045   for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
8046     {
8047       column = tmp_list->data;
8048       button = gtk_tree_view_column_get_button (column);
8049
8050       if (button)
8051         (* callback) (button, callback_data);
8052     }
8053 }
8054
8055 /* Returns TRUE is any of the columns contains a cell that can-focus.
8056  * If this is not the case, a column-spanning focus rectangle will be
8057  * drawn.
8058  */
8059 static gboolean
8060 gtk_tree_view_has_can_focus_cell (GtkTreeView *tree_view)
8061 {
8062   GList *list;
8063
8064   for (list = tree_view->priv->columns; list; list = list->next)
8065     {
8066       GtkTreeViewColumn *column = list->data;
8067
8068       if (!gtk_tree_view_column_get_visible (column))
8069         continue;
8070       if (gtk_cell_area_is_activatable (gtk_cell_layout_get_area (GTK_CELL_LAYOUT (column))))
8071         return TRUE;
8072     }
8073
8074   return FALSE;
8075 }
8076
8077 static void
8078 column_sizing_notify (GObject    *object,
8079                       GParamSpec *pspec,
8080                       gpointer    data)
8081 {
8082   GtkTreeViewColumn *c = GTK_TREE_VIEW_COLUMN (object);
8083
8084   if (gtk_tree_view_column_get_sizing (c) != GTK_TREE_VIEW_COLUMN_FIXED)
8085     /* disable fixed height mode */
8086     g_object_set (data, "fixed-height-mode", FALSE, NULL);
8087 }
8088
8089 /**
8090  * gtk_tree_view_set_fixed_height_mode:
8091  * @tree_view: a #GtkTreeView 
8092  * @enable: %TRUE to enable fixed height mode
8093  * 
8094  * Enables or disables the fixed height mode of @tree_view. 
8095  * Fixed height mode speeds up #GtkTreeView by assuming that all 
8096  * rows have the same height. 
8097  * Only enable this option if all rows are the same height and all
8098  * columns are of type %GTK_TREE_VIEW_COLUMN_FIXED.
8099  *
8100  * Since: 2.6 
8101  **/
8102 void
8103 gtk_tree_view_set_fixed_height_mode (GtkTreeView *tree_view,
8104                                      gboolean     enable)
8105 {
8106   GList *l;
8107   
8108   enable = enable != FALSE;
8109
8110   if (enable == tree_view->priv->fixed_height_mode)
8111     return;
8112
8113   if (!enable)
8114     {
8115       tree_view->priv->fixed_height_mode = 0;
8116       tree_view->priv->fixed_height = -1;
8117
8118       /* force a revalidation */
8119       install_presize_handler (tree_view);
8120     }
8121   else 
8122     {
8123       /* make sure all columns are of type FIXED */
8124       for (l = tree_view->priv->columns; l; l = l->next)
8125         {
8126           GtkTreeViewColumn *c = l->data;
8127           
8128           g_return_if_fail (gtk_tree_view_column_get_sizing (c) == GTK_TREE_VIEW_COLUMN_FIXED);
8129         }
8130       
8131       /* yes, we really have to do this is in a separate loop */
8132       for (l = tree_view->priv->columns; l; l = l->next)
8133         g_signal_connect (l->data, "notify::sizing",
8134                           G_CALLBACK (column_sizing_notify), tree_view);
8135       
8136       tree_view->priv->fixed_height_mode = 1;
8137       tree_view->priv->fixed_height = -1;
8138       
8139       if (tree_view->priv->tree)
8140         initialize_fixed_height_mode (tree_view);
8141     }
8142
8143   g_object_notify (G_OBJECT (tree_view), "fixed-height-mode");
8144 }
8145
8146 /**
8147  * gtk_tree_view_get_fixed_height_mode:
8148  * @tree_view: a #GtkTreeView
8149  * 
8150  * Returns whether fixed height mode is turned on for @tree_view.
8151  * 
8152  * Return value: %TRUE if @tree_view is in fixed height mode
8153  * 
8154  * Since: 2.6
8155  **/
8156 gboolean
8157 gtk_tree_view_get_fixed_height_mode (GtkTreeView *tree_view)
8158 {
8159   return tree_view->priv->fixed_height_mode;
8160 }
8161
8162 /* Returns TRUE if the focus is within the headers, after the focus operation is
8163  * done
8164  */
8165 static gboolean
8166 gtk_tree_view_header_focus (GtkTreeView      *tree_view,
8167                             GtkDirectionType  dir,
8168                             gboolean          clamp_column_visible)
8169 {
8170   GtkTreeViewColumn *column;
8171   GtkWidget *focus_child;
8172   GtkWidget *button;
8173   GList *last_column, *first_column;
8174   GList *tmp_list;
8175   gboolean rtl;
8176
8177   if (! tree_view->priv->headers_visible)
8178     return FALSE;
8179
8180   focus_child = gtk_container_get_focus_child (GTK_CONTAINER (tree_view));
8181
8182   first_column = tree_view->priv->columns;
8183   while (first_column)
8184     {
8185       column = GTK_TREE_VIEW_COLUMN (first_column->data);
8186       button = gtk_tree_view_column_get_button (column);
8187
8188       if (gtk_widget_get_can_focus (button) &&
8189           gtk_tree_view_column_get_visible (column) &&
8190           (gtk_tree_view_column_get_clickable (column) ||
8191            gtk_tree_view_column_get_reorderable (column)))
8192         break;
8193       first_column = first_column->next;
8194     }
8195
8196   /* No headers are visible, or are focusable.  We can't focus in or out.
8197    */
8198   if (first_column == NULL)
8199     return FALSE;
8200
8201   last_column = g_list_last (tree_view->priv->columns);
8202   while (last_column)
8203     {
8204       column = GTK_TREE_VIEW_COLUMN (last_column->data);
8205       button = gtk_tree_view_column_get_button (column);
8206
8207       if (gtk_widget_get_can_focus (button) &&
8208           gtk_tree_view_column_get_visible (column) &&
8209           (gtk_tree_view_column_get_clickable (column) ||
8210            gtk_tree_view_column_get_reorderable (column)))
8211         break;
8212       last_column = last_column->prev;
8213     }
8214
8215
8216   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
8217
8218   switch (dir)
8219     {
8220     case GTK_DIR_TAB_BACKWARD:
8221     case GTK_DIR_TAB_FORWARD:
8222     case GTK_DIR_UP:
8223     case GTK_DIR_DOWN:
8224       if (focus_child == NULL)
8225         {
8226           if (tree_view->priv->focus_column != NULL)
8227             button = gtk_tree_view_column_get_button (tree_view->priv->focus_column);
8228           else 
8229             button = NULL;
8230
8231           if (button && gtk_widget_get_can_focus (button))
8232             focus_child = button;
8233           else
8234             focus_child = gtk_tree_view_column_get_button (GTK_TREE_VIEW_COLUMN (first_column->data));
8235
8236           gtk_widget_grab_focus (focus_child);
8237           break;
8238         }
8239       return FALSE;
8240
8241     case GTK_DIR_LEFT:
8242     case GTK_DIR_RIGHT:
8243       if (focus_child == NULL)
8244         {
8245           if (tree_view->priv->focus_column != NULL)
8246             focus_child = gtk_tree_view_column_get_button (tree_view->priv->focus_column);
8247           else if (dir == GTK_DIR_LEFT)
8248             focus_child = gtk_tree_view_column_get_button (GTK_TREE_VIEW_COLUMN (last_column->data));
8249           else
8250             focus_child = gtk_tree_view_column_get_button (GTK_TREE_VIEW_COLUMN (first_column->data));
8251
8252           gtk_widget_grab_focus (focus_child);
8253           break;
8254         }
8255
8256       if (gtk_widget_child_focus (focus_child, dir))
8257         {
8258           /* The focus moves inside the button. */
8259           /* This is probably a great example of bad UI */
8260           break;
8261         }
8262
8263       /* We need to move the focus among the row of buttons. */
8264       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
8265         if (gtk_tree_view_column_get_button (GTK_TREE_VIEW_COLUMN (tmp_list->data)) == focus_child)
8266           break;
8267
8268       if ((tmp_list == first_column && dir == (rtl ? GTK_DIR_RIGHT : GTK_DIR_LEFT))
8269           || (tmp_list == last_column && dir == (rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT)))
8270         {
8271           gtk_widget_error_bell (GTK_WIDGET (tree_view));
8272           break;
8273         }
8274
8275       while (tmp_list)
8276         {
8277           GtkTreeViewColumn *column;
8278           GtkWidget         *button;
8279
8280           if (dir == (rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT))
8281             tmp_list = tmp_list->next;
8282           else
8283             tmp_list = tmp_list->prev;
8284
8285           if (tmp_list == NULL)
8286             {
8287               g_warning ("Internal button not found");
8288               break;
8289             }
8290           column = tmp_list->data;
8291           button = gtk_tree_view_column_get_button (column);
8292           if (button &&
8293               gtk_tree_view_column_get_visible (column) &&
8294               gtk_widget_get_can_focus (button))
8295             {
8296               focus_child = button;
8297               gtk_widget_grab_focus (button);
8298               break;
8299             }
8300         }
8301       break;
8302     default:
8303       g_assert_not_reached ();
8304       break;
8305     }
8306
8307   /* if focus child is non-null, we assume it's been set to the current focus child
8308    */
8309   if (focus_child)
8310     {
8311       for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
8312         if (gtk_tree_view_column_get_button (GTK_TREE_VIEW_COLUMN (tmp_list->data)) == focus_child)
8313           {
8314             tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
8315             break;
8316           }
8317
8318       if (clamp_column_visible)
8319         {
8320           gtk_tree_view_clamp_column_visible (tree_view,
8321                                               tree_view->priv->focus_column,
8322                                               FALSE);
8323         }
8324     }
8325
8326   return (focus_child != NULL);
8327 }
8328
8329 /* This function returns in 'path' the first focusable path, if the given path
8330  * is already focusable, it's the returned one.
8331  */
8332 static gboolean
8333 search_first_focusable_path (GtkTreeView  *tree_view,
8334                              GtkTreePath **path,
8335                              gboolean      search_forward,
8336                              GtkRBTree   **new_tree,
8337                              GtkRBNode   **new_node)
8338 {
8339   GtkRBTree *tree = NULL;
8340   GtkRBNode *node = NULL;
8341
8342   if (!path || !*path)
8343     return FALSE;
8344
8345   _gtk_tree_view_find_node (tree_view, *path, &tree, &node);
8346
8347   if (!tree || !node)
8348     return FALSE;
8349
8350   while (node && row_is_separator (tree_view, NULL, *path))
8351     {
8352       if (search_forward)
8353         _gtk_rbtree_next_full (tree, node, &tree, &node);
8354       else
8355         _gtk_rbtree_prev_full (tree, node, &tree, &node);
8356
8357       if (*path)
8358         gtk_tree_path_free (*path);
8359
8360       if (node)
8361         *path = _gtk_tree_view_find_path (tree_view, tree, node);
8362       else
8363         *path = NULL;
8364     }
8365
8366   if (new_tree)
8367     *new_tree = tree;
8368
8369   if (new_node)
8370     *new_node = node;
8371
8372   return (*path != NULL);
8373 }
8374
8375 static gint
8376 gtk_tree_view_focus (GtkWidget        *widget,
8377                      GtkDirectionType  direction)
8378 {
8379   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
8380   GtkContainer *container = GTK_CONTAINER (widget);
8381   GtkWidget *focus_child;
8382
8383   if (!gtk_widget_is_sensitive (widget) || !gtk_widget_get_can_focus (widget))
8384     return FALSE;
8385
8386   focus_child = gtk_container_get_focus_child (container);
8387
8388   gtk_tree_view_stop_editing (GTK_TREE_VIEW (widget), FALSE);
8389   /* Case 1.  Headers currently have focus. */
8390   if (focus_child)
8391     {
8392       switch (direction)
8393         {
8394         case GTK_DIR_LEFT:
8395         case GTK_DIR_RIGHT:
8396           gtk_tree_view_header_focus (tree_view, direction, TRUE);
8397           return TRUE;
8398         case GTK_DIR_TAB_BACKWARD:
8399         case GTK_DIR_UP:
8400           return FALSE;
8401         case GTK_DIR_TAB_FORWARD:
8402         case GTK_DIR_DOWN:
8403           gtk_widget_grab_focus (widget);
8404           return TRUE;
8405         default:
8406           g_assert_not_reached ();
8407           return FALSE;
8408         }
8409     }
8410
8411   /* Case 2. We don't have focus at all. */
8412   if (!gtk_widget_has_focus (widget))
8413     {
8414       gtk_widget_grab_focus (widget);
8415       return TRUE;
8416     }
8417
8418   /* Case 3. We have focus already. */
8419   if (direction == GTK_DIR_TAB_BACKWARD)
8420     return (gtk_tree_view_header_focus (tree_view, direction, FALSE));
8421   else if (direction == GTK_DIR_TAB_FORWARD)
8422     return FALSE;
8423
8424   /* Other directions caught by the keybindings */
8425   gtk_widget_grab_focus (widget);
8426   return TRUE;
8427 }
8428
8429 static void
8430 gtk_tree_view_grab_focus (GtkWidget *widget)
8431 {
8432   GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->grab_focus (widget);
8433
8434   gtk_tree_view_focus_to_cursor (GTK_TREE_VIEW (widget));
8435 }
8436
8437 static void
8438 gtk_tree_view_style_updated (GtkWidget *widget)
8439 {
8440   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
8441   GList *list;
8442   GtkTreeViewColumn *column;
8443
8444   GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->style_updated (widget);
8445
8446   if (gtk_widget_get_realized (widget))
8447     {
8448       GtkStyleContext *context;
8449
8450       context = gtk_widget_get_style_context (widget);
8451
8452       gtk_style_context_save (context);
8453       gtk_style_context_add_class (context, GTK_STYLE_CLASS_VIEW);
8454       gtk_style_context_set_background (context, tree_view->priv->bin_window);
8455       gtk_style_context_restore (context);
8456
8457       gtk_style_context_set_background (context, tree_view->priv->header_window);
8458
8459       gtk_tree_view_set_grid_lines (tree_view, tree_view->priv->grid_lines);
8460       gtk_tree_view_set_enable_tree_lines (tree_view, tree_view->priv->tree_lines_enabled);
8461     }
8462
8463   gtk_widget_style_get (widget,
8464                         "expander-size", &tree_view->priv->expander_size,
8465                         NULL);
8466   tree_view->priv->expander_size += EXPANDER_EXTRA_PADDING;
8467
8468   for (list = tree_view->priv->columns; list; list = list->next)
8469     {
8470       column = list->data;
8471       _gtk_tree_view_column_cell_set_dirty (column, TRUE);
8472     }
8473
8474   tree_view->priv->fixed_height = -1;
8475   _gtk_rbtree_mark_invalid (tree_view->priv->tree);
8476
8477   gtk_widget_queue_resize (widget);
8478 }
8479
8480
8481 static void
8482 gtk_tree_view_set_focus_child (GtkContainer *container,
8483                                GtkWidget    *child)
8484 {
8485   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
8486   GList *list;
8487
8488   for (list = tree_view->priv->columns; list; list = list->next)
8489     {
8490       if (gtk_tree_view_column_get_button (GTK_TREE_VIEW_COLUMN (list->data)) == child)
8491         {
8492           tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (list->data);
8493           break;
8494         }
8495     }
8496
8497   GTK_CONTAINER_CLASS (gtk_tree_view_parent_class)->set_focus_child (container, child);
8498 }
8499
8500 static GtkWidgetPath *
8501 gtk_tree_view_get_path_for_child (GtkContainer *container,
8502                                   GtkWidget    *child)
8503 {
8504   GtkTreeView *tree_view = GTK_TREE_VIEW (container);
8505   GtkWidgetPath *path;
8506   gboolean rtl;
8507   GList *list;
8508   gint n_col = 0;
8509
8510   path = GTK_CONTAINER_CLASS (gtk_tree_view_parent_class)->get_path_for_child (container, child);
8511   rtl = (gtk_widget_get_direction (GTK_WIDGET (container)) == GTK_TEXT_DIR_RTL);
8512
8513   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
8514        list;
8515        list = (rtl ? list->prev : list->next))
8516     {
8517       GtkTreeViewColumn *column = list->data;
8518       GtkRegionFlags flags = 0;
8519
8520       if (!gtk_tree_view_column_get_visible (column))
8521         continue;
8522
8523       n_col++;
8524
8525       if (gtk_tree_view_column_get_widget (column) != child &&
8526           gtk_tree_view_column_get_button (column) != child)
8527         continue;
8528
8529       if ((n_col % 2) == 0)
8530         flags |= GTK_REGION_EVEN;
8531       else
8532         flags |= GTK_REGION_ODD;
8533
8534       if (n_col == 1)
8535         flags |= GTK_REGION_FIRST;
8536
8537       if ((rtl && !list->prev) ||
8538           (!rtl && !list->next))
8539         flags |= GTK_REGION_LAST;
8540
8541       gtk_widget_path_iter_add_region (path, -1, GTK_STYLE_REGION_COLUMN_HEADER, flags);
8542       break;
8543     }
8544
8545   gtk_widget_path_append_for_widget (path, child);
8546
8547   return path;
8548 }
8549
8550 static gboolean
8551 gtk_tree_view_real_move_cursor (GtkTreeView       *tree_view,
8552                                 GtkMovementStep    step,
8553                                 gint               count)
8554 {
8555   GdkModifierType state;
8556
8557   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
8558   g_return_val_if_fail (step == GTK_MOVEMENT_LOGICAL_POSITIONS ||
8559                         step == GTK_MOVEMENT_VISUAL_POSITIONS ||
8560                         step == GTK_MOVEMENT_DISPLAY_LINES ||
8561                         step == GTK_MOVEMENT_PAGES ||
8562                         step == GTK_MOVEMENT_BUFFER_ENDS, FALSE);
8563
8564   if (tree_view->priv->tree == NULL)
8565     return FALSE;
8566   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
8567     return FALSE;
8568
8569   gtk_tree_view_stop_editing (tree_view, FALSE);
8570   tree_view->priv->draw_keyfocus = TRUE;
8571   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
8572
8573   if (gtk_get_current_event_state (&state))
8574     {
8575       if ((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
8576         tree_view->priv->ctrl_pressed = TRUE;
8577       if ((state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
8578         tree_view->priv->shift_pressed = TRUE;
8579     }
8580   /* else we assume not pressed */
8581
8582   switch (step)
8583     {
8584       /* currently we make no distinction.  When we go bi-di, we need to */
8585     case GTK_MOVEMENT_LOGICAL_POSITIONS:
8586     case GTK_MOVEMENT_VISUAL_POSITIONS:
8587       gtk_tree_view_move_cursor_left_right (tree_view, count);
8588       break;
8589     case GTK_MOVEMENT_DISPLAY_LINES:
8590       gtk_tree_view_move_cursor_up_down (tree_view, count);
8591       break;
8592     case GTK_MOVEMENT_PAGES:
8593       gtk_tree_view_move_cursor_page_up_down (tree_view, count);
8594       break;
8595     case GTK_MOVEMENT_BUFFER_ENDS:
8596       gtk_tree_view_move_cursor_start_end (tree_view, count);
8597       break;
8598     default:
8599       g_assert_not_reached ();
8600     }
8601
8602   tree_view->priv->ctrl_pressed = FALSE;
8603   tree_view->priv->shift_pressed = FALSE;
8604
8605   return TRUE;
8606 }
8607
8608 static void
8609 gtk_tree_view_put (GtkTreeView *tree_view,
8610                    GtkWidget   *child_widget,
8611                    /* in bin_window coordinates */
8612                    gint         x,
8613                    gint         y,
8614                    gint         width,
8615                    gint         height)
8616 {
8617   GtkTreeViewChild *child;
8618   
8619   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8620   g_return_if_fail (GTK_IS_WIDGET (child_widget));
8621
8622   child = g_slice_new (GtkTreeViewChild);
8623
8624   child->widget = child_widget;
8625   child->x = x;
8626   child->y = y;
8627   child->width = width;
8628   child->height = height;
8629
8630   tree_view->priv->children = g_list_append (tree_view->priv->children, child);
8631
8632   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
8633     gtk_widget_set_parent_window (child->widget, tree_view->priv->bin_window);
8634   
8635   gtk_widget_set_parent (child_widget, GTK_WIDGET (tree_view));
8636 }
8637
8638 void
8639 _gtk_tree_view_child_move_resize (GtkTreeView *tree_view,
8640                                   GtkWidget   *widget,
8641                                   /* in tree coordinates */
8642                                   gint         x,
8643                                   gint         y,
8644                                   gint         width,
8645                                   gint         height)
8646 {
8647   GtkTreeViewChild *child = NULL;
8648   GList *list;
8649   GdkRectangle allocation;
8650
8651   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
8652   g_return_if_fail (GTK_IS_WIDGET (widget));
8653
8654   for (list = tree_view->priv->children; list; list = list->next)
8655     {
8656       if (((GtkTreeViewChild *)list->data)->widget == widget)
8657         {
8658           child = list->data;
8659           break;
8660         }
8661     }
8662   if (child == NULL)
8663     return;
8664
8665   allocation.x = child->x = x;
8666   allocation.y = child->y = y;
8667   allocation.width = child->width = width;
8668   allocation.height = child->height = height;
8669
8670   if (gtk_widget_get_realized (widget))
8671     gtk_widget_size_allocate (widget, &allocation);
8672 }
8673
8674
8675 /* TreeModel Callbacks
8676  */
8677
8678 static void
8679 gtk_tree_view_row_changed (GtkTreeModel *model,
8680                            GtkTreePath  *path,
8681                            GtkTreeIter  *iter,
8682                            gpointer      data)
8683 {
8684   GtkTreeView *tree_view = (GtkTreeView *)data;
8685   GtkRBTree *tree;
8686   GtkRBNode *node;
8687   gboolean free_path = FALSE;
8688   GList *list;
8689   GtkTreePath *cursor_path;
8690
8691   g_return_if_fail (path != NULL || iter != NULL);
8692
8693   if (tree_view->priv->cursor != NULL)
8694     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
8695   else
8696     cursor_path = NULL;
8697
8698   if (tree_view->priv->edited_column &&
8699       (cursor_path == NULL || gtk_tree_path_compare (cursor_path, path) == 0))
8700     gtk_tree_view_stop_editing (tree_view, TRUE);
8701
8702   if (cursor_path != NULL)
8703     gtk_tree_path_free (cursor_path);
8704
8705   if (path == NULL)
8706     {
8707       path = gtk_tree_model_get_path (model, iter);
8708       free_path = TRUE;
8709     }
8710   else if (iter == NULL)
8711     gtk_tree_model_get_iter (model, iter, path);
8712
8713   if (_gtk_tree_view_find_node (tree_view,
8714                                 path,
8715                                 &tree,
8716                                 &node))
8717     /* We aren't actually showing the node */
8718     goto done;
8719
8720   if (tree == NULL)
8721     goto done;
8722
8723   if (tree_view->priv->fixed_height_mode
8724       && tree_view->priv->fixed_height >= 0)
8725     {
8726       _gtk_rbtree_node_set_height (tree, node, tree_view->priv->fixed_height);
8727       if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
8728         gtk_tree_view_node_queue_redraw (tree_view, tree, node);
8729     }
8730   else
8731     {
8732       _gtk_rbtree_node_mark_invalid (tree, node);
8733       for (list = tree_view->priv->columns; list; list = list->next)
8734         {
8735           GtkTreeViewColumn *column;
8736
8737           column = list->data;
8738           if (!gtk_tree_view_column_get_visible (column))
8739             continue;
8740
8741           if (gtk_tree_view_column_get_sizing (column) == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
8742             {
8743               _gtk_tree_view_column_cell_set_dirty (column, TRUE);
8744             }
8745         }
8746     }
8747
8748  done:
8749   if (!tree_view->priv->fixed_height_mode &&
8750       gtk_widget_get_realized (GTK_WIDGET (tree_view)))
8751     install_presize_handler (tree_view);
8752   if (free_path)
8753     gtk_tree_path_free (path);
8754 }
8755
8756 static void
8757 gtk_tree_view_row_inserted (GtkTreeModel *model,
8758                             GtkTreePath  *path,
8759                             GtkTreeIter  *iter,
8760                             gpointer      data)
8761 {
8762   GtkTreeView *tree_view = (GtkTreeView *) data;
8763   gint *indices;
8764   GtkRBTree *tmptree, *tree;
8765   GtkRBNode *tmpnode = NULL;
8766   gint depth;
8767   gint i = 0;
8768   gint height;
8769   gboolean free_path = FALSE;
8770   gboolean node_visible = TRUE;
8771
8772   g_return_if_fail (path != NULL || iter != NULL);
8773
8774   if (tree_view->priv->fixed_height_mode
8775       && tree_view->priv->fixed_height >= 0)
8776     height = tree_view->priv->fixed_height;
8777   else
8778     height = 0;
8779
8780   if (path == NULL)
8781     {
8782       path = gtk_tree_model_get_path (model, iter);
8783       free_path = TRUE;
8784     }
8785   else if (iter == NULL)
8786     gtk_tree_model_get_iter (model, iter, path);
8787
8788   if (tree_view->priv->tree == NULL)
8789     tree_view->priv->tree = _gtk_rbtree_new ();
8790
8791   tmptree = tree = tree_view->priv->tree;
8792
8793   /* Update all row-references */
8794   gtk_tree_row_reference_inserted (G_OBJECT (data), path);
8795   depth = gtk_tree_path_get_depth (path);
8796   indices = gtk_tree_path_get_indices (path);
8797
8798   /* First, find the parent tree */
8799   while (i < depth - 1)
8800     {
8801       if (tmptree == NULL)
8802         {
8803           /* We aren't showing the node */
8804           node_visible = FALSE;
8805           goto done;
8806         }
8807
8808       tmpnode = _gtk_rbtree_find_count (tmptree, indices[i] + 1);
8809       if (tmpnode == NULL)
8810         {
8811           g_warning ("A node was inserted with a parent that's not in the tree.\n" \
8812                      "This possibly means that a GtkTreeModel inserted a child node\n" \
8813                      "before the parent was inserted.");
8814           goto done;
8815         }
8816       else if (!GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_IS_PARENT))
8817         {
8818           /* FIXME enforce correct behavior on model, probably */
8819           /* In theory, the model should have emitted has_child_toggled here.  We
8820            * try to catch it anyway, just to be safe, in case the model hasn't.
8821            */
8822           GtkTreePath *tmppath = _gtk_tree_view_find_path (tree_view,
8823                                                            tree,
8824                                                            tmpnode);
8825           gtk_tree_view_row_has_child_toggled (model, tmppath, NULL, data);
8826           gtk_tree_path_free (tmppath);
8827           goto done;
8828         }
8829
8830       tmptree = tmpnode->children;
8831       tree = tmptree;
8832       i++;
8833     }
8834
8835   if (tree == NULL)
8836     {
8837       node_visible = FALSE;
8838       goto done;
8839     }
8840
8841   /* ref the node */
8842   gtk_tree_model_ref_node (tree_view->priv->model, iter);
8843   if (indices[depth - 1] == 0)
8844     {
8845       tmpnode = _gtk_rbtree_find_count (tree, 1);
8846       tmpnode = _gtk_rbtree_insert_before (tree, tmpnode, height, FALSE);
8847     }
8848   else
8849     {
8850       tmpnode = _gtk_rbtree_find_count (tree, indices[depth - 1]);
8851       tmpnode = _gtk_rbtree_insert_after (tree, tmpnode, height, FALSE);
8852     }
8853
8854  done:
8855   if (height > 0)
8856     {
8857       if (tree)
8858         _gtk_rbtree_node_mark_valid (tree, tmpnode);
8859
8860       if (node_visible && node_is_visible (tree_view, tree, tmpnode))
8861         gtk_widget_queue_resize (GTK_WIDGET (tree_view));
8862       else
8863         gtk_widget_queue_resize_no_redraw (GTK_WIDGET (tree_view));
8864     }
8865   else
8866     install_presize_handler (tree_view);
8867   if (free_path)
8868     gtk_tree_path_free (path);
8869 }
8870
8871 static void
8872 gtk_tree_view_row_has_child_toggled (GtkTreeModel *model,
8873                                      GtkTreePath  *path,
8874                                      GtkTreeIter  *iter,
8875                                      gpointer      data)
8876 {
8877   GtkTreeView *tree_view = (GtkTreeView *)data;
8878   GtkTreeIter real_iter;
8879   gboolean has_child;
8880   GtkRBTree *tree;
8881   GtkRBNode *node;
8882   gboolean free_path = FALSE;
8883
8884   g_return_if_fail (path != NULL || iter != NULL);
8885
8886   if (iter)
8887     real_iter = *iter;
8888
8889   if (path == NULL)
8890     {
8891       path = gtk_tree_model_get_path (model, iter);
8892       free_path = TRUE;
8893     }
8894   else if (iter == NULL)
8895     gtk_tree_model_get_iter (model, &real_iter, path);
8896
8897   if (_gtk_tree_view_find_node (tree_view,
8898                                 path,
8899                                 &tree,
8900                                 &node))
8901     /* We aren't actually showing the node */
8902     goto done;
8903
8904   if (tree == NULL)
8905     goto done;
8906
8907   has_child = gtk_tree_model_iter_has_child (model, &real_iter);
8908   /* Sanity check.
8909    */
8910   if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT) == has_child)
8911     goto done;
8912
8913   if (has_child)
8914     GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_PARENT);
8915   else
8916     GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_PARENT);
8917
8918   if (has_child && tree_view->priv->is_list)
8919     {
8920       tree_view->priv->is_list = FALSE;
8921       if (tree_view->priv->show_expanders)
8922         {
8923           GList *list;
8924
8925           for (list = tree_view->priv->columns; list; list = list->next)
8926             if (gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (list->data)))
8927               {
8928                 _gtk_tree_view_column_cell_set_dirty (GTK_TREE_VIEW_COLUMN (list->data), TRUE);
8929                 break;
8930               }
8931         }
8932       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
8933     }
8934   else
8935     {
8936       _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
8937     }
8938
8939  done:
8940   if (free_path)
8941     gtk_tree_path_free (path);
8942 }
8943
8944 static void
8945 count_children_helper (GtkRBTree *tree,
8946                        GtkRBNode *node,
8947                        gpointer   data)
8948 {
8949   if (node->children)
8950     _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, data);
8951   (*((gint *)data))++;
8952 }
8953
8954 static void
8955 check_selection_helper (GtkRBTree *tree,
8956                         GtkRBNode *node,
8957                         gpointer   data)
8958 {
8959   gint *value = (gint *)data;
8960
8961   *value = GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED);
8962
8963   if (node->children && !*value)
8964     _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, check_selection_helper, data);
8965 }
8966
8967 static void
8968 gtk_tree_view_row_deleted (GtkTreeModel *model,
8969                            GtkTreePath  *path,
8970                            gpointer      data)
8971 {
8972   GtkTreeView *tree_view = (GtkTreeView *)data;
8973   GtkRBTree *tree;
8974   GtkRBNode *node;
8975   GList *list;
8976   gint selection_changed = FALSE;
8977   GtkStyleContext *context;
8978
8979   g_return_if_fail (path != NULL);
8980
8981   gtk_tree_row_reference_deleted (G_OBJECT (data), path);
8982
8983   if (_gtk_tree_view_find_node (tree_view, path, &tree, &node))
8984     return;
8985
8986   if (tree == NULL)
8987     return;
8988
8989   /* check if the selection has been changed */
8990   _gtk_rbtree_traverse (tree, node, G_POST_ORDER,
8991                         check_selection_helper, &selection_changed);
8992
8993   for (list = tree_view->priv->columns; list; list = list->next)
8994     if (gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (list->data)) &&
8995         gtk_tree_view_column_get_sizing (GTK_TREE_VIEW_COLUMN (list->data)) == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
8996       _gtk_tree_view_column_cell_set_dirty ((GtkTreeViewColumn *)list->data, TRUE);
8997
8998   /* Ensure we don't have a dangling pointer to a dead node */
8999   ensure_unprelighted (tree_view);
9000
9001   /* Cancel editting if we've started */
9002   gtk_tree_view_stop_editing (tree_view, TRUE);
9003
9004   if (tree_view->priv->destroy_count_func)
9005     {
9006       gint child_count = 0;
9007       if (node->children)
9008         _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, &child_count);
9009       tree_view->priv->destroy_count_func (tree_view, path, child_count, tree_view->priv->destroy_count_data);
9010     }
9011
9012   if (tree->root->count == 1)
9013     {
9014       if (tree_view->priv->tree == tree)
9015         tree_view->priv->tree = NULL;
9016
9017       _gtk_rbtree_remove (tree);
9018     }
9019   else
9020     {
9021       _gtk_rbtree_remove_node (tree, node);
9022     }
9023
9024   if (! gtk_tree_row_reference_valid (tree_view->priv->top_row))
9025     {
9026       gtk_tree_row_reference_free (tree_view->priv->top_row);
9027       tree_view->priv->top_row = NULL;
9028     }
9029
9030   /* Cancel any ongoing animation happening within the row */
9031   context = gtk_widget_get_style_context (GTK_WIDGET (tree_view));
9032   gtk_style_context_cancel_animations (context, node);
9033
9034   install_scroll_sync_handler (tree_view);
9035
9036   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
9037
9038   if (selection_changed)
9039     g_signal_emit_by_name (tree_view->priv->selection, "changed");
9040 }
9041
9042 static void
9043 gtk_tree_view_rows_reordered (GtkTreeModel *model,
9044                               GtkTreePath  *parent,
9045                               GtkTreeIter  *iter,
9046                               gint         *new_order,
9047                               gpointer      data)
9048 {
9049   GtkTreeView *tree_view = GTK_TREE_VIEW (data);
9050   GtkRBTree *tree;
9051   GtkRBNode *node;
9052   gint len;
9053
9054   len = gtk_tree_model_iter_n_children (model, iter);
9055
9056   if (len < 2)
9057     return;
9058
9059   gtk_tree_row_reference_reordered (G_OBJECT (data),
9060                                     parent,
9061                                     iter,
9062                                     new_order);
9063
9064   if (_gtk_tree_view_find_node (tree_view,
9065                                 parent,
9066                                 &tree,
9067                                 &node))
9068     return;
9069
9070   /* We need to special case the parent path */
9071   if (tree == NULL)
9072     tree = tree_view->priv->tree;
9073   else
9074     tree = node->children;
9075
9076   if (tree == NULL)
9077     return;
9078
9079   if (tree_view->priv->edited_column)
9080     gtk_tree_view_stop_editing (tree_view, TRUE);
9081
9082   /* we need to be unprelighted */
9083   ensure_unprelighted (tree_view);
9084
9085   _gtk_rbtree_reorder (tree, new_order, len);
9086
9087   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
9088
9089   gtk_tree_view_dy_to_top_row (tree_view);
9090 }
9091
9092
9093 /* Internal tree functions
9094  */
9095
9096
9097 static void
9098 gtk_tree_view_get_background_xrange (GtkTreeView       *tree_view,
9099                                      GtkRBTree         *tree,
9100                                      GtkTreeViewColumn *column,
9101                                      gint              *x1,
9102                                      gint              *x2)
9103 {
9104   GtkTreeViewColumn *tmp_column = NULL;
9105   gint total_width;
9106   GList *list;
9107   gboolean rtl;
9108
9109   if (x1)
9110     *x1 = 0;
9111
9112   if (x2)
9113     *x2 = 0;
9114
9115   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
9116
9117   total_width = 0;
9118   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
9119        list;
9120        list = (rtl ? list->prev : list->next))
9121     {
9122       tmp_column = list->data;
9123
9124       if (tmp_column == column)
9125         break;
9126
9127       if (gtk_tree_view_column_get_visible (tmp_column))
9128         total_width += gtk_tree_view_column_get_width (tmp_column);
9129     }
9130
9131   if (tmp_column != column)
9132     {
9133       g_warning (G_STRLOC": passed-in column isn't in the tree");
9134       return;
9135     }
9136
9137   if (x1)
9138     *x1 = total_width;
9139
9140   if (x2)
9141     {
9142       if (gtk_tree_view_column_get_visible (column))
9143         *x2 = total_width + gtk_tree_view_column_get_width (column);
9144       else
9145         *x2 = total_width; /* width of 0 */
9146     }
9147 }
9148
9149 static void
9150 gtk_tree_view_get_arrow_xrange (GtkTreeView *tree_view,
9151                                 GtkRBTree   *tree,
9152                                 gint        *x1,
9153                                 gint        *x2)
9154 {
9155   gint x_offset = 0;
9156   GList *list;
9157   GtkTreeViewColumn *tmp_column = NULL;
9158   gint total_width;
9159   gboolean indent_expanders;
9160   gboolean rtl;
9161
9162   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
9163
9164   total_width = 0;
9165   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
9166        list;
9167        list = (rtl ? list->prev : list->next))
9168     {
9169       tmp_column = list->data;
9170
9171       if (gtk_tree_view_is_expander_column (tree_view, tmp_column))
9172         {
9173           if (rtl)
9174             x_offset = total_width + gtk_tree_view_column_get_width (tmp_column) - tree_view->priv->expander_size;
9175           else
9176             x_offset = total_width;
9177           break;
9178         }
9179
9180       if (gtk_tree_view_column_get_visible (tmp_column))
9181         total_width += gtk_tree_view_column_get_width (tmp_column);
9182     }
9183
9184   gtk_widget_style_get (GTK_WIDGET (tree_view),
9185                         "indent-expanders", &indent_expanders,
9186                         NULL);
9187
9188   if (indent_expanders)
9189     {
9190       if (rtl)
9191         x_offset -= tree_view->priv->expander_size * _gtk_rbtree_get_depth (tree);
9192       else
9193         x_offset += tree_view->priv->expander_size * _gtk_rbtree_get_depth (tree);
9194     }
9195
9196   *x1 = x_offset;
9197
9198   if (tmp_column &&
9199       gtk_tree_view_column_get_visible (tmp_column))
9200     /* +1 because x2 isn't included in the range. */
9201     *x2 = *x1 + tree_view->priv->expander_size + 1;
9202   else
9203     *x2 = *x1;
9204 }
9205
9206 static void
9207 gtk_tree_view_build_tree (GtkTreeView *tree_view,
9208                           GtkRBTree   *tree,
9209                           GtkTreeIter *iter,
9210                           gint         depth,
9211                           gboolean     recurse)
9212 {
9213   GtkRBNode *temp = NULL;
9214   GtkTreePath *path = NULL;
9215
9216   do
9217     {
9218       gtk_tree_model_ref_node (tree_view->priv->model, iter);
9219       temp = _gtk_rbtree_insert_after (tree, temp, 0, FALSE);
9220
9221       if (tree_view->priv->fixed_height > 0)
9222         {
9223           if (GTK_RBNODE_FLAG_SET (temp, GTK_RBNODE_INVALID))
9224             {
9225               _gtk_rbtree_node_set_height (tree, temp, tree_view->priv->fixed_height);
9226               _gtk_rbtree_node_mark_valid (tree, temp);
9227             }
9228         }
9229
9230       if (tree_view->priv->is_list)
9231         continue;
9232
9233       if (recurse)
9234         {
9235           GtkTreeIter child;
9236
9237           if (!path)
9238             path = gtk_tree_model_get_path (tree_view->priv->model, iter);
9239           else
9240             gtk_tree_path_next (path);
9241
9242           if (gtk_tree_model_iter_children (tree_view->priv->model, &child, iter))
9243             {
9244               gboolean expand;
9245
9246               g_signal_emit (tree_view, tree_view_signals[TEST_EXPAND_ROW], 0, iter, path, &expand);
9247
9248               if (gtk_tree_model_iter_has_child (tree_view->priv->model, iter)
9249                   && !expand)
9250                 {
9251                   temp->children = _gtk_rbtree_new ();
9252                   temp->children->parent_tree = tree;
9253                   temp->children->parent_node = temp;
9254                   gtk_tree_view_build_tree (tree_view, temp->children, &child, depth + 1, recurse);
9255                 }
9256             }
9257         }
9258
9259       if (gtk_tree_model_iter_has_child (tree_view->priv->model, iter))
9260         {
9261           if ((temp->flags&GTK_RBNODE_IS_PARENT) != GTK_RBNODE_IS_PARENT)
9262             temp->flags ^= GTK_RBNODE_IS_PARENT;
9263         }
9264     }
9265   while (gtk_tree_model_iter_next (tree_view->priv->model, iter));
9266
9267   if (path)
9268     gtk_tree_path_free (path);
9269 }
9270
9271 /* Make sure the node is visible vertically */
9272 static void
9273 gtk_tree_view_clamp_node_visible (GtkTreeView *tree_view,
9274                                   GtkRBTree   *tree,
9275                                   GtkRBNode   *node)
9276 {
9277   gint node_dy, height;
9278   GtkTreePath *path = NULL;
9279
9280   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
9281     return;
9282
9283   /* just return if the node is visible, avoiding a costly expose */
9284   node_dy = _gtk_rbtree_node_find_offset (tree, node);
9285   height = gtk_tree_view_get_row_height (tree_view, node);
9286   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID)
9287       && node_dy >= gtk_adjustment_get_value (tree_view->priv->vadjustment)
9288       && node_dy + height <= (gtk_adjustment_get_value (tree_view->priv->vadjustment)
9289                               + gtk_adjustment_get_page_size (tree_view->priv->vadjustment)))
9290     return;
9291
9292   path = _gtk_tree_view_find_path (tree_view, tree, node);
9293   if (path)
9294     {
9295       /* We process updates because we want to clear old selected items when we scroll.
9296        * if this is removed, we get a "selection streak" at the bottom. */
9297       gtk_tree_view_bin_process_updates (tree_view);
9298
9299       gtk_tree_view_scroll_to_cell (tree_view, path, NULL, FALSE, 0.0, 0.0);
9300       gtk_tree_path_free (path);
9301     }
9302 }
9303
9304 static void
9305 gtk_tree_view_clamp_column_visible (GtkTreeView       *tree_view,
9306                                     GtkTreeViewColumn *column,
9307                                     gboolean           focus_to_cell)
9308 {
9309   GtkAllocation allocation;
9310   gint x, width;
9311
9312   if (column == NULL)
9313     return;
9314
9315   gtk_widget_get_allocation (gtk_tree_view_column_get_button (column), &allocation);
9316   x = allocation.x;
9317   width = allocation.width;
9318
9319   if (width > gtk_adjustment_get_page_size (tree_view->priv->hadjustment))
9320     {
9321       /* The column is larger than the horizontal page size.  If the
9322        * column has cells which can be focussed individually, then we make
9323        * sure the cell which gets focus is fully visible (if even the
9324        * focus cell is bigger than the page size, we make sure the
9325        * left-hand side of the cell is visible).
9326        *
9327        * If the column does not have an activatable cell, we
9328        * make sure the left-hand side of the column is visible.
9329        */
9330
9331       if (focus_to_cell && gtk_tree_view_has_can_focus_cell (tree_view))
9332         {
9333           GtkCellArea *cell_area;
9334           GtkCellRenderer *focus_cell;
9335
9336           cell_area = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (column));
9337           focus_cell = gtk_cell_area_get_focus_cell (cell_area);
9338
9339           if (gtk_tree_view_column_cell_get_position (column, focus_cell,
9340                                                       &x, &width))
9341             {
9342               if (width < gtk_adjustment_get_page_size (tree_view->priv->hadjustment))
9343                 {
9344                   if (gtk_adjustment_get_value (tree_view->priv->hadjustment) + gtk_adjustment_get_page_size (tree_view->priv->hadjustment) < x + width)
9345                     gtk_adjustment_set_value (tree_view->priv->hadjustment,
9346                                               x + width - gtk_adjustment_get_page_size (tree_view->priv->hadjustment));
9347                   else if (gtk_adjustment_get_value (tree_view->priv->hadjustment) > x)
9348                     gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
9349                 }
9350             }
9351         }
9352
9353       gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
9354     }
9355   else
9356     {
9357       if ((gtk_adjustment_get_value (tree_view->priv->hadjustment) + gtk_adjustment_get_page_size (tree_view->priv->hadjustment)) < (x + width))
9358           gtk_adjustment_set_value (tree_view->priv->hadjustment,
9359                                     x + width - gtk_adjustment_get_page_size (tree_view->priv->hadjustment));
9360       else if (gtk_adjustment_get_value (tree_view->priv->hadjustment) > x)
9361         gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
9362   }
9363 }
9364
9365 /* This function could be more efficient.  I'll optimize it if profiling seems
9366  * to imply that it is important */
9367 GtkTreePath *
9368 _gtk_tree_view_find_path (GtkTreeView *tree_view,
9369                           GtkRBTree   *tree,
9370                           GtkRBNode   *node)
9371 {
9372   GtkTreePath *path;
9373   GtkRBTree *tmp_tree;
9374   GtkRBNode *tmp_node, *last;
9375   gint count;
9376
9377   path = gtk_tree_path_new ();
9378
9379   g_return_val_if_fail (node != NULL, path);
9380   g_return_val_if_fail (node != tree->nil, path);
9381
9382   count = 1 + node->left->count;
9383
9384   last = node;
9385   tmp_node = node->parent;
9386   tmp_tree = tree;
9387   while (tmp_tree)
9388     {
9389       while (tmp_node != tmp_tree->nil)
9390         {
9391           if (tmp_node->right == last)
9392             count += 1 + tmp_node->left->count;
9393           last = tmp_node;
9394           tmp_node = tmp_node->parent;
9395         }
9396       gtk_tree_path_prepend_index (path, count - 1);
9397       last = tmp_tree->parent_node;
9398       tmp_tree = tmp_tree->parent_tree;
9399       if (last)
9400         {
9401           count = 1 + last->left->count;
9402           tmp_node = last->parent;
9403         }
9404     }
9405   return path;
9406 }
9407
9408 /* Returns TRUE if we ran out of tree before finding the path.  If the path is
9409  * invalid (ie. points to a node that's not in the tree), *tree and *node are
9410  * both set to NULL.
9411  */
9412 gboolean
9413 _gtk_tree_view_find_node (GtkTreeView  *tree_view,
9414                           GtkTreePath  *path,
9415                           GtkRBTree   **tree,
9416                           GtkRBNode   **node)
9417 {
9418   GtkRBNode *tmpnode = NULL;
9419   GtkRBTree *tmptree = tree_view->priv->tree;
9420   gint *indices = gtk_tree_path_get_indices (path);
9421   gint depth = gtk_tree_path_get_depth (path);
9422   gint i = 0;
9423
9424   *node = NULL;
9425   *tree = NULL;
9426
9427   if (depth == 0 || tmptree == NULL)
9428     return FALSE;
9429   do
9430     {
9431       tmpnode = _gtk_rbtree_find_count (tmptree, indices[i] + 1);
9432       ++i;
9433       if (tmpnode == NULL)
9434         {
9435           *tree = NULL;
9436           *node = NULL;
9437           return FALSE;
9438         }
9439       if (i >= depth)
9440         {
9441           *tree = tmptree;
9442           *node = tmpnode;
9443           return FALSE;
9444         }
9445       *tree = tmptree;
9446       *node = tmpnode;
9447       tmptree = tmpnode->children;
9448       if (tmptree == NULL)
9449         return TRUE;
9450     }
9451   while (1);
9452 }
9453
9454 static gboolean
9455 gtk_tree_view_is_expander_column (GtkTreeView       *tree_view,
9456                                   GtkTreeViewColumn *column)
9457 {
9458   GList *list;
9459
9460   if (tree_view->priv->is_list)
9461     return FALSE;
9462
9463   if (tree_view->priv->expander_column != NULL)
9464     {
9465       if (tree_view->priv->expander_column == column)
9466         return TRUE;
9467       return FALSE;
9468     }
9469   else
9470     {
9471       for (list = tree_view->priv->columns;
9472            list;
9473            list = list->next)
9474         if (gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (list->data)))
9475           break;
9476       if (list && list->data == column)
9477         return TRUE;
9478     }
9479   return FALSE;
9480 }
9481
9482 static inline gboolean
9483 gtk_tree_view_draw_expanders (GtkTreeView *tree_view)
9484 {
9485   if (!tree_view->priv->is_list && tree_view->priv->show_expanders)
9486     return TRUE;
9487   /* else */
9488   return FALSE;
9489 }
9490
9491 static void
9492 gtk_tree_view_add_move_binding (GtkBindingSet  *binding_set,
9493                                 guint           keyval,
9494                                 guint           modmask,
9495                                 gboolean        add_shifted_binding,
9496                                 GtkMovementStep step,
9497                                 gint            count)
9498 {
9499   
9500   gtk_binding_entry_add_signal (binding_set, keyval, modmask,
9501                                 "move-cursor", 2,
9502                                 G_TYPE_ENUM, step,
9503                                 G_TYPE_INT, count);
9504
9505   if (add_shifted_binding)
9506     gtk_binding_entry_add_signal (binding_set, keyval, GDK_SHIFT_MASK,
9507                                   "move-cursor", 2,
9508                                   G_TYPE_ENUM, step,
9509                                   G_TYPE_INT, count);
9510
9511   if ((modmask & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
9512    return;
9513
9514   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK | GDK_SHIFT_MASK,
9515                                 "move-cursor", 2,
9516                                 G_TYPE_ENUM, step,
9517                                 G_TYPE_INT, count);
9518
9519   gtk_binding_entry_add_signal (binding_set, keyval, GDK_CONTROL_MASK,
9520                                 "move-cursor", 2,
9521                                 G_TYPE_ENUM, step,
9522                                 G_TYPE_INT, count);
9523 }
9524
9525 static gint
9526 gtk_tree_view_unref_tree_helper (GtkTreeModel *model,
9527                                  GtkTreeIter  *iter,
9528                                  GtkRBTree    *tree,
9529                                  GtkRBNode    *node)
9530 {
9531   gint retval = FALSE;
9532   do
9533     {
9534       g_return_val_if_fail (node != NULL, FALSE);
9535
9536       if (node->children)
9537         {
9538           GtkTreeIter child;
9539           GtkRBTree *new_tree;
9540           GtkRBNode *new_node;
9541
9542           new_tree = node->children;
9543           new_node = new_tree->root;
9544
9545           while (new_node && new_node->left != new_tree->nil)
9546             new_node = new_node->left;
9547
9548           if (!gtk_tree_model_iter_children (model, &child, iter))
9549             return FALSE;
9550
9551           retval = retval || gtk_tree_view_unref_tree_helper (model, &child, new_tree, new_node);
9552         }
9553
9554       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
9555         retval = TRUE;
9556       gtk_tree_model_unref_node (model, iter);
9557       node = _gtk_rbtree_next (tree, node);
9558     }
9559   while (gtk_tree_model_iter_next (model, iter));
9560
9561   return retval;
9562 }
9563
9564 static gint
9565 gtk_tree_view_unref_and_check_selection_tree (GtkTreeView *tree_view,
9566                                               GtkRBTree   *tree)
9567 {
9568   GtkTreeIter iter;
9569   GtkTreePath *path;
9570   GtkRBNode *node;
9571   gint retval;
9572
9573   if (!tree)
9574     return FALSE;
9575
9576   node = tree->root;
9577   while (node && node->left != tree->nil)
9578     node = node->left;
9579
9580   g_return_val_if_fail (node != NULL, FALSE);
9581   path = _gtk_tree_view_find_path (tree_view, tree, node);
9582   gtk_tree_model_get_iter (GTK_TREE_MODEL (tree_view->priv->model),
9583                            &iter, path);
9584   retval = gtk_tree_view_unref_tree_helper (GTK_TREE_MODEL (tree_view->priv->model), &iter, tree, node);
9585   gtk_tree_path_free (path);
9586
9587   return retval;
9588 }
9589
9590 static void
9591 gtk_tree_view_set_column_drag_info (GtkTreeView       *tree_view,
9592                                     GtkTreeViewColumn *column)
9593 {
9594   GtkTreeViewColumn *left_column;
9595   GtkTreeViewColumn *cur_column = NULL;
9596   GtkTreeViewColumnReorder *reorder;
9597   gboolean rtl;
9598   GList *tmp_list;
9599   gint left;
9600
9601   /* We want to precalculate the motion list such that we know what column slots
9602    * are available.
9603    */
9604   left_column = NULL;
9605   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
9606
9607   /* First, identify all possible drop spots */
9608   if (rtl)
9609     tmp_list = g_list_last (tree_view->priv->columns);
9610   else
9611     tmp_list = g_list_first (tree_view->priv->columns);
9612
9613   while (tmp_list)
9614     {
9615       cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
9616       tmp_list = rtl?g_list_previous (tmp_list):g_list_next (tmp_list);
9617
9618       if (gtk_tree_view_column_get_visible (cur_column) == FALSE)
9619         continue;
9620
9621       /* If it's not the column moving and func tells us to skip over the column, we continue. */
9622       if (left_column != column && cur_column != column &&
9623           tree_view->priv->column_drop_func &&
9624           ! tree_view->priv->column_drop_func (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
9625         {
9626           left_column = cur_column;
9627           continue;
9628         }
9629       reorder = g_slice_new0 (GtkTreeViewColumnReorder);
9630       reorder->left_column = left_column;
9631       left_column = reorder->right_column = cur_column;
9632
9633       tree_view->priv->column_drag_info = g_list_append (tree_view->priv->column_drag_info, reorder);
9634     }
9635
9636   /* Add the last one */
9637   if (tree_view->priv->column_drop_func == NULL ||
9638       ((left_column != column) &&
9639        tree_view->priv->column_drop_func (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data)))
9640     {
9641       reorder = g_slice_new0 (GtkTreeViewColumnReorder);
9642       reorder->left_column = left_column;
9643       reorder->right_column = NULL;
9644       tree_view->priv->column_drag_info = g_list_append (tree_view->priv->column_drag_info, reorder);
9645     }
9646
9647   /* We quickly check to see if it even makes sense to reorder columns. */
9648   /* If there is nothing that can be moved, then we return */
9649
9650   if (tree_view->priv->column_drag_info == NULL)
9651     return;
9652
9653   /* We know there are always 2 slots possbile, as you can always return column. */
9654   /* If that's all there is, return */
9655   if (tree_view->priv->column_drag_info->next == NULL || 
9656       (tree_view->priv->column_drag_info->next->next == NULL &&
9657        ((GtkTreeViewColumnReorder *)tree_view->priv->column_drag_info->data)->right_column == column &&
9658        ((GtkTreeViewColumnReorder *)tree_view->priv->column_drag_info->next->data)->left_column == column))
9659     {
9660       for (tmp_list = tree_view->priv->column_drag_info; tmp_list; tmp_list = tmp_list->next)
9661         g_slice_free (GtkTreeViewColumnReorder, tmp_list->data);
9662       g_list_free (tree_view->priv->column_drag_info);
9663       tree_view->priv->column_drag_info = NULL;
9664       return;
9665     }
9666   /* We fill in the ranges for the columns, now that we've isolated them */
9667   left = - TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER (tree_view);
9668
9669   for (tmp_list = tree_view->priv->column_drag_info; tmp_list; tmp_list = tmp_list->next)
9670     {
9671       reorder = (GtkTreeViewColumnReorder *) tmp_list->data;
9672
9673       reorder->left_align = left;
9674       if (tmp_list->next != NULL)
9675         {
9676           GtkAllocation right_allocation, left_allocation;
9677           GtkWidget    *left_button, *right_button;
9678
9679           g_assert (tmp_list->next->data);
9680
9681           right_button = gtk_tree_view_column_get_button (reorder->right_column);
9682           left_button  = gtk_tree_view_column_get_button
9683             (((GtkTreeViewColumnReorder *)tmp_list->next->data)->left_column);
9684
9685           gtk_widget_get_allocation (right_button, &right_allocation);
9686           gtk_widget_get_allocation (left_button, &left_allocation);
9687           left = reorder->right_align = (right_allocation.x + right_allocation.width + left_allocation.x) / 2;
9688         }
9689       else
9690         {
9691           reorder->right_align = gdk_window_get_width (tree_view->priv->header_window)
9692                                  + TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER (tree_view);
9693         }
9694     }
9695 }
9696
9697 void
9698 _gtk_tree_view_column_start_drag (GtkTreeView       *tree_view,
9699                                   GtkTreeViewColumn *column,
9700                                   GdkDevice         *device)
9701 {
9702   GdkEvent *send_event;
9703   GtkAllocation allocation;
9704   GtkAllocation button_allocation;
9705   GdkScreen *screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
9706   GtkWidget *button;
9707   GdkDevice *pointer, *keyboard;
9708
9709   g_return_if_fail (tree_view->priv->column_drag_info == NULL);
9710   g_return_if_fail (tree_view->priv->cur_reorder == NULL);
9711
9712   gtk_tree_view_set_column_drag_info (tree_view, column);
9713
9714   if (tree_view->priv->column_drag_info == NULL)
9715     return;
9716
9717   button = gtk_tree_view_column_get_button (column);
9718
9719   if (tree_view->priv->drag_window == NULL)
9720     {
9721       GdkWindowAttr attributes;
9722       guint attributes_mask;
9723
9724       gtk_widget_get_allocation (button, &button_allocation);
9725
9726       attributes.window_type = GDK_WINDOW_CHILD;
9727       attributes.wclass = GDK_INPUT_OUTPUT;
9728       attributes.x = button_allocation.x;
9729       attributes.y = 0;
9730       attributes.width = button_allocation.width;
9731       attributes.height = button_allocation.height;
9732       attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
9733       attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
9734       attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
9735
9736       tree_view->priv->drag_window = gdk_window_new (tree_view->priv->bin_window,
9737                                                      &attributes,
9738                                                      attributes_mask);
9739       gdk_window_set_user_data (tree_view->priv->drag_window, GTK_WIDGET (tree_view));
9740     }
9741
9742   if (gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD)
9743     {
9744       keyboard = device;
9745       pointer = gdk_device_get_associated_device (device);
9746     }
9747   else
9748     {
9749       pointer = device;
9750       keyboard = gdk_device_get_associated_device (device);
9751     }
9752
9753   gdk_device_ungrab (pointer, GDK_CURRENT_TIME);
9754   gdk_device_ungrab (keyboard, GDK_CURRENT_TIME);
9755
9756   gtk_grab_remove (button);
9757
9758   send_event = gdk_event_new (GDK_LEAVE_NOTIFY);
9759   send_event->crossing.send_event = TRUE;
9760   send_event->crossing.window = g_object_ref (gtk_button_get_event_window (GTK_BUTTON (button)));
9761   send_event->crossing.subwindow = NULL;
9762   send_event->crossing.detail = GDK_NOTIFY_ANCESTOR;
9763   send_event->crossing.time = GDK_CURRENT_TIME;
9764   gdk_event_set_device (send_event, device);
9765
9766   gtk_propagate_event (button, send_event);
9767   gdk_event_free (send_event);
9768
9769   send_event = gdk_event_new (GDK_BUTTON_RELEASE);
9770   send_event->button.window = g_object_ref (gdk_screen_get_root_window (screen));
9771   send_event->button.send_event = TRUE;
9772   send_event->button.time = GDK_CURRENT_TIME;
9773   send_event->button.x = -1;
9774   send_event->button.y = -1;
9775   send_event->button.axes = NULL;
9776   send_event->button.state = 0;
9777   send_event->button.button = 1;
9778   send_event->button.x_root = 0;
9779   send_event->button.y_root = 0;
9780   gdk_event_set_device (send_event, device);
9781
9782   gtk_propagate_event (button, send_event);
9783   gdk_event_free (send_event);
9784
9785   /* Kids, don't try this at home */
9786   g_object_ref (button);
9787   gtk_container_remove (GTK_CONTAINER (tree_view), button);
9788   gtk_widget_set_parent_window (button, tree_view->priv->drag_window);
9789   gtk_widget_set_parent (button, GTK_WIDGET (tree_view));
9790   g_object_unref (button);
9791
9792   gtk_widget_get_allocation (button, &button_allocation);
9793   tree_view->priv->drag_column_x = button_allocation.x;
9794   allocation = button_allocation;
9795   allocation.x = 0;
9796   gtk_widget_size_allocate (button, &allocation);
9797   gtk_widget_set_parent_window (button, tree_view->priv->drag_window);
9798
9799   tree_view->priv->drag_column = column;
9800   gdk_window_show (tree_view->priv->drag_window);
9801
9802   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
9803   while (gtk_events_pending ())
9804     gtk_main_iteration ();
9805
9806   tree_view->priv->in_column_drag = TRUE;
9807
9808   gdk_device_grab (pointer,
9809                    tree_view->priv->drag_window,
9810                    GDK_OWNERSHIP_NONE,
9811                    FALSE,
9812                    GDK_POINTER_MOTION_MASK|GDK_BUTTON_RELEASE_MASK,
9813                    NULL,
9814                    GDK_CURRENT_TIME);
9815   gdk_device_grab (keyboard,
9816                    tree_view->priv->drag_window,
9817                    GDK_OWNERSHIP_NONE,
9818                    FALSE,
9819                    GDK_KEY_PRESS_MASK|GDK_KEY_RELEASE_MASK,
9820                    NULL,
9821                    GDK_CURRENT_TIME);
9822 }
9823
9824 static void
9825 gtk_tree_view_queue_draw_arrow (GtkTreeView        *tree_view,
9826                                 GtkRBTree          *tree,
9827                                 GtkRBNode          *node)
9828 {
9829   GtkAllocation allocation;
9830   GdkRectangle rect;
9831
9832   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
9833     return;
9834
9835   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
9836   rect.x = 0;
9837   rect.width = MAX (tree_view->priv->expander_size, MAX (tree_view->priv->width, allocation.width));
9838
9839   rect.y = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
9840   rect.height = gtk_tree_view_get_row_height (tree_view, node);
9841
9842   gdk_window_invalidate_rect (tree_view->priv->bin_window, &rect, TRUE);
9843 }
9844
9845 void
9846 _gtk_tree_view_queue_draw_node (GtkTreeView        *tree_view,
9847                                 GtkRBTree          *tree,
9848                                 GtkRBNode          *node,
9849                                 const GdkRectangle *clip_rect)
9850 {
9851   GtkAllocation allocation;
9852   GdkRectangle rect;
9853
9854   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
9855     return;
9856
9857   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
9858   rect.x = 0;
9859   rect.width = MAX (tree_view->priv->width, allocation.width);
9860
9861   rect.y = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
9862   rect.height = gtk_tree_view_get_row_height (tree_view, node);
9863
9864   if (clip_rect)
9865     {
9866       GdkRectangle new_rect;
9867
9868       gdk_rectangle_intersect (clip_rect, &rect, &new_rect);
9869
9870       gdk_window_invalidate_rect (tree_view->priv->bin_window, &new_rect, TRUE);
9871     }
9872   else
9873     {
9874       gdk_window_invalidate_rect (tree_view->priv->bin_window, &rect, TRUE);
9875     }
9876 }
9877
9878 static inline gint
9879 gtk_tree_view_get_effective_header_height (GtkTreeView *tree_view)
9880 {
9881   if (tree_view->priv->headers_visible)
9882     return tree_view->priv->header_height;
9883   /* else */
9884   return 0;
9885 }
9886
9887 gint
9888 _gtk_tree_view_get_header_height (GtkTreeView *tree_view)
9889 {
9890   return tree_view->priv->header_height;
9891 }
9892
9893 void
9894 _gtk_tree_view_get_row_separator_func (GtkTreeView                 *tree_view,
9895                                        GtkTreeViewRowSeparatorFunc *func,
9896                                        gpointer                    *data)
9897 {
9898   *func = tree_view->priv->row_separator_func;
9899   *data = tree_view->priv->row_separator_data;
9900 }
9901
9902 GtkTreePath *
9903 _gtk_tree_view_get_anchor_path (GtkTreeView *tree_view)
9904 {
9905   if (tree_view->priv->anchor)
9906     return gtk_tree_row_reference_get_path (tree_view->priv->anchor);
9907
9908   return NULL;
9909 }
9910
9911 void
9912 _gtk_tree_view_set_anchor_path (GtkTreeView *tree_view,
9913                                 GtkTreePath *anchor_path)
9914 {
9915   if (tree_view->priv->anchor)
9916     {
9917       gtk_tree_row_reference_free (tree_view->priv->anchor);
9918       tree_view->priv->anchor = NULL;
9919     }
9920
9921   if (anchor_path && tree_view->priv->model)
9922     tree_view->priv->anchor =
9923       gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), 
9924                                         tree_view->priv->model, anchor_path);
9925 }
9926
9927 GtkRBTree *
9928 _gtk_tree_view_get_rbtree (GtkTreeView *tree_view)
9929 {
9930   return tree_view->priv->tree;
9931 }
9932
9933 GdkWindow *
9934 _gtk_tree_view_get_header_window (GtkTreeView *tree_view)
9935 {
9936   return tree_view->priv->header_window;
9937 }
9938
9939 void
9940 _gtk_tree_view_set_focus_column (GtkTreeView       *tree_view,
9941                                  GtkTreeViewColumn *column)
9942 {
9943   tree_view->priv->focus_column = column;
9944 }
9945
9946
9947 static void
9948 gtk_tree_view_queue_draw_path (GtkTreeView        *tree_view,
9949                                GtkTreePath        *path,
9950                                const GdkRectangle *clip_rect)
9951 {
9952   GtkRBTree *tree = NULL;
9953   GtkRBNode *node = NULL;
9954
9955   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
9956
9957   if (tree)
9958     _gtk_tree_view_queue_draw_node (tree_view, tree, node, clip_rect);
9959 }
9960
9961 /* x and y are the mouse position
9962  */
9963 static void
9964 gtk_tree_view_draw_arrow (GtkTreeView *tree_view,
9965                           cairo_t     *cr,
9966                           GtkRBTree   *tree,
9967                           GtkRBNode   *node,
9968                           /* in bin_window coordinates */
9969                           gint         x,
9970                           gint         y)
9971 {
9972   GdkRectangle area;
9973   GtkStateFlags state = 0;
9974   GtkStyleContext *context;
9975   GtkWidget *widget;
9976   gint x_offset = 0;
9977   gint x2;
9978   gint vertical_separator;
9979   gint expander_size;
9980   GtkCellRendererState flags;
9981
9982   widget = GTK_WIDGET (tree_view);
9983   context = gtk_widget_get_style_context (widget);
9984
9985   gtk_widget_style_get (widget,
9986                         "vertical-separator", &vertical_separator,
9987                         NULL);
9988   expander_size = tree_view->priv->expander_size - EXPANDER_EXTRA_PADDING;
9989
9990   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
9991     return;
9992
9993   gtk_tree_view_get_arrow_xrange (tree_view, tree, &x_offset, &x2);
9994
9995   area.x = x_offset;
9996   area.y = gtk_tree_view_get_cell_area_y_offset (tree_view, tree, node,
9997                                                  vertical_separator);
9998   area.width = expander_size;
9999   area.height = gtk_tree_view_get_cell_area_height (tree_view, node,
10000                                                     vertical_separator);
10001
10002   if (!gtk_widget_get_sensitive (widget))
10003     state |= GTK_STATE_FLAG_INSENSITIVE;
10004   else
10005     {
10006       flags = 0;
10007
10008       if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
10009         flags |= GTK_CELL_RENDERER_SELECTED;
10010
10011       state = gtk_cell_renderer_get_state (NULL, widget, flags);
10012
10013       if (node == tree_view->priv->button_pressed_node &&
10014           x >= area.x && x <= (area.x + area.width) &&
10015           y >= area.y && y <= (area.y + area.height))
10016         state |= GTK_STATE_FLAG_FOCUSED;
10017
10018       if (node == tree_view->priv->prelight_node &&
10019           tree_view->priv->arrow_prelit)
10020         state |= GTK_STATE_FLAG_PRELIGHT;
10021     }
10022
10023   if (node->children != NULL)
10024     state |= GTK_STATE_FLAG_ACTIVE;
10025
10026   gtk_style_context_save (context);
10027
10028   gtk_style_context_set_state (context, state);
10029   gtk_style_context_add_class (context, GTK_STYLE_CLASS_EXPANDER);
10030
10031   gtk_style_context_push_animatable_region (context, node);
10032
10033   gtk_render_expander (context, cr,
10034                        area.x, area.y,
10035                        area.width, area.height);
10036
10037   gtk_style_context_pop_animatable_region (context);
10038   gtk_style_context_restore (context);
10039 }
10040
10041 static void
10042 gtk_tree_view_focus_to_cursor (GtkTreeView *tree_view)
10043
10044 {
10045   GtkTreePath *cursor_path;
10046
10047   if ((tree_view->priv->tree == NULL) ||
10048       (! gtk_widget_get_realized (GTK_WIDGET (tree_view))))
10049     return;
10050
10051   cursor_path = NULL;
10052   if (tree_view->priv->cursor)
10053     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10054
10055   if (cursor_path == NULL)
10056     {
10057       /* Consult the selection before defaulting to the
10058        * first focusable element
10059        */
10060       GList *selected_rows;
10061       GtkTreeModel *model;
10062       GtkTreeSelection *selection;
10063
10064       selection = gtk_tree_view_get_selection (tree_view);
10065       selected_rows = gtk_tree_selection_get_selected_rows (selection, &model);
10066
10067       if (selected_rows)
10068         {
10069           cursor_path = gtk_tree_path_copy((const GtkTreePath *)(selected_rows->data));
10070           g_list_foreach (selected_rows, (GFunc)gtk_tree_path_free, NULL);
10071           g_list_free (selected_rows);
10072         }
10073       else
10074         {
10075           cursor_path = gtk_tree_path_new_first ();
10076           search_first_focusable_path (tree_view, &cursor_path,
10077                                        TRUE, NULL, NULL);
10078         }
10079
10080       gtk_tree_row_reference_free (tree_view->priv->cursor);
10081       tree_view->priv->cursor = NULL;
10082
10083       if (cursor_path)
10084         {
10085           if (gtk_tree_selection_get_mode (tree_view->priv->selection) == GTK_SELECTION_MULTIPLE)
10086             gtk_tree_view_real_set_cursor (tree_view, cursor_path, FALSE, FALSE);
10087           else
10088             gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE);
10089         }
10090     }
10091
10092   if (cursor_path)
10093     {
10094       tree_view->priv->draw_keyfocus = TRUE;
10095
10096       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10097       gtk_tree_path_free (cursor_path);
10098
10099       if (tree_view->priv->focus_column == NULL)
10100         {
10101           GList *list;
10102           for (list = tree_view->priv->columns; list; list = list->next)
10103             {
10104               if (gtk_tree_view_column_get_visible (GTK_TREE_VIEW_COLUMN (list->data)))
10105                 {
10106                   GtkCellArea *cell_area;
10107
10108                   tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (list->data);
10109
10110                   /* This happens when the treeview initially grabs focus and there
10111                    * is no column in focus, here we explicitly focus into the first cell */
10112                   cell_area = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (tree_view->priv->focus_column));
10113                   if (!gtk_cell_area_get_focus_cell (cell_area))
10114                     {
10115                       gboolean rtl;
10116
10117                       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
10118                       gtk_cell_area_focus (cell_area,
10119                                            rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT);
10120                     }
10121
10122                   break;
10123                 }
10124             }
10125         }
10126     }
10127 }
10128
10129 static void
10130 gtk_tree_view_move_cursor_up_down (GtkTreeView *tree_view,
10131                                    gint         count)
10132 {
10133   gint selection_count;
10134   GtkRBTree *cursor_tree = NULL;
10135   GtkRBNode *cursor_node = NULL;
10136   GtkRBTree *new_cursor_tree = NULL;
10137   GtkRBNode *new_cursor_node = NULL;
10138   GtkTreePath *cursor_path = NULL;
10139   gboolean grab_focus = TRUE;
10140   gboolean selectable;
10141   GtkDirectionType direction;
10142   GtkCellArea *cell_area = NULL;
10143   GtkCellRenderer *last_focus_cell = NULL;
10144   GtkTreeIter iter;
10145
10146   if (! gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10147     return;
10148
10149   cursor_path = NULL;
10150   if (!gtk_tree_row_reference_valid (tree_view->priv->cursor))
10151     /* FIXME: we lost the cursor; should we get the first? */
10152     return;
10153
10154   cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10155   _gtk_tree_view_find_node (tree_view, cursor_path,
10156                             &cursor_tree, &cursor_node);
10157
10158   if (cursor_tree == NULL)
10159     /* FIXME: we lost the cursor; should we get the first? */
10160     return;
10161
10162   direction = count < 0 ? GTK_DIR_UP : GTK_DIR_DOWN;
10163
10164   if (tree_view->priv->focus_column)
10165     cell_area = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (tree_view->priv->focus_column));
10166
10167   /* If focus stays in the area for this row, then just return for this round */
10168   if (cell_area && (count == -1 || count == 1) &&
10169       gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path))
10170     {
10171       gtk_tree_view_column_cell_set_cell_data (tree_view->priv->focus_column,
10172                                                tree_view->priv->model,
10173                                                &iter,
10174                                                GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_PARENT),
10175                                                cursor_node->children?TRUE:FALSE);
10176
10177       /* Save the last cell that had focus, if we hit the end of the view we'll give
10178        * focus back to it. */
10179       last_focus_cell = gtk_cell_area_get_focus_cell (cell_area);
10180
10181       /* If focus stays in the area, no need to change the cursor row */
10182       if (gtk_cell_area_focus (cell_area, direction))
10183         return;
10184     }
10185
10186   selection_count = gtk_tree_selection_count_selected_rows (tree_view->priv->selection);
10187   selectable = _gtk_tree_selection_row_is_selectable (tree_view->priv->selection,
10188                                                       cursor_node,
10189                                                       cursor_path);
10190
10191   if (selection_count == 0
10192       && gtk_tree_selection_get_mode (tree_view->priv->selection) != GTK_SELECTION_NONE
10193       && !tree_view->priv->ctrl_pressed
10194       && selectable)
10195     {
10196       /* Don't move the cursor, but just select the current node */
10197       new_cursor_tree = cursor_tree;
10198       new_cursor_node = cursor_node;
10199     }
10200   else
10201     {
10202       if (count == -1)
10203         _gtk_rbtree_prev_full (cursor_tree, cursor_node,
10204                                &new_cursor_tree, &new_cursor_node);
10205       else
10206         _gtk_rbtree_next_full (cursor_tree, cursor_node,
10207                                &new_cursor_tree, &new_cursor_node);
10208     }
10209
10210   gtk_tree_path_free (cursor_path);
10211
10212   if (new_cursor_node)
10213     {
10214       cursor_path = _gtk_tree_view_find_path (tree_view,
10215                                               new_cursor_tree, new_cursor_node);
10216
10217       search_first_focusable_path (tree_view, &cursor_path,
10218                                    (count != -1),
10219                                    &new_cursor_tree,
10220                                    &new_cursor_node);
10221
10222       if (cursor_path)
10223         gtk_tree_path_free (cursor_path);
10224     }
10225
10226   /*
10227    * If the list has only one item and multi-selection is set then select
10228    * the row (if not yet selected).
10229    */
10230   if (gtk_tree_selection_get_mode (tree_view->priv->selection) == GTK_SELECTION_MULTIPLE &&
10231       new_cursor_node == NULL)
10232     {
10233       if (count == -1)
10234         _gtk_rbtree_next_full (cursor_tree, cursor_node,
10235                                &new_cursor_tree, &new_cursor_node);
10236       else
10237         _gtk_rbtree_prev_full (cursor_tree, cursor_node,
10238                                &new_cursor_tree, &new_cursor_node);
10239
10240       if (new_cursor_node == NULL
10241           && !GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_SELECTED))
10242         {
10243           new_cursor_node = cursor_node;
10244           new_cursor_tree = cursor_tree;
10245         }
10246       else
10247         {
10248           new_cursor_node = NULL;
10249         }
10250     }
10251
10252   if (new_cursor_node)
10253     {
10254       cursor_path = _gtk_tree_view_find_path (tree_view, new_cursor_tree, new_cursor_node);
10255       gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, TRUE);
10256       gtk_tree_path_free (cursor_path);
10257
10258       /* Give focus to the area in the new row */
10259       if (cell_area)
10260         gtk_cell_area_focus (cell_area, direction);
10261     }
10262   else
10263     {
10264       gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10265
10266       if (!tree_view->priv->shift_pressed)
10267         {
10268           if (! gtk_widget_keynav_failed (GTK_WIDGET (tree_view),
10269                                           count < 0 ?
10270                                           GTK_DIR_UP : GTK_DIR_DOWN))
10271             {
10272               GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (tree_view));
10273
10274               if (toplevel)
10275                 gtk_widget_child_focus (toplevel,
10276                                         count < 0 ?
10277                                         GTK_DIR_TAB_BACKWARD :
10278                                         GTK_DIR_TAB_FORWARD);
10279
10280               grab_focus = FALSE;
10281             }
10282         }
10283       else
10284         {
10285           gtk_widget_error_bell (GTK_WIDGET (tree_view));
10286         }
10287
10288       if (cell_area)
10289         gtk_cell_area_set_focus_cell (cell_area, last_focus_cell);
10290     }
10291
10292   if (grab_focus)
10293     gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10294 }
10295
10296 static void
10297 gtk_tree_view_move_cursor_page_up_down (GtkTreeView *tree_view,
10298                                         gint         count)
10299 {
10300   GtkRBTree *cursor_tree = NULL;
10301   GtkRBNode *cursor_node = NULL;
10302   GtkTreePath *old_cursor_path = NULL;
10303   GtkTreePath *cursor_path = NULL;
10304   GtkRBTree *start_cursor_tree = NULL;
10305   GtkRBNode *start_cursor_node = NULL;
10306   gint y;
10307   gint window_y;
10308   gint vertical_separator;
10309
10310   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10311     return;
10312
10313   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
10314     old_cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10315   else
10316     /* This is sorta weird.  Focus in should give us a cursor */
10317     return;
10318
10319   gtk_widget_style_get (GTK_WIDGET (tree_view), "vertical-separator", &vertical_separator, NULL);
10320   _gtk_tree_view_find_node (tree_view, old_cursor_path,
10321                             &cursor_tree, &cursor_node);
10322
10323   if (cursor_tree == NULL)
10324     {
10325       /* FIXME: we lost the cursor.  Should we try to get one? */
10326       gtk_tree_path_free (old_cursor_path);
10327       return;
10328     }
10329   g_return_if_fail (cursor_node != NULL);
10330
10331   y = _gtk_rbtree_node_find_offset (cursor_tree, cursor_node);
10332   window_y = RBTREE_Y_TO_TREE_WINDOW_Y (tree_view, y);
10333   y += tree_view->priv->cursor_offset;
10334   y += count * (int)gtk_adjustment_get_page_increment (tree_view->priv->vadjustment);
10335   y = CLAMP (y, (gint)gtk_adjustment_get_lower (tree_view->priv->vadjustment),  (gint)gtk_adjustment_get_upper (tree_view->priv->vadjustment) - vertical_separator);
10336
10337   if (y >= tree_view->priv->height)
10338     y = tree_view->priv->height - 1;
10339
10340   tree_view->priv->cursor_offset =
10341     _gtk_rbtree_find_offset (tree_view->priv->tree, y,
10342                              &cursor_tree, &cursor_node);
10343
10344   if (cursor_tree == NULL)
10345     {
10346       /* FIXME: we lost the cursor.  Should we try to get one? */
10347       gtk_tree_path_free (old_cursor_path);
10348       return;
10349     }
10350
10351   if (tree_view->priv->cursor_offset
10352       > gtk_tree_view_get_row_height (tree_view, cursor_node))
10353     {
10354       _gtk_rbtree_next_full (cursor_tree, cursor_node,
10355                              &cursor_tree, &cursor_node);
10356       tree_view->priv->cursor_offset -= gtk_tree_view_get_row_height (tree_view, cursor_node);
10357     }
10358
10359   y -= tree_view->priv->cursor_offset;
10360   cursor_path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
10361
10362   start_cursor_tree = cursor_tree;
10363   start_cursor_node = cursor_node;
10364
10365   if (! search_first_focusable_path (tree_view, &cursor_path,
10366                                      (count != -1),
10367                                      &cursor_tree, &cursor_node))
10368     {
10369       /* It looks like we reached the end of the view without finding
10370        * a focusable row.  We will step backwards to find the last
10371        * focusable row.
10372        */
10373       cursor_tree = start_cursor_tree;
10374       cursor_node = start_cursor_node;
10375       cursor_path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
10376
10377       search_first_focusable_path (tree_view, &cursor_path,
10378                                    (count == -1),
10379                                    &cursor_tree, &cursor_node);
10380     }
10381
10382   if (!cursor_path)
10383     goto cleanup;
10384
10385   /* update y */
10386   y = _gtk_rbtree_node_find_offset (cursor_tree, cursor_node);
10387
10388   gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE);
10389
10390   y -= window_y;
10391   gtk_tree_view_scroll_to_point (tree_view, -1, y);
10392   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10393   _gtk_tree_view_queue_draw_node (tree_view, cursor_tree, cursor_node, NULL);
10394
10395   if (!gtk_tree_path_compare (old_cursor_path, cursor_path))
10396     gtk_widget_error_bell (GTK_WIDGET (tree_view));
10397
10398   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10399
10400 cleanup:
10401   gtk_tree_path_free (old_cursor_path);
10402   gtk_tree_path_free (cursor_path);
10403 }
10404
10405 static void
10406 gtk_tree_view_move_cursor_left_right (GtkTreeView *tree_view,
10407                                       gint         count)
10408 {
10409   GtkRBTree *cursor_tree = NULL;
10410   GtkRBNode *cursor_node = NULL;
10411   GtkTreePath *cursor_path = NULL;
10412   GtkTreeViewColumn *column;
10413   GtkTreeIter iter;
10414   GList *list;
10415   gboolean found_column = FALSE;
10416   gboolean rtl;
10417   GtkDirectionType direction;
10418   GtkCellArea     *cell_area;
10419   GtkCellRenderer *last_focus_cell = NULL;
10420   GtkCellArea     *last_focus_area = NULL;
10421
10422   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
10423
10424   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10425     return;
10426
10427   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
10428     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10429   else
10430     return;
10431
10432   _gtk_tree_view_find_node (tree_view, cursor_path, &cursor_tree, &cursor_node);
10433   if (cursor_tree == NULL)
10434     return;
10435   if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path) == FALSE)
10436     {
10437       gtk_tree_path_free (cursor_path);
10438       return;
10439     }
10440   gtk_tree_path_free (cursor_path);
10441
10442   list = rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns);
10443   if (tree_view->priv->focus_column)
10444     {
10445       /* Save the cell/area we are moving focus from, if moving the cursor
10446        * by one step hits the end we'll set focus back here */
10447       last_focus_area = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (tree_view->priv->focus_column));
10448       last_focus_cell = gtk_cell_area_get_focus_cell (last_focus_area);
10449
10450       for (; list; list = (rtl ? list->prev : list->next))
10451         {
10452           if (list->data == tree_view->priv->focus_column)
10453             break;
10454         }
10455     }
10456
10457   direction = count > 0 ? GTK_DIR_RIGHT : GTK_DIR_LEFT;
10458
10459   while (list)
10460     {
10461       column = list->data;
10462       if (gtk_tree_view_column_get_visible (column) == FALSE)
10463         goto loop_end;
10464
10465       gtk_tree_view_column_cell_set_cell_data (column,
10466                                                tree_view->priv->model,
10467                                                &iter,
10468                                                GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_PARENT),
10469                                                cursor_node->children?TRUE:FALSE);
10470
10471       cell_area = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (column));
10472       if (gtk_cell_area_focus (cell_area, direction))
10473         {
10474           tree_view->priv->focus_column = column;
10475           found_column = TRUE;
10476           break;
10477         }
10478
10479     loop_end:
10480       if (count == 1)
10481         list = rtl ? list->prev : list->next;
10482       else
10483         list = rtl ? list->next : list->prev;
10484     }
10485
10486   if (found_column)
10487     {
10488       if (!gtk_tree_view_has_can_focus_cell (tree_view))
10489         _gtk_tree_view_queue_draw_node (tree_view,
10490                                         cursor_tree,
10491                                         cursor_node,
10492                                         NULL);
10493       g_signal_emit (tree_view, tree_view_signals[CURSOR_CHANGED], 0);
10494       gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10495     }
10496   else
10497     {
10498       gtk_widget_error_bell (GTK_WIDGET (tree_view));
10499
10500       if (last_focus_area)
10501         gtk_cell_area_set_focus_cell (last_focus_area, last_focus_cell);
10502     }
10503
10504   gtk_tree_view_clamp_column_visible (tree_view,
10505                                       tree_view->priv->focus_column, TRUE);
10506 }
10507
10508 static void
10509 gtk_tree_view_move_cursor_start_end (GtkTreeView *tree_view,
10510                                      gint         count)
10511 {
10512   GtkRBTree *cursor_tree;
10513   GtkRBNode *cursor_node;
10514   GtkTreePath *path;
10515   GtkTreePath *old_path;
10516
10517   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10518     return;
10519
10520   g_return_if_fail (tree_view->priv->tree != NULL);
10521
10522   gtk_tree_view_get_cursor (tree_view, &old_path, NULL);
10523
10524   cursor_tree = tree_view->priv->tree;
10525   cursor_node = cursor_tree->root;
10526
10527   if (count == -1)
10528     {
10529       while (cursor_node && cursor_node->left != cursor_tree->nil)
10530         cursor_node = cursor_node->left;
10531
10532       /* Now go forward to find the first focusable row. */
10533       path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
10534       search_first_focusable_path (tree_view, &path,
10535                                    TRUE, &cursor_tree, &cursor_node);
10536     }
10537   else
10538     {
10539       do
10540         {
10541           while (cursor_node && cursor_node->right != cursor_tree->nil)
10542             cursor_node = cursor_node->right;
10543           if (cursor_node->children == NULL)
10544             break;
10545
10546           cursor_tree = cursor_node->children;
10547           cursor_node = cursor_tree->root;
10548         }
10549       while (1);
10550
10551       /* Now go backwards to find last focusable row. */
10552       path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
10553       search_first_focusable_path (tree_view, &path,
10554                                    FALSE, &cursor_tree, &cursor_node);
10555     }
10556
10557   if (!path)
10558     goto cleanup;
10559
10560   if (gtk_tree_path_compare (old_path, path))
10561     {
10562       gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
10563       gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10564     }
10565   else
10566     {
10567       gtk_widget_error_bell (GTK_WIDGET (tree_view));
10568     }
10569
10570 cleanup:
10571   gtk_tree_path_free (old_path);
10572   gtk_tree_path_free (path);
10573 }
10574
10575 static gboolean
10576 gtk_tree_view_real_select_all (GtkTreeView *tree_view)
10577 {
10578   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10579     return FALSE;
10580
10581   if (gtk_tree_selection_get_mode (tree_view->priv->selection) != GTK_SELECTION_MULTIPLE)
10582     return FALSE;
10583
10584   gtk_tree_selection_select_all (tree_view->priv->selection);
10585
10586   return TRUE;
10587 }
10588
10589 static gboolean
10590 gtk_tree_view_real_unselect_all (GtkTreeView *tree_view)
10591 {
10592   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10593     return FALSE;
10594
10595   if (gtk_tree_selection_get_mode (tree_view->priv->selection) != GTK_SELECTION_MULTIPLE)
10596     return FALSE;
10597
10598   gtk_tree_selection_unselect_all (tree_view->priv->selection);
10599
10600   return TRUE;
10601 }
10602
10603 static gboolean
10604 gtk_tree_view_real_select_cursor_row (GtkTreeView *tree_view,
10605                                       gboolean     start_editing)
10606 {
10607   GtkRBTree *new_tree = NULL;
10608   GtkRBNode *new_node = NULL;
10609   GtkRBTree *cursor_tree = NULL;
10610   GtkRBNode *cursor_node = NULL;
10611   GtkTreePath *cursor_path = NULL;
10612   GtkTreeSelectMode mode = 0;
10613
10614   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10615     return FALSE;
10616
10617   if (tree_view->priv->cursor)
10618     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10619
10620   if (cursor_path == NULL)
10621     return FALSE;
10622
10623   _gtk_tree_view_find_node (tree_view, cursor_path,
10624                             &cursor_tree, &cursor_node);
10625
10626   if (cursor_tree == NULL)
10627     {
10628       gtk_tree_path_free (cursor_path);
10629       return FALSE;
10630     }
10631
10632   if (!tree_view->priv->shift_pressed && start_editing &&
10633       tree_view->priv->focus_column)
10634     {
10635       if (gtk_tree_view_start_editing (tree_view, cursor_path, FALSE))
10636         {
10637           gtk_tree_path_free (cursor_path);
10638           return TRUE;
10639         }
10640     }
10641
10642   if (tree_view->priv->ctrl_pressed)
10643     mode |= GTK_TREE_SELECT_MODE_TOGGLE;
10644   if (tree_view->priv->shift_pressed)
10645     mode |= GTK_TREE_SELECT_MODE_EXTEND;
10646
10647   _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
10648                                             cursor_node,
10649                                             cursor_tree,
10650                                             cursor_path,
10651                                             mode,
10652                                             FALSE);
10653
10654   /* We bail out if the original (tree, node) don't exist anymore after
10655    * handling the selection-changed callback.  We do return TRUE because
10656    * the key press has been handled at this point.
10657    */
10658   _gtk_tree_view_find_node (tree_view, cursor_path, &new_tree, &new_node);
10659
10660   if (cursor_tree != new_tree || cursor_node != new_node)
10661     return FALSE;
10662
10663   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10664
10665   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10666   _gtk_tree_view_queue_draw_node (tree_view, cursor_tree, cursor_node, NULL);
10667
10668   if (!tree_view->priv->shift_pressed)
10669     gtk_tree_view_row_activated (tree_view, cursor_path,
10670                                  tree_view->priv->focus_column);
10671     
10672   gtk_tree_path_free (cursor_path);
10673
10674   return TRUE;
10675 }
10676
10677 static gboolean
10678 gtk_tree_view_real_toggle_cursor_row (GtkTreeView *tree_view)
10679 {
10680   GtkRBTree *new_tree = NULL;
10681   GtkRBNode *new_node = NULL;
10682   GtkRBTree *cursor_tree = NULL;
10683   GtkRBNode *cursor_node = NULL;
10684   GtkTreePath *cursor_path = NULL;
10685
10686   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10687     return FALSE;
10688
10689   cursor_path = NULL;
10690   if (tree_view->priv->cursor)
10691     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10692
10693   if (cursor_path == NULL)
10694     return FALSE;
10695
10696   _gtk_tree_view_find_node (tree_view, cursor_path,
10697                             &cursor_tree, &cursor_node);
10698   if (cursor_tree == NULL)
10699     {
10700       gtk_tree_path_free (cursor_path);
10701       return FALSE;
10702     }
10703
10704   _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
10705                                             cursor_node,
10706                                             cursor_tree,
10707                                             cursor_path,
10708                                             GTK_TREE_SELECT_MODE_TOGGLE,
10709                                             FALSE);
10710
10711   /* We bail out if the original (tree, node) don't exist anymore after
10712    * handling the selection-changed callback.  We do return TRUE because
10713    * the key press has been handled at this point.
10714    */
10715   _gtk_tree_view_find_node (tree_view, cursor_path, &new_tree, &new_node);
10716
10717   if (cursor_tree != new_tree || cursor_node != new_node)
10718     return FALSE;
10719
10720   gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10721
10722   gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10723   gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10724   gtk_tree_path_free (cursor_path);
10725
10726   return TRUE;
10727 }
10728
10729 static gboolean
10730 gtk_tree_view_real_expand_collapse_cursor_row (GtkTreeView *tree_view,
10731                                                gboolean     logical,
10732                                                gboolean     expand,
10733                                                gboolean     open_all)
10734 {
10735   GtkTreePath *cursor_path = NULL;
10736   GtkRBTree *tree;
10737   GtkRBNode *node;
10738
10739   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10740     return FALSE;
10741
10742   cursor_path = NULL;
10743   if (tree_view->priv->cursor)
10744     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10745
10746   if (cursor_path == NULL)
10747     return FALSE;
10748
10749   if (_gtk_tree_view_find_node (tree_view, cursor_path, &tree, &node))
10750     return FALSE;
10751
10752   /* Don't handle the event if we aren't an expander */
10753   if (!((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT))
10754     return FALSE;
10755
10756   if (!logical
10757       && gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL)
10758     expand = !expand;
10759
10760   if (expand)
10761     gtk_tree_view_real_expand_row (tree_view, cursor_path, tree, node, open_all, TRUE);
10762   else
10763     gtk_tree_view_real_collapse_row (tree_view, cursor_path, tree, node, TRUE);
10764
10765   gtk_tree_path_free (cursor_path);
10766
10767   return TRUE;
10768 }
10769
10770 static gboolean
10771 gtk_tree_view_real_select_cursor_parent (GtkTreeView *tree_view)
10772 {
10773   GtkRBTree *cursor_tree = NULL;
10774   GtkRBNode *cursor_node = NULL;
10775   GtkTreePath *cursor_path = NULL;
10776   GdkModifierType state;
10777
10778   if (!gtk_widget_has_focus (GTK_WIDGET (tree_view)))
10779     goto out;
10780
10781   cursor_path = NULL;
10782   if (tree_view->priv->cursor)
10783     cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
10784
10785   if (cursor_path == NULL)
10786     goto out;
10787
10788   _gtk_tree_view_find_node (tree_view, cursor_path,
10789                             &cursor_tree, &cursor_node);
10790   if (cursor_tree == NULL)
10791     {
10792       gtk_tree_path_free (cursor_path);
10793       goto out;
10794     }
10795
10796   if (cursor_tree->parent_node)
10797     {
10798       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10799       cursor_node = cursor_tree->parent_node;
10800       cursor_tree = cursor_tree->parent_tree;
10801
10802       gtk_tree_path_up (cursor_path);
10803
10804       if (gtk_get_current_event_state (&state))
10805         {
10806           if ((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
10807             tree_view->priv->ctrl_pressed = TRUE;
10808         }
10809
10810       gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE);
10811       gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
10812
10813       gtk_widget_grab_focus (GTK_WIDGET (tree_view));
10814       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
10815       gtk_tree_path_free (cursor_path);
10816
10817       tree_view->priv->ctrl_pressed = FALSE;
10818
10819       return TRUE;
10820     }
10821
10822  out:
10823
10824   tree_view->priv->search_entry_avoid_unhandled_binding = TRUE;
10825   return FALSE;
10826 }
10827
10828 static gboolean
10829 gtk_tree_view_search_entry_flush_timeout (GtkTreeView *tree_view)
10830 {
10831   gtk_tree_view_search_dialog_hide (tree_view->priv->search_window, tree_view, NULL);
10832   tree_view->priv->typeselect_flush_timeout = 0;
10833
10834   return FALSE;
10835 }
10836
10837 /* Cut and paste from gtkwindow.c */
10838 static void
10839 send_focus_change (GtkWidget *widget,
10840                    GdkDevice *device,
10841                    gboolean   in)
10842 {
10843   GdkDeviceManager *device_manager;
10844   GList *devices, *d;
10845
10846   device_manager = gdk_display_get_device_manager (gtk_widget_get_display (widget));
10847   devices = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER);
10848   devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_SLAVE));
10849   devices = g_list_concat (devices, gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_FLOATING));
10850
10851   for (d = devices; d; d = d->next)
10852     {
10853       GdkDevice *dev = d->data;
10854       GdkEvent *fevent;
10855       GdkWindow *window;
10856
10857       if (gdk_device_get_source (dev) != GDK_SOURCE_KEYBOARD)
10858         continue;
10859
10860       window = gtk_widget_get_window (widget);
10861
10862       /* Skip non-master keyboards that haven't
10863        * selected for events from this window
10864        */
10865       if (gdk_device_get_device_type (dev) != GDK_DEVICE_TYPE_MASTER &&
10866           !gdk_window_get_device_events (window, dev))
10867         continue;
10868
10869       fevent = gdk_event_new (GDK_FOCUS_CHANGE);
10870
10871       fevent->focus_change.type = GDK_FOCUS_CHANGE;
10872       fevent->focus_change.window = g_object_ref (window);
10873       fevent->focus_change.in = in;
10874       gdk_event_set_device (fevent, device);
10875
10876       gtk_widget_send_focus_change (widget, fevent);
10877
10878       gdk_event_free (fevent);
10879     }
10880
10881   g_list_free (devices);
10882 }
10883
10884 static void
10885 gtk_tree_view_ensure_interactive_directory (GtkTreeView *tree_view)
10886 {
10887   GtkWidget *frame, *vbox, *toplevel;
10888   GdkScreen *screen;
10889
10890   if (tree_view->priv->search_custom_entry_set)
10891     return;
10892
10893   toplevel = gtk_widget_get_toplevel (GTK_WIDGET (tree_view));
10894   screen = gtk_widget_get_screen (GTK_WIDGET (tree_view));
10895
10896    if (tree_view->priv->search_window != NULL)
10897      {
10898        if (gtk_window_has_group (GTK_WINDOW (toplevel)))
10899          gtk_window_group_add_window (gtk_window_get_group (GTK_WINDOW (toplevel)),
10900                                       GTK_WINDOW (tree_view->priv->search_window));
10901        else if (gtk_window_has_group (GTK_WINDOW (tree_view->priv->search_window)))
10902          gtk_window_group_remove_window (gtk_window_get_group (GTK_WINDOW (tree_view->priv->search_window)),
10903                                          GTK_WINDOW (tree_view->priv->search_window));
10904
10905        gtk_window_set_screen (GTK_WINDOW (tree_view->priv->search_window), screen);
10906
10907        return;
10908      }
10909    
10910   tree_view->priv->search_window = gtk_window_new (GTK_WINDOW_POPUP);
10911   gtk_window_set_screen (GTK_WINDOW (tree_view->priv->search_window), screen);
10912
10913   if (gtk_window_has_group (GTK_WINDOW (toplevel)))
10914     gtk_window_group_add_window (gtk_window_get_group (GTK_WINDOW (toplevel)),
10915                                  GTK_WINDOW (tree_view->priv->search_window));
10916
10917   gtk_window_set_type_hint (GTK_WINDOW (tree_view->priv->search_window),
10918                             GDK_WINDOW_TYPE_HINT_UTILITY);
10919   gtk_window_set_modal (GTK_WINDOW (tree_view->priv->search_window), TRUE);
10920   g_signal_connect (tree_view->priv->search_window, "delete-event",
10921                     G_CALLBACK (gtk_tree_view_search_delete_event),
10922                     tree_view);
10923   g_signal_connect (tree_view->priv->search_window, "key-press-event",
10924                     G_CALLBACK (gtk_tree_view_search_key_press_event),
10925                     tree_view);
10926   g_signal_connect (tree_view->priv->search_window, "button-press-event",
10927                     G_CALLBACK (gtk_tree_view_search_button_press_event),
10928                     tree_view);
10929   g_signal_connect (tree_view->priv->search_window, "scroll-event",
10930                     G_CALLBACK (gtk_tree_view_search_scroll_event),
10931                     tree_view);
10932
10933   frame = gtk_frame_new (NULL);
10934   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
10935   gtk_widget_show (frame);
10936   gtk_container_add (GTK_CONTAINER (tree_view->priv->search_window), frame);
10937
10938   vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
10939   gtk_widget_show (vbox);
10940   gtk_container_add (GTK_CONTAINER (frame), vbox);
10941   gtk_container_set_border_width (GTK_CONTAINER (vbox), 3);
10942
10943   /* add entry */
10944   tree_view->priv->search_entry = gtk_entry_new ();
10945   gtk_widget_show (tree_view->priv->search_entry);
10946   g_signal_connect (tree_view->priv->search_entry, "populate-popup",
10947                     G_CALLBACK (gtk_tree_view_search_disable_popdown),
10948                     tree_view);
10949   g_signal_connect (tree_view->priv->search_entry,
10950                     "activate", G_CALLBACK (gtk_tree_view_search_activate),
10951                     tree_view);
10952
10953   g_signal_connect (_gtk_entry_get_im_context (GTK_ENTRY (tree_view->priv->search_entry)),
10954                     "preedit-changed",
10955                     G_CALLBACK (gtk_tree_view_search_preedit_changed),
10956                     tree_view);
10957
10958   gtk_container_add (GTK_CONTAINER (vbox),
10959                      tree_view->priv->search_entry);
10960
10961   gtk_widget_realize (tree_view->priv->search_entry);
10962 }
10963
10964 /* Pops up the interactive search entry.  If keybinding is TRUE then the user
10965  * started this by typing the start_interactive_search keybinding.  Otherwise, it came from 
10966  */
10967 static gboolean
10968 gtk_tree_view_real_start_interactive_search (GtkTreeView *tree_view,
10969                                              GdkDevice   *device,
10970                                              gboolean     keybinding)
10971 {
10972   /* We only start interactive search if we have focus or the columns
10973    * have focus.  If one of our children have focus, we don't want to
10974    * start the search.
10975    */
10976   GList *list;
10977   gboolean found_focus = FALSE;
10978   GtkWidgetClass *entry_parent_class;
10979   
10980   if (!tree_view->priv->enable_search && !keybinding)
10981     return FALSE;
10982
10983   if (tree_view->priv->search_custom_entry_set)
10984     return FALSE;
10985
10986   if (tree_view->priv->search_window != NULL &&
10987       gtk_widget_get_visible (tree_view->priv->search_window))
10988     return TRUE;
10989
10990   for (list = tree_view->priv->columns; list; list = list->next)
10991     {
10992       GtkTreeViewColumn *column;
10993       GtkWidget         *button;
10994
10995       column = list->data;
10996       if (!gtk_tree_view_column_get_visible (column))
10997         continue;
10998
10999       button = gtk_tree_view_column_get_button (column);
11000       if (gtk_widget_has_focus (button))
11001         {
11002           found_focus = TRUE;
11003           break;
11004         }
11005     }
11006   
11007   if (gtk_widget_has_focus (GTK_WIDGET (tree_view)))
11008     found_focus = TRUE;
11009
11010   if (!found_focus)
11011     return FALSE;
11012
11013   if (tree_view->priv->search_column < 0)
11014     return FALSE;
11015
11016   gtk_tree_view_ensure_interactive_directory (tree_view);
11017
11018   if (keybinding)
11019     gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
11020
11021   /* done, show it */
11022   tree_view->priv->search_position_func (tree_view, tree_view->priv->search_window, tree_view->priv->search_position_user_data);
11023   gtk_widget_show (tree_view->priv->search_window);
11024   if (tree_view->priv->search_entry_changed_id == 0)
11025     {
11026       tree_view->priv->search_entry_changed_id =
11027         g_signal_connect (tree_view->priv->search_entry, "changed",
11028                           G_CALLBACK (gtk_tree_view_search_init),
11029                           tree_view);
11030     }
11031
11032   tree_view->priv->typeselect_flush_timeout =
11033     gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
11034                    (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
11035                    tree_view);
11036
11037   /* Grab focus will select all the text.  We don't want that to happen, so we
11038    * call the parent instance and bypass the selection change.  This is probably
11039    * really non-kosher. */
11040   entry_parent_class = g_type_class_peek_parent (GTK_ENTRY_GET_CLASS (tree_view->priv->search_entry));
11041   (entry_parent_class->grab_focus) (tree_view->priv->search_entry);
11042
11043   /* send focus-in event */
11044   send_focus_change (tree_view->priv->search_entry, device, TRUE);
11045
11046   /* search first matching iter */
11047   gtk_tree_view_search_init (tree_view->priv->search_entry, tree_view);
11048
11049   return TRUE;
11050 }
11051
11052 static gboolean
11053 gtk_tree_view_start_interactive_search (GtkTreeView *tree_view)
11054 {
11055   return gtk_tree_view_real_start_interactive_search (tree_view,
11056                                                       gtk_get_current_event_device (),
11057                                                       TRUE);
11058 }
11059
11060 /* this function returns the new width of the column being resized given
11061  * the column and x position of the cursor; the x cursor position is passed
11062  * in as a pointer and automagicly corrected if it's beyond min/max limits
11063  */
11064 static gint
11065 gtk_tree_view_new_column_width (GtkTreeView *tree_view,
11066                                 gint       i,
11067                                 gint      *x)
11068 {
11069   GtkAllocation allocation;
11070   GtkTreeViewColumn *column;
11071   GtkRequisition button_req;
11072   gint max_width, min_width;
11073   gint width;
11074   gboolean rtl;
11075
11076   /* first translate the x position from widget->window
11077    * to clist->clist_window
11078    */
11079   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
11080   column = g_list_nth (tree_view->priv->columns, i)->data;
11081   gtk_widget_get_allocation (gtk_tree_view_column_get_button (column), &allocation);
11082   width = rtl ? (allocation.x + allocation.width - *x) : (*x - allocation.x);
11083
11084   /* Clamp down the value */
11085   min_width = gtk_tree_view_column_get_min_width (column);
11086   if (min_width == -1)
11087     {
11088       gtk_widget_get_preferred_size (gtk_tree_view_column_get_button (column), &button_req, NULL);
11089       width = MAX (button_req.width, width);
11090     }
11091   else
11092     width = MAX (min_width, width);
11093
11094   max_width = gtk_tree_view_column_get_max_width (column);
11095   if (max_width != -1)
11096     width = MIN (width, max_width);
11097
11098   *x = rtl ? (allocation.x + allocation.width - width) : (allocation.x + width);
11099
11100   return width;
11101 }
11102
11103
11104 /* FIXME this adjust_allocation is a big cut-and-paste from
11105  * GtkCList, needs to be some "official" way to do this
11106  * factored out.
11107  */
11108 typedef struct
11109 {
11110   GdkWindow *window;
11111   int dx;
11112   int dy;
11113 } ScrollData;
11114
11115 /* The window to which widget->window is relative */
11116 #define ALLOCATION_WINDOW(widget)               \
11117    (!gtk_widget_get_has_window (widget) ?                   \
11118     gtk_widget_get_window (widget) :                        \
11119     gdk_window_get_parent (gtk_widget_get_window (widget)))
11120
11121 static void
11122 adjust_allocation_recurse (GtkWidget *widget,
11123                            gpointer   data)
11124 {
11125   GtkAllocation allocation;
11126   ScrollData *scroll_data = data;
11127
11128   /* Need to really size allocate instead of just poking
11129    * into widget->allocation if the widget is not realized.
11130    * FIXME someone figure out why this was.
11131    */
11132   gtk_widget_get_allocation (widget, &allocation);
11133   if (!gtk_widget_get_realized (widget))
11134     {
11135       if (gtk_widget_get_visible (widget))
11136         {
11137           GdkRectangle tmp_rectangle = allocation;
11138           tmp_rectangle.x += scroll_data->dx;
11139           tmp_rectangle.y += scroll_data->dy;
11140           
11141           gtk_widget_size_allocate (widget, &tmp_rectangle);
11142         }
11143     }
11144   else
11145     {
11146       if (ALLOCATION_WINDOW (widget) == scroll_data->window)
11147         {
11148           allocation.x += scroll_data->dx;
11149           allocation.y += scroll_data->dy;
11150           gtk_widget_set_allocation (widget, &allocation);
11151
11152           if (GTK_IS_CONTAINER (widget))
11153             gtk_container_forall (GTK_CONTAINER (widget),
11154                                   adjust_allocation_recurse,
11155                                   data);
11156         }
11157     }
11158 }
11159
11160 static void
11161 adjust_allocation (GtkWidget *widget,
11162                    int        dx,
11163                    int        dy)
11164 {
11165   ScrollData scroll_data;
11166
11167   if (gtk_widget_get_realized (widget))
11168     scroll_data.window = ALLOCATION_WINDOW (widget);
11169   else
11170     scroll_data.window = NULL;
11171     
11172   scroll_data.dx = dx;
11173   scroll_data.dy = dy;
11174   
11175   adjust_allocation_recurse (widget, &scroll_data);
11176 }
11177
11178 /* Callbacks */
11179 static void
11180 gtk_tree_view_adjustment_changed (GtkAdjustment *adjustment,
11181                                   GtkTreeView   *tree_view)
11182 {
11183   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11184     {
11185       GtkStyleContext *context;
11186       gint dy;
11187         
11188       gdk_window_move (tree_view->priv->bin_window,
11189                        - gtk_adjustment_get_value (tree_view->priv->hadjustment),
11190                        gtk_tree_view_get_effective_header_height (tree_view));
11191       gdk_window_move (tree_view->priv->header_window,
11192                        - gtk_adjustment_get_value (tree_view->priv->hadjustment),
11193                        0);
11194       dy = tree_view->priv->dy - (int) gtk_adjustment_get_value (tree_view->priv->vadjustment);
11195       if (dy)
11196         {
11197           update_prelight (tree_view,
11198                            tree_view->priv->event_last_x,
11199                            tree_view->priv->event_last_y - dy);
11200
11201           if (tree_view->priv->edited_column)
11202             {
11203               GList *list;
11204               GtkTreeViewChild *child = NULL;
11205               GtkCellEditable *edit_widget;
11206               GtkCellArea *area;
11207
11208               area        = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (tree_view->priv->edited_column));
11209               edit_widget = gtk_cell_area_get_edit_widget (area);
11210               if (GTK_IS_WIDGET (edit_widget))
11211                 {
11212                   adjust_allocation (GTK_WIDGET (edit_widget), 0, dy);
11213
11214                   for (list = tree_view->priv->children; list; list = list->next)
11215                     {
11216                       child = (GtkTreeViewChild *)list->data;
11217                       if (child->widget == GTK_WIDGET (edit_widget))
11218                         {
11219                           child->y += dy;
11220                           break;
11221                         }
11222                     }
11223                 }
11224             }
11225         }
11226       gdk_window_scroll (tree_view->priv->bin_window, 0, dy);
11227
11228       context = gtk_widget_get_style_context (GTK_WIDGET (tree_view));
11229       gtk_style_context_scroll_animations (context, tree_view->priv->bin_window, 0, dy);
11230
11231       if (tree_view->priv->dy != (int) gtk_adjustment_get_value (tree_view->priv->vadjustment))
11232         {
11233           /* update our dy and top_row */
11234           tree_view->priv->dy = (int) gtk_adjustment_get_value (tree_view->priv->vadjustment);
11235
11236           if (!tree_view->priv->in_top_row_to_dy)
11237             gtk_tree_view_dy_to_top_row (tree_view);
11238         }
11239
11240       gdk_window_process_updates (tree_view->priv->header_window, TRUE);
11241       gtk_tree_view_bin_process_updates (tree_view);
11242     }
11243 }
11244
11245 \f
11246
11247 /* Public methods
11248  */
11249
11250 /**
11251  * gtk_tree_view_new:
11252  *
11253  * Creates a new #GtkTreeView widget.
11254  *
11255  * Return value: A newly created #GtkTreeView widget.
11256  **/
11257 GtkWidget *
11258 gtk_tree_view_new (void)
11259 {
11260   return g_object_new (GTK_TYPE_TREE_VIEW, NULL);
11261 }
11262
11263 /**
11264  * gtk_tree_view_new_with_model:
11265  * @model: the model.
11266  *
11267  * Creates a new #GtkTreeView widget with the model initialized to @model.
11268  *
11269  * Return value: A newly created #GtkTreeView widget.
11270  **/
11271 GtkWidget *
11272 gtk_tree_view_new_with_model (GtkTreeModel *model)
11273 {
11274   return g_object_new (GTK_TYPE_TREE_VIEW, "model", model, NULL);
11275 }
11276
11277 /* Public Accessors
11278  */
11279
11280 /**
11281  * gtk_tree_view_get_model:
11282  * @tree_view: a #GtkTreeView
11283  *
11284  * Returns the model the #GtkTreeView is based on.  Returns %NULL if the
11285  * model is unset.
11286  *
11287  * Return value: (transfer none): A #GtkTreeModel, or %NULL if none is currently being used.
11288  **/
11289 GtkTreeModel *
11290 gtk_tree_view_get_model (GtkTreeView *tree_view)
11291 {
11292   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11293
11294   return tree_view->priv->model;
11295 }
11296
11297 /**
11298  * gtk_tree_view_set_model:
11299  * @tree_view: A #GtkTreeNode.
11300  * @model: (allow-none): The model.
11301  *
11302  * Sets the model for a #GtkTreeView.  If the @tree_view already has a model
11303  * set, it will remove it before setting the new model.  If @model is %NULL,
11304  * then it will unset the old model.
11305  **/
11306 void
11307 gtk_tree_view_set_model (GtkTreeView  *tree_view,
11308                          GtkTreeModel *model)
11309 {
11310   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11311   g_return_if_fail (model == NULL || GTK_IS_TREE_MODEL (model));
11312
11313   if (model == tree_view->priv->model)
11314     return;
11315
11316   if (tree_view->priv->scroll_to_path)
11317     {
11318       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
11319       tree_view->priv->scroll_to_path = NULL;
11320     }
11321
11322   if (tree_view->priv->model)
11323     {
11324       GList *tmplist = tree_view->priv->columns;
11325       GtkStyleContext *context;
11326
11327       gtk_tree_view_unref_and_check_selection_tree (tree_view, tree_view->priv->tree);
11328       gtk_tree_view_stop_editing (tree_view, TRUE);
11329
11330       context = gtk_widget_get_style_context (GTK_WIDGET (tree_view));
11331       gtk_style_context_cancel_animations (context, NULL);
11332
11333       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
11334                                             gtk_tree_view_row_changed,
11335                                             tree_view);
11336       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
11337                                             gtk_tree_view_row_inserted,
11338                                             tree_view);
11339       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
11340                                             gtk_tree_view_row_has_child_toggled,
11341                                             tree_view);
11342       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
11343                                             gtk_tree_view_row_deleted,
11344                                             tree_view);
11345       g_signal_handlers_disconnect_by_func (tree_view->priv->model,
11346                                             gtk_tree_view_rows_reordered,
11347                                             tree_view);
11348
11349       for (; tmplist; tmplist = tmplist->next)
11350         _gtk_tree_view_column_unset_model (tmplist->data,
11351                                            tree_view->priv->model);
11352
11353       if (tree_view->priv->tree)
11354         gtk_tree_view_free_rbtree (tree_view);
11355
11356       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
11357       tree_view->priv->drag_dest_row = NULL;
11358       gtk_tree_row_reference_free (tree_view->priv->cursor);
11359       tree_view->priv->cursor = NULL;
11360       gtk_tree_row_reference_free (tree_view->priv->anchor);
11361       tree_view->priv->anchor = NULL;
11362       gtk_tree_row_reference_free (tree_view->priv->top_row);
11363       tree_view->priv->top_row = NULL;
11364       gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
11365       tree_view->priv->scroll_to_path = NULL;
11366
11367       tree_view->priv->scroll_to_column = NULL;
11368
11369       g_object_unref (tree_view->priv->model);
11370
11371       tree_view->priv->search_column = -1;
11372       tree_view->priv->fixed_height_check = 0;
11373       tree_view->priv->fixed_height = -1;
11374       tree_view->priv->dy = tree_view->priv->top_row_dy = 0;
11375       tree_view->priv->last_button_x = -1;
11376       tree_view->priv->last_button_y = -1;
11377     }
11378
11379   tree_view->priv->model = model;
11380
11381   if (tree_view->priv->model)
11382     {
11383       gint i;
11384       GtkTreePath *path;
11385       GtkTreeIter iter;
11386       GtkTreeModelFlags flags;
11387
11388       if (tree_view->priv->search_column == -1)
11389         {
11390           for (i = 0; i < gtk_tree_model_get_n_columns (model); i++)
11391             {
11392               GType type = gtk_tree_model_get_column_type (model, i);
11393
11394               if (g_value_type_transformable (type, G_TYPE_STRING))
11395                 {
11396                   tree_view->priv->search_column = i;
11397                   break;
11398                 }
11399             }
11400         }
11401
11402       g_object_ref (tree_view->priv->model);
11403       g_signal_connect (tree_view->priv->model,
11404                         "row-changed",
11405                         G_CALLBACK (gtk_tree_view_row_changed),
11406                         tree_view);
11407       g_signal_connect (tree_view->priv->model,
11408                         "row-inserted",
11409                         G_CALLBACK (gtk_tree_view_row_inserted),
11410                         tree_view);
11411       g_signal_connect (tree_view->priv->model,
11412                         "row-has-child-toggled",
11413                         G_CALLBACK (gtk_tree_view_row_has_child_toggled),
11414                         tree_view);
11415       g_signal_connect (tree_view->priv->model,
11416                         "row-deleted",
11417                         G_CALLBACK (gtk_tree_view_row_deleted),
11418                         tree_view);
11419       g_signal_connect (tree_view->priv->model,
11420                         "rows-reordered",
11421                         G_CALLBACK (gtk_tree_view_rows_reordered),
11422                         tree_view);
11423
11424       flags = gtk_tree_model_get_flags (tree_view->priv->model);
11425       if ((flags & GTK_TREE_MODEL_LIST_ONLY) == GTK_TREE_MODEL_LIST_ONLY)
11426         tree_view->priv->is_list = TRUE;
11427       else
11428         tree_view->priv->is_list = FALSE;
11429
11430       path = gtk_tree_path_new_first ();
11431       if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, path))
11432         {
11433           tree_view->priv->tree = _gtk_rbtree_new ();
11434           gtk_tree_view_build_tree (tree_view, tree_view->priv->tree, &iter, 1, FALSE);
11435         }
11436       gtk_tree_path_free (path);
11437
11438       /*  FIXME: do I need to do this? gtk_tree_view_create_buttons (tree_view); */
11439       install_presize_handler (tree_view);
11440     }
11441
11442   g_object_notify (G_OBJECT (tree_view), "model");
11443
11444   if (tree_view->priv->selection)
11445   _gtk_tree_selection_emit_changed (tree_view->priv->selection);
11446
11447   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11448     gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11449 }
11450
11451 /**
11452  * gtk_tree_view_get_selection:
11453  * @tree_view: A #GtkTreeView.
11454  *
11455  * Gets the #GtkTreeSelection associated with @tree_view.
11456  *
11457  * Return value: (transfer none): A #GtkTreeSelection object.
11458  **/
11459 GtkTreeSelection *
11460 gtk_tree_view_get_selection (GtkTreeView *tree_view)
11461 {
11462   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11463
11464   return tree_view->priv->selection;
11465 }
11466
11467 /**
11468  * gtk_tree_view_get_hadjustment:
11469  * @tree_view: A #GtkTreeView
11470  *
11471  * Gets the #GtkAdjustment currently being used for the horizontal aspect.
11472  *
11473  * Return value: (transfer none): A #GtkAdjustment object, or %NULL
11474  *     if none is currently being used.
11475  *
11476  * Deprecated: 3.0: Use gtk_scrollable_get_hadjustment()
11477  **/
11478 GtkAdjustment *
11479 gtk_tree_view_get_hadjustment (GtkTreeView *tree_view)
11480 {
11481   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11482
11483   return tree_view->priv->hadjustment;
11484 }
11485
11486 /**
11487  * gtk_tree_view_set_hadjustment:
11488  * @tree_view: A #GtkTreeView
11489  * @adjustment: (allow-none): The #GtkAdjustment to set, or %NULL
11490  *
11491  * Sets the #GtkAdjustment for the current horizontal aspect.
11492  *
11493  * Deprecated: 3.0: Use gtk_scrollable_set_hadjustment()
11494  **/
11495 void
11496 gtk_tree_view_set_hadjustment (GtkTreeView   *tree_view,
11497                                GtkAdjustment *adjustment)
11498 {
11499   GtkTreeViewPrivate *priv = tree_view->priv;
11500
11501   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11502   g_return_if_fail (adjustment == NULL || GTK_IS_ADJUSTMENT (adjustment));
11503
11504   if (adjustment && priv->hadjustment == adjustment)
11505     return;
11506
11507   if (priv->hadjustment != NULL)
11508     {
11509       g_signal_handlers_disconnect_by_func (priv->hadjustment,
11510                                             gtk_tree_view_adjustment_changed,
11511                                             tree_view);
11512       g_object_unref (priv->hadjustment);
11513     }
11514
11515   if (adjustment == NULL)
11516     adjustment = gtk_adjustment_new (0.0, 0.0, 0.0,
11517                                      0.0, 0.0, 0.0);
11518
11519   g_signal_connect (adjustment, "value-changed",
11520                     G_CALLBACK (gtk_tree_view_adjustment_changed), tree_view);
11521   priv->hadjustment = g_object_ref_sink (adjustment);
11522   /* FIXME: Adjustment should probably be populated here with fresh values, but
11523    * internal details are too complicated for me to decipher right now.
11524    */
11525   gtk_tree_view_adjustment_changed (NULL, tree_view);
11526
11527   g_object_notify (G_OBJECT (tree_view), "hadjustment");
11528 }
11529
11530 /**
11531  * gtk_tree_view_get_vadjustment:
11532  * @tree_view: A #GtkTreeView
11533  *
11534  * Gets the #GtkAdjustment currently being used for the vertical aspect.
11535  *
11536  * Return value: (transfer none): A #GtkAdjustment object, or %NULL
11537  *     if none is currently being used.
11538  *
11539  * Deprecated: 3.0: Use gtk_scrollable_get_vadjustment()
11540  **/
11541 GtkAdjustment *
11542 gtk_tree_view_get_vadjustment (GtkTreeView *tree_view)
11543 {
11544   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
11545
11546   return tree_view->priv->vadjustment;
11547 }
11548
11549 /**
11550  * gtk_tree_view_set_vadjustment:
11551  * @tree_view: A #GtkTreeView
11552  * @adjustment: (allow-none): The #GtkAdjustment to set, or %NULL
11553  *
11554  * Sets the #GtkAdjustment for the current vertical aspect.
11555  *
11556  * Deprecated: 3.0: Use gtk_scrollable_set_vadjustment()
11557  **/
11558 void
11559 gtk_tree_view_set_vadjustment (GtkTreeView   *tree_view,
11560                                GtkAdjustment *adjustment)
11561 {
11562   GtkTreeViewPrivate *priv = tree_view->priv;
11563
11564   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11565   g_return_if_fail (adjustment == NULL || GTK_IS_ADJUSTMENT (adjustment));
11566
11567   if (adjustment && priv->vadjustment == adjustment)
11568     return;
11569
11570   if (priv->vadjustment != NULL)
11571     {
11572       g_signal_handlers_disconnect_by_func (priv->vadjustment,
11573                                             gtk_tree_view_adjustment_changed,
11574                                             tree_view);
11575       g_object_unref (priv->vadjustment);
11576     }
11577
11578   if (adjustment == NULL)
11579     adjustment = gtk_adjustment_new (0.0, 0.0, 0.0,
11580                                      0.0, 0.0, 0.0);
11581
11582   g_signal_connect (adjustment, "value-changed",
11583                     G_CALLBACK (gtk_tree_view_adjustment_changed), tree_view);
11584   priv->vadjustment = g_object_ref_sink (adjustment);
11585   /* FIXME: Adjustment should probably be populated here with fresh values, but
11586    * internal details are too complicated for me to decipher right now.
11587    */
11588   gtk_tree_view_adjustment_changed (NULL, tree_view);
11589   g_object_notify (G_OBJECT (tree_view), "vadjustment");
11590 }
11591
11592 /* Column and header operations */
11593
11594 /**
11595  * gtk_tree_view_get_headers_visible:
11596  * @tree_view: A #GtkTreeView.
11597  *
11598  * Returns %TRUE if the headers on the @tree_view are visible.
11599  *
11600  * Return value: Whether the headers are visible or not.
11601  **/
11602 gboolean
11603 gtk_tree_view_get_headers_visible (GtkTreeView *tree_view)
11604 {
11605   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
11606
11607   return tree_view->priv->headers_visible;
11608 }
11609
11610 /**
11611  * gtk_tree_view_set_headers_visible:
11612  * @tree_view: A #GtkTreeView.
11613  * @headers_visible: %TRUE if the headers are visible
11614  *
11615  * Sets the visibility state of the headers.
11616  **/
11617 void
11618 gtk_tree_view_set_headers_visible (GtkTreeView *tree_view,
11619                                    gboolean     headers_visible)
11620 {
11621   gint x, y;
11622   GList *list;
11623   GtkTreeViewColumn *column;
11624   GtkAllocation allocation;
11625   GtkWidget *button;
11626
11627   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11628
11629   headers_visible = !! headers_visible;
11630
11631   if (tree_view->priv->headers_visible == headers_visible)
11632     return;
11633
11634   tree_view->priv->headers_visible = headers_visible == TRUE;
11635
11636   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11637     {
11638       gdk_window_get_position (tree_view->priv->bin_window, &x, &y);
11639       if (headers_visible)
11640         {
11641           gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
11642           gdk_window_move_resize (tree_view->priv->bin_window,
11643                                   x, y  + gtk_tree_view_get_effective_header_height (tree_view),
11644                                   tree_view->priv->width, allocation.height -  + gtk_tree_view_get_effective_header_height (tree_view));
11645
11646           if (gtk_widget_get_mapped (GTK_WIDGET (tree_view)))
11647             gtk_tree_view_map_buttons (tree_view);
11648         }
11649       else
11650         {
11651           gdk_window_move_resize (tree_view->priv->bin_window, x, y, tree_view->priv->width, tree_view->priv->height);
11652
11653           for (list = tree_view->priv->columns; list; list = list->next)
11654             {
11655               column = list->data;
11656               button = gtk_tree_view_column_get_button (column);
11657
11658               gtk_widget_hide (button);
11659               gtk_widget_unmap (button);
11660             }
11661           gdk_window_hide (tree_view->priv->header_window);
11662         }
11663     }
11664
11665   gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
11666   gtk_adjustment_configure (tree_view->priv->vadjustment,
11667                             gtk_adjustment_get_value (tree_view->priv->vadjustment),
11668                             0,
11669                             tree_view->priv->height,
11670                             gtk_adjustment_get_step_increment (tree_view->priv->vadjustment),
11671                             (allocation.height - gtk_tree_view_get_effective_header_height (tree_view)) / 2,
11672                             allocation.height - gtk_tree_view_get_effective_header_height (tree_view));
11673
11674   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11675
11676   g_object_notify (G_OBJECT (tree_view), "headers-visible");
11677 }
11678
11679 /**
11680  * gtk_tree_view_columns_autosize:
11681  * @tree_view: A #GtkTreeView.
11682  *
11683  * Resizes all columns to their optimal width. Only works after the
11684  * treeview has been realized.
11685  **/
11686 void
11687 gtk_tree_view_columns_autosize (GtkTreeView *tree_view)
11688 {
11689   gboolean dirty = FALSE;
11690   GList *list;
11691   GtkTreeViewColumn *column;
11692
11693   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11694
11695   for (list = tree_view->priv->columns; list; list = list->next)
11696     {
11697       column = list->data;
11698       if (gtk_tree_view_column_get_sizing (column) == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
11699         continue;
11700       _gtk_tree_view_column_cell_set_dirty (column, TRUE);
11701       dirty = TRUE;
11702     }
11703
11704   if (dirty)
11705     gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11706 }
11707
11708 /**
11709  * gtk_tree_view_set_headers_clickable:
11710  * @tree_view: A #GtkTreeView.
11711  * @setting: %TRUE if the columns are clickable.
11712  *
11713  * Allow the column title buttons to be clicked.
11714  **/
11715 void
11716 gtk_tree_view_set_headers_clickable (GtkTreeView *tree_view,
11717                                      gboolean   setting)
11718 {
11719   GList *list;
11720
11721   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11722
11723   for (list = tree_view->priv->columns; list; list = list->next)
11724     gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (list->data), setting);
11725
11726   g_object_notify (G_OBJECT (tree_view), "headers-clickable");
11727 }
11728
11729
11730 /**
11731  * gtk_tree_view_get_headers_clickable:
11732  * @tree_view: A #GtkTreeView.
11733  *
11734  * Returns whether all header columns are clickable.
11735  *
11736  * Return value: %TRUE if all header columns are clickable, otherwise %FALSE
11737  *
11738  * Since: 2.10
11739  **/
11740 gboolean 
11741 gtk_tree_view_get_headers_clickable (GtkTreeView *tree_view)
11742 {
11743   GList *list;
11744   
11745   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
11746
11747   for (list = tree_view->priv->columns; list; list = list->next)
11748     if (!gtk_tree_view_column_get_clickable (GTK_TREE_VIEW_COLUMN (list->data)))
11749       return FALSE;
11750
11751   return TRUE;
11752 }
11753
11754 /**
11755  * gtk_tree_view_set_rules_hint
11756  * @tree_view: a #GtkTreeView
11757  * @setting: %TRUE if the tree requires reading across rows
11758  *
11759  * This function tells GTK+ that the user interface for your
11760  * application requires users to read across tree rows and associate
11761  * cells with one another. By default, GTK+ will then render the tree
11762  * with alternating row colors. Do <emphasis>not</emphasis> use it
11763  * just because you prefer the appearance of the ruled tree; that's a
11764  * question for the theme. Some themes will draw tree rows in
11765  * alternating colors even when rules are turned off, and users who
11766  * prefer that appearance all the time can choose those themes. You
11767  * should call this function only as a <emphasis>semantic</emphasis>
11768  * hint to the theme engine that your tree makes alternating colors
11769  * useful from a functional standpoint (since it has lots of columns,
11770  * generally).
11771  *
11772  **/
11773 void
11774 gtk_tree_view_set_rules_hint (GtkTreeView  *tree_view,
11775                               gboolean      setting)
11776 {
11777   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
11778
11779   setting = setting != FALSE;
11780
11781   if (tree_view->priv->has_rules != setting)
11782     {
11783       tree_view->priv->has_rules = setting;
11784       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
11785     }
11786
11787   g_object_notify (G_OBJECT (tree_view), "rules-hint");
11788 }
11789
11790 /**
11791  * gtk_tree_view_get_rules_hint
11792  * @tree_view: a #GtkTreeView
11793  *
11794  * Gets the setting set by gtk_tree_view_set_rules_hint().
11795  *
11796  * Return value: %TRUE if rules are useful for the user of this tree
11797  **/
11798 gboolean
11799 gtk_tree_view_get_rules_hint (GtkTreeView  *tree_view)
11800 {
11801   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
11802
11803   return tree_view->priv->has_rules;
11804 }
11805
11806 /* Public Column functions
11807  */
11808
11809 /**
11810  * gtk_tree_view_append_column:
11811  * @tree_view: A #GtkTreeView.
11812  * @column: The #GtkTreeViewColumn to add.
11813  *
11814  * Appends @column to the list of columns. If @tree_view has "fixed_height"
11815  * mode enabled, then @column must have its "sizing" property set to be
11816  * GTK_TREE_VIEW_COLUMN_FIXED.
11817  *
11818  * Return value: The number of columns in @tree_view after appending.
11819  **/
11820 gint
11821 gtk_tree_view_append_column (GtkTreeView       *tree_view,
11822                              GtkTreeViewColumn *column)
11823 {
11824   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11825   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
11826   g_return_val_if_fail (gtk_tree_view_column_get_tree_view (column) == NULL, -1);
11827
11828   return gtk_tree_view_insert_column (tree_view, column, -1);
11829 }
11830
11831 void
11832 _gtk_tree_view_reset_header_styles (GtkTreeView *tree_view)
11833 {
11834   GList *columns;
11835
11836   for (columns = tree_view->priv->columns; columns; columns = columns->next)
11837     {
11838       GtkTreeViewColumn *column = columns->data;
11839       GtkWidget *header_widget;
11840
11841       if (gtk_tree_view_column_get_visible (column))
11842         continue;
11843
11844       header_widget = gtk_tree_view_column_get_widget (column);
11845
11846       if (!header_widget)
11847         header_widget = gtk_tree_view_column_get_button (column);
11848
11849       gtk_widget_reset_style (header_widget);
11850     }
11851 }
11852
11853
11854 /**
11855  * gtk_tree_view_remove_column:
11856  * @tree_view: A #GtkTreeView.
11857  * @column: The #GtkTreeViewColumn to remove.
11858  *
11859  * Removes @column from @tree_view.
11860  *
11861  * Return value: The number of columns in @tree_view after removing.
11862  **/
11863 gint
11864 gtk_tree_view_remove_column (GtkTreeView       *tree_view,
11865                              GtkTreeViewColumn *column)
11866 {
11867   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11868   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
11869   g_return_val_if_fail (gtk_tree_view_column_get_tree_view (column) == GTK_WIDGET (tree_view), -1);
11870
11871   if (tree_view->priv->focus_column == column)
11872     tree_view->priv->focus_column = NULL;
11873
11874   if (tree_view->priv->edited_column == column)
11875     {
11876       gtk_tree_view_stop_editing (tree_view, TRUE);
11877
11878       /* no need to, but just to be sure ... */
11879       tree_view->priv->edited_column = NULL;
11880     }
11881
11882   if (tree_view->priv->expander_column == column)
11883     tree_view->priv->expander_column = NULL;
11884
11885   g_signal_handlers_disconnect_by_func (column,
11886                                         G_CALLBACK (column_sizing_notify),
11887                                         tree_view);
11888
11889   _gtk_tree_view_column_unset_tree_view (column);
11890
11891   tree_view->priv->columns = g_list_remove (tree_view->priv->columns, column);
11892   tree_view->priv->n_columns--;
11893
11894   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11895     {
11896       GList *list;
11897
11898       _gtk_tree_view_column_unrealize_button (column);
11899       for (list = tree_view->priv->columns; list; list = list->next)
11900         {
11901           GtkTreeViewColumn *tmp_column;
11902
11903           tmp_column = GTK_TREE_VIEW_COLUMN (list->data);
11904           if (gtk_tree_view_column_get_visible (tmp_column))
11905             _gtk_tree_view_column_cell_set_dirty (tmp_column, TRUE);
11906         }
11907
11908       if (tree_view->priv->n_columns == 0 &&
11909           gtk_tree_view_get_headers_visible (tree_view))
11910         gdk_window_hide (tree_view->priv->header_window);
11911
11912       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11913     }
11914
11915   _gtk_tree_view_reset_header_styles (tree_view);
11916
11917   g_object_unref (column);
11918   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
11919
11920   return tree_view->priv->n_columns;
11921 }
11922
11923 /**
11924  * gtk_tree_view_insert_column:
11925  * @tree_view: A #GtkTreeView.
11926  * @column: The #GtkTreeViewColumn to be inserted.
11927  * @position: The position to insert @column in.
11928  *
11929  * This inserts the @column into the @tree_view at @position.  If @position is
11930  * -1, then the column is inserted at the end. If @tree_view has
11931  * "fixed_height" mode enabled, then @column must have its "sizing" property
11932  * set to be GTK_TREE_VIEW_COLUMN_FIXED.
11933  *
11934  * Return value: The number of columns in @tree_view after insertion.
11935  **/
11936 gint
11937 gtk_tree_view_insert_column (GtkTreeView       *tree_view,
11938                              GtkTreeViewColumn *column,
11939                              gint               position)
11940 {
11941   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
11942   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
11943   g_return_val_if_fail (gtk_tree_view_column_get_tree_view (column) == NULL, -1);
11944
11945   if (tree_view->priv->fixed_height_mode)
11946     g_return_val_if_fail (gtk_tree_view_column_get_sizing (column)
11947                           == GTK_TREE_VIEW_COLUMN_FIXED, -1);
11948
11949   g_object_ref_sink (column);
11950
11951   if (tree_view->priv->n_columns == 0 &&
11952       gtk_widget_get_realized (GTK_WIDGET (tree_view)) &&
11953       gtk_tree_view_get_headers_visible (tree_view))
11954     {
11955       gdk_window_show (tree_view->priv->header_window);
11956     }
11957
11958   g_signal_connect (column, "notify::sizing",
11959                     G_CALLBACK (column_sizing_notify), tree_view);
11960
11961   tree_view->priv->columns = g_list_insert (tree_view->priv->columns,
11962                                             column, position);
11963   tree_view->priv->n_columns++;
11964
11965   _gtk_tree_view_column_set_tree_view (column, tree_view);
11966
11967   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
11968     {
11969       GList *list;
11970
11971       _gtk_tree_view_column_realize_button (column);
11972
11973       for (list = tree_view->priv->columns; list; list = list->next)
11974         {
11975           column = GTK_TREE_VIEW_COLUMN (list->data);
11976           if (gtk_tree_view_column_get_visible (column))
11977             _gtk_tree_view_column_cell_set_dirty (column, TRUE);
11978         }
11979       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
11980     }
11981
11982   _gtk_tree_view_reset_header_styles (tree_view);
11983   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
11984
11985   return tree_view->priv->n_columns;
11986 }
11987
11988 /**
11989  * gtk_tree_view_insert_column_with_attributes:
11990  * @tree_view: A #GtkTreeView
11991  * @position: The position to insert the new column in
11992  * @title: The title to set the header to
11993  * @cell: The #GtkCellRenderer
11994  * @...: A %NULL-terminated list of attributes
11995  *
11996  * Creates a new #GtkTreeViewColumn and inserts it into the @tree_view at
11997  * @position.  If @position is -1, then the newly created column is inserted at
11998  * the end.  The column is initialized with the attributes given. If @tree_view
11999  * has "fixed_height" mode enabled, then the new column will have its sizing
12000  * property set to be GTK_TREE_VIEW_COLUMN_FIXED.
12001  *
12002  * Return value: The number of columns in @tree_view after insertion.
12003  **/
12004 gint
12005 gtk_tree_view_insert_column_with_attributes (GtkTreeView     *tree_view,
12006                                              gint             position,
12007                                              const gchar     *title,
12008                                              GtkCellRenderer *cell,
12009                                              ...)
12010 {
12011   GtkTreeViewColumn *column;
12012   gchar *attribute;
12013   va_list args;
12014   gint column_id;
12015
12016   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
12017
12018   column = gtk_tree_view_column_new ();
12019   if (tree_view->priv->fixed_height_mode)
12020     gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
12021
12022   gtk_tree_view_column_set_title (column, title);
12023   gtk_tree_view_column_pack_start (column, cell, TRUE);
12024
12025   va_start (args, cell);
12026
12027   attribute = va_arg (args, gchar *);
12028
12029   while (attribute != NULL)
12030     {
12031       column_id = va_arg (args, gint);
12032       gtk_tree_view_column_add_attribute (column, cell, attribute, column_id);
12033       attribute = va_arg (args, gchar *);
12034     }
12035
12036   va_end (args);
12037
12038   gtk_tree_view_insert_column (tree_view, column, position);
12039
12040   return tree_view->priv->n_columns;
12041 }
12042
12043 /**
12044  * gtk_tree_view_insert_column_with_data_func:
12045  * @tree_view: a #GtkTreeView
12046  * @position: Position to insert, -1 for append
12047  * @title: column title
12048  * @cell: cell renderer for column
12049  * @func: function to set attributes of cell renderer
12050  * @data: data for @func
12051  * @dnotify: destroy notifier for @data
12052  *
12053  * Convenience function that inserts a new column into the #GtkTreeView
12054  * with the given cell renderer and a #GtkCellDataFunc to set cell renderer
12055  * attributes (normally using data from the model). See also
12056  * gtk_tree_view_column_set_cell_data_func(), gtk_tree_view_column_pack_start().
12057  * If @tree_view has "fixed_height" mode enabled, then the new column will have its
12058  * "sizing" property set to be GTK_TREE_VIEW_COLUMN_FIXED.
12059  *
12060  * Return value: number of columns in the tree view post-insert
12061  **/
12062 gint
12063 gtk_tree_view_insert_column_with_data_func  (GtkTreeView               *tree_view,
12064                                              gint                       position,
12065                                              const gchar               *title,
12066                                              GtkCellRenderer           *cell,
12067                                              GtkTreeCellDataFunc        func,
12068                                              gpointer                   data,
12069                                              GDestroyNotify             dnotify)
12070 {
12071   GtkTreeViewColumn *column;
12072
12073   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
12074
12075   column = gtk_tree_view_column_new ();
12076   if (tree_view->priv->fixed_height_mode)
12077     gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
12078
12079   gtk_tree_view_column_set_title (column, title);
12080   gtk_tree_view_column_pack_start (column, cell, TRUE);
12081   gtk_tree_view_column_set_cell_data_func (column, cell, func, data, dnotify);
12082
12083   gtk_tree_view_insert_column (tree_view, column, position);
12084
12085   return tree_view->priv->n_columns;
12086 }
12087
12088 /**
12089  * gtk_tree_view_get_column:
12090  * @tree_view: A #GtkTreeView.
12091  * @n: The position of the column, counting from 0.
12092  *
12093  * Gets the #GtkTreeViewColumn at the given position in the #tree_view.
12094  *
12095  * Return value: (transfer none): The #GtkTreeViewColumn, or %NULL if the
12096  *     position is outside the range of columns.
12097  **/
12098 GtkTreeViewColumn *
12099 gtk_tree_view_get_column (GtkTreeView *tree_view,
12100                           gint         n)
12101 {
12102   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
12103
12104   if (n < 0 || n >= tree_view->priv->n_columns)
12105     return NULL;
12106
12107   if (tree_view->priv->columns == NULL)
12108     return NULL;
12109
12110   return GTK_TREE_VIEW_COLUMN (g_list_nth (tree_view->priv->columns, n)->data);
12111 }
12112
12113 /**
12114  * gtk_tree_view_get_columns:
12115  * @tree_view: A #GtkTreeView
12116  *
12117  * Returns a #GList of all the #GtkTreeViewColumn s currently in @tree_view.
12118  * The returned list must be freed with g_list_free ().
12119  *
12120  * Return value: (element-type GtkTreeViewColumn) (transfer container): A list of #GtkTreeViewColumn s
12121  **/
12122 GList *
12123 gtk_tree_view_get_columns (GtkTreeView *tree_view)
12124 {
12125   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
12126
12127   return g_list_copy (tree_view->priv->columns);
12128 }
12129
12130 /**
12131  * gtk_tree_view_move_column_after:
12132  * @tree_view: A #GtkTreeView
12133  * @column: The #GtkTreeViewColumn to be moved.
12134  * @base_column: (allow-none): The #GtkTreeViewColumn to be moved relative to, or %NULL.
12135  *
12136  * Moves @column to be after to @base_column.  If @base_column is %NULL, then
12137  * @column is placed in the first position.
12138  **/
12139 void
12140 gtk_tree_view_move_column_after (GtkTreeView       *tree_view,
12141                                  GtkTreeViewColumn *column,
12142                                  GtkTreeViewColumn *base_column)
12143 {
12144   GList *column_list_el, *base_el = NULL;
12145
12146   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12147
12148   column_list_el = g_list_find (tree_view->priv->columns, column);
12149   g_return_if_fail (column_list_el != NULL);
12150
12151   if (base_column)
12152     {
12153       base_el = g_list_find (tree_view->priv->columns, base_column);
12154       g_return_if_fail (base_el != NULL);
12155     }
12156
12157   if (column_list_el->prev == base_el)
12158     return;
12159
12160   tree_view->priv->columns = g_list_remove_link (tree_view->priv->columns, column_list_el);
12161   if (base_el == NULL)
12162     {
12163       column_list_el->prev = NULL;
12164       column_list_el->next = tree_view->priv->columns;
12165       if (column_list_el->next)
12166         column_list_el->next->prev = column_list_el;
12167       tree_view->priv->columns = column_list_el;
12168     }
12169   else
12170     {
12171       column_list_el->prev = base_el;
12172       column_list_el->next = base_el->next;
12173       if (column_list_el->next)
12174         column_list_el->next->prev = column_list_el;
12175       base_el->next = column_list_el;
12176     }
12177
12178   if (gtk_widget_get_realized (GTK_WIDGET (tree_view)))
12179     {
12180       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
12181       gtk_tree_view_size_allocate_columns (GTK_WIDGET (tree_view), NULL);
12182     }
12183
12184   _gtk_tree_view_reset_header_styles (tree_view);
12185   g_signal_emit (tree_view, tree_view_signals[COLUMNS_CHANGED], 0);
12186 }
12187
12188 /**
12189  * gtk_tree_view_set_expander_column:
12190  * @tree_view: A #GtkTreeView
12191  * @column: %NULL, or the column to draw the expander arrow at.
12192  *
12193  * Sets the column to draw the expander arrow at. It must be in @tree_view.  
12194  * If @column is %NULL, then the expander arrow is always at the first 
12195  * visible column.
12196  *
12197  * If you do not want expander arrow to appear in your tree, set the 
12198  * expander column to a hidden column.
12199  **/
12200 void
12201 gtk_tree_view_set_expander_column (GtkTreeView       *tree_view,
12202                                    GtkTreeViewColumn *column)
12203 {
12204   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12205   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
12206
12207   if (tree_view->priv->expander_column != column)
12208     {
12209       GList *list;
12210
12211       if (column)
12212         {
12213           /* Confirm that column is in tree_view */
12214           for (list = tree_view->priv->columns; list; list = list->next)
12215             if (list->data == column)
12216               break;
12217           g_return_if_fail (list != NULL);
12218         }
12219
12220       tree_view->priv->expander_column = column;
12221       g_object_notify (G_OBJECT (tree_view), "expander-column");
12222     }
12223 }
12224
12225 /**
12226  * gtk_tree_view_get_expander_column:
12227  * @tree_view: A #GtkTreeView
12228  *
12229  * Returns the column that is the current expander column.
12230  * This column has the expander arrow drawn next to it.
12231  *
12232  * Return value: (transfer none): The expander column.
12233  **/
12234 GtkTreeViewColumn *
12235 gtk_tree_view_get_expander_column (GtkTreeView *tree_view)
12236 {
12237   GList *list;
12238
12239   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
12240
12241   for (list = tree_view->priv->columns; list; list = list->next)
12242     if (gtk_tree_view_is_expander_column (tree_view, GTK_TREE_VIEW_COLUMN (list->data)))
12243       return (GtkTreeViewColumn *) list->data;
12244   return NULL;
12245 }
12246
12247
12248 /**
12249  * gtk_tree_view_set_column_drag_function:
12250  * @tree_view: A #GtkTreeView.
12251  * @func: (allow-none): A function to determine which columns are reorderable, or %NULL.
12252  * @user_data: (allow-none): User data to be passed to @func, or %NULL
12253  * @destroy: (allow-none): Destroy notifier for @user_data, or %NULL
12254  *
12255  * Sets a user function for determining where a column may be dropped when
12256  * dragged.  This function is called on every column pair in turn at the
12257  * beginning of a column drag to determine where a drop can take place.  The
12258  * arguments passed to @func are: the @tree_view, the #GtkTreeViewColumn being
12259  * dragged, the two #GtkTreeViewColumn s determining the drop spot, and
12260  * @user_data.  If either of the #GtkTreeViewColumn arguments for the drop spot
12261  * are %NULL, then they indicate an edge.  If @func is set to be %NULL, then
12262  * @tree_view reverts to the default behavior of allowing all columns to be
12263  * dropped everywhere.
12264  **/
12265 void
12266 gtk_tree_view_set_column_drag_function (GtkTreeView               *tree_view,
12267                                         GtkTreeViewColumnDropFunc  func,
12268                                         gpointer                   user_data,
12269                                         GDestroyNotify             destroy)
12270 {
12271   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12272
12273   if (tree_view->priv->column_drop_func_data_destroy)
12274     tree_view->priv->column_drop_func_data_destroy (tree_view->priv->column_drop_func_data);
12275
12276   tree_view->priv->column_drop_func = func;
12277   tree_view->priv->column_drop_func_data = user_data;
12278   tree_view->priv->column_drop_func_data_destroy = destroy;
12279 }
12280
12281 /**
12282  * gtk_tree_view_scroll_to_point:
12283  * @tree_view: a #GtkTreeView
12284  * @tree_x: X coordinate of new top-left pixel of visible area, or -1
12285  * @tree_y: Y coordinate of new top-left pixel of visible area, or -1
12286  *
12287  * Scrolls the tree view such that the top-left corner of the visible
12288  * area is @tree_x, @tree_y, where @tree_x and @tree_y are specified
12289  * in tree coordinates.  The @tree_view must be realized before
12290  * this function is called.  If it isn't, you probably want to be
12291  * using gtk_tree_view_scroll_to_cell().
12292  *
12293  * If either @tree_x or @tree_y are -1, then that direction isn't scrolled.
12294  **/
12295 void
12296 gtk_tree_view_scroll_to_point (GtkTreeView *tree_view,
12297                                gint         tree_x,
12298                                gint         tree_y)
12299 {
12300   GtkAdjustment *hadj;
12301   GtkAdjustment *vadj;
12302
12303   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12304   g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (tree_view)));
12305
12306   hadj = tree_view->priv->hadjustment;
12307   vadj = tree_view->priv->vadjustment;
12308
12309   if (tree_x != -1)
12310     gtk_adjustment_set_value (hadj, tree_x);
12311   if (tree_y != -1)
12312     gtk_adjustment_set_value (vadj, tree_y);
12313 }
12314
12315 /**
12316  * gtk_tree_view_scroll_to_cell:
12317  * @tree_view: A #GtkTreeView.
12318  * @path: (allow-none): The path of the row to move to, or %NULL.
12319  * @column: (allow-none): The #GtkTreeViewColumn to move horizontally to, or %NULL.
12320  * @use_align: whether to use alignment arguments, or %FALSE.
12321  * @row_align: The vertical alignment of the row specified by @path.
12322  * @col_align: The horizontal alignment of the column specified by @column.
12323  *
12324  * Moves the alignments of @tree_view to the position specified by @column and
12325  * @path.  If @column is %NULL, then no horizontal scrolling occurs.  Likewise,
12326  * if @path is %NULL no vertical scrolling occurs.  At a minimum, one of @column
12327  * or @path need to be non-%NULL.  @row_align determines where the row is
12328  * placed, and @col_align determines where @column is placed.  Both are expected
12329  * to be between 0.0 and 1.0. 0.0 means left/top alignment, 1.0 means
12330  * right/bottom alignment, 0.5 means center.
12331  *
12332  * If @use_align is %FALSE, then the alignment arguments are ignored, and the
12333  * tree does the minimum amount of work to scroll the cell onto the screen.
12334  * This means that the cell will be scrolled to the edge closest to its current
12335  * position.  If the cell is currently visible on the screen, nothing is done.
12336  *
12337  * This function only works if the model is set, and @path is a valid row on the
12338  * model.  If the model changes before the @tree_view is realized, the centered
12339  * path will be modified to reflect this change.
12340  **/
12341 void
12342 gtk_tree_view_scroll_to_cell (GtkTreeView       *tree_view,
12343                               GtkTreePath       *path,
12344                               GtkTreeViewColumn *column,
12345                               gboolean           use_align,
12346                               gfloat             row_align,
12347                               gfloat             col_align)
12348 {
12349   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12350   g_return_if_fail (tree_view->priv->model != NULL);
12351   g_return_if_fail (tree_view->priv->tree != NULL);
12352   g_return_if_fail (row_align >= 0.0 && row_align <= 1.0);
12353   g_return_if_fail (col_align >= 0.0 && col_align <= 1.0);
12354   g_return_if_fail (path != NULL || column != NULL);
12355
12356 #if 0
12357   g_print ("gtk_tree_view_scroll_to_cell:\npath: %s\ncolumn: %s\nuse_align: %d\nrow_align: %f\ncol_align: %f\n",
12358            gtk_tree_path_to_string (path), column?"non-null":"null", use_align, row_align, col_align);
12359 #endif
12360   row_align = CLAMP (row_align, 0.0, 1.0);
12361   col_align = CLAMP (col_align, 0.0, 1.0);
12362
12363
12364   /* Note: Despite the benefits that come from having one code path for the
12365    * scrolling code, we short-circuit validate_visible_area's immplementation as
12366    * it is much slower than just going to the point.
12367    */
12368   if (!gtk_widget_get_visible (GTK_WIDGET (tree_view)) ||
12369       !gtk_widget_get_realized (GTK_WIDGET (tree_view)) ||
12370       _gtk_widget_get_alloc_needed (GTK_WIDGET (tree_view)) ||
12371       GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID))
12372     {
12373       if (tree_view->priv->scroll_to_path)
12374         gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
12375
12376       tree_view->priv->scroll_to_path = NULL;
12377       tree_view->priv->scroll_to_column = NULL;
12378
12379       if (path)
12380         tree_view->priv->scroll_to_path = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
12381       if (column)
12382         tree_view->priv->scroll_to_column = column;
12383       tree_view->priv->scroll_to_use_align = use_align;
12384       tree_view->priv->scroll_to_row_align = row_align;
12385       tree_view->priv->scroll_to_col_align = col_align;
12386
12387       install_presize_handler (tree_view);
12388     }
12389   else
12390     {
12391       GdkRectangle cell_rect;
12392       GdkRectangle vis_rect;
12393       gint dest_x, dest_y;
12394
12395       gtk_tree_view_get_background_area (tree_view, path, column, &cell_rect);
12396       gtk_tree_view_get_visible_rect (tree_view, &vis_rect);
12397
12398       cell_rect.y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, cell_rect.y);
12399
12400       dest_x = vis_rect.x;
12401       dest_y = vis_rect.y;
12402
12403       if (column)
12404         {
12405           if (use_align)
12406             {
12407               dest_x = cell_rect.x - ((vis_rect.width - cell_rect.width) * col_align);
12408             }
12409           else
12410             {
12411               if (cell_rect.x < vis_rect.x)
12412                 dest_x = cell_rect.x;
12413               if (cell_rect.x + cell_rect.width > vis_rect.x + vis_rect.width)
12414                 dest_x = cell_rect.x + cell_rect.width - vis_rect.width;
12415             }
12416         }
12417
12418       if (path)
12419         {
12420           if (use_align)
12421             {
12422               dest_y = cell_rect.y - ((vis_rect.height - cell_rect.height) * row_align);
12423               dest_y = MAX (dest_y, 0);
12424             }
12425           else
12426             {
12427               if (cell_rect.y < vis_rect.y)
12428                 dest_y = cell_rect.y;
12429               if (cell_rect.y + cell_rect.height > vis_rect.y + vis_rect.height)
12430                 dest_y = cell_rect.y + cell_rect.height - vis_rect.height;
12431             }
12432         }
12433
12434       gtk_tree_view_scroll_to_point (tree_view, dest_x, dest_y);
12435     }
12436 }
12437
12438 /**
12439  * gtk_tree_view_row_activated:
12440  * @tree_view: A #GtkTreeView
12441  * @path: The #GtkTreePath to be activated.
12442  * @column: The #GtkTreeViewColumn to be activated.
12443  *
12444  * Activates the cell determined by @path and @column.
12445  **/
12446 void
12447 gtk_tree_view_row_activated (GtkTreeView       *tree_view,
12448                              GtkTreePath       *path,
12449                              GtkTreeViewColumn *column)
12450 {
12451   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12452
12453   g_signal_emit (tree_view, tree_view_signals[ROW_ACTIVATED], 0, path, column);
12454 }
12455
12456
12457 static void
12458 gtk_tree_view_expand_all_emission_helper (GtkRBTree *tree,
12459                                           GtkRBNode *node,
12460                                           gpointer   data)
12461 {
12462   GtkTreeView *tree_view = data;
12463
12464   if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT &&
12465       node->children)
12466     {
12467       GtkTreePath *path;
12468       GtkTreeIter iter;
12469
12470       path = _gtk_tree_view_find_path (tree_view, tree, node);
12471       gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
12472
12473       g_signal_emit (tree_view, tree_view_signals[ROW_EXPANDED], 0, &iter, path);
12474
12475       gtk_tree_path_free (path);
12476     }
12477
12478   if (node->children)
12479     _gtk_rbtree_traverse (node->children,
12480                           node->children->root,
12481                           G_PRE_ORDER,
12482                           gtk_tree_view_expand_all_emission_helper,
12483                           tree_view);
12484 }
12485
12486 /**
12487  * gtk_tree_view_expand_all:
12488  * @tree_view: A #GtkTreeView.
12489  *
12490  * Recursively expands all nodes in the @tree_view.
12491  **/
12492 void
12493 gtk_tree_view_expand_all (GtkTreeView *tree_view)
12494 {
12495   GtkTreePath *path;
12496   GtkRBTree *tree;
12497   GtkRBNode *node;
12498
12499   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12500
12501   if (tree_view->priv->tree == NULL)
12502     return;
12503
12504   path = gtk_tree_path_new_first ();
12505   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
12506
12507   while (node)
12508     {
12509       gtk_tree_view_real_expand_row (tree_view, path, tree, node, TRUE, FALSE);
12510       node = _gtk_rbtree_next (tree, node);
12511       gtk_tree_path_next (path);
12512   }
12513
12514   gtk_tree_path_free (path);
12515 }
12516
12517 /**
12518  * gtk_tree_view_collapse_all:
12519  * @tree_view: A #GtkTreeView.
12520  *
12521  * Recursively collapses all visible, expanded nodes in @tree_view.
12522  **/
12523 void
12524 gtk_tree_view_collapse_all (GtkTreeView *tree_view)
12525 {
12526   GtkRBTree *tree;
12527   GtkRBNode *node;
12528   GtkTreePath *path;
12529   gint *indices;
12530
12531   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12532
12533   if (tree_view->priv->tree == NULL)
12534     return;
12535
12536   path = gtk_tree_path_new ();
12537   gtk_tree_path_down (path);
12538   indices = gtk_tree_path_get_indices (path);
12539
12540   tree = tree_view->priv->tree;
12541   node = tree->root;
12542   while (node && node->left != tree->nil)
12543     node = node->left;
12544
12545   while (node)
12546     {
12547       if (node->children)
12548         gtk_tree_view_real_collapse_row (tree_view, path, tree, node, FALSE);
12549       indices[0]++;
12550       node = _gtk_rbtree_next (tree, node);
12551     }
12552
12553   gtk_tree_path_free (path);
12554 }
12555
12556 /**
12557  * gtk_tree_view_expand_to_path:
12558  * @tree_view: A #GtkTreeView.
12559  * @path: path to a row.
12560  *
12561  * Expands the row at @path. This will also expand all parent rows of
12562  * @path as necessary.
12563  *
12564  * Since: 2.2
12565  **/
12566 void
12567 gtk_tree_view_expand_to_path (GtkTreeView *tree_view,
12568                               GtkTreePath *path)
12569 {
12570   gint i, depth;
12571   gint *indices;
12572   GtkTreePath *tmp;
12573
12574   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12575   g_return_if_fail (path != NULL);
12576
12577   depth = gtk_tree_path_get_depth (path);
12578   indices = gtk_tree_path_get_indices (path);
12579
12580   tmp = gtk_tree_path_new ();
12581   g_return_if_fail (tmp != NULL);
12582
12583   for (i = 0; i < depth; i++)
12584     {
12585       gtk_tree_path_append_index (tmp, indices[i]);
12586       gtk_tree_view_expand_row (tree_view, tmp, FALSE);
12587     }
12588
12589   gtk_tree_path_free (tmp);
12590 }
12591
12592 /* FIXME the bool return values for expand_row and collapse_row are
12593  * not analagous; they should be TRUE if the row had children and
12594  * was not already in the requested state.
12595  */
12596
12597
12598 static gboolean
12599 gtk_tree_view_real_expand_row (GtkTreeView *tree_view,
12600                                GtkTreePath *path,
12601                                GtkRBTree   *tree,
12602                                GtkRBNode   *node,
12603                                gboolean     open_all,
12604                                gboolean     animate)
12605 {
12606   GtkTreeIter iter;
12607   GtkTreeIter temp;
12608   gboolean expand;
12609
12610   if (animate)
12611     g_object_get (gtk_widget_get_settings (GTK_WIDGET (tree_view)),
12612                   "gtk-enable-animations", &animate,
12613                   NULL);
12614
12615   remove_auto_expand_timeout (tree_view);
12616
12617   if (node->children && !open_all)
12618     return FALSE;
12619
12620   if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
12621     return FALSE;
12622
12623   gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
12624   if (! gtk_tree_model_iter_has_child (tree_view->priv->model, &iter))
12625     return FALSE;
12626
12627
12628    if (node->children && open_all)
12629     {
12630       gboolean retval = FALSE;
12631       GtkTreePath *tmp_path = gtk_tree_path_copy (path);
12632
12633       gtk_tree_path_append_index (tmp_path, 0);
12634       tree = node->children;
12635       node = tree->root;
12636       while (node->left != tree->nil)
12637         node = node->left;
12638       /* try to expand the children */
12639       do
12640         {
12641          gboolean t;
12642          t = gtk_tree_view_real_expand_row (tree_view, tmp_path, tree, node,
12643                                             TRUE, animate);
12644          if (t)
12645            retval = TRUE;
12646
12647          gtk_tree_path_next (tmp_path);
12648          node = _gtk_rbtree_next (tree, node);
12649        }
12650       while (node != NULL);
12651
12652       gtk_tree_path_free (tmp_path);
12653
12654       return retval;
12655     }
12656
12657   g_signal_emit (tree_view, tree_view_signals[TEST_EXPAND_ROW], 0, &iter, path, &expand);
12658
12659   if (!gtk_tree_model_iter_has_child (tree_view->priv->model, &iter))
12660     return FALSE;
12661
12662   if (expand)
12663     return FALSE;
12664
12665   node->children = _gtk_rbtree_new ();
12666   node->children->parent_tree = tree;
12667   node->children->parent_node = node;
12668
12669   gtk_tree_model_iter_children (tree_view->priv->model, &temp, &iter);
12670
12671   gtk_tree_view_build_tree (tree_view,
12672                             node->children,
12673                             &temp,
12674                             gtk_tree_path_get_depth (path) + 1,
12675                             open_all);
12676
12677   if (animate)
12678     {
12679       GtkStyleContext *context;
12680
12681       context = gtk_widget_get_style_context (GTK_WIDGET (tree_view));
12682
12683       gtk_style_context_save (context);
12684       gtk_style_context_add_class (context, GTK_STYLE_CLASS_EXPANDER);
12685
12686       gtk_style_context_notify_state_change (context, tree_view->priv->bin_window,
12687                                              node, GTK_STATE_ACTIVE, TRUE);
12688
12689       _gtk_style_context_invalidate_animation_areas (context);
12690       gtk_style_context_restore (context);
12691     }
12692
12693   install_presize_handler (tree_view);
12694
12695   g_signal_emit (tree_view, tree_view_signals[ROW_EXPANDED], 0, &iter, path);
12696   if (open_all && node->children)
12697     {
12698       _gtk_rbtree_traverse (node->children,
12699                             node->children->root,
12700                             G_PRE_ORDER,
12701                             gtk_tree_view_expand_all_emission_helper,
12702                             tree_view);
12703     }
12704   return TRUE;
12705 }
12706
12707
12708 /**
12709  * gtk_tree_view_expand_row:
12710  * @tree_view: a #GtkTreeView
12711  * @path: path to a row
12712  * @open_all: whether to recursively expand, or just expand immediate children
12713  *
12714  * Opens the row so its children are visible.
12715  *
12716  * Return value: %TRUE if the row existed and had children
12717  **/
12718 gboolean
12719 gtk_tree_view_expand_row (GtkTreeView *tree_view,
12720                           GtkTreePath *path,
12721                           gboolean     open_all)
12722 {
12723   GtkRBTree *tree;
12724   GtkRBNode *node;
12725
12726   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12727   g_return_val_if_fail (tree_view->priv->model != NULL, FALSE);
12728   g_return_val_if_fail (path != NULL, FALSE);
12729
12730   if (_gtk_tree_view_find_node (tree_view,
12731                                 path,
12732                                 &tree,
12733                                 &node))
12734     return FALSE;
12735
12736   if (tree != NULL)
12737     return gtk_tree_view_real_expand_row (tree_view, path, tree, node, open_all, FALSE);
12738   else
12739     return FALSE;
12740 }
12741
12742 static gboolean
12743 gtk_tree_view_real_collapse_row (GtkTreeView *tree_view,
12744                                  GtkTreePath *path,
12745                                  GtkRBTree   *tree,
12746                                  GtkRBNode   *node,
12747                                  gboolean     animate)
12748 {
12749   GtkTreeIter iter;
12750   GtkTreeIter children;
12751   gboolean collapse;
12752   gint x, y;
12753   GList *list;
12754   GdkWindow *child, *parent;
12755
12756   if (animate)
12757     g_object_get (gtk_widget_get_settings (GTK_WIDGET (tree_view)),
12758                   "gtk-enable-animations", &animate,
12759                   NULL);
12760
12761   remove_auto_expand_timeout (tree_view);
12762
12763   if (node->children == NULL)
12764     return FALSE;
12765   gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
12766
12767   g_signal_emit (tree_view, tree_view_signals[TEST_COLLAPSE_ROW], 0, &iter, path, &collapse);
12768
12769   if (collapse)
12770     return FALSE;
12771
12772   /* if the prelighted node is a child of us, we want to unprelight it.  We have
12773    * a chance to prelight the correct node below */
12774
12775   if (tree_view->priv->prelight_tree)
12776     {
12777       GtkRBTree *parent_tree;
12778       GtkRBNode *parent_node;
12779
12780       parent_tree = tree_view->priv->prelight_tree->parent_tree;
12781       parent_node = tree_view->priv->prelight_tree->parent_node;
12782       while (parent_tree)
12783         {
12784           if (parent_tree == tree && parent_node == node)
12785             {
12786               ensure_unprelighted (tree_view);
12787               break;
12788             }
12789           parent_node = parent_tree->parent_node;
12790           parent_tree = parent_tree->parent_tree;
12791         }
12792     }
12793
12794   TREE_VIEW_INTERNAL_ASSERT (gtk_tree_model_iter_children (tree_view->priv->model, &children, &iter), FALSE);
12795
12796   for (list = tree_view->priv->columns; list; list = list->next)
12797     {
12798       GtkTreeViewColumn *column = list->data;
12799
12800       if (gtk_tree_view_column_get_visible (column) == FALSE)
12801         continue;
12802       if (gtk_tree_view_column_get_sizing (column) == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
12803         _gtk_tree_view_column_cell_set_dirty (column, TRUE);
12804     }
12805
12806   if (tree_view->priv->destroy_count_func)
12807     {
12808       GtkTreePath *child_path;
12809       gint child_count = 0;
12810       child_path = gtk_tree_path_copy (path);
12811       gtk_tree_path_down (child_path);
12812       if (node->children)
12813         _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, count_children_helper, &child_count);
12814       tree_view->priv->destroy_count_func (tree_view, child_path, child_count, tree_view->priv->destroy_count_data);
12815       gtk_tree_path_free (child_path);
12816     }
12817
12818   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
12819     {
12820       GtkTreePath *cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
12821
12822       if (gtk_tree_path_is_ancestor (path, cursor_path))
12823         {
12824           gtk_tree_row_reference_free (tree_view->priv->cursor);
12825           tree_view->priv->cursor = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
12826                                                                       tree_view->priv->model,
12827                                                                       path);
12828         }
12829       gtk_tree_path_free (cursor_path);
12830     }
12831
12832   if (gtk_tree_row_reference_valid (tree_view->priv->anchor))
12833     {
12834       GtkTreePath *anchor_path = gtk_tree_row_reference_get_path (tree_view->priv->anchor);
12835       if (gtk_tree_path_is_ancestor (path, anchor_path))
12836         {
12837           gtk_tree_row_reference_free (tree_view->priv->anchor);
12838           tree_view->priv->anchor = NULL;
12839         }
12840       gtk_tree_path_free (anchor_path);
12841     }
12842
12843   /* Stop a pending double click */
12844   tree_view->priv->last_button_x = -1;
12845   tree_view->priv->last_button_y = -1;
12846
12847   if (gtk_tree_view_unref_and_check_selection_tree (tree_view, node->children))
12848     {
12849       _gtk_rbtree_remove (node->children);
12850       g_signal_emit_by_name (tree_view->priv->selection, "changed");
12851     }
12852   else
12853     _gtk_rbtree_remove (node->children);
12854
12855   if (animate)
12856     {
12857       GtkStyleContext *context;
12858
12859       context = gtk_widget_get_style_context (GTK_WIDGET (tree_view));
12860
12861       gtk_style_context_save (context);
12862       gtk_style_context_add_class (context, GTK_STYLE_CLASS_EXPANDER);
12863
12864       gtk_style_context_notify_state_change (context, tree_view->priv->bin_window,
12865                                              node, GTK_STATE_ACTIVE, FALSE);
12866
12867       _gtk_style_context_invalidate_animation_areas (context);
12868       gtk_style_context_restore (context);
12869     }
12870
12871   if (gtk_widget_get_mapped (GTK_WIDGET (tree_view)))
12872     {
12873       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
12874     }
12875
12876   g_signal_emit (tree_view, tree_view_signals[ROW_COLLAPSED], 0, &iter, path);
12877   
12878   if (gtk_widget_get_mapped (GTK_WIDGET (tree_view)))
12879     {
12880       /* now that we've collapsed all rows, we want to try to set the prelight
12881        * again. To do this, we fake a motion event and send it to ourselves. */
12882
12883       child = tree_view->priv->bin_window;
12884       parent = gdk_window_get_parent (child);
12885
12886       if (gdk_window_get_pointer (parent, &x, &y, NULL) == child)
12887         {
12888           GdkEventMotion event;
12889           gint child_x, child_y;
12890
12891           gdk_window_get_position (child, &child_x, &child_y);
12892
12893           event.window = tree_view->priv->bin_window;
12894           event.x = x - child_x;
12895           event.y = y - child_y;
12896
12897           /* despite the fact this isn't a real event, I'm almost positive it will
12898            * never trigger a drag event.  maybe_drag is the only function that uses
12899            * more than just event.x and event.y. */
12900           gtk_tree_view_motion_bin_window (GTK_WIDGET (tree_view), &event);
12901         }
12902     }
12903
12904   return TRUE;
12905 }
12906
12907 /**
12908  * gtk_tree_view_collapse_row:
12909  * @tree_view: a #GtkTreeView
12910  * @path: path to a row in the @tree_view
12911  *
12912  * Collapses a row (hides its child rows, if they exist).
12913  *
12914  * Return value: %TRUE if the row was collapsed.
12915  **/
12916 gboolean
12917 gtk_tree_view_collapse_row (GtkTreeView *tree_view,
12918                             GtkTreePath *path)
12919 {
12920   GtkRBTree *tree;
12921   GtkRBNode *node;
12922
12923   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
12924   g_return_val_if_fail (tree_view->priv->tree != NULL, FALSE);
12925   g_return_val_if_fail (path != NULL, FALSE);
12926
12927   if (_gtk_tree_view_find_node (tree_view,
12928                                 path,
12929                                 &tree,
12930                                 &node))
12931     return FALSE;
12932
12933   if (tree == NULL || node->children == NULL)
12934     return FALSE;
12935
12936   return gtk_tree_view_real_collapse_row (tree_view, path, tree, node, FALSE);
12937 }
12938
12939 static void
12940 gtk_tree_view_map_expanded_rows_helper (GtkTreeView            *tree_view,
12941                                         GtkRBTree              *tree,
12942                                         GtkTreePath            *path,
12943                                         GtkTreeViewMappingFunc  func,
12944                                         gpointer                user_data)
12945 {
12946   GtkRBNode *node;
12947
12948   if (tree == NULL || tree->root == NULL)
12949     return;
12950
12951   node = tree->root;
12952
12953   while (node && node->left != tree->nil)
12954     node = node->left;
12955
12956   while (node)
12957     {
12958       if (node->children)
12959         {
12960           (* func) (tree_view, path, user_data);
12961           gtk_tree_path_down (path);
12962           gtk_tree_view_map_expanded_rows_helper (tree_view, node->children, path, func, user_data);
12963           gtk_tree_path_up (path);
12964         }
12965       gtk_tree_path_next (path);
12966       node = _gtk_rbtree_next (tree, node);
12967     }
12968 }
12969
12970 /**
12971  * gtk_tree_view_map_expanded_rows:
12972  * @tree_view: A #GtkTreeView
12973  * @func: (scope call): A function to be called
12974  * @data: User data to be passed to the function.
12975  *
12976  * Calls @func on all expanded rows.
12977  **/
12978 void
12979 gtk_tree_view_map_expanded_rows (GtkTreeView            *tree_view,
12980                                  GtkTreeViewMappingFunc  func,
12981                                  gpointer                user_data)
12982 {
12983   GtkTreePath *path;
12984
12985   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
12986   g_return_if_fail (func != NULL);
12987
12988   path = gtk_tree_path_new_first ();
12989
12990   gtk_tree_view_map_expanded_rows_helper (tree_view,
12991                                           tree_view->priv->tree,
12992                                           path, func, user_data);
12993
12994   gtk_tree_path_free (path);
12995 }
12996
12997 /**
12998  * gtk_tree_view_row_expanded:
12999  * @tree_view: A #GtkTreeView.
13000  * @path: A #GtkTreePath to test expansion state.
13001  *
13002  * Returns %TRUE if the node pointed to by @path is expanded in @tree_view.
13003  *
13004  * Return value: %TRUE if #path is expanded.
13005  **/
13006 gboolean
13007 gtk_tree_view_row_expanded (GtkTreeView *tree_view,
13008                             GtkTreePath *path)
13009 {
13010   GtkRBTree *tree;
13011   GtkRBNode *node;
13012
13013   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
13014   g_return_val_if_fail (path != NULL, FALSE);
13015
13016   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
13017
13018   if (node == NULL)
13019     return FALSE;
13020
13021   return (node->children != NULL);
13022 }
13023
13024 /**
13025  * gtk_tree_view_get_reorderable:
13026  * @tree_view: a #GtkTreeView
13027  *
13028  * Retrieves whether the user can reorder the tree via drag-and-drop. See
13029  * gtk_tree_view_set_reorderable().
13030  *
13031  * Return value: %TRUE if the tree can be reordered.
13032  **/
13033 gboolean
13034 gtk_tree_view_get_reorderable (GtkTreeView *tree_view)
13035 {
13036   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
13037
13038   return tree_view->priv->reorderable;
13039 }
13040
13041 /**
13042  * gtk_tree_view_set_reorderable:
13043  * @tree_view: A #GtkTreeView.
13044  * @reorderable: %TRUE, if the tree can be reordered.
13045  *
13046  * This function is a convenience function to allow you to reorder
13047  * models that support the #GtkTreeDragSourceIface and the
13048  * #GtkTreeDragDestIface.  Both #GtkTreeStore and #GtkListStore support
13049  * these.  If @reorderable is %TRUE, then the user can reorder the
13050  * model by dragging and dropping rows. The developer can listen to
13051  * these changes by connecting to the model's row_inserted and
13052  * row_deleted signals. The reordering is implemented by setting up
13053  * the tree view as a drag source and destination. Therefore, drag and
13054  * drop can not be used in a reorderable view for any other purpose.
13055  *
13056  * This function does not give you any degree of control over the order -- any
13057  * reordering is allowed.  If more control is needed, you should probably
13058  * handle drag and drop manually.
13059  **/
13060 void
13061 gtk_tree_view_set_reorderable (GtkTreeView *tree_view,
13062                                gboolean     reorderable)
13063 {
13064   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13065
13066   reorderable = reorderable != FALSE;
13067
13068   if (tree_view->priv->reorderable == reorderable)
13069     return;
13070
13071   if (reorderable)
13072     {
13073       const GtkTargetEntry row_targets[] = {
13074         { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, 0 }
13075       };
13076
13077       gtk_tree_view_enable_model_drag_source (tree_view,
13078                                               GDK_BUTTON1_MASK,
13079                                               row_targets,
13080                                               G_N_ELEMENTS (row_targets),
13081                                               GDK_ACTION_MOVE);
13082       gtk_tree_view_enable_model_drag_dest (tree_view,
13083                                             row_targets,
13084                                             G_N_ELEMENTS (row_targets),
13085                                             GDK_ACTION_MOVE);
13086     }
13087   else
13088     {
13089       gtk_tree_view_unset_rows_drag_source (tree_view);
13090       gtk_tree_view_unset_rows_drag_dest (tree_view);
13091     }
13092
13093   tree_view->priv->reorderable = reorderable;
13094
13095   g_object_notify (G_OBJECT (tree_view), "reorderable");
13096 }
13097
13098 static void
13099 gtk_tree_view_real_set_cursor (GtkTreeView     *tree_view,
13100                                GtkTreePath     *path,
13101                                gboolean         clear_and_select,
13102                                gboolean         clamp_node)
13103 {
13104   GtkRBTree *tree = NULL;
13105   GtkRBNode *node = NULL;
13106
13107   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
13108     {
13109       GtkTreePath *cursor_path;
13110       cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
13111       gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
13112       gtk_tree_path_free (cursor_path);
13113     }
13114
13115   gtk_tree_row_reference_free (tree_view->priv->cursor);
13116   tree_view->priv->cursor = NULL;
13117
13118   /* One cannot set the cursor on a separator.   Also, if
13119    * _gtk_tree_view_find_node returns TRUE, it ran out of tree
13120    * before finding the tree and node belonging to path.  The
13121    * path maps to a non-existing path and we will silently bail out.
13122    * We unset tree and node to avoid further processing.
13123    */
13124   if (!row_is_separator (tree_view, NULL, path)
13125       && _gtk_tree_view_find_node (tree_view, path, &tree, &node) == FALSE)
13126     {
13127       tree_view->priv->cursor =
13128           gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
13129                                             tree_view->priv->model,
13130                                             path);
13131     }
13132   else
13133     {
13134       tree = NULL;
13135       node = NULL;
13136     }
13137
13138   if (tree != NULL)
13139     {
13140       GtkRBTree *new_tree = NULL;
13141       GtkRBNode *new_node = NULL;
13142
13143       if (clear_and_select && !tree_view->priv->ctrl_pressed)
13144         {
13145           GtkTreeSelectMode mode = 0;
13146
13147           if (tree_view->priv->shift_pressed)
13148             mode |= GTK_TREE_SELECT_MODE_EXTEND;
13149
13150           _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
13151                                                     node, tree, path, mode,
13152                                                     FALSE);
13153         }
13154
13155       /* We have to re-find tree and node here again, somebody might have
13156        * cleared the node or the whole tree in the GtkTreeSelection::changed
13157        * callback. If the nodes differ we bail out here.
13158        */
13159       _gtk_tree_view_find_node (tree_view, path, &new_tree, &new_node);
13160
13161       if (tree != new_tree || node != new_node)
13162         return;
13163
13164       if (clamp_node)
13165         {
13166           gtk_tree_view_clamp_node_visible (tree_view, tree, node);
13167           _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
13168         }
13169     }
13170
13171   g_signal_emit (tree_view, tree_view_signals[CURSOR_CHANGED], 0);
13172 }
13173
13174 /**
13175  * gtk_tree_view_get_cursor:
13176  * @tree_view: A #GtkTreeView
13177  * @path: (out) (transfer full) (allow-none): A pointer to be filled with the current cursor path, or %NULL
13178  * @focus_column: (out) (transfer none) (allow-none): A pointer to be filled with the current focus column, or %NULL
13179  *
13180  * Fills in @path and @focus_column with the current path and focus column.  If
13181  * the cursor isn't currently set, then *@path will be %NULL.  If no column
13182  * currently has focus, then *@focus_column will be %NULL.
13183  *
13184  * The returned #GtkTreePath must be freed with gtk_tree_path_free() when
13185  * you are done with it.
13186  **/
13187 void
13188 gtk_tree_view_get_cursor (GtkTreeView        *tree_view,
13189                           GtkTreePath       **path,
13190                           GtkTreeViewColumn **focus_column)
13191 {
13192   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13193
13194   if (path)
13195     {
13196       if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
13197         *path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
13198       else
13199         *path = NULL;
13200     }
13201
13202   if (focus_column)
13203     {
13204       *focus_column = tree_view->priv->focus_column;
13205     }
13206 }
13207
13208 /**
13209  * gtk_tree_view_set_cursor:
13210  * @tree_view: A #GtkTreeView
13211  * @path: A #GtkTreePath
13212  * @focus_column: (allow-none): A #GtkTreeViewColumn, or %NULL
13213  * @start_editing: %TRUE if the specified cell should start being edited.
13214  *
13215  * Sets the current keyboard focus to be at @path, and selects it.  This is
13216  * useful when you want to focus the user's attention on a particular row.  If
13217  * @focus_column is not %NULL, then focus is given to the column specified by 
13218  * it. Additionally, if @focus_column is specified, and @start_editing is 
13219  * %TRUE, then editing should be started in the specified cell.  
13220  * This function is often followed by @gtk_widget_grab_focus (@tree_view) 
13221  * in order to give keyboard focus to the widget.  Please note that editing 
13222  * can only happen when the widget is realized.
13223  *
13224  * If @path is invalid for @model, the current cursor (if any) will be unset
13225  * and the function will return without failing.
13226  **/
13227 void
13228 gtk_tree_view_set_cursor (GtkTreeView       *tree_view,
13229                           GtkTreePath       *path,
13230                           GtkTreeViewColumn *focus_column,
13231                           gboolean           start_editing)
13232 {
13233   gtk_tree_view_set_cursor_on_cell (tree_view, path, focus_column,
13234                                     NULL, start_editing);
13235 }
13236
13237 /**
13238  * gtk_tree_view_set_cursor_on_cell:
13239  * @tree_view: A #GtkTreeView
13240  * @path: A #GtkTreePath
13241  * @focus_column: (allow-none): A #GtkTreeViewColumn, or %NULL
13242  * @focus_cell: (allow-none): A #GtkCellRenderer, or %NULL
13243  * @start_editing: %TRUE if the specified cell should start being edited.
13244  *
13245  * Sets the current keyboard focus to be at @path, and selects it.  This is
13246  * useful when you want to focus the user's attention on a particular row.  If
13247  * @focus_column is not %NULL, then focus is given to the column specified by
13248  * it. If @focus_column and @focus_cell are not %NULL, and @focus_column
13249  * contains 2 or more editable or activatable cells, then focus is given to
13250  * the cell specified by @focus_cell. Additionally, if @focus_column is
13251  * specified, and @start_editing is %TRUE, then editing should be started in
13252  * the specified cell.  This function is often followed by
13253  * @gtk_widget_grab_focus (@tree_view) in order to give keyboard focus to the
13254  * widget.  Please note that editing can only happen when the widget is
13255  * realized.
13256  *
13257  * If @path is invalid for @model, the current cursor (if any) will be unset
13258  * and the function will return without failing.
13259  *
13260  * Since: 2.2
13261  **/
13262 void
13263 gtk_tree_view_set_cursor_on_cell (GtkTreeView       *tree_view,
13264                                   GtkTreePath       *path,
13265                                   GtkTreeViewColumn *focus_column,
13266                                   GtkCellRenderer   *focus_cell,
13267                                   gboolean           start_editing)
13268 {
13269   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13270   g_return_if_fail (path != NULL);
13271   g_return_if_fail (focus_column == NULL || GTK_IS_TREE_VIEW_COLUMN (focus_column));
13272
13273   if (!tree_view->priv->model)
13274     return;
13275
13276   if (focus_cell)
13277     {
13278       g_return_if_fail (focus_column);
13279       g_return_if_fail (GTK_IS_CELL_RENDERER (focus_cell));
13280     }
13281
13282   /* cancel the current editing, if it exists */
13283   if (tree_view->priv->edited_column &&
13284       gtk_cell_area_get_edit_widget
13285       (gtk_cell_layout_get_area (GTK_CELL_LAYOUT (tree_view->priv->edited_column))))
13286     gtk_tree_view_stop_editing (tree_view, TRUE);
13287
13288   gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
13289
13290   if (focus_column &&
13291       gtk_tree_view_column_get_visible (focus_column))
13292     {
13293       GList *list;
13294       gboolean column_in_tree = FALSE;
13295
13296       for (list = tree_view->priv->columns; list; list = list->next)
13297         if (list->data == focus_column)
13298           {
13299             column_in_tree = TRUE;
13300             break;
13301           }
13302       g_return_if_fail (column_in_tree);
13303       tree_view->priv->focus_column = focus_column;
13304       if (focus_cell)
13305         gtk_tree_view_column_focus_cell (focus_column, focus_cell);
13306       if (start_editing)
13307         gtk_tree_view_start_editing (tree_view, path, TRUE);
13308     }
13309 }
13310
13311 /**
13312  * gtk_tree_view_get_bin_window:
13313  * @tree_view: A #GtkTreeView
13314  *
13315  * Returns the window that @tree_view renders to.
13316  * This is used primarily to compare to <literal>event->window</literal>
13317  * to confirm that the event on @tree_view is on the right window.
13318  *
13319  * Return value: (transfer none): A #GdkWindow, or %NULL when @tree_view
13320  *     hasn't been realized yet
13321  **/
13322 GdkWindow *
13323 gtk_tree_view_get_bin_window (GtkTreeView *tree_view)
13324 {
13325   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
13326
13327   return tree_view->priv->bin_window;
13328 }
13329
13330 /**
13331  * gtk_tree_view_get_path_at_pos:
13332  * @tree_view: A #GtkTreeView.
13333  * @x: The x position to be identified (relative to bin_window).
13334  * @y: The y position to be identified (relative to bin_window).
13335  * @path: (out) (allow-none): A pointer to a #GtkTreePath pointer to be filled in, or %NULL
13336  * @column: (out) (transfer none) (allow-none): A pointer to a #GtkTreeViewColumn pointer to be filled in, or %NULL
13337  * @cell_x: (out) (allow-none): A pointer where the X coordinate relative to the cell can be placed, or %NULL
13338  * @cell_y: (out) (allow-none): A pointer where the Y coordinate relative to the cell can be placed, or %NULL
13339  *
13340  * Finds the path at the point (@x, @y), relative to bin_window coordinates
13341  * (please see gtk_tree_view_get_bin_window()).
13342  * That is, @x and @y are relative to an events coordinates. @x and @y must
13343  * come from an event on the @tree_view only where <literal>event->window ==
13344  * gtk_tree_view_get_bin_window (<!-- -->)</literal>. It is primarily for
13345  * things like popup menus. If @path is non-%NULL, then it will be filled
13346  * with the #GtkTreePath at that point.  This path should be freed with
13347  * gtk_tree_path_free().  If @column is non-%NULL, then it will be filled
13348  * with the column at that point.  @cell_x and @cell_y return the coordinates
13349  * relative to the cell background (i.e. the @background_area passed to
13350  * gtk_cell_renderer_render()).  This function is only meaningful if
13351  * @tree_view is realized.  Therefore this function will always return %FALSE
13352  * if @tree_view is not realized or does not have a model.
13353  *
13354  * For converting widget coordinates (eg. the ones you get from
13355  * GtkWidget::query-tooltip), please see
13356  * gtk_tree_view_convert_widget_to_bin_window_coords().
13357  *
13358  * Return value: %TRUE if a row exists at that coordinate.
13359  **/
13360 gboolean
13361 gtk_tree_view_get_path_at_pos (GtkTreeView        *tree_view,
13362                                gint                x,
13363                                gint                y,
13364                                GtkTreePath       **path,
13365                                GtkTreeViewColumn **column,
13366                                gint               *cell_x,
13367                                gint               *cell_y)
13368 {
13369   GtkRBTree *tree;
13370   GtkRBNode *node;
13371   gint y_offset;
13372
13373   g_return_val_if_fail (tree_view != NULL, FALSE);
13374
13375   if (path)
13376     *path = NULL;
13377   if (column)
13378     *column = NULL;
13379
13380   if (tree_view->priv->bin_window == NULL)
13381     return FALSE;
13382
13383   if (tree_view->priv->tree == NULL)
13384     return FALSE;
13385
13386   if (x > gtk_adjustment_get_upper (tree_view->priv->hadjustment))
13387     return FALSE;
13388
13389   if (x < 0 || y < 0)
13390     return FALSE;
13391
13392   if (column || cell_x)
13393     {
13394       GtkTreeViewColumn *tmp_column;
13395       GtkTreeViewColumn *last_column = NULL;
13396       GList *list;
13397       gint remaining_x = x;
13398       gboolean found = FALSE;
13399       gboolean rtl;
13400       gint width;
13401
13402       rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
13403       for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
13404            list;
13405            list = (rtl ? list->prev : list->next))
13406         {
13407           tmp_column = list->data;
13408
13409           if (gtk_tree_view_column_get_visible (tmp_column) == FALSE)
13410             continue;
13411
13412           last_column = tmp_column;
13413           width = gtk_tree_view_column_get_width (tmp_column);
13414           if (remaining_x <= width)
13415             {
13416               found = TRUE;
13417
13418               if (column)
13419                 *column = tmp_column;
13420
13421               if (cell_x)
13422                 *cell_x = remaining_x;
13423
13424               break;
13425             }
13426           remaining_x -= width;
13427         }
13428
13429       /* If found is FALSE and there is a last_column, then it the remainder
13430        * space is in that area
13431        */
13432       if (!found)
13433         {
13434           if (last_column)
13435             {
13436               if (column)
13437                 *column = last_column;
13438               
13439               if (cell_x)
13440                 *cell_x = gtk_tree_view_column_get_width (last_column) + remaining_x;
13441             }
13442           else
13443             {
13444               return FALSE;
13445             }
13446         }
13447     }
13448
13449   y_offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
13450                                       TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, y),
13451                                       &tree, &node);
13452
13453   if (tree == NULL)
13454     return FALSE;
13455
13456   if (cell_y)
13457     *cell_y = y_offset;
13458
13459   if (path)
13460     *path = _gtk_tree_view_find_path (tree_view, tree, node);
13461
13462   return TRUE;
13463 }
13464
13465
13466 static inline gint
13467 gtk_tree_view_get_cell_area_height (GtkTreeView *tree_view,
13468                                     GtkRBNode   *node,
13469                                     gint         vertical_separator)
13470 {
13471   int height;
13472
13473   /* The "cell" areas are the cell_area passed in to gtk_cell_renderer_render(),
13474    * i.e. just the cells, no spacing.
13475    *
13476    * The cell area height is at least expander_size - vertical_separator.
13477    * For regular nodes, the height is then at least expander_size. We should
13478    * be able to enforce the expander_size minimum here, because this
13479    * function will not be called for irregular (e.g. separator) rows.
13480    */
13481   height = gtk_tree_view_get_row_height (tree_view, node);
13482   if (height < tree_view->priv->expander_size)
13483     height = tree_view->priv->expander_size;
13484
13485   return height - vertical_separator;
13486 }
13487
13488 static inline gint
13489 gtk_tree_view_get_cell_area_y_offset (GtkTreeView *tree_view,
13490                                       GtkRBTree   *tree,
13491                                       GtkRBNode   *node,
13492                                       gint         vertical_separator)
13493 {
13494   int offset;
13495
13496   offset = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
13497   offset += vertical_separator / 2;
13498
13499   return offset;
13500 }
13501
13502 /**
13503  * gtk_tree_view_get_cell_area:
13504  * @tree_view: a #GtkTreeView
13505  * @path: (allow-none): a #GtkTreePath for the row, or %NULL to get only horizontal coordinates
13506  * @column: (allow-none): a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordinates
13507  * @rect: (out): rectangle to fill with cell rect
13508  *
13509  * Fills the bounding rectangle in bin_window coordinates for the cell at the
13510  * row specified by @path and the column specified by @column.  If @path is
13511  * %NULL, or points to a path not currently displayed, the @y and @height fields
13512  * of the rectangle will be filled with 0. If @column is %NULL, the @x and @width
13513  * fields will be filled with 0.  The sum of all cell rects does not cover the
13514  * entire tree; there are extra pixels in between rows, for example. The
13515  * returned rectangle is equivalent to the @cell_area passed to
13516  * gtk_cell_renderer_render().  This function is only valid if @tree_view is
13517  * realized.
13518  **/
13519 void
13520 gtk_tree_view_get_cell_area (GtkTreeView        *tree_view,
13521                              GtkTreePath        *path,
13522                              GtkTreeViewColumn  *column,
13523                              GdkRectangle       *rect)
13524 {
13525   GtkRBTree *tree = NULL;
13526   GtkRBNode *node = NULL;
13527   gint vertical_separator;
13528   gint horizontal_separator;
13529
13530   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13531   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
13532   g_return_if_fail (rect != NULL);
13533   g_return_if_fail (!column || gtk_tree_view_column_get_tree_view (column) == (GtkWidget *) tree_view);
13534   g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (tree_view)));
13535
13536   gtk_widget_style_get (GTK_WIDGET (tree_view),
13537                         "vertical-separator", &vertical_separator,
13538                         "horizontal-separator", &horizontal_separator,
13539                         NULL);
13540
13541   rect->x = 0;
13542   rect->y = 0;
13543   rect->width = 0;
13544   rect->height = 0;
13545
13546   if (column)
13547     {
13548       rect->x = gtk_tree_view_column_get_x_offset (column) + horizontal_separator/2;
13549       rect->width = gtk_tree_view_column_get_width (column) - horizontal_separator;
13550     }
13551
13552   if (path)
13553     {
13554       gboolean ret = _gtk_tree_view_find_node (tree_view, path, &tree, &node);
13555
13556       /* Get vertical coords */
13557       if ((!ret && tree == NULL) || ret)
13558         return;
13559
13560       if (row_is_separator (tree_view, NULL, path))
13561         {
13562           /* There isn't really a "cell area" for separator, so we
13563            * return the y, height values for background area instead.
13564            */
13565           rect->y = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
13566           rect->height = gtk_tree_view_get_row_height (tree_view, node);
13567         }
13568       else
13569         {
13570           rect->y = gtk_tree_view_get_cell_area_y_offset (tree_view, tree, node,
13571                                                           vertical_separator);
13572           rect->height = gtk_tree_view_get_cell_area_height (tree_view, node,
13573                                                              vertical_separator);
13574         }
13575
13576       if (column &&
13577           gtk_tree_view_is_expander_column (tree_view, column))
13578         {
13579           gint depth = gtk_tree_path_get_depth (path);
13580           gboolean rtl;
13581
13582           rtl = gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL;
13583
13584           if (!rtl)
13585             rect->x += (depth - 1) * tree_view->priv->level_indentation;
13586           rect->width -= (depth - 1) * tree_view->priv->level_indentation;
13587
13588           if (gtk_tree_view_draw_expanders (tree_view))
13589             {
13590               if (!rtl)
13591                 rect->x += depth * tree_view->priv->expander_size;
13592               rect->width -= depth * tree_view->priv->expander_size;
13593             }
13594
13595           rect->width = MAX (rect->width, 0);
13596         }
13597     }
13598 }
13599
13600 static inline gint
13601 gtk_tree_view_get_row_height (GtkTreeView *tree_view,
13602                               GtkRBNode   *node)
13603 {
13604   int height;
13605
13606   /* The "background" areas of all rows/cells add up to cover the entire tree.
13607    * The background includes all inter-row and inter-cell spacing.
13608    *
13609    * If the row pointed at by node does not have a height set, we default
13610    * to expander_size, which is the minimum height for regular nodes.
13611    * Non-regular nodes (e.g. separators) can have a height set smaller
13612    * than expander_size and should not be overruled here.
13613    */
13614   height = GTK_RBNODE_GET_HEIGHT (node);
13615   if (height <= 0)
13616     height = tree_view->priv->expander_size;
13617
13618   return height;
13619 }
13620
13621 static inline gint
13622 gtk_tree_view_get_row_y_offset (GtkTreeView *tree_view,
13623                                 GtkRBTree   *tree,
13624                                 GtkRBNode   *node)
13625 {
13626   int offset;
13627
13628   offset = _gtk_rbtree_node_find_offset (tree, node);
13629
13630   return RBTREE_Y_TO_TREE_WINDOW_Y (tree_view, offset);
13631 }
13632
13633 /**
13634  * gtk_tree_view_get_background_area:
13635  * @tree_view: a #GtkTreeView
13636  * @path: (allow-none): a #GtkTreePath for the row, or %NULL to get only horizontal coordinates
13637  * @column: (allow-none): a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordiantes
13638  * @rect: (out): rectangle to fill with cell background rect
13639  *
13640  * Fills the bounding rectangle in bin_window coordinates for the cell at the
13641  * row specified by @path and the column specified by @column.  If @path is
13642  * %NULL, or points to a node not found in the tree, the @y and @height fields of
13643  * the rectangle will be filled with 0. If @column is %NULL, the @x and @width
13644  * fields will be filled with 0.  The returned rectangle is equivalent to the
13645  * @background_area passed to gtk_cell_renderer_render().  These background
13646  * areas tile to cover the entire bin window.  Contrast with the @cell_area,
13647  * returned by gtk_tree_view_get_cell_area(), which returns only the cell
13648  * itself, excluding surrounding borders and the tree expander area.
13649  *
13650  **/
13651 void
13652 gtk_tree_view_get_background_area (GtkTreeView        *tree_view,
13653                                    GtkTreePath        *path,
13654                                    GtkTreeViewColumn  *column,
13655                                    GdkRectangle       *rect)
13656 {
13657   GtkRBTree *tree = NULL;
13658   GtkRBNode *node = NULL;
13659
13660   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13661   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
13662   g_return_if_fail (rect != NULL);
13663
13664   rect->x = 0;
13665   rect->y = 0;
13666   rect->width = 0;
13667   rect->height = 0;
13668
13669   if (path)
13670     {
13671       /* Get vertical coords */
13672
13673       if (!_gtk_tree_view_find_node (tree_view, path, &tree, &node) &&
13674           tree == NULL)
13675         return;
13676
13677       rect->y = gtk_tree_view_get_row_y_offset (tree_view, tree, node);
13678       rect->height = gtk_tree_view_get_row_height (tree_view, node);
13679     }
13680
13681   if (column)
13682     {
13683       gint x2 = 0;
13684
13685       gtk_tree_view_get_background_xrange (tree_view, tree, column, &rect->x, &x2);
13686       rect->width = x2 - rect->x;
13687     }
13688 }
13689
13690 /**
13691  * gtk_tree_view_get_visible_rect:
13692  * @tree_view: a #GtkTreeView
13693  * @visible_rect: (out): rectangle to fill
13694  *
13695  * Fills @visible_rect with the currently-visible region of the
13696  * buffer, in tree coordinates. Convert to bin_window coordinates with
13697  * gtk_tree_view_convert_tree_to_bin_window_coords().
13698  * Tree coordinates start at 0,0 for row 0 of the tree, and cover the entire
13699  * scrollable area of the tree.
13700  **/
13701 void
13702 gtk_tree_view_get_visible_rect (GtkTreeView  *tree_view,
13703                                 GdkRectangle *visible_rect)
13704 {
13705   GtkAllocation allocation;
13706   GtkWidget *widget;
13707
13708   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13709
13710   widget = GTK_WIDGET (tree_view);
13711
13712   if (visible_rect)
13713     {
13714       gtk_widget_get_allocation (widget, &allocation);
13715       visible_rect->x = gtk_adjustment_get_value (tree_view->priv->hadjustment);
13716       visible_rect->y = gtk_adjustment_get_value (tree_view->priv->vadjustment);
13717       visible_rect->width = allocation.width;
13718       visible_rect->height = allocation.height - gtk_tree_view_get_effective_header_height (tree_view);
13719     }
13720 }
13721
13722 /**
13723  * gtk_tree_view_convert_widget_to_tree_coords:
13724  * @tree_view: a #GtkTreeView
13725  * @wx: X coordinate relative to the widget
13726  * @wy: Y coordinate relative to the widget
13727  * @tx: (out): return location for tree X coordinate
13728  * @ty: (out): return location for tree Y coordinate
13729  *
13730  * Converts widget coordinates to coordinates for the
13731  * tree (the full scrollable area of the tree).
13732  *
13733  * Since: 2.12
13734  **/
13735 void
13736 gtk_tree_view_convert_widget_to_tree_coords (GtkTreeView *tree_view,
13737                                              gint         wx,
13738                                              gint         wy,
13739                                              gint        *tx,
13740                                              gint        *ty)
13741 {
13742   gint x, y;
13743
13744   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13745
13746   gtk_tree_view_convert_widget_to_bin_window_coords (tree_view,
13747                                                      wx, wy,
13748                                                      &x, &y);
13749   gtk_tree_view_convert_bin_window_to_tree_coords (tree_view,
13750                                                    x, y,
13751                                                    tx, ty);
13752 }
13753
13754 /**
13755  * gtk_tree_view_convert_tree_to_widget_coords:
13756  * @tree_view: a #GtkTreeView
13757  * @tx: X coordinate relative to the tree
13758  * @ty: Y coordinate relative to the tree
13759  * @wx: (out): return location for widget X coordinate
13760  * @wy: (out): return location for widget Y coordinate
13761  *
13762  * Converts tree coordinates (coordinates in full scrollable area of the tree)
13763  * to widget coordinates.
13764  *
13765  * Since: 2.12
13766  **/
13767 void
13768 gtk_tree_view_convert_tree_to_widget_coords (GtkTreeView *tree_view,
13769                                              gint         tx,
13770                                              gint         ty,
13771                                              gint        *wx,
13772                                              gint        *wy)
13773 {
13774   gint x, y;
13775
13776   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13777
13778   gtk_tree_view_convert_tree_to_bin_window_coords (tree_view,
13779                                                    tx, ty,
13780                                                    &x, &y);
13781   gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
13782                                                      x, y,
13783                                                      wx, wy);
13784 }
13785
13786 /**
13787  * gtk_tree_view_convert_widget_to_bin_window_coords:
13788  * @tree_view: a #GtkTreeView
13789  * @wx: X coordinate relative to the widget
13790  * @wy: Y coordinate relative to the widget
13791  * @bx: (out): return location for bin_window X coordinate
13792  * @by: (out): return location for bin_window Y coordinate
13793  *
13794  * Converts widget coordinates to coordinates for the bin_window
13795  * (see gtk_tree_view_get_bin_window()).
13796  *
13797  * Since: 2.12
13798  **/
13799 void
13800 gtk_tree_view_convert_widget_to_bin_window_coords (GtkTreeView *tree_view,
13801                                                    gint         wx,
13802                                                    gint         wy,
13803                                                    gint        *bx,
13804                                                    gint        *by)
13805 {
13806   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13807
13808   if (bx)
13809     *bx = wx + gtk_adjustment_get_value (tree_view->priv->hadjustment);
13810   if (by)
13811     *by = wy - gtk_tree_view_get_effective_header_height (tree_view);
13812 }
13813
13814 /**
13815  * gtk_tree_view_convert_bin_window_to_widget_coords:
13816  * @tree_view: a #GtkTreeView
13817  * @bx: bin_window X coordinate
13818  * @by: bin_window Y coordinate
13819  * @wx: (out): return location for widget X coordinate
13820  * @wy: (out): return location for widget Y coordinate
13821  *
13822  * Converts bin_window coordinates (see gtk_tree_view_get_bin_window())
13823  * to widget relative coordinates.
13824  *
13825  * Since: 2.12
13826  **/
13827 void
13828 gtk_tree_view_convert_bin_window_to_widget_coords (GtkTreeView *tree_view,
13829                                                    gint         bx,
13830                                                    gint         by,
13831                                                    gint        *wx,
13832                                                    gint        *wy)
13833 {
13834   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13835
13836   if (wx)
13837     *wx = bx - gtk_adjustment_get_value (tree_view->priv->hadjustment);
13838   if (wy)
13839     *wy = by + gtk_tree_view_get_effective_header_height (tree_view);
13840 }
13841
13842 /**
13843  * gtk_tree_view_convert_tree_to_bin_window_coords:
13844  * @tree_view: a #GtkTreeView
13845  * @tx: tree X coordinate
13846  * @ty: tree Y coordinate
13847  * @bx: (out): return location for X coordinate relative to bin_window
13848  * @by: (out): return location for Y coordinate relative to bin_window
13849  *
13850  * Converts tree coordinates (coordinates in full scrollable area of the tree)
13851  * to bin_window coordinates.
13852  *
13853  * Since: 2.12
13854  **/
13855 void
13856 gtk_tree_view_convert_tree_to_bin_window_coords (GtkTreeView *tree_view,
13857                                                  gint         tx,
13858                                                  gint         ty,
13859                                                  gint        *bx,
13860                                                  gint        *by)
13861 {
13862   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13863
13864   if (bx)
13865     *bx = tx;
13866   if (by)
13867     *by = ty - tree_view->priv->dy;
13868 }
13869
13870 /**
13871  * gtk_tree_view_convert_bin_window_to_tree_coords:
13872  * @tree_view: a #GtkTreeView
13873  * @bx: X coordinate relative to bin_window
13874  * @by: Y coordinate relative to bin_window
13875  * @tx: (out): return location for tree X coordinate
13876  * @ty: (out): return location for tree Y coordinate
13877  *
13878  * Converts bin_window coordinates to coordinates for the
13879  * tree (the full scrollable area of the tree).
13880  *
13881  * Since: 2.12
13882  **/
13883 void
13884 gtk_tree_view_convert_bin_window_to_tree_coords (GtkTreeView *tree_view,
13885                                                  gint         bx,
13886                                                  gint         by,
13887                                                  gint        *tx,
13888                                                  gint        *ty)
13889 {
13890   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
13891
13892   if (tx)
13893     *tx = bx;
13894   if (ty)
13895     *ty = by + tree_view->priv->dy;
13896 }
13897
13898
13899
13900 /**
13901  * gtk_tree_view_get_visible_range:
13902  * @tree_view: A #GtkTreeView
13903  * @start_path: (out) (allow-none): Return location for start of region,
13904  *              or %NULL.
13905  * @end_path: (out) (allow-none): Return location for end of region, or %NULL.
13906  *
13907  * Sets @start_path and @end_path to be the first and last visible path.
13908  * Note that there may be invisible paths in between.
13909  *
13910  * The paths should be freed with gtk_tree_path_free() after use.
13911  *
13912  * Returns: %TRUE, if valid paths were placed in @start_path and @end_path.
13913  *
13914  * Since: 2.8
13915  **/
13916 gboolean
13917 gtk_tree_view_get_visible_range (GtkTreeView  *tree_view,
13918                                  GtkTreePath **start_path,
13919                                  GtkTreePath **end_path)
13920 {
13921   GtkRBTree *tree;
13922   GtkRBNode *node;
13923   gboolean retval;
13924   
13925   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
13926
13927   if (!tree_view->priv->tree)
13928     return FALSE;
13929
13930   retval = TRUE;
13931
13932   if (start_path)
13933     {
13934       _gtk_rbtree_find_offset (tree_view->priv->tree,
13935                                TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, 0),
13936                                &tree, &node);
13937       if (node)
13938         *start_path = _gtk_tree_view_find_path (tree_view, tree, node);
13939       else
13940         retval = FALSE;
13941     }
13942
13943   if (end_path)
13944     {
13945       gint y;
13946
13947       if (tree_view->priv->height < gtk_adjustment_get_page_size (tree_view->priv->vadjustment))
13948         y = tree_view->priv->height - 1;
13949       else
13950         y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, gtk_adjustment_get_page_size (tree_view->priv->vadjustment)) - 1;
13951
13952       _gtk_rbtree_find_offset (tree_view->priv->tree, y, &tree, &node);
13953       if (node)
13954         *end_path = _gtk_tree_view_find_path (tree_view, tree, node);
13955       else
13956         retval = FALSE;
13957     }
13958
13959   return retval;
13960 }
13961
13962 /**
13963  * gtk_tree_view_is_blank_at_pos:
13964  * @tree_view: A #GtkTreeView
13965  * @x: The x position to be identified (relative to bin_window)
13966  * @y: The y position to be identified (relative to bin_window)
13967  * @path: (out) (allow-none): A pointer to a #GtkTreePath pointer to be filled in, or %NULL
13968  * @column: (out) (allow-none): A pointer to a #GtkTreeViewColumn pointer to be filled in, or %NULL
13969  * @cell_x: (out) (allow-none): A pointer where the X coordinate relative to the cell can be placed, or %NULL
13970  * @cell_y: (out) (allow-none): A pointer where the Y coordinate relative to the cell can be placed, or %NULL
13971  *
13972  * Determine whether the point (@x, @y) in @tree_view is blank, that is no
13973  * cell content nor an expander arrow is drawn at the location. If so, the
13974  * location can be considered as the background. You might wish to take
13975  * special action on clicks on the background, such as clearing a current
13976  * selection, having a custom context menu or starting rubber banding.
13977  *
13978  * The @x and @y coordinate that are provided must be relative to bin_window
13979  * coordinates.  That is, @x and @y must come from an event on @tree_view
13980  * where <literal>event->window == gtk_tree_view_get_bin_window (<!-- -->)</literal>.
13981  *
13982  * For converting widget coordinates (eg. the ones you get from
13983  * GtkWidget::query-tooltip), please see
13984  * gtk_tree_view_convert_widget_to_bin_window_coords().
13985  *
13986  * The @path, @column, @cell_x and @cell_y arguments will be filled in
13987  * likewise as for gtk_tree_view_get_path_at_pos().  Please see
13988  * gtk_tree_view_get_path_at_pos() for more information.
13989  *
13990  * Return value: %TRUE if the area at the given coordinates is blank,
13991  * %FALSE otherwise.
13992  *
13993  * Since: 3.0
13994  */
13995 gboolean
13996 gtk_tree_view_is_blank_at_pos (GtkTreeView       *tree_view,
13997                                gint                x,
13998                                gint                y,
13999                                GtkTreePath       **path,
14000                                GtkTreeViewColumn **column,
14001                                gint               *cell_x,
14002                                gint               *cell_y)
14003 {
14004   GtkRBTree *tree;
14005   GtkRBNode *node;
14006   GtkTreeIter iter;
14007   GtkTreePath *real_path;
14008   GtkTreeViewColumn *real_column;
14009   GdkRectangle cell_area, background_area;
14010
14011   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
14012
14013   if (!gtk_tree_view_get_path_at_pos (tree_view, x, y,
14014                                       &real_path, &real_column,
14015                                       cell_x, cell_y))
14016     /* If there's no path here, it is blank */
14017     return TRUE;
14018
14019   if (path)
14020     *path = real_path;
14021
14022   if (column)
14023     *column = real_column;
14024
14025   gtk_tree_model_get_iter (tree_view->priv->model, &iter, real_path);
14026   _gtk_tree_view_find_node (tree_view, real_path, &tree, &node);
14027
14028   /* Check if there's an expander arrow at (x, y) */
14029   if (real_column == tree_view->priv->expander_column
14030       && gtk_tree_view_draw_expanders (tree_view))
14031     {
14032       gboolean over_arrow;
14033
14034       over_arrow = coords_are_over_arrow (tree_view, tree, node, x, y);
14035
14036       if (over_arrow)
14037         {
14038           if (!path)
14039             gtk_tree_path_free (real_path);
14040           return FALSE;
14041         }
14042     }
14043
14044   /* Otherwise, have the column see if there's a cell at (x, y) */
14045   gtk_tree_view_column_cell_set_cell_data (real_column,
14046                                            tree_view->priv->model,
14047                                            &iter,
14048                                            GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
14049                                            node->children ? TRUE : FALSE);
14050
14051   gtk_tree_view_get_background_area (tree_view, real_path, real_column,
14052                                      &background_area);
14053   gtk_tree_view_get_cell_area (tree_view, real_path, real_column,
14054                                &cell_area);
14055
14056   if (!path)
14057     gtk_tree_path_free (real_path);
14058
14059   return _gtk_tree_view_column_is_blank_at_pos (real_column,
14060                                                 &cell_area,
14061                                                 &background_area,
14062                                                 x, y);
14063 }
14064
14065 static void
14066 unset_reorderable (GtkTreeView *tree_view)
14067 {
14068   if (tree_view->priv->reorderable)
14069     {
14070       tree_view->priv->reorderable = FALSE;
14071       g_object_notify (G_OBJECT (tree_view), "reorderable");
14072     }
14073 }
14074
14075 /**
14076  * gtk_tree_view_enable_model_drag_source:
14077  * @tree_view: a #GtkTreeView
14078  * @start_button_mask: Mask of allowed buttons to start drag
14079  * @targets: (array length=n_targets): the table of targets that the drag will support
14080  * @n_targets: the number of items in @targets
14081  * @actions: the bitmask of possible actions for a drag from this
14082  *    widget
14083  *
14084  * Turns @tree_view into a drag source for automatic DND. Calling this
14085  * method sets #GtkTreeView:reorderable to %FALSE.
14086  **/
14087 void
14088 gtk_tree_view_enable_model_drag_source (GtkTreeView              *tree_view,
14089                                         GdkModifierType           start_button_mask,
14090                                         const GtkTargetEntry     *targets,
14091                                         gint                      n_targets,
14092                                         GdkDragAction             actions)
14093 {
14094   TreeViewDragInfo *di;
14095
14096   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14097
14098   gtk_drag_source_set (GTK_WIDGET (tree_view),
14099                        0,
14100                        targets,
14101                        n_targets,
14102                        actions);
14103
14104   di = ensure_info (tree_view);
14105
14106   di->start_button_mask = start_button_mask;
14107   di->source_actions = actions;
14108   di->source_set = TRUE;
14109
14110   unset_reorderable (tree_view);
14111 }
14112
14113 /**
14114  * gtk_tree_view_enable_model_drag_dest:
14115  * @tree_view: a #GtkTreeView
14116  * @targets: (array length=n_targets): the table of targets that
14117  *           the drag will support
14118  * @n_targets: the number of items in @targets
14119  * @actions: the bitmask of possible actions for a drag from this
14120  *    widget
14121  * 
14122  * Turns @tree_view into a drop destination for automatic DND. Calling
14123  * this method sets #GtkTreeView:reorderable to %FALSE.
14124  **/
14125 void
14126 gtk_tree_view_enable_model_drag_dest (GtkTreeView              *tree_view,
14127                                       const GtkTargetEntry     *targets,
14128                                       gint                      n_targets,
14129                                       GdkDragAction             actions)
14130 {
14131   TreeViewDragInfo *di;
14132
14133   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14134
14135   gtk_drag_dest_set (GTK_WIDGET (tree_view),
14136                      0,
14137                      targets,
14138                      n_targets,
14139                      actions);
14140
14141   di = ensure_info (tree_view);
14142   di->dest_set = TRUE;
14143
14144   unset_reorderable (tree_view);
14145 }
14146
14147 /**
14148  * gtk_tree_view_unset_rows_drag_source:
14149  * @tree_view: a #GtkTreeView
14150  *
14151  * Undoes the effect of
14152  * gtk_tree_view_enable_model_drag_source(). Calling this method sets
14153  * #GtkTreeView:reorderable to %FALSE.
14154  **/
14155 void
14156 gtk_tree_view_unset_rows_drag_source (GtkTreeView *tree_view)
14157 {
14158   TreeViewDragInfo *di;
14159
14160   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14161
14162   di = get_info (tree_view);
14163
14164   if (di)
14165     {
14166       if (di->source_set)
14167         {
14168           gtk_drag_source_unset (GTK_WIDGET (tree_view));
14169           di->source_set = FALSE;
14170         }
14171
14172       if (!di->dest_set && !di->source_set)
14173         remove_info (tree_view);
14174     }
14175   
14176   unset_reorderable (tree_view);
14177 }
14178
14179 /**
14180  * gtk_tree_view_unset_rows_drag_dest:
14181  * @tree_view: a #GtkTreeView
14182  *
14183  * Undoes the effect of
14184  * gtk_tree_view_enable_model_drag_dest(). Calling this method sets
14185  * #GtkTreeView:reorderable to %FALSE.
14186  **/
14187 void
14188 gtk_tree_view_unset_rows_drag_dest (GtkTreeView *tree_view)
14189 {
14190   TreeViewDragInfo *di;
14191
14192   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14193
14194   di = get_info (tree_view);
14195
14196   if (di)
14197     {
14198       if (di->dest_set)
14199         {
14200           gtk_drag_dest_unset (GTK_WIDGET (tree_view));
14201           di->dest_set = FALSE;
14202         }
14203
14204       if (!di->dest_set && !di->source_set)
14205         remove_info (tree_view);
14206     }
14207
14208   unset_reorderable (tree_view);
14209 }
14210
14211 /**
14212  * gtk_tree_view_set_drag_dest_row:
14213  * @tree_view: a #GtkTreeView
14214  * @path: (allow-none): The path of the row to highlight, or %NULL
14215  * @pos: Specifies whether to drop before, after or into the row
14216  *
14217  * Sets the row that is highlighted for feedback.
14218  * If @path is %NULL, an existing highlight is removed.
14219  */
14220 void
14221 gtk_tree_view_set_drag_dest_row (GtkTreeView            *tree_view,
14222                                  GtkTreePath            *path,
14223                                  GtkTreeViewDropPosition pos)
14224 {
14225   GtkTreePath *current_dest;
14226
14227   /* Note; this function is exported to allow a custom DND
14228    * implementation, so it can't touch TreeViewDragInfo
14229    */
14230
14231   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14232
14233   current_dest = NULL;
14234
14235   if (tree_view->priv->drag_dest_row)
14236     {
14237       current_dest = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
14238       gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
14239     }
14240
14241   /* special case a drop on an empty model */
14242   tree_view->priv->empty_view_drop = 0;
14243
14244   if (pos == GTK_TREE_VIEW_DROP_BEFORE && path
14245       && gtk_tree_path_get_depth (path) == 1
14246       && gtk_tree_path_get_indices (path)[0] == 0)
14247     {
14248       gint n_children;
14249
14250       n_children = gtk_tree_model_iter_n_children (tree_view->priv->model,
14251                                                    NULL);
14252
14253       if (!n_children)
14254         tree_view->priv->empty_view_drop = 1;
14255     }
14256
14257   tree_view->priv->drag_dest_pos = pos;
14258
14259   if (path)
14260     {
14261       tree_view->priv->drag_dest_row =
14262         gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
14263       gtk_tree_view_queue_draw_path (tree_view, path, NULL);
14264     }
14265   else
14266     tree_view->priv->drag_dest_row = NULL;
14267
14268   if (current_dest)
14269     {
14270       GtkRBTree *tree, *new_tree;
14271       GtkRBNode *node, *new_node;
14272
14273       _gtk_tree_view_find_node (tree_view, current_dest, &tree, &node);
14274       _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
14275
14276       if (tree && node)
14277         {
14278           _gtk_rbtree_next_full (tree, node, &new_tree, &new_node);
14279           if (new_tree && new_node)
14280             _gtk_tree_view_queue_draw_node (tree_view, new_tree, new_node, NULL);
14281
14282           _gtk_rbtree_prev_full (tree, node, &new_tree, &new_node);
14283           if (new_tree && new_node)
14284             _gtk_tree_view_queue_draw_node (tree_view, new_tree, new_node, NULL);
14285         }
14286       gtk_tree_path_free (current_dest);
14287     }
14288 }
14289
14290 /**
14291  * gtk_tree_view_get_drag_dest_row:
14292  * @tree_view: a #GtkTreeView
14293  * @path: (out) (allow-none): Return location for the path of the highlighted row, or %NULL.
14294  * @pos: (out) (allow-none): Return location for the drop position, or %NULL
14295  * 
14296  * Gets information about the row that is highlighted for feedback.
14297  **/
14298 void
14299 gtk_tree_view_get_drag_dest_row (GtkTreeView              *tree_view,
14300                                  GtkTreePath             **path,
14301                                  GtkTreeViewDropPosition  *pos)
14302 {
14303   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14304
14305   if (path)
14306     {
14307       if (tree_view->priv->drag_dest_row)
14308         *path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
14309       else
14310         {
14311           if (tree_view->priv->empty_view_drop)
14312             *path = gtk_tree_path_new_from_indices (0, -1);
14313           else
14314             *path = NULL;
14315         }
14316     }
14317
14318   if (pos)
14319     *pos = tree_view->priv->drag_dest_pos;
14320 }
14321
14322 /**
14323  * gtk_tree_view_get_dest_row_at_pos:
14324  * @tree_view: a #GtkTreeView
14325  * @drag_x: the position to determine the destination row for
14326  * @drag_y: the position to determine the destination row for
14327  * @path: (out) (allow-none): Return location for the path of the highlighted row, or %NULL.
14328  * @pos: (out) (allow-none): Return location for the drop position, or %NULL
14329  * 
14330  * Determines the destination row for a given position.  @drag_x and
14331  * @drag_y are expected to be in widget coordinates.  This function is only
14332  * meaningful if @tree_view is realized.  Therefore this function will always
14333  * return %FALSE if @tree_view is not realized or does not have a model.
14334  * 
14335  * Return value: whether there is a row at the given position, %TRUE if this
14336  * is indeed the case.
14337  **/
14338 gboolean
14339 gtk_tree_view_get_dest_row_at_pos (GtkTreeView             *tree_view,
14340                                    gint                     drag_x,
14341                                    gint                     drag_y,
14342                                    GtkTreePath            **path,
14343                                    GtkTreeViewDropPosition *pos)
14344 {
14345   gint cell_y;
14346   gint bin_x, bin_y;
14347   gdouble offset_into_row;
14348   gdouble third;
14349   GdkRectangle cell;
14350   GtkTreeViewColumn *column = NULL;
14351   GtkTreePath *tmp_path = NULL;
14352
14353   /* Note; this function is exported to allow a custom DND
14354    * implementation, so it can't touch TreeViewDragInfo
14355    */
14356
14357   g_return_val_if_fail (tree_view != NULL, FALSE);
14358   g_return_val_if_fail (drag_x >= 0, FALSE);
14359   g_return_val_if_fail (drag_y >= 0, FALSE);
14360
14361   if (path)
14362     *path = NULL;
14363
14364   if (tree_view->priv->bin_window == NULL)
14365     return FALSE;
14366
14367   if (tree_view->priv->tree == NULL)
14368     return FALSE;
14369
14370   /* If in the top third of a row, we drop before that row; if
14371    * in the bottom third, drop after that row; if in the middle,
14372    * and the row has children, drop into the row.
14373    */
14374   gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, drag_x, drag_y,
14375                                                      &bin_x, &bin_y);
14376
14377   if (!gtk_tree_view_get_path_at_pos (tree_view,
14378                                       bin_x,
14379                                       bin_y,
14380                                       &tmp_path,
14381                                       &column,
14382                                       NULL,
14383                                       &cell_y))
14384     return FALSE;
14385
14386   gtk_tree_view_get_background_area (tree_view, tmp_path, column,
14387                                      &cell);
14388
14389   offset_into_row = cell_y;
14390
14391   if (path)
14392     *path = tmp_path;
14393   else
14394     gtk_tree_path_free (tmp_path);
14395
14396   tmp_path = NULL;
14397
14398   third = cell.height / 3.0;
14399
14400   if (pos)
14401     {
14402       if (offset_into_row < third)
14403         {
14404           *pos = GTK_TREE_VIEW_DROP_BEFORE;
14405         }
14406       else if (offset_into_row < (cell.height / 2.0))
14407         {
14408           *pos = GTK_TREE_VIEW_DROP_INTO_OR_BEFORE;
14409         }
14410       else if (offset_into_row < third * 2.0)
14411         {
14412           *pos = GTK_TREE_VIEW_DROP_INTO_OR_AFTER;
14413         }
14414       else
14415         {
14416           *pos = GTK_TREE_VIEW_DROP_AFTER;
14417         }
14418     }
14419
14420   return TRUE;
14421 }
14422
14423
14424
14425 /* KEEP IN SYNC WITH GTK_TREE_VIEW_BIN_EXPOSE */
14426 /**
14427  * gtk_tree_view_create_row_drag_icon:
14428  * @tree_view: a #GtkTreeView
14429  * @path: a #GtkTreePath in @tree_view
14430  *
14431  * Creates a #cairo_surface_t representation of the row at @path.  
14432  * This image is used for a drag icon.
14433  *
14434  * Return value: (transfer full): a newly-allocated surface of the drag icon.
14435  **/
14436 cairo_surface_t *
14437 gtk_tree_view_create_row_drag_icon (GtkTreeView  *tree_view,
14438                                     GtkTreePath  *path)
14439 {
14440   GtkTreeIter   iter;
14441   GtkRBTree    *tree;
14442   GtkRBNode    *node;
14443   GtkStyleContext *context;
14444   GtkStateFlags state;
14445   gint cell_offset;
14446   GList *list;
14447   GdkRectangle background_area;
14448   GtkWidget *widget;
14449   gint depth;
14450   /* start drawing inside the black outline */
14451   gint x = 1, y = 1;
14452   cairo_surface_t *surface;
14453   gint bin_window_width;
14454   gboolean is_separator = FALSE;
14455   gboolean rtl, allow_rules;
14456   cairo_t *cr;
14457
14458   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14459   g_return_val_if_fail (path != NULL, NULL);
14460
14461   widget = GTK_WIDGET (tree_view);
14462
14463   if (!gtk_widget_get_realized (widget))
14464     return NULL;
14465
14466   depth = gtk_tree_path_get_depth (path);
14467
14468   _gtk_tree_view_find_node (tree_view,
14469                             path,
14470                             &tree,
14471                             &node);
14472
14473   if (tree == NULL)
14474     return NULL;
14475
14476   if (!gtk_tree_model_get_iter (tree_view->priv->model,
14477                                 &iter,
14478                                 path))
14479     return NULL;
14480
14481   context = gtk_widget_get_style_context (widget);
14482
14483   gtk_style_context_save (context);
14484
14485   state = gtk_widget_get_state_flags (widget);
14486   gtk_style_context_set_state (context, state);
14487
14488   gtk_style_context_add_class (context, GTK_STYLE_CLASS_VIEW);
14489   gtk_style_context_add_region (context, GTK_STYLE_REGION_COLUMN, 0);
14490
14491   gtk_widget_style_get (widget,
14492                         "allow-rules", &allow_rules,
14493                         NULL);
14494
14495   if (allow_rules && tree_view->priv->has_rules)
14496     {
14497       GtkRegionFlags row_flags;
14498
14499       if (_gtk_rbtree_node_find_parity (tree, node))
14500         row_flags = GTK_REGION_ODD;
14501       else
14502         row_flags = GTK_REGION_EVEN;
14503
14504       gtk_style_context_add_region (context, GTK_STYLE_REGION_ROW, row_flags);
14505     }
14506
14507   is_separator = row_is_separator (tree_view, &iter, NULL);
14508
14509   cell_offset = x;
14510
14511   background_area.y = y;
14512   background_area.height = gtk_tree_view_get_row_height (tree_view, node);
14513
14514   bin_window_width = gdk_window_get_width (tree_view->priv->bin_window);
14515
14516   surface = gdk_window_create_similar_surface (tree_view->priv->bin_window,
14517                                                CAIRO_CONTENT_COLOR,
14518                                                bin_window_width + 2,
14519                                                background_area.height + 2);
14520
14521   cr = cairo_create (surface);
14522
14523   gtk_render_background (context, cr, 0, 0,
14524                          bin_window_width + 2,
14525                          background_area.height + 2);
14526
14527   rtl = gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL;
14528
14529   for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
14530       list;
14531       list = (rtl ? list->prev : list->next))
14532     {
14533       GtkTreeViewColumn *column = list->data;
14534       GdkRectangle cell_area;
14535       gint vertical_separator;
14536
14537       if (!gtk_tree_view_column_get_visible (column))
14538         continue;
14539
14540       gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, &iter,
14541                                                GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
14542                                                node->children?TRUE:FALSE);
14543
14544       background_area.x = cell_offset;
14545       background_area.width = gtk_tree_view_column_get_width (column);
14546
14547       gtk_widget_style_get (widget,
14548                             "vertical-separator", &vertical_separator,
14549                             NULL);
14550
14551       cell_area = background_area;
14552
14553       cell_area.y += vertical_separator / 2;
14554       cell_area.height -= vertical_separator;
14555
14556       if (gtk_tree_view_is_expander_column (tree_view, column))
14557         {
14558           if (!rtl)
14559             cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
14560           cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
14561
14562           if (gtk_tree_view_draw_expanders (tree_view))
14563             {
14564               if (!rtl)
14565                 cell_area.x += depth * tree_view->priv->expander_size;
14566               cell_area.width -= depth * tree_view->priv->expander_size;
14567             }
14568         }
14569
14570       if (gtk_tree_view_column_cell_is_visible (column))
14571         {
14572           if (is_separator)
14573             {
14574               gtk_style_context_save (context);
14575               gtk_style_context_add_class (context, GTK_STYLE_CLASS_SEPARATOR);
14576
14577               gtk_render_line (context, cr,
14578                                cell_area.x,
14579                                cell_area.y + cell_area.height / 2,
14580                                cell_area.x + cell_area.width,
14581                                cell_area.y + cell_area.height / 2);
14582
14583               gtk_style_context_restore (context);
14584             }
14585           else
14586             {
14587               _gtk_tree_view_column_cell_render (column,
14588                                                  cr,
14589                                                  &background_area,
14590                                                  &cell_area,
14591                                                  0, FALSE);
14592             }
14593         }
14594       cell_offset += gtk_tree_view_column_get_width (column);
14595     }
14596
14597   cairo_set_source_rgb (cr, 0, 0, 0);
14598   cairo_rectangle (cr, 
14599                    0.5, 0.5, 
14600                    bin_window_width + 1,
14601                    background_area.height + 1);
14602   cairo_set_line_width (cr, 1.0);
14603   cairo_stroke (cr);
14604
14605   cairo_destroy (cr);
14606
14607   cairo_surface_set_device_offset (surface, 2, 2);
14608
14609   gtk_style_context_restore (context);
14610
14611   return surface;
14612 }
14613
14614
14615 /**
14616  * gtk_tree_view_set_destroy_count_func:
14617  * @tree_view: A #GtkTreeView
14618  * @func: (allow-none): Function to be called when a view row is destroyed, or %NULL
14619  * @data: (allow-none): User data to be passed to @func, or %NULL
14620  * @destroy: (allow-none): Destroy notifier for @data, or %NULL
14621  *
14622  * This function should almost never be used.  It is meant for private use by
14623  * ATK for determining the number of visible children that are removed when the
14624  * user collapses a row, or a row is deleted.
14625  **/
14626 void
14627 gtk_tree_view_set_destroy_count_func (GtkTreeView             *tree_view,
14628                                       GtkTreeDestroyCountFunc  func,
14629                                       gpointer                 data,
14630                                       GDestroyNotify           destroy)
14631 {
14632   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14633
14634   if (tree_view->priv->destroy_count_destroy)
14635     tree_view->priv->destroy_count_destroy (tree_view->priv->destroy_count_data);
14636
14637   tree_view->priv->destroy_count_func = func;
14638   tree_view->priv->destroy_count_data = data;
14639   tree_view->priv->destroy_count_destroy = destroy;
14640 }
14641
14642
14643 /*
14644  * Interactive search
14645  */
14646
14647 /**
14648  * gtk_tree_view_set_enable_search:
14649  * @tree_view: A #GtkTreeView
14650  * @enable_search: %TRUE, if the user can search interactively
14651  *
14652  * If @enable_search is set, then the user can type in text to search through
14653  * the tree interactively (this is sometimes called "typeahead find").
14654  * 
14655  * Note that even if this is %FALSE, the user can still initiate a search 
14656  * using the "start-interactive-search" key binding.
14657  */
14658 void
14659 gtk_tree_view_set_enable_search (GtkTreeView *tree_view,
14660                                  gboolean     enable_search)
14661 {
14662   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14663
14664   enable_search = !!enable_search;
14665   
14666   if (tree_view->priv->enable_search != enable_search)
14667     {
14668        tree_view->priv->enable_search = enable_search;
14669        g_object_notify (G_OBJECT (tree_view), "enable-search");
14670     }
14671 }
14672
14673 /**
14674  * gtk_tree_view_get_enable_search:
14675  * @tree_view: A #GtkTreeView
14676  *
14677  * Returns whether or not the tree allows to start interactive searching 
14678  * by typing in text.
14679  *
14680  * Return value: whether or not to let the user search interactively
14681  */
14682 gboolean
14683 gtk_tree_view_get_enable_search (GtkTreeView *tree_view)
14684 {
14685   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
14686
14687   return tree_view->priv->enable_search;
14688 }
14689
14690
14691 /**
14692  * gtk_tree_view_get_search_column:
14693  * @tree_view: A #GtkTreeView
14694  *
14695  * Gets the column searched on by the interactive search code.
14696  *
14697  * Return value: the column the interactive search code searches in.
14698  */
14699 gint
14700 gtk_tree_view_get_search_column (GtkTreeView *tree_view)
14701 {
14702   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
14703
14704   return (tree_view->priv->search_column);
14705 }
14706
14707 /**
14708  * gtk_tree_view_set_search_column:
14709  * @tree_view: A #GtkTreeView
14710  * @column: the column of the model to search in, or -1 to disable searching
14711  *
14712  * Sets @column as the column where the interactive search code should
14713  * search in for the current model. 
14714  * 
14715  * If the search column is set, users can use the "start-interactive-search"
14716  * key binding to bring up search popup. The enable-search property controls
14717  * whether simply typing text will also start an interactive search.
14718  *
14719  * Note that @column refers to a column of the current model. The search 
14720  * column is reset to -1 when the model is changed.
14721  */
14722 void
14723 gtk_tree_view_set_search_column (GtkTreeView *tree_view,
14724                                  gint         column)
14725 {
14726   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14727   g_return_if_fail (column >= -1);
14728
14729   if (tree_view->priv->search_column == column)
14730     return;
14731
14732   tree_view->priv->search_column = column;
14733   g_object_notify (G_OBJECT (tree_view), "search-column");
14734 }
14735
14736 /**
14737  * gtk_tree_view_get_search_equal_func: (skip)
14738  * @tree_view: A #GtkTreeView
14739  *
14740  * Returns the compare function currently in use.
14741  *
14742  * Return value: the currently used compare function for the search code.
14743  */
14744
14745 GtkTreeViewSearchEqualFunc
14746 gtk_tree_view_get_search_equal_func (GtkTreeView *tree_view)
14747 {
14748   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14749
14750   return tree_view->priv->search_equal_func;
14751 }
14752
14753 /**
14754  * gtk_tree_view_set_search_equal_func:
14755  * @tree_view: A #GtkTreeView
14756  * @search_equal_func: the compare function to use during the search
14757  * @search_user_data: (allow-none): user data to pass to @search_equal_func, or %NULL
14758  * @search_destroy: (allow-none): Destroy notifier for @search_user_data, or %NULL
14759  *
14760  * Sets the compare function for the interactive search capabilities; note
14761  * that somewhat like strcmp() returning 0 for equality
14762  * #GtkTreeViewSearchEqualFunc returns %FALSE on matches.
14763  **/
14764 void
14765 gtk_tree_view_set_search_equal_func (GtkTreeView                *tree_view,
14766                                      GtkTreeViewSearchEqualFunc  search_equal_func,
14767                                      gpointer                    search_user_data,
14768                                      GDestroyNotify              search_destroy)
14769 {
14770   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14771   g_return_if_fail (search_equal_func != NULL);
14772
14773   if (tree_view->priv->search_destroy)
14774     tree_view->priv->search_destroy (tree_view->priv->search_user_data);
14775
14776   tree_view->priv->search_equal_func = search_equal_func;
14777   tree_view->priv->search_user_data = search_user_data;
14778   tree_view->priv->search_destroy = search_destroy;
14779   if (tree_view->priv->search_equal_func == NULL)
14780     tree_view->priv->search_equal_func = gtk_tree_view_search_equal_func;
14781 }
14782
14783 /**
14784  * gtk_tree_view_get_search_entry:
14785  * @tree_view: A #GtkTreeView
14786  *
14787  * Returns the #GtkEntry which is currently in use as interactive search
14788  * entry for @tree_view.  In case the built-in entry is being used, %NULL
14789  * will be returned.
14790  *
14791  * Return value: (transfer none): the entry currently in use as search entry.
14792  *
14793  * Since: 2.10
14794  */
14795 GtkEntry *
14796 gtk_tree_view_get_search_entry (GtkTreeView *tree_view)
14797 {
14798   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14799
14800   if (tree_view->priv->search_custom_entry_set)
14801     return GTK_ENTRY (tree_view->priv->search_entry);
14802
14803   return NULL;
14804 }
14805
14806 /**
14807  * gtk_tree_view_set_search_entry:
14808  * @tree_view: A #GtkTreeView
14809  * @entry: (allow-none): the entry the interactive search code of @tree_view should use or %NULL
14810  *
14811  * Sets the entry which the interactive search code will use for this
14812  * @tree_view.  This is useful when you want to provide a search entry
14813  * in our interface at all time at a fixed position.  Passing %NULL for
14814  * @entry will make the interactive search code use the built-in popup
14815  * entry again.
14816  *
14817  * Since: 2.10
14818  */
14819 void
14820 gtk_tree_view_set_search_entry (GtkTreeView *tree_view,
14821                                 GtkEntry    *entry)
14822 {
14823   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14824   g_return_if_fail (entry == NULL || GTK_IS_ENTRY (entry));
14825
14826   if (tree_view->priv->search_custom_entry_set)
14827     {
14828       if (tree_view->priv->search_entry_changed_id)
14829         {
14830           g_signal_handler_disconnect (tree_view->priv->search_entry,
14831                                        tree_view->priv->search_entry_changed_id);
14832           tree_view->priv->search_entry_changed_id = 0;
14833         }
14834       g_signal_handlers_disconnect_by_func (tree_view->priv->search_entry,
14835                                             G_CALLBACK (gtk_tree_view_search_key_press_event),
14836                                             tree_view);
14837
14838       g_object_unref (tree_view->priv->search_entry);
14839     }
14840   else if (tree_view->priv->search_window)
14841     {
14842       gtk_widget_destroy (tree_view->priv->search_window);
14843
14844       tree_view->priv->search_window = NULL;
14845     }
14846
14847   if (entry)
14848     {
14849       tree_view->priv->search_entry = g_object_ref (entry);
14850       tree_view->priv->search_custom_entry_set = TRUE;
14851
14852       if (tree_view->priv->search_entry_changed_id == 0)
14853         {
14854           tree_view->priv->search_entry_changed_id =
14855             g_signal_connect (tree_view->priv->search_entry, "changed",
14856                               G_CALLBACK (gtk_tree_view_search_init),
14857                               tree_view);
14858         }
14859       
14860         g_signal_connect (tree_view->priv->search_entry, "key-press-event",
14861                           G_CALLBACK (gtk_tree_view_search_key_press_event),
14862                           tree_view);
14863
14864         gtk_tree_view_search_init (tree_view->priv->search_entry, tree_view);
14865     }
14866   else
14867     {
14868       tree_view->priv->search_entry = NULL;
14869       tree_view->priv->search_custom_entry_set = FALSE;
14870     }
14871 }
14872
14873 /**
14874  * gtk_tree_view_set_search_position_func:
14875  * @tree_view: A #GtkTreeView
14876  * @func: (allow-none): the function to use to position the search dialog, or %NULL
14877  *    to use the default search position function
14878  * @data: (allow-none): user data to pass to @func, or %NULL
14879  * @destroy: (allow-none): Destroy notifier for @data, or %NULL
14880  *
14881  * Sets the function to use when positioning the search dialog.
14882  *
14883  * Since: 2.10
14884  **/
14885 void
14886 gtk_tree_view_set_search_position_func (GtkTreeView                   *tree_view,
14887                                         GtkTreeViewSearchPositionFunc  func,
14888                                         gpointer                       user_data,
14889                                         GDestroyNotify                 destroy)
14890 {
14891   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
14892
14893   if (tree_view->priv->search_position_destroy)
14894     tree_view->priv->search_position_destroy (tree_view->priv->search_position_user_data);
14895
14896   tree_view->priv->search_position_func = func;
14897   tree_view->priv->search_position_user_data = user_data;
14898   tree_view->priv->search_position_destroy = destroy;
14899   if (tree_view->priv->search_position_func == NULL)
14900     tree_view->priv->search_position_func = gtk_tree_view_search_position_func;
14901 }
14902
14903 /**
14904  * gtk_tree_view_get_search_position_func: (skip)
14905  * @tree_view: A #GtkTreeView
14906  *
14907  * Returns the positioning function currently in use.
14908  *
14909  * Return value: the currently used function for positioning the search dialog.
14910  *
14911  * Since: 2.10
14912  */
14913 GtkTreeViewSearchPositionFunc
14914 gtk_tree_view_get_search_position_func (GtkTreeView *tree_view)
14915 {
14916   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
14917
14918   return tree_view->priv->search_position_func;
14919 }
14920
14921
14922 static void
14923 gtk_tree_view_search_dialog_hide (GtkWidget   *search_dialog,
14924                                   GtkTreeView *tree_view,
14925                                   GdkDevice   *device)
14926 {
14927   if (tree_view->priv->disable_popdown)
14928     return;
14929
14930   if (tree_view->priv->search_entry_changed_id)
14931     {
14932       g_signal_handler_disconnect (tree_view->priv->search_entry,
14933                                    tree_view->priv->search_entry_changed_id);
14934       tree_view->priv->search_entry_changed_id = 0;
14935     }
14936   if (tree_view->priv->typeselect_flush_timeout)
14937     {
14938       g_source_remove (tree_view->priv->typeselect_flush_timeout);
14939       tree_view->priv->typeselect_flush_timeout = 0;
14940     }
14941         
14942   if (gtk_widget_get_visible (search_dialog))
14943     {
14944       /* send focus-in event */
14945       send_focus_change (GTK_WIDGET (tree_view->priv->search_entry), device, FALSE);
14946       gtk_widget_hide (search_dialog);
14947       gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
14948       send_focus_change (GTK_WIDGET (tree_view), device, TRUE);
14949     }
14950 }
14951
14952 static void
14953 gtk_tree_view_search_position_func (GtkTreeView *tree_view,
14954                                     GtkWidget   *search_dialog,
14955                                     gpointer     user_data)
14956 {
14957   gint x, y;
14958   gint tree_x, tree_y;
14959   gint tree_width, tree_height;
14960   GdkWindow *tree_window = gtk_widget_get_window (GTK_WIDGET (tree_view));
14961   GdkScreen *screen = gdk_window_get_screen (tree_window);
14962   GtkRequisition requisition;
14963   gint monitor_num;
14964   GdkRectangle monitor;
14965
14966   monitor_num = gdk_screen_get_monitor_at_window (screen, tree_window);
14967   gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
14968
14969   gtk_widget_realize (search_dialog);
14970
14971   gdk_window_get_origin (tree_window, &tree_x, &tree_y);
14972   tree_width = gdk_window_get_width (tree_window);
14973   tree_height = gdk_window_get_height (tree_window);
14974   gtk_widget_get_preferred_size (search_dialog, &requisition, NULL);
14975
14976   if (tree_x + tree_width > gdk_screen_get_width (screen))
14977     x = gdk_screen_get_width (screen) - requisition.width;
14978   else if (tree_x + tree_width - requisition.width < 0)
14979     x = 0;
14980   else
14981     x = tree_x + tree_width - requisition.width;
14982
14983   if (tree_y + tree_height + requisition.height > gdk_screen_get_height (screen))
14984     y = gdk_screen_get_height (screen) - requisition.height;
14985   else if (tree_y + tree_height < 0) /* isn't really possible ... */
14986     y = 0;
14987   else
14988     y = tree_y + tree_height;
14989
14990   gtk_window_move (GTK_WINDOW (search_dialog), x, y);
14991 }
14992
14993 static void
14994 gtk_tree_view_search_disable_popdown (GtkEntry *entry,
14995                                       GtkMenu  *menu,
14996                                       gpointer  data)
14997 {
14998   GtkTreeView *tree_view = (GtkTreeView *)data;
14999
15000   tree_view->priv->disable_popdown = 1;
15001   g_signal_connect (menu, "hide",
15002                     G_CALLBACK (gtk_tree_view_search_enable_popdown), data);
15003 }
15004
15005 /* Because we're visible but offscreen, we just set a flag in the preedit
15006  * callback.
15007  */
15008 static void
15009 gtk_tree_view_search_preedit_changed (GtkIMContext *im_context,
15010                                       GtkTreeView  *tree_view)
15011 {
15012   tree_view->priv->imcontext_changed = 1;
15013   if (tree_view->priv->typeselect_flush_timeout)
15014     {
15015       g_source_remove (tree_view->priv->typeselect_flush_timeout);
15016       tree_view->priv->typeselect_flush_timeout =
15017         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
15018                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
15019                        tree_view);
15020     }
15021
15022 }
15023
15024 static void
15025 gtk_tree_view_search_activate (GtkEntry    *entry,
15026                                GtkTreeView *tree_view)
15027 {
15028   GtkTreePath *path;
15029   GtkRBNode *node;
15030   GtkRBTree *tree;
15031
15032   gtk_tree_view_search_dialog_hide (tree_view->priv->search_window,
15033                                     tree_view,
15034                                     gtk_get_current_event_device ());
15035
15036   /* If we have a row selected and it's the cursor row, we activate
15037    * the row XXX */
15038   if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
15039     {
15040       path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
15041       
15042       _gtk_tree_view_find_node (tree_view, path, &tree, &node);
15043       
15044       if (node && GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
15045         gtk_tree_view_row_activated (tree_view, path, tree_view->priv->focus_column);
15046       
15047       gtk_tree_path_free (path);
15048     }
15049 }
15050
15051 static gboolean
15052 gtk_tree_view_real_search_enable_popdown (gpointer data)
15053 {
15054   GtkTreeView *tree_view = (GtkTreeView *)data;
15055
15056   tree_view->priv->disable_popdown = 0;
15057
15058   return FALSE;
15059 }
15060
15061 static void
15062 gtk_tree_view_search_enable_popdown (GtkWidget *widget,
15063                                      gpointer   data)
15064 {
15065   gdk_threads_add_timeout_full (G_PRIORITY_HIGH, 200, gtk_tree_view_real_search_enable_popdown, g_object_ref (data), g_object_unref);
15066 }
15067
15068 static gboolean
15069 gtk_tree_view_search_delete_event (GtkWidget *widget,
15070                                    GdkEventAny *event,
15071                                    GtkTreeView *tree_view)
15072 {
15073   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
15074
15075   gtk_tree_view_search_dialog_hide (widget, tree_view, NULL);
15076
15077   return TRUE;
15078 }
15079
15080 static gboolean
15081 gtk_tree_view_search_button_press_event (GtkWidget *widget,
15082                                          GdkEventButton *event,
15083                                          GtkTreeView *tree_view)
15084 {
15085   GdkDevice *keyb_device;
15086
15087   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
15088
15089   keyb_device = gdk_device_get_associated_device (event->device);
15090   gtk_tree_view_search_dialog_hide (widget, tree_view, keyb_device);
15091
15092   if (event->window == tree_view->priv->bin_window)
15093     gtk_tree_view_button_press (GTK_WIDGET (tree_view), event);
15094
15095   return TRUE;
15096 }
15097
15098 static gboolean
15099 gtk_tree_view_search_scroll_event (GtkWidget *widget,
15100                                    GdkEventScroll *event,
15101                                    GtkTreeView *tree_view)
15102 {
15103   gboolean retval = FALSE;
15104
15105   if (event->direction == GDK_SCROLL_UP)
15106     {
15107       gtk_tree_view_search_move (widget, tree_view, TRUE);
15108       retval = TRUE;
15109     }
15110   else if (event->direction == GDK_SCROLL_DOWN)
15111     {
15112       gtk_tree_view_search_move (widget, tree_view, FALSE);
15113       retval = TRUE;
15114     }
15115
15116   /* renew the flush timeout */
15117   if (retval && tree_view->priv->typeselect_flush_timeout
15118       && !tree_view->priv->search_custom_entry_set)
15119     {
15120       g_source_remove (tree_view->priv->typeselect_flush_timeout);
15121       tree_view->priv->typeselect_flush_timeout =
15122         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
15123                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
15124                        tree_view);
15125     }
15126
15127   return retval;
15128 }
15129
15130 static gboolean
15131 gtk_tree_view_search_key_press_event (GtkWidget *widget,
15132                                       GdkEventKey *event,
15133                                       GtkTreeView *tree_view)
15134 {
15135   gboolean retval = FALSE;
15136
15137   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
15138   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15139
15140   /* close window and cancel the search */
15141   if (!tree_view->priv->search_custom_entry_set
15142       && (event->keyval == GDK_KEY_Escape ||
15143           event->keyval == GDK_KEY_Tab ||
15144             event->keyval == GDK_KEY_KP_Tab ||
15145             event->keyval == GDK_KEY_ISO_Left_Tab))
15146     {
15147       gtk_tree_view_search_dialog_hide (widget, tree_view,
15148                                         gdk_event_get_device ((GdkEvent *) event));
15149       return TRUE;
15150     }
15151
15152   /* select previous matching iter */
15153   if (event->keyval == GDK_KEY_Up || event->keyval == GDK_KEY_KP_Up)
15154     {
15155       if (!gtk_tree_view_search_move (widget, tree_view, TRUE))
15156         gtk_widget_error_bell (widget);
15157
15158       retval = TRUE;
15159     }
15160
15161   if (((event->state & (GTK_DEFAULT_ACCEL_MOD_MASK | GDK_SHIFT_MASK)) == (GTK_DEFAULT_ACCEL_MOD_MASK | GDK_SHIFT_MASK))
15162       && (event->keyval == GDK_KEY_g || event->keyval == GDK_KEY_G))
15163     {
15164       if (!gtk_tree_view_search_move (widget, tree_view, TRUE))
15165         gtk_widget_error_bell (widget);
15166
15167       retval = TRUE;
15168     }
15169
15170   /* select next matching iter */
15171   if (event->keyval == GDK_KEY_Down || event->keyval == GDK_KEY_KP_Down)
15172     {
15173       if (!gtk_tree_view_search_move (widget, tree_view, FALSE))
15174         gtk_widget_error_bell (widget);
15175
15176       retval = TRUE;
15177     }
15178
15179   if (((event->state & (GTK_DEFAULT_ACCEL_MOD_MASK | GDK_SHIFT_MASK)) == GTK_DEFAULT_ACCEL_MOD_MASK)
15180       && (event->keyval == GDK_KEY_g || event->keyval == GDK_KEY_G))
15181     {
15182       if (!gtk_tree_view_search_move (widget, tree_view, FALSE))
15183         gtk_widget_error_bell (widget);
15184
15185       retval = TRUE;
15186     }
15187
15188   /* renew the flush timeout */
15189   if (retval && tree_view->priv->typeselect_flush_timeout
15190       && !tree_view->priv->search_custom_entry_set)
15191     {
15192       g_source_remove (tree_view->priv->typeselect_flush_timeout);
15193       tree_view->priv->typeselect_flush_timeout =
15194         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
15195                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
15196                        tree_view);
15197     }
15198
15199   return retval;
15200 }
15201
15202 /*  this function returns FALSE if there is a search string but
15203  *  nothing was found, and TRUE otherwise.
15204  */
15205 static gboolean
15206 gtk_tree_view_search_move (GtkWidget   *window,
15207                            GtkTreeView *tree_view,
15208                            gboolean     up)
15209 {
15210   gboolean ret;
15211   gint len;
15212   gint count = 0;
15213   const gchar *text;
15214   GtkTreeIter iter;
15215   GtkTreeModel *model;
15216   GtkTreeSelection *selection;
15217
15218   text = gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry));
15219
15220   g_return_val_if_fail (text != NULL, FALSE);
15221
15222   len = strlen (text);
15223
15224   if (up && tree_view->priv->selected_iter == 1)
15225     return strlen (text) < 1;
15226
15227   len = strlen (text);
15228
15229   if (len < 1)
15230     return TRUE;
15231
15232   model = gtk_tree_view_get_model (tree_view);
15233   selection = gtk_tree_view_get_selection (tree_view);
15234
15235   /* search */
15236   gtk_tree_selection_unselect_all (selection);
15237   if (!gtk_tree_model_get_iter_first (model, &iter))
15238     return TRUE;
15239
15240   ret = gtk_tree_view_search_iter (model, selection, &iter, text,
15241                                    &count, up?((tree_view->priv->selected_iter) - 1):((tree_view->priv->selected_iter + 1)));
15242
15243   if (ret)
15244     {
15245       /* found */
15246       tree_view->priv->selected_iter += up?(-1):(1);
15247       return TRUE;
15248     }
15249   else
15250     {
15251       /* return to old iter */
15252       count = 0;
15253       gtk_tree_model_get_iter_first (model, &iter);
15254       gtk_tree_view_search_iter (model, selection,
15255                                  &iter, text,
15256                                  &count, tree_view->priv->selected_iter);
15257       return FALSE;
15258     }
15259 }
15260
15261 static gboolean
15262 gtk_tree_view_search_equal_func (GtkTreeModel *model,
15263                                  gint          column,
15264                                  const gchar  *key,
15265                                  GtkTreeIter  *iter,
15266                                  gpointer      search_data)
15267 {
15268   gboolean retval = TRUE;
15269   const gchar *str;
15270   gchar *normalized_string;
15271   gchar *normalized_key;
15272   gchar *case_normalized_string = NULL;
15273   gchar *case_normalized_key = NULL;
15274   GValue value = {0,};
15275   GValue transformed = {0,};
15276
15277   gtk_tree_model_get_value (model, iter, column, &value);
15278
15279   g_value_init (&transformed, G_TYPE_STRING);
15280
15281   if (!g_value_transform (&value, &transformed))
15282     {
15283       g_value_unset (&value);
15284       return TRUE;
15285     }
15286
15287   g_value_unset (&value);
15288
15289   str = g_value_get_string (&transformed);
15290   if (!str)
15291     {
15292       g_value_unset (&transformed);
15293       return TRUE;
15294     }
15295
15296   normalized_string = g_utf8_normalize (str, -1, G_NORMALIZE_ALL);
15297   normalized_key = g_utf8_normalize (key, -1, G_NORMALIZE_ALL);
15298
15299   if (normalized_string && normalized_key)
15300     {
15301       case_normalized_string = g_utf8_casefold (normalized_string, -1);
15302       case_normalized_key = g_utf8_casefold (normalized_key, -1);
15303
15304       if (strncmp (case_normalized_key, case_normalized_string, strlen (case_normalized_key)) == 0)
15305         retval = FALSE;
15306     }
15307
15308   g_value_unset (&transformed);
15309   g_free (normalized_key);
15310   g_free (normalized_string);
15311   g_free (case_normalized_key);
15312   g_free (case_normalized_string);
15313
15314   return retval;
15315 }
15316
15317 static gboolean
15318 gtk_tree_view_search_iter (GtkTreeModel     *model,
15319                            GtkTreeSelection *selection,
15320                            GtkTreeIter      *iter,
15321                            const gchar      *text,
15322                            gint             *count,
15323                            gint              n)
15324 {
15325   GtkRBTree *tree = NULL;
15326   GtkRBNode *node = NULL;
15327   GtkTreePath *path;
15328
15329   GtkTreeView *tree_view = gtk_tree_selection_get_tree_view (selection);
15330
15331   path = gtk_tree_model_get_path (model, iter);
15332   _gtk_tree_view_find_node (tree_view, path, &tree, &node);
15333
15334   do
15335     {
15336       if (! tree_view->priv->search_equal_func (model, tree_view->priv->search_column, text, iter, tree_view->priv->search_user_data))
15337         {
15338           (*count)++;
15339           if (*count == n)
15340             {
15341               gtk_tree_view_scroll_to_cell (tree_view, path, NULL,
15342                                             TRUE, 0.5, 0.0);
15343               gtk_tree_selection_select_iter (selection, iter);
15344               gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
15345
15346               if (path)
15347                 gtk_tree_path_free (path);
15348
15349               return TRUE;
15350             }
15351         }
15352
15353       if (node->children)
15354         {
15355           gboolean has_child;
15356           GtkTreeIter tmp;
15357
15358           tree = node->children;
15359           node = tree->root;
15360
15361           while (node->left != tree->nil)
15362             node = node->left;
15363
15364           tmp = *iter;
15365           has_child = gtk_tree_model_iter_children (model, iter, &tmp);
15366           gtk_tree_path_down (path);
15367
15368           /* sanity check */
15369           TREE_VIEW_INTERNAL_ASSERT (has_child, FALSE);
15370         }
15371       else
15372         {
15373           gboolean done = FALSE;
15374
15375           do
15376             {
15377               node = _gtk_rbtree_next (tree, node);
15378
15379               if (node)
15380                 {
15381                   gboolean has_next;
15382
15383                   has_next = gtk_tree_model_iter_next (model, iter);
15384
15385                   done = TRUE;
15386                   gtk_tree_path_next (path);
15387
15388                   /* sanity check */
15389                   TREE_VIEW_INTERNAL_ASSERT (has_next, FALSE);
15390                 }
15391               else
15392                 {
15393                   gboolean has_parent;
15394                   GtkTreeIter tmp_iter = *iter;
15395
15396                   node = tree->parent_node;
15397                   tree = tree->parent_tree;
15398
15399                   if (!tree)
15400                     {
15401                       if (path)
15402                         gtk_tree_path_free (path);
15403
15404                       /* we've run out of tree, done with this func */
15405                       return FALSE;
15406                     }
15407
15408                   has_parent = gtk_tree_model_iter_parent (model,
15409                                                            iter,
15410                                                            &tmp_iter);
15411                   gtk_tree_path_up (path);
15412
15413                   /* sanity check */
15414                   TREE_VIEW_INTERNAL_ASSERT (has_parent, FALSE);
15415                 }
15416             }
15417           while (!done);
15418         }
15419     }
15420   while (1);
15421
15422   return FALSE;
15423 }
15424
15425 static void
15426 gtk_tree_view_search_init (GtkWidget   *entry,
15427                            GtkTreeView *tree_view)
15428 {
15429   gint ret;
15430   gint count = 0;
15431   const gchar *text;
15432   GtkTreeIter iter;
15433   GtkTreeModel *model;
15434   GtkTreeSelection *selection;
15435
15436   g_return_if_fail (GTK_IS_ENTRY (entry));
15437   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15438
15439   text = gtk_entry_get_text (GTK_ENTRY (entry));
15440
15441   model = gtk_tree_view_get_model (tree_view);
15442   selection = gtk_tree_view_get_selection (tree_view);
15443
15444   /* search */
15445   gtk_tree_selection_unselect_all (selection);
15446   if (tree_view->priv->typeselect_flush_timeout
15447       && !tree_view->priv->search_custom_entry_set)
15448     {
15449       g_source_remove (tree_view->priv->typeselect_flush_timeout);
15450       tree_view->priv->typeselect_flush_timeout =
15451         gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
15452                        (GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
15453                        tree_view);
15454     }
15455
15456   if (*text == '\0')
15457     return;
15458
15459   if (!gtk_tree_model_get_iter_first (model, &iter))
15460     return;
15461
15462   ret = gtk_tree_view_search_iter (model, selection,
15463                                    &iter, text,
15464                                    &count, 1);
15465
15466   if (ret)
15467     tree_view->priv->selected_iter = 1;
15468 }
15469
15470 void
15471 _gtk_tree_view_remove_editable (GtkTreeView       *tree_view,
15472                                 GtkTreeViewColumn *column,
15473                                 GtkCellEditable   *cell_editable)
15474 {
15475   if (tree_view->priv->edited_column == NULL)
15476     return;
15477
15478   g_return_if_fail (column == tree_view->priv->edited_column);
15479
15480   tree_view->priv->edited_column = NULL;
15481
15482   if (gtk_widget_has_focus (GTK_WIDGET (cell_editable)))
15483     gtk_widget_grab_focus (GTK_WIDGET (tree_view));
15484
15485   gtk_container_remove (GTK_CONTAINER (tree_view),
15486                         GTK_WIDGET (cell_editable));
15487
15488   /* FIXME should only redraw a single node */
15489   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15490 }
15491
15492 static gboolean
15493 gtk_tree_view_start_editing (GtkTreeView *tree_view,
15494                              GtkTreePath *cursor_path,
15495                              gboolean     edit_only)
15496 {
15497   GtkTreeIter iter;
15498   GdkRectangle cell_area;
15499   GtkTreeViewColumn *focus_column;
15500   guint flags = 0; /* can be 0, as the flags are primarily for rendering */
15501   gint retval = FALSE;
15502   GtkRBTree *cursor_tree;
15503   GtkRBNode *cursor_node;
15504
15505   g_assert (tree_view->priv->focus_column);
15506   focus_column = tree_view->priv->focus_column;
15507
15508   if (!gtk_widget_get_realized (GTK_WIDGET (tree_view)))
15509     return FALSE;
15510
15511   if (_gtk_tree_view_find_node (tree_view, cursor_path, &cursor_tree, &cursor_node) ||
15512       cursor_node == NULL)
15513     return FALSE;
15514
15515   gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path);
15516
15517   validate_row (tree_view, cursor_tree, cursor_node, &iter, cursor_path);
15518
15519   gtk_tree_view_column_cell_set_cell_data (focus_column,
15520                                            tree_view->priv->model,
15521                                            &iter,
15522                                            GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_PARENT),
15523                                            cursor_node->children ? TRUE : FALSE);
15524   gtk_tree_view_get_cell_area (tree_view,
15525                                cursor_path,
15526                                focus_column,
15527                                &cell_area);
15528
15529   if (gtk_cell_area_activate (gtk_cell_layout_get_area (GTK_CELL_LAYOUT (focus_column)),
15530                               _gtk_tree_view_column_get_context (focus_column),
15531                               GTK_WIDGET (tree_view),
15532                               &cell_area,
15533                               flags, edit_only))
15534     retval = TRUE;
15535
15536   return retval;
15537 }
15538
15539 void
15540 _gtk_tree_view_add_editable (GtkTreeView       *tree_view,
15541                              GtkTreeViewColumn *column,
15542                              GtkTreePath       *path,
15543                              GtkCellEditable   *cell_editable,
15544                              GdkRectangle      *cell_area)
15545 {
15546   gint pre_val = gtk_adjustment_get_value (tree_view->priv->vadjustment);
15547   GtkRequisition requisition;
15548
15549   tree_view->priv->edited_column = column;
15550
15551   gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
15552   cell_area->y += pre_val - (int)gtk_adjustment_get_value (tree_view->priv->vadjustment);
15553
15554   gtk_widget_get_preferred_size (GTK_WIDGET (cell_editable),
15555                                  &requisition, NULL);
15556
15557   tree_view->priv->draw_keyfocus = TRUE;
15558
15559   if (requisition.height < cell_area->height)
15560     {
15561       gint diff = cell_area->height - requisition.height;
15562       gtk_tree_view_put (tree_view,
15563                          GTK_WIDGET (cell_editable),
15564                          cell_area->x, cell_area->y + diff/2,
15565                          cell_area->width, requisition.height);
15566     }
15567   else
15568     {
15569       gtk_tree_view_put (tree_view,
15570                          GTK_WIDGET (cell_editable),
15571                          cell_area->x, cell_area->y,
15572                          cell_area->width, cell_area->height);
15573     }
15574 }
15575
15576 static void
15577 gtk_tree_view_stop_editing (GtkTreeView *tree_view,
15578                             gboolean     cancel_editing)
15579 {
15580   GtkTreeViewColumn *column;
15581
15582   if (tree_view->priv->edited_column == NULL)
15583     return;
15584
15585   /*
15586    * This is very evil. We need to do this, because
15587    * gtk_cell_editable_editing_done may trigger gtk_tree_view_row_changed
15588    * later on. If gtk_tree_view_row_changed notices
15589    * tree_view->priv->edited_column != NULL, it'll call
15590    * gtk_tree_view_stop_editing again. Bad things will happen then.
15591    *
15592    * Please read that again if you intend to modify anything here.
15593    */
15594
15595   column = tree_view->priv->edited_column;
15596   gtk_cell_area_stop_editing (gtk_cell_layout_get_area (GTK_CELL_LAYOUT (column)), cancel_editing);
15597   tree_view->priv->edited_column = NULL;
15598 }
15599
15600
15601 /**
15602  * gtk_tree_view_set_hover_selection:
15603  * @tree_view: a #GtkTreeView
15604  * @hover: %TRUE to enable hover selection mode
15605  *
15606  * Enables of disables the hover selection mode of @tree_view.
15607  * Hover selection makes the selected row follow the pointer.
15608  * Currently, this works only for the selection modes 
15609  * %GTK_SELECTION_SINGLE and %GTK_SELECTION_BROWSE.
15610  * 
15611  * Since: 2.6
15612  **/
15613 void     
15614 gtk_tree_view_set_hover_selection (GtkTreeView *tree_view,
15615                                    gboolean     hover)
15616 {
15617   hover = hover != FALSE;
15618
15619   if (hover != tree_view->priv->hover_selection)
15620     {
15621       tree_view->priv->hover_selection = hover;
15622
15623       g_object_notify (G_OBJECT (tree_view), "hover-selection");
15624     }
15625 }
15626
15627 /**
15628  * gtk_tree_view_get_hover_selection:
15629  * @tree_view: a #GtkTreeView
15630  * 
15631  * Returns whether hover selection mode is turned on for @tree_view.
15632  * 
15633  * Return value: %TRUE if @tree_view is in hover selection mode
15634  *
15635  * Since: 2.6 
15636  **/
15637 gboolean 
15638 gtk_tree_view_get_hover_selection (GtkTreeView *tree_view)
15639 {
15640   return tree_view->priv->hover_selection;
15641 }
15642
15643 /**
15644  * gtk_tree_view_set_hover_expand:
15645  * @tree_view: a #GtkTreeView
15646  * @expand: %TRUE to enable hover selection mode
15647  *
15648  * Enables of disables the hover expansion mode of @tree_view.
15649  * Hover expansion makes rows expand or collapse if the pointer 
15650  * moves over them.
15651  * 
15652  * Since: 2.6
15653  **/
15654 void     
15655 gtk_tree_view_set_hover_expand (GtkTreeView *tree_view,
15656                                 gboolean     expand)
15657 {
15658   expand = expand != FALSE;
15659
15660   if (expand != tree_view->priv->hover_expand)
15661     {
15662       tree_view->priv->hover_expand = expand;
15663
15664       g_object_notify (G_OBJECT (tree_view), "hover-expand");
15665     }
15666 }
15667
15668 /**
15669  * gtk_tree_view_get_hover_expand:
15670  * @tree_view: a #GtkTreeView
15671  * 
15672  * Returns whether hover expansion mode is turned on for @tree_view.
15673  * 
15674  * Return value: %TRUE if @tree_view is in hover expansion mode
15675  *
15676  * Since: 2.6 
15677  **/
15678 gboolean 
15679 gtk_tree_view_get_hover_expand (GtkTreeView *tree_view)
15680 {
15681   return tree_view->priv->hover_expand;
15682 }
15683
15684 /**
15685  * gtk_tree_view_set_rubber_banding:
15686  * @tree_view: a #GtkTreeView
15687  * @enable: %TRUE to enable rubber banding
15688  *
15689  * Enables or disables rubber banding in @tree_view.  If the selection mode
15690  * is #GTK_SELECTION_MULTIPLE, rubber banding will allow the user to select
15691  * multiple rows by dragging the mouse.
15692  * 
15693  * Since: 2.10
15694  **/
15695 void
15696 gtk_tree_view_set_rubber_banding (GtkTreeView *tree_view,
15697                                   gboolean     enable)
15698 {
15699   enable = enable != FALSE;
15700
15701   if (enable != tree_view->priv->rubber_banding_enable)
15702     {
15703       tree_view->priv->rubber_banding_enable = enable;
15704
15705       g_object_notify (G_OBJECT (tree_view), "rubber-banding");
15706     }
15707 }
15708
15709 /**
15710  * gtk_tree_view_get_rubber_banding:
15711  * @tree_view: a #GtkTreeView
15712  * 
15713  * Returns whether rubber banding is turned on for @tree_view.  If the
15714  * selection mode is #GTK_SELECTION_MULTIPLE, rubber banding will allow the
15715  * user to select multiple rows by dragging the mouse.
15716  * 
15717  * Return value: %TRUE if rubber banding in @tree_view is enabled.
15718  *
15719  * Since: 2.10
15720  **/
15721 gboolean
15722 gtk_tree_view_get_rubber_banding (GtkTreeView *tree_view)
15723 {
15724   return tree_view->priv->rubber_banding_enable;
15725 }
15726
15727 /**
15728  * gtk_tree_view_is_rubber_banding_active:
15729  * @tree_view: a #GtkTreeView
15730  * 
15731  * Returns whether a rubber banding operation is currently being done
15732  * in @tree_view.
15733  *
15734  * Return value: %TRUE if a rubber banding operation is currently being
15735  * done in @tree_view.
15736  *
15737  * Since: 2.12
15738  **/
15739 gboolean
15740 gtk_tree_view_is_rubber_banding_active (GtkTreeView *tree_view)
15741 {
15742   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15743
15744   if (tree_view->priv->rubber_banding_enable
15745       && tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
15746     return TRUE;
15747
15748   return FALSE;
15749 }
15750
15751 /**
15752  * gtk_tree_view_get_row_separator_func: (skip)
15753  * @tree_view: a #GtkTreeView
15754  * 
15755  * Returns the current row separator function.
15756  * 
15757  * Return value: the current row separator function.
15758  *
15759  * Since: 2.6
15760  **/
15761 GtkTreeViewRowSeparatorFunc 
15762 gtk_tree_view_get_row_separator_func (GtkTreeView *tree_view)
15763 {
15764   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
15765
15766   return tree_view->priv->row_separator_func;
15767 }
15768
15769 /**
15770  * gtk_tree_view_set_row_separator_func:
15771  * @tree_view: a #GtkTreeView
15772  * @func: (allow-none): a #GtkTreeViewRowSeparatorFunc
15773  * @data: (allow-none): user data to pass to @func, or %NULL
15774  * @destroy: (allow-none): destroy notifier for @data, or %NULL
15775  * 
15776  * Sets the row separator function, which is used to determine
15777  * whether a row should be drawn as a separator. If the row separator
15778  * function is %NULL, no separators are drawn. This is the default value.
15779  *
15780  * Since: 2.6
15781  **/
15782 void
15783 gtk_tree_view_set_row_separator_func (GtkTreeView                 *tree_view,
15784                                       GtkTreeViewRowSeparatorFunc  func,
15785                                       gpointer                     data,
15786                                       GDestroyNotify               destroy)
15787 {
15788   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15789
15790   if (tree_view->priv->row_separator_destroy)
15791     tree_view->priv->row_separator_destroy (tree_view->priv->row_separator_data);
15792
15793   tree_view->priv->row_separator_func = func;
15794   tree_view->priv->row_separator_data = data;
15795   tree_view->priv->row_separator_destroy = destroy;
15796
15797   /* Have the tree recalculate heights */
15798   _gtk_rbtree_mark_invalid (tree_view->priv->tree);
15799   gtk_widget_queue_resize (GTK_WIDGET (tree_view));
15800 }
15801
15802   
15803 static void
15804 gtk_tree_view_grab_notify (GtkWidget *widget,
15805                            gboolean   was_grabbed)
15806 {
15807   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
15808
15809   tree_view->priv->in_grab = !was_grabbed;
15810
15811   if (!was_grabbed)
15812     {
15813       tree_view->priv->pressed_button = -1;
15814
15815       if (tree_view->priv->rubber_band_status)
15816         gtk_tree_view_stop_rubber_band (tree_view);
15817     }
15818 }
15819
15820 static void
15821 gtk_tree_view_state_flags_changed (GtkWidget     *widget,
15822                                    GtkStateFlags  previous_state)
15823 {
15824   if (gtk_widget_get_realized (widget))
15825     {
15826       GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
15827       GtkStyleContext *context;
15828
15829       context = gtk_widget_get_style_context (widget);
15830       gtk_style_context_set_background (context, tree_view->priv->bin_window);
15831     }
15832
15833   gtk_widget_queue_draw (widget);
15834 }
15835
15836 /**
15837  * gtk_tree_view_get_grid_lines:
15838  * @tree_view: a #GtkTreeView
15839  *
15840  * Returns which grid lines are enabled in @tree_view.
15841  *
15842  * Return value: a #GtkTreeViewGridLines value indicating which grid lines
15843  * are enabled.
15844  *
15845  * Since: 2.10
15846  */
15847 GtkTreeViewGridLines
15848 gtk_tree_view_get_grid_lines (GtkTreeView *tree_view)
15849 {
15850   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
15851
15852   return tree_view->priv->grid_lines;
15853 }
15854
15855 /**
15856  * gtk_tree_view_set_grid_lines:
15857  * @tree_view: a #GtkTreeView
15858  * @grid_lines: a #GtkTreeViewGridLines value indicating which grid lines to
15859  * enable.
15860  *
15861  * Sets which grid lines to draw in @tree_view.
15862  *
15863  * Since: 2.10
15864  */
15865 void
15866 gtk_tree_view_set_grid_lines (GtkTreeView           *tree_view,
15867                               GtkTreeViewGridLines   grid_lines)
15868 {
15869   GtkTreeViewPrivate *priv;
15870   GtkWidget *widget;
15871   GtkTreeViewGridLines old_grid_lines;
15872
15873   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15874
15875   priv = tree_view->priv;
15876   widget = GTK_WIDGET (tree_view);
15877
15878   old_grid_lines = priv->grid_lines;
15879   priv->grid_lines = grid_lines;
15880   
15881   if (gtk_widget_get_realized (widget))
15882     {
15883       if (grid_lines == GTK_TREE_VIEW_GRID_LINES_NONE &&
15884           priv->grid_line_width)
15885         {
15886           priv->grid_line_width = 0;
15887         }
15888       
15889       if (grid_lines != GTK_TREE_VIEW_GRID_LINES_NONE && 
15890           !priv->grid_line_width)
15891         {
15892           gint8 *dash_list;
15893
15894           gtk_widget_style_get (widget,
15895                                 "grid-line-width", &priv->grid_line_width,
15896                                 "grid-line-pattern", (gchar *)&dash_list,
15897                                 NULL);
15898       
15899           if (dash_list)
15900             {
15901               priv->grid_line_dashes[0] = dash_list[0];
15902               if (dash_list[0])
15903                 priv->grid_line_dashes[1] = dash_list[1];
15904               
15905               g_free (dash_list);
15906             }
15907           else
15908             {
15909               priv->grid_line_dashes[0] = 1;
15910               priv->grid_line_dashes[1] = 1;
15911             }
15912         }      
15913     }
15914
15915   if (old_grid_lines != grid_lines)
15916     {
15917       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
15918       
15919       g_object_notify (G_OBJECT (tree_view), "enable-grid-lines");
15920     }
15921 }
15922
15923 /**
15924  * gtk_tree_view_get_enable_tree_lines:
15925  * @tree_view: a #GtkTreeView.
15926  *
15927  * Returns whether or not tree lines are drawn in @tree_view.
15928  *
15929  * Return value: %TRUE if tree lines are drawn in @tree_view, %FALSE
15930  * otherwise.
15931  *
15932  * Since: 2.10
15933  */
15934 gboolean
15935 gtk_tree_view_get_enable_tree_lines (GtkTreeView *tree_view)
15936 {
15937   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
15938
15939   return tree_view->priv->tree_lines_enabled;
15940 }
15941
15942 /**
15943  * gtk_tree_view_set_enable_tree_lines:
15944  * @tree_view: a #GtkTreeView
15945  * @enabled: %TRUE to enable tree line drawing, %FALSE otherwise.
15946  *
15947  * Sets whether to draw lines interconnecting the expanders in @tree_view.
15948  * This does not have any visible effects for lists.
15949  *
15950  * Since: 2.10
15951  */
15952 void
15953 gtk_tree_view_set_enable_tree_lines (GtkTreeView *tree_view,
15954                                      gboolean     enabled)
15955 {
15956   GtkTreeViewPrivate *priv;
15957   GtkWidget *widget;
15958   gboolean was_enabled;
15959
15960   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
15961
15962   enabled = enabled != FALSE;
15963
15964   priv = tree_view->priv;
15965   widget = GTK_WIDGET (tree_view);
15966
15967   was_enabled = priv->tree_lines_enabled;
15968
15969   priv->tree_lines_enabled = enabled;
15970
15971   if (gtk_widget_get_realized (widget))
15972     {
15973       if (!enabled && priv->tree_line_width)
15974         {
15975           priv->tree_line_width = 0;
15976         }
15977       
15978       if (enabled && !priv->tree_line_width)
15979         {
15980           gint8 *dash_list;
15981           gtk_widget_style_get (widget,
15982                                 "tree-line-width", &priv->tree_line_width,
15983                                 "tree-line-pattern", (gchar *)&dash_list,
15984                                 NULL);
15985           
15986           if (dash_list)
15987             {
15988               priv->tree_line_dashes[0] = dash_list[0];
15989               if (dash_list[0])
15990                 priv->tree_line_dashes[1] = dash_list[1];
15991               
15992               g_free (dash_list);
15993             }
15994           else
15995             {
15996               priv->tree_line_dashes[0] = 1;
15997               priv->tree_line_dashes[1] = 1;
15998             }
15999         }
16000     }
16001
16002   if (was_enabled != enabled)
16003     {
16004       gtk_widget_queue_draw (GTK_WIDGET (tree_view));
16005
16006       g_object_notify (G_OBJECT (tree_view), "enable-tree-lines");
16007     }
16008 }
16009
16010
16011 /**
16012  * gtk_tree_view_set_show_expanders:
16013  * @tree_view: a #GtkTreeView
16014  * @enabled: %TRUE to enable expander drawing, %FALSE otherwise.
16015  *
16016  * Sets whether to draw and enable expanders and indent child rows in
16017  * @tree_view.  When disabled there will be no expanders visible in trees
16018  * and there will be no way to expand and collapse rows by default.  Also
16019  * note that hiding the expanders will disable the default indentation.  You
16020  * can set a custom indentation in this case using
16021  * gtk_tree_view_set_level_indentation().
16022  * This does not have any visible effects for lists.
16023  *
16024  * Since: 2.12
16025  */
16026 void
16027 gtk_tree_view_set_show_expanders (GtkTreeView *tree_view,
16028                                   gboolean     enabled)
16029 {
16030   gboolean was_enabled;
16031
16032   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
16033
16034   enabled = enabled != FALSE;
16035   was_enabled = tree_view->priv->show_expanders;
16036
16037   tree_view->priv->show_expanders = enabled == TRUE;
16038
16039   if (enabled != was_enabled)
16040     gtk_widget_queue_draw (GTK_WIDGET (tree_view));
16041 }
16042
16043 /**
16044  * gtk_tree_view_get_show_expanders:
16045  * @tree_view: a #GtkTreeView.
16046  *
16047  * Returns whether or not expanders are drawn in @tree_view.
16048  *
16049  * Return value: %TRUE if expanders are drawn in @tree_view, %FALSE
16050  * otherwise.
16051  *
16052  * Since: 2.12
16053  */
16054 gboolean
16055 gtk_tree_view_get_show_expanders (GtkTreeView *tree_view)
16056 {
16057   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
16058
16059   return tree_view->priv->show_expanders;
16060 }
16061
16062 /**
16063  * gtk_tree_view_set_level_indentation:
16064  * @tree_view: a #GtkTreeView
16065  * @indentation: the amount, in pixels, of extra indentation in @tree_view.
16066  *
16067  * Sets the amount of extra indentation for child levels to use in @tree_view
16068  * in addition to the default indentation.  The value should be specified in
16069  * pixels, a value of 0 disables this feature and in this case only the default
16070  * indentation will be used.
16071  * This does not have any visible effects for lists.
16072  *
16073  * Since: 2.12
16074  */
16075 void
16076 gtk_tree_view_set_level_indentation (GtkTreeView *tree_view,
16077                                      gint         indentation)
16078 {
16079   tree_view->priv->level_indentation = indentation;
16080
16081   gtk_widget_queue_draw (GTK_WIDGET (tree_view));
16082 }
16083
16084 /**
16085  * gtk_tree_view_get_level_indentation:
16086  * @tree_view: a #GtkTreeView.
16087  *
16088  * Returns the amount, in pixels, of extra indentation for child levels
16089  * in @tree_view.
16090  *
16091  * Return value: the amount of extra indentation for child levels in
16092  * @tree_view.  A return value of 0 means that this feature is disabled.
16093  *
16094  * Since: 2.12
16095  */
16096 gint
16097 gtk_tree_view_get_level_indentation (GtkTreeView *tree_view)
16098 {
16099   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
16100
16101   return tree_view->priv->level_indentation;
16102 }
16103
16104 /**
16105  * gtk_tree_view_set_tooltip_row:
16106  * @tree_view: a #GtkTreeView
16107  * @tooltip: a #GtkTooltip
16108  * @path: a #GtkTreePath
16109  *
16110  * Sets the tip area of @tooltip to be the area covered by the row at @path.
16111  * See also gtk_tree_view_set_tooltip_column() for a simpler alternative.
16112  * See also gtk_tooltip_set_tip_area().
16113  *
16114  * Since: 2.12
16115  */
16116 void
16117 gtk_tree_view_set_tooltip_row (GtkTreeView *tree_view,
16118                                GtkTooltip  *tooltip,
16119                                GtkTreePath *path)
16120 {
16121   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
16122   g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
16123
16124   gtk_tree_view_set_tooltip_cell (tree_view, tooltip, path, NULL, NULL);
16125 }
16126
16127 /**
16128  * gtk_tree_view_set_tooltip_cell:
16129  * @tree_view: a #GtkTreeView
16130  * @tooltip: a #GtkTooltip
16131  * @path: (allow-none): a #GtkTreePath or %NULL
16132  * @column: (allow-none): a #GtkTreeViewColumn or %NULL
16133  * @cell: (allow-none): a #GtkCellRenderer or %NULL
16134  *
16135  * Sets the tip area of @tooltip to the area @path, @column and @cell have
16136  * in common.  For example if @path is %NULL and @column is set, the tip
16137  * area will be set to the full area covered by @column.  See also
16138  * gtk_tooltip_set_tip_area().
16139  *
16140  * Note that if @path is not specified and @cell is set and part of a column
16141  * containing the expander, the tooltip might not show and hide at the correct
16142  * position.  In such cases @path must be set to the current node under the
16143  * mouse cursor for this function to operate correctly.
16144  *
16145  * See also gtk_tree_view_set_tooltip_column() for a simpler alternative.
16146  *
16147  * Since: 2.12
16148  */
16149 void
16150 gtk_tree_view_set_tooltip_cell (GtkTreeView       *tree_view,
16151                                 GtkTooltip        *tooltip,
16152                                 GtkTreePath       *path,
16153                                 GtkTreeViewColumn *column,
16154                                 GtkCellRenderer   *cell)
16155 {
16156   GtkAllocation allocation;
16157   GdkRectangle rect;
16158
16159   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
16160   g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
16161   g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
16162   g_return_if_fail (cell == NULL || GTK_IS_CELL_RENDERER (cell));
16163
16164   /* Determine x values. */
16165   if (column && cell)
16166     {
16167       GdkRectangle tmp;
16168       gint start, width;
16169
16170       /* We always pass in path here, whether it is NULL or not.
16171        * For cells in expander columns path must be specified so that
16172        * we can correctly account for the indentation.  This also means
16173        * that the tooltip is constrained vertically by the "Determine y
16174        * values" code below; this is not a real problem since cells actually
16175        * don't stretch vertically in constrast to columns.
16176        */
16177       gtk_tree_view_get_cell_area (tree_view, path, column, &tmp);
16178       gtk_tree_view_column_cell_get_position (column, cell, &start, &width);
16179
16180       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
16181                                                          tmp.x + start, 0,
16182                                                          &rect.x, NULL);
16183       rect.width = width;
16184     }
16185   else if (column)
16186     {
16187       GdkRectangle tmp;
16188
16189       gtk_tree_view_get_background_area (tree_view, NULL, column, &tmp);
16190       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
16191                                                          tmp.x, 0,
16192                                                          &rect.x, NULL);
16193       rect.width = tmp.width;
16194     }
16195   else
16196     {
16197       gtk_widget_get_allocation (GTK_WIDGET (tree_view), &allocation);
16198       rect.x = 0;
16199       rect.width = allocation.width;
16200     }
16201
16202   /* Determine y values. */
16203   if (path)
16204     {
16205       GdkRectangle tmp;
16206
16207       gtk_tree_view_get_background_area (tree_view, path, NULL, &tmp);
16208       gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
16209                                                          0, tmp.y,
16210                                                          NULL, &rect.y);
16211       rect.height = tmp.height;
16212     }
16213   else
16214     {
16215       rect.y = 0;
16216       rect.height = gtk_adjustment_get_page_size (tree_view->priv->vadjustment);
16217     }
16218
16219   gtk_tooltip_set_tip_area (tooltip, &rect);
16220 }
16221
16222 /**
16223  * gtk_tree_view_get_tooltip_context:
16224  * @tree_view: a #GtkTreeView
16225  * @x: (inout): the x coordinate (relative to widget coordinates)
16226  * @y: (inout): the y coordinate (relative to widget coordinates)
16227  * @keyboard_tip: whether this is a keyboard tooltip or not
16228  * @model: (out) (allow-none): a pointer to receive a #GtkTreeModel or %NULL
16229  * @path: (out) (allow-none): a pointer to receive a #GtkTreePath or %NULL
16230  * @iter: (out) (allow-none): a pointer to receive a #GtkTreeIter or %NULL
16231  *
16232  * This function is supposed to be used in a #GtkWidget::query-tooltip
16233  * signal handler for #GtkTreeView.  The @x, @y and @keyboard_tip values
16234  * which are received in the signal handler, should be passed to this
16235  * function without modification.
16236  *
16237  * The return value indicates whether there is a tree view row at the given
16238  * coordinates (%TRUE) or not (%FALSE) for mouse tooltips.  For keyboard
16239  * tooltips the row returned will be the cursor row.  When %TRUE, then any of
16240  * @model, @path and @iter which have been provided will be set to point to
16241  * that row and the corresponding model.  @x and @y will always be converted
16242  * to be relative to @tree_view's bin_window if @keyboard_tooltip is %FALSE.
16243  *
16244  * Return value: whether or not the given tooltip context points to a row.
16245  *
16246  * Since: 2.12
16247  */
16248 gboolean
16249 gtk_tree_view_get_tooltip_context (GtkTreeView   *tree_view,
16250                                    gint          *x,
16251                                    gint          *y,
16252                                    gboolean       keyboard_tip,
16253                                    GtkTreeModel **model,
16254                                    GtkTreePath  **path,
16255                                    GtkTreeIter   *iter)
16256 {
16257   GtkTreePath *tmppath = NULL;
16258
16259   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
16260   g_return_val_if_fail (x != NULL, FALSE);
16261   g_return_val_if_fail (y != NULL, FALSE);
16262
16263   if (keyboard_tip)
16264     {
16265       gtk_tree_view_get_cursor (tree_view, &tmppath, NULL);
16266
16267       if (!tmppath)
16268         return FALSE;
16269     }
16270   else
16271     {
16272       gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, *x, *y,
16273                                                          x, y);
16274
16275       if (!gtk_tree_view_get_path_at_pos (tree_view, *x, *y,
16276                                           &tmppath, NULL, NULL, NULL))
16277         return FALSE;
16278     }
16279
16280   if (model)
16281     *model = gtk_tree_view_get_model (tree_view);
16282
16283   if (iter)
16284     gtk_tree_model_get_iter (gtk_tree_view_get_model (tree_view),
16285                              iter, tmppath);
16286
16287   if (path)
16288     *path = tmppath;
16289   else
16290     gtk_tree_path_free (tmppath);
16291
16292   return TRUE;
16293 }
16294
16295 static gboolean
16296 gtk_tree_view_set_tooltip_query_cb (GtkWidget  *widget,
16297                                     gint        x,
16298                                     gint        y,
16299                                     gboolean    keyboard_tip,
16300                                     GtkTooltip *tooltip,
16301                                     gpointer    data)
16302 {
16303   GValue value = { 0, };
16304   GValue transformed = { 0, };
16305   GtkTreeIter iter;
16306   GtkTreePath *path;
16307   GtkTreeModel *model;
16308   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
16309
16310   if (!gtk_tree_view_get_tooltip_context (GTK_TREE_VIEW (widget),
16311                                           &x, &y,
16312                                           keyboard_tip,
16313                                           &model, &path, &iter))
16314     return FALSE;
16315
16316   gtk_tree_model_get_value (model, &iter,
16317                             tree_view->priv->tooltip_column, &value);
16318
16319   g_value_init (&transformed, G_TYPE_STRING);
16320
16321   if (!g_value_transform (&value, &transformed))
16322     {
16323       g_value_unset (&value);
16324       gtk_tree_path_free (path);
16325
16326       return FALSE;
16327     }
16328
16329   g_value_unset (&value);
16330
16331   if (!g_value_get_string (&transformed))
16332     {
16333       g_value_unset (&transformed);
16334       gtk_tree_path_free (path);
16335
16336       return FALSE;
16337     }
16338
16339   gtk_tooltip_set_markup (tooltip, g_value_get_string (&transformed));
16340   gtk_tree_view_set_tooltip_row (tree_view, tooltip, path);
16341
16342   gtk_tree_path_free (path);
16343   g_value_unset (&transformed);
16344
16345   return TRUE;
16346 }
16347
16348 /**
16349  * gtk_tree_view_set_tooltip_column:
16350  * @tree_view: a #GtkTreeView
16351  * @column: an integer, which is a valid column number for @tree_view's model
16352  *
16353  * If you only plan to have simple (text-only) tooltips on full rows, you
16354  * can use this function to have #GtkTreeView handle these automatically
16355  * for you. @column should be set to the column in @tree_view's model
16356  * containing the tooltip texts, or -1 to disable this feature.
16357  *
16358  * When enabled, #GtkWidget::has-tooltip will be set to %TRUE and
16359  * @tree_view will connect a #GtkWidget::query-tooltip signal handler.
16360  *
16361  * Note that the signal handler sets the text with gtk_tooltip_set_markup(),
16362  * so &amp;, &lt;, etc have to be escaped in the text.
16363  *
16364  * Since: 2.12
16365  */
16366 void
16367 gtk_tree_view_set_tooltip_column (GtkTreeView *tree_view,
16368                                   gint         column)
16369 {
16370   g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
16371
16372   if (column == tree_view->priv->tooltip_column)
16373     return;
16374
16375   if (column == -1)
16376     {
16377       g_signal_handlers_disconnect_by_func (tree_view,
16378                                             gtk_tree_view_set_tooltip_query_cb,
16379                                             NULL);
16380       gtk_widget_set_has_tooltip (GTK_WIDGET (tree_view), FALSE);
16381     }
16382   else
16383     {
16384       if (tree_view->priv->tooltip_column == -1)
16385         {
16386           g_signal_connect (tree_view, "query-tooltip",
16387                             G_CALLBACK (gtk_tree_view_set_tooltip_query_cb), NULL);
16388           gtk_widget_set_has_tooltip (GTK_WIDGET (tree_view), TRUE);
16389         }
16390     }
16391
16392   tree_view->priv->tooltip_column = column;
16393   g_object_notify (G_OBJECT (tree_view), "tooltip-column");
16394 }
16395
16396 /**
16397  * gtk_tree_view_get_tooltip_column:
16398  * @tree_view: a #GtkTreeView
16399  *
16400  * Returns the column of @tree_view's model which is being used for
16401  * displaying tooltips on @tree_view's rows.
16402  *
16403  * Return value: the index of the tooltip column that is currently being
16404  * used, or -1 if this is disabled.
16405  *
16406  * Since: 2.12
16407  */
16408 gint
16409 gtk_tree_view_get_tooltip_column (GtkTreeView *tree_view)
16410 {
16411   g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
16412
16413   return tree_view->priv->tooltip_column;
16414 }